From 9c7aa8b3336216c5d9ac0b0024dca01174bb0a34 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 14 Feb 2023 14:46:08 +0000 Subject: [PATCH 01/20] Map Updates Allow OpenSkyNetwork DB, OpenAIP and OurAirports DB stuctures to be shared by different plugins, to speed up loading. Perform map anti-aliasing on the whole map, rather than just info boxes, to improve rendering speed when there are many items. Add map multisampling as a preference. Add plotting of airspaces, airports, navaids on Map feature. Add support for polylines and polygons to be plotted on Map feature. Add support for images to 2D Map feature. Add distance and name filters to Map feature. Filter map items when zoomed out or if off screen, to improve rendering performance. Add UK DAB, FM and AM transmitters to Map feature. Use labelless maps for 2D transmit maps in Map feature (same as in ADS-B demod). --- plugins/channelrx/demodadsb/CMakeLists.txt | 1 - plugins/channelrx/demodadsb/adsbdemodgui.cpp | 398 +- plugins/channelrx/demodadsb/adsbdemodgui.h | 56 +- plugins/channelrx/demodadsb/adsbdemodgui.ui | 3 + plugins/channelrx/demodadsb/map/map.qml | 16 +- plugins/channelrx/demodadsb/ourairportsdb.h | 303 -- plugins/feature/map/CMakeLists.txt | 3 + plugins/feature/map/cesiuminterface.cpp | 19 +- plugins/feature/map/cesiuminterface.h | 9 +- plugins/feature/map/czml.cpp | 185 +- plugins/feature/map/czml.h | 11 +- plugins/feature/map/data.qrc | 5 + plugins/feature/map/data/transmitters.csv | 3478 +++++++++++++++++ plugins/feature/map/icons.qrc | 2 + plugins/feature/map/icons/controltower.png | Bin 0 -> 308 bytes plugins/feature/map/icons/vor.png | Bin 0 -> 365 bytes plugins/feature/map/map.qrc | 12 + plugins/feature/map/map/DME.png | Bin 0 -> 10606 bytes plugins/feature/map/map/DVOR-DME.png | Bin 0 -> 652 bytes plugins/feature/map/map/DVOR.png | Bin 0 -> 415 bytes plugins/feature/map/map/DVORTAC.png | Bin 0 -> 847 bytes plugins/feature/map/map/NDB.png | Bin 0 -> 674 bytes plugins/feature/map/map/VOR-DME.png | Bin 0 -> 652 bytes plugins/feature/map/map/VOR.png | Bin 0 -> 415 bytes plugins/feature/map/map/VORTAC.png | Bin 0 -> 847 bytes plugins/feature/map/map/airport_large.png | Bin 0 -> 1261 bytes plugins/feature/map/map/airport_medium.png | Bin 0 -> 1015 bytes plugins/feature/map/map/airport_small.png | Bin 0 -> 1084 bytes plugins/feature/map/map/heliport.png | Bin 0 -> 1131 bytes plugins/feature/map/map/map.qml | 146 +- plugins/feature/map/map/map3d.html | 27 +- plugins/feature/map/mapgui.cpp | 495 ++- plugins/feature/map/mapgui.h | 25 +- plugins/feature/map/mapitem.cpp | 288 ++ plugins/feature/map/mapitem.h | 184 + plugins/feature/map/mapmodel.cpp | 1068 +++-- plugins/feature/map/mapmodel.h | 452 ++- plugins/feature/map/mapsettings.cpp | 128 +- plugins/feature/map/mapsettings.h | 22 +- plugins/feature/map/mapsettingsdialog.cpp | 130 +- plugins/feature/map/mapsettingsdialog.h | 23 +- plugins/feature/map/mapsettingsdialog.ui | 237 +- plugins/feature/map/osmtemplateserver.h | 19 + plugins/feature/map/readme.md | 7 +- sdrbase/CMakeLists.txt | 3 + sdrbase/settings/mainsettings.h | 7 + sdrbase/settings/preferences.cpp | 3 + sdrbase/settings/preferences.h | 9 +- sdrbase/util/openaip.cpp | 320 +- sdrbase/util/openaip.h | 268 +- sdrbase/util/osndb.cpp | 546 +++ sdrbase/util/osndb.h | 501 +-- sdrbase/util/ourairportsdb.cpp | 419 ++ sdrbase/util/ourairportsdb.h | 119 + sdrgui/gui/graphicsdialog.cpp | 7 + sdrgui/gui/graphicsdialog.ui | 145 +- swagger/sdrangel/api/swagger/include/Map.yaml | 20 +- .../sdrangel/code/qt5/client/SWGMapItem.cpp | 100 + swagger/sdrangel/code/qt5/client/SWGMapItem.h | 24 + .../sdrangel/code/qt5/client/SWGMapItem_2.cpp | 100 + .../sdrangel/code/qt5/client/SWGMapItem_2.h | 24 + 61 files changed, 8373 insertions(+), 1994 deletions(-) delete mode 100644 plugins/channelrx/demodadsb/ourairportsdb.h create mode 100644 plugins/feature/map/data.qrc create mode 100644 plugins/feature/map/data/transmitters.csv create mode 100644 plugins/feature/map/icons/controltower.png create mode 100644 plugins/feature/map/icons/vor.png create mode 100644 plugins/feature/map/map/DME.png create mode 100644 plugins/feature/map/map/DVOR-DME.png create mode 100644 plugins/feature/map/map/DVOR.png create mode 100644 plugins/feature/map/map/DVORTAC.png create mode 100644 plugins/feature/map/map/NDB.png create mode 100644 plugins/feature/map/map/VOR-DME.png create mode 100644 plugins/feature/map/map/VOR.png create mode 100644 plugins/feature/map/map/VORTAC.png create mode 100644 plugins/feature/map/map/airport_large.png create mode 100644 plugins/feature/map/map/airport_medium.png create mode 100644 plugins/feature/map/map/airport_small.png create mode 100644 plugins/feature/map/map/heliport.png create mode 100644 plugins/feature/map/mapitem.cpp create mode 100644 plugins/feature/map/mapitem.h create mode 100644 sdrbase/util/ourairportsdb.cpp create mode 100644 sdrbase/util/ourairportsdb.h diff --git a/plugins/channelrx/demodadsb/CMakeLists.txt b/plugins/channelrx/demodadsb/CMakeLists.txt index 02078f24a..6d2e72368 100644 --- a/plugins/channelrx/demodadsb/CMakeLists.txt +++ b/plugins/channelrx/demodadsb/CMakeLists.txt @@ -29,7 +29,6 @@ set(adsb_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${Boost_INCLUDE_DIRS} - ${Qt${QT_DEFAULT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS} ) if(NOT SERVER_MODE) diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index 3b404e035..446ce3f46 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -35,8 +35,6 @@ #include #include -#include - #include "ui_adsbdemodgui.h" #include "device/deviceapi.h" #include "channel/channelwebapiutils.h" @@ -531,14 +529,7 @@ QVariant AirportModel::data(const QModelIndex &index, int role) const else if (role == AirportModel::airportImageRole) { // Select an image to use for the airport - if (m_airports[row]->m_type == ADSBDemodSettings::AirportType::Large) - return QVariant::fromValue(QString("airport_large.png")); - else if (m_airports[row]->m_type == ADSBDemodSettings::AirportType::Medium) - return QVariant::fromValue(QString("airport_medium.png")); - else if (m_airports[row]->m_type == ADSBDemodSettings::AirportType::Heliport) - return QVariant::fromValue(QString("heliport.png")); - else - return QVariant::fromValue(QString("airport_small.png")); + return QVariant::fromValue(m_airports[row]->getImageName()); } else if (role == AirportModel::bubbleColourRole) { @@ -618,23 +609,17 @@ QVariant AirspaceModel::data(const QModelIndex &index, int role) const } else if (role == AirspaceModel::airspaceBorderColorRole) { - if (m_airspaces[row]->m_category == "D") - { - return QVariant::fromValue(QColor("blue")); - } - else - { - return QVariant::fromValue(QColor("red")); + if (m_airspaces[row]->m_category == "D") { + return QVariant::fromValue(QColor(0x00, 0x00, 0xff, 0x00)); + } else { + return QVariant::fromValue(QColor(0xff, 0x00, 0x00, 0x00)); } } else if (role == AirspaceModel::airspaceFillColorRole) { - if (m_airspaces[row]->m_category == "D") - { + if (m_airspaces[row]->m_category == "D") { return QVariant::fromValue(QColor(0x00, 0x00, 0xff, 0x10)); - } - else - { + } else { return QVariant::fromValue(QColor(0xff, 0x00, 0x00, 0x10)); } } @@ -789,6 +774,22 @@ bool ADSBDemodGUI::updateLocalPosition(Aircraft *aircraft, double latitude, doub } } +void ADSBDemodGUI::clearFromMap(const QString& name) +{ + QList mapPipes; + MainCore::instance()->getMessagePipes().getMessagePipes(m_adsbDemod, "mapitems", mapPipes); + + for (const auto& pipe : mapPipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + swgMapItem->setName(new QString(name)); + swgMapItem->setImage(new QString("")); + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_adsbDemod, swgMapItem); + messageQueue->push(msg); + } +} + void ADSBDemodGUI::sendToMap(Aircraft *aircraft, QList *animations) { // Send to Map feature @@ -817,6 +818,7 @@ void ADSBDemodGUI::sendToMap(Aircraft *aircraft, QListsetAltitude(altitudeM); swgMapItem->setPositionDateTime(new QString(aircraft->m_positionDateTime.toString(Qt::ISODateWithMs))); swgMapItem->setFixedPosition(false); + swgMapItem->setAvailableUntil(new QString(aircraft->m_positionDateTime.addSecs(60).toString(Qt::ISODateWithMs))); swgMapItem->setImage(new QString(QString("qrc:///map/%1").arg(aircraft->getImage()))); swgMapItem->setImageRotation(aircraft->m_heading); swgMapItem->setText(new QString(aircraft->getText(true))); @@ -996,9 +998,12 @@ Aircraft *ADSBDemodGUI::getAircraft(int icao, bool &newAircraft) } } - if (m_settings.m_autoResizeTableColumns) - ui->adsbData->resizeColumnsToContents(); - ui->adsbData->setSortingEnabled(true); + if (!m_loadingData) + { + if (m_settings.m_autoResizeTableColumns) + ui->adsbData->resizeColumnsToContents(); + ui->adsbData->setSortingEnabled(true); + } // Check to see if we need to emit a notification about this new aircraft checkStaticNotification(aircraft); } @@ -3586,17 +3591,10 @@ void ADSBDemodGUI::on_getOSNDB_clicked() // Don't try to download while already in progress if (m_progressDialog == nullptr) { - QString osnDBFilename = AircraftInformation::getOSNDBZipFilename(); - if (confirmDownload(osnDBFilename)) - { - // Download Opensky network database to a file - QUrl dbURL(QString(OSNDB_URL)); - m_progressDialog = new QProgressDialog(this); - m_progressDialog->setCancelButton(nullptr); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(OSNDB_URL)); - QNetworkReply *reply = m_dlm.download(dbURL, osnDBFilename); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64))); - } + m_progressDialog = new QProgressDialog(this); + m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setWindowFlag(Qt::WindowCloseButtonHint, false); + m_osnDB.downloadAircraftInformation(); } } @@ -3605,17 +3603,10 @@ void ADSBDemodGUI::on_getAirportDB_clicked() // Don't try to download while already in progress if (m_progressDialog == nullptr) { - QString airportDBFile = getAirportDBFilename(); - if (confirmDownload(airportDBFile)) - { - // Download Opensky network database to a file - QUrl dbURL(QString(AIRPORTS_URL)); - m_progressDialog = new QProgressDialog(this); - m_progressDialog->setCancelButton(nullptr); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(AIRPORTS_URL)); - QNetworkReply *reply = m_dlm.download(dbURL, airportDBFile); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64))); - } + m_progressDialog = new QProgressDialog(this); + m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setWindowFlag(Qt::WindowCloseButtonHint, false); + m_ourAirportsDB.downloadAirportInformation(); } } @@ -3627,6 +3618,7 @@ void ADSBDemodGUI::on_getAirspacesDB_clicked() m_progressDialog = new QProgressDialog(this); m_progressDialog->setMaximum(OpenAIP::m_countryCodes.size()); m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setWindowFlag(Qt::WindowCloseButtonHint, false); m_openAIP.downloadAirspaces(); } } @@ -3651,136 +3643,6 @@ QString ADSBDemodGUI::getDataDir() return locations[0]; } -QString ADSBDemodGUI::getAirportDBFilename() -{ - return getDataDir() + "/airportDatabase.csv"; -} - -QString ADSBDemodGUI::getAirportFrequenciesDBFilename() -{ - return getDataDir() + "/airportFrequenciesDatabase.csv"; -} - -qint64 ADSBDemodGUI::fileAgeInDays(QString filename) -{ - QFile file(filename); - if (file.exists()) - { - QDateTime modified = file.fileTime(QFileDevice::FileModificationTime); - if (modified.isValid()) - return modified.daysTo(QDateTime::currentDateTime()); - else - return -1; - } - return -1; -} - -bool ADSBDemodGUI::confirmDownload(QString filename) -{ - qint64 age = fileAgeInDays(filename); - if ((age == -1) || (age > 100)) - return true; - else - { - QMessageBox::StandardButton reply; - if (age == 0) - reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded today. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No); - else if (age == 1) - reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded yesterday. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No); - else - reply = QMessageBox::question(this, "Confirm download", QString("This file was last downloaded %1 days ago. Are you sure you wish to redownload this file?").arg(age), QMessageBox::Yes|QMessageBox::No); - return reply == QMessageBox::Yes; - } -} - -bool ADSBDemodGUI::readOSNDB(const QString& filename) -{ - m_aircraftInfo = AircraftInformation::readOSNDB(filename); - return m_aircraftInfo != nullptr; -} - -bool ADSBDemodGUI::readFastDB(const QString& filename) -{ - m_aircraftInfo = AircraftInformation::readFastDB(filename); - return m_aircraftInfo != nullptr; -} - -void ADSBDemodGUI::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes) -{ - if (m_progressDialog) - { - m_progressDialog->setMaximum(totalBytes); - m_progressDialog->setValue(bytesRead); - } -} - -void ADSBDemodGUI::downloadFinished(const QString& filename, bool success) -{ - bool closeDialog = true; - if (success) - { - if (filename == AircraftInformation::getOSNDBZipFilename()) - { - // Extract .csv file from .zip file - QZipReader reader(filename); - QByteArray database = reader.fileData("media/data/samples/metadata/aircraftDatabase.csv"); - if (database.size() > 0) - { - QFile file(AircraftInformation::getOSNDBFilename()); - if (file.open(QIODevice::WriteOnly)) - { - file.write(database); - file.close(); - } - else - { - qWarning() << "ADSBDemodGUI::downloadFinished - Failed to open " << file.fileName() << " for writing"; - } - } - else - { - qWarning() << "ADSBDemodGUI::downloadFinished - aircraftDatabase.csv not in expected dir. Extracting all."; - if (!reader.extractAll(getDataDir())) { - qWarning() << "ADSBDemodGUI::downloadFinished - Failed to extract files from " << filename; - } - } - readOSNDB(AircraftInformation::getOSNDBFilename()); - // Convert to condensed format for faster loading later - m_progressDialog->setLabelText("Processing."); - AircraftInformation::writeFastDB(AircraftInformation::getFastDBFilename(), m_aircraftInfo); - } - else if (filename == getAirportDBFilename()) - { - m_airportInfo = AirportInformation::readAirportsDB(filename); - // Now download airport frequencies - QUrl dbURL(QString(AIRPORT_FREQUENCIES_URL)); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(AIRPORT_FREQUENCIES_URL)); - QNetworkReply *reply = m_dlm.download(dbURL, getAirportFrequenciesDBFilename()); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64))); - closeDialog = false; - } - else if (filename == getAirportFrequenciesDBFilename()) - { - if (m_airportInfo != nullptr) - { - AirportInformation::readFrequenciesDB(filename, m_airportInfo); - // Update airports on map - updateAirports(); - } - } - else - { - qDebug() << "ADSBDemodGUI::downloadFinished: Unexpected filename: " << filename; - } - } - if (closeDialog && m_progressDialog) - { - m_progressDialog->close(); - delete m_progressDialog; - m_progressDialog = nullptr; - } -} - void ADSBDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; @@ -4335,12 +4197,12 @@ void ADSBDemodGUI::updateAirports() } m_airportModel.removeAllAirports(); - QHash::iterator i = m_airportInfo->begin(); + QHash::const_iterator i = m_airportInfo->begin(); AzEl azEl = m_azEl; while (i != m_airportInfo->end()) { - AirportInformation *airportInfo = i.value(); + const AirportInformation *airportInfo = i.value(); // Calculate distance and az/el to airport from My Position azEl.setTarget(airportInfo->m_latitude, airportInfo->m_longitude, Units::feetToMetres(airportInfo->m_elevation)); @@ -4370,7 +4232,7 @@ void ADSBDemodGUI::updateAirspaces() { AzEl azEl = m_azEl; m_airspaceModel.removeAllAirspaces(); - for (const auto& airspace: m_airspaces) + for (const auto airspace: *m_airspaces) { if (m_settings.m_airspaces.contains(airspace->m_category)) { @@ -4392,7 +4254,7 @@ void ADSBDemodGUI::updateNavAids() m_navAidModel.removeAllNavAids(); if (m_settings.m_displayNavAids) { - for (const auto& navAid: m_navAids) + for (const auto navAid: *m_navAids) { // Calculate distance to NavAid from My Position azEl.setTarget(navAid->m_latitude, navAid->m_longitude, Units::feetToMetres(navAid->m_elevation)); @@ -4745,7 +4607,8 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_airspaceModel(this), m_trackAircraft(nullptr), m_highlightAircraft(nullptr), - m_progressDialog(nullptr) + m_progressDialog(nullptr), + m_loadingData(false) { setAttribute(Qt::WA_DeleteOnClose, true); m_helpURL = "plugins/channelrx/demodadsb/readme.md"; @@ -4755,7 +4618,17 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb rollupContents->arrangeRollups(); connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - m_osmPort = 0; // Pick a free port + // Enable MSAA antialiasing on 2D map + // This is much faster than using layer.smooth in the QML, when there are many items + int multisamples = MainCore::instance()->getSettings().getMapMultisampling(); + if (multisamples > 0) + { + QSurfaceFormat format; + format.setSamples(multisamples); + ui->map->setFormat(format); + } + + m_osmPort = 0; // Pick a free port m_templateServer = new ADSBOSMTemplateServer("q2RVNAe3eFKCH4XsrE3r", m_osmPort); ui->map->setAttribute(Qt::WA_AcceptTouchEvents, true); @@ -4767,7 +4640,6 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map.qml"))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); - connect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &ADSBDemodGUI::downloadFinished); m_adsbDemod = reinterpret_cast(rxChannel); //new ADSBDemod(m_deviceUISet->m_deviceSourceAPI); m_adsbDemod->setMessageQueueToGUI(getInputMessageQueue()); @@ -4836,28 +4708,28 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb ui->flightDetails->setVisible(false); ui->aircraftDetails->setVisible(false); - AircraftInformation::init(); - // Read aircraft information database, if it has previously been downloaded - if (!readFastDB(AircraftInformation::getFastDBFilename())) - { - if (readOSNDB(AircraftInformation::getOSNDBFilename())) - AircraftInformation::writeFastDB(AircraftInformation::getFastDBFilename(), m_aircraftInfo); - } - // Read airport information database, if it has previously been downloaded - m_airportInfo = AirportInformation::readAirportsDB(getAirportDBFilename()); - if (m_airportInfo != nullptr) - AirportInformation::readFrequenciesDB(getAirportFrequenciesDBFilename(), m_airportInfo); + AircraftInformation::init(); + connect(&m_osnDB, &OsnDB::downloadingURL, this, &ADSBDemodGUI::downloadingURL); + connect(&m_osnDB, &OsnDB::downloadError, this, &ADSBDemodGUI::downloadError); + connect(&m_osnDB, &OsnDB::downloadProgress, this, &ADSBDemodGUI::downloadProgress); + connect(&m_osnDB, &OsnDB::downloadAircraftInformationFinished, this, &ADSBDemodGUI::downloadAircraftInformationFinished); + m_aircraftInfo = OsnDB::getAircraftInformation(); + // Read airport information database, if it has previously been downloaded + connect(&m_ourAirportsDB, &OurAirportsDB::downloadingURL, this, &ADSBDemodGUI::downloadingURL); + connect(&m_ourAirportsDB, &OurAirportsDB::downloadError, this, &ADSBDemodGUI::downloadError); + connect(&m_ourAirportsDB, &OurAirportsDB::downloadProgress, this, &ADSBDemodGUI::downloadProgress); + connect(&m_ourAirportsDB, &OurAirportsDB::downloadAirportInformationFinished, this, &ADSBDemodGUI::downloadAirportInformationFinished); + m_airportInfo = OurAirportsDB::getAirportsById(); + + // Read airspaces and NAVAIDs connect(&m_openAIP, &OpenAIP::downloadingURL, this, &ADSBDemodGUI::downloadingURL); connect(&m_openAIP, &OpenAIP::downloadError, this, &ADSBDemodGUI::downloadError); connect(&m_openAIP, &OpenAIP::downloadAirspaceFinished, this, &ADSBDemodGUI::downloadAirspaceFinished); connect(&m_openAIP, &OpenAIP::downloadNavAidsFinished, this, &ADSBDemodGUI::downloadNavAidsFinished); - - // Read airspaces - m_airspaces = OpenAIP::readAirspaces(); - // Read NavAids - m_navAids = OpenAIP::readNavAids(); + m_airspaces = OpenAIP::getAirspaces(); + m_navAids = OpenAIP::getNavAids(); // Get station position Real stationLatitude = MainCore::instance()->getSettings().getLatitude(); @@ -4929,26 +4801,24 @@ ADSBDemodGUI::~ADSBDemodGUI() disconnect(&m_openAIP, &OpenAIP::downloadNavAidsFinished, this, &ADSBDemodGUI::downloadNavAidsFinished); disconnect(&m_planeSpotters, &PlaneSpotters::aircraftPhoto, this, &ADSBDemodGUI::aircraftPhoto); disconnect(&m_redrawMapTimer, &QTimer::timeout, this, &ADSBDemodGUI::redrawMap); + disconnect(&MainCore::instance()->getMasterTimer(), &QTimer::timeout, this, &ADSBDemodGUI::tick); m_redrawMapTimer.stop(); + // Remove aircraft from Map feature + QHash::iterator i = m_aircraft.begin(); + while (i != m_aircraft.end()) + { + Aircraft *aircraft = i.value(); + clearFromMap(QString("%1").arg(aircraft->m_icao, 0, 16)); + ++i; + } delete ui; qDeleteAll(m_aircraft); - if (m_airportInfo) { - qDeleteAll(*m_airportInfo); - } - if (m_aircraftInfo) { - qDeleteAll(*m_aircraftInfo); - } if (m_flightInformation) { disconnect(m_flightInformation, &FlightInformation::flightUpdated, this, &ADSBDemodGUI::flightInformationUpdated); delete m_flightInformation; } - if (m_aviationWeather) - { - delete m_aviationWeather; - } - qDeleteAll(m_airspaces); - qDeleteAll(m_navAids); + delete m_aviationWeather; qDeleteAll(m_3DModelMatch); delete m_networkManager; } @@ -5116,7 +4986,7 @@ void ADSBDemodGUI::tick() // Tick is called 20x a second - lets check this every 10 seconds if (m_tickCount % (20*10) == 0) { - // Remove aircraft that haven't been heard of for a minute as probably out of range + // Remove aircraft that haven't been heard of for a user-defined time, as probably out of range QDateTime now = QDateTime::currentDateTime(); qint64 nowSecs = now.toSecsSinceEpoch(); QHash::iterator i = m_aircraft.begin(); @@ -5142,18 +5012,7 @@ void ADSBDemodGUI::tick() // Remove aircraft from hash i = m_aircraft.erase(i); // Remove from map feature - QList mapPipes; - MainCore::instance()->getMessagePipes().getMessagePipes(this, "mapitems", mapPipes); - - for (const auto& pipe : mapPipes) - { - MessageQueue *messageQueue = qobject_cast(pipe->m_element); - SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); - swgMapItem->setName(new QString(QString("%1").arg(aircraft->m_icao, 0, 16))); - swgMapItem->setImage(new QString("")); - MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_adsbDemod, swgMapItem); - messageQueue->push(msg); - } + clearFromMap(QString("%1").arg(aircraft->m_icao, 0, 16)); // And finally free its memory delete aircraft; @@ -5376,6 +5235,9 @@ void ADSBDemodGUI::on_logOpen_clicked() QFile file(fileNames[0]); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QDateTime startTime = QDateTime::currentDateTime(); + m_loadingData = true; + ui->adsbData->blockSignals(true); QTextStream in(&file); QString error; QHash colIndexes = CSV::readHeader(in, {"Data", "Correlation"}, error); @@ -5414,7 +5276,7 @@ void ADSBDemodGUI::on_logOpen_clicked() } //qDebug() << "bytes.szie " << bytes.size() << " crc " << Qt::hex << crcCalc; handleADSB(bytes, dateTime, correlation, correlation, crcCalc, false); - if ((count > 0) && (count % 10000 == 0)) + if ((count > 0) && (count % 100000 == 0)) { dialog.setText(QString("Reading ADS-B data\n%1 (Skipped %2)").arg(count).arg(countOtherDF)); QApplication::processEvents(); @@ -5437,6 +5299,13 @@ void ADSBDemodGUI::on_logOpen_clicked() { QMessageBox::critical(this, "ADS-B", error); } + ui->adsbData->blockSignals(false); + m_loadingData = false; + if (m_settings.m_autoResizeTableColumns) + ui->adsbData->resizeColumnsToContents(); + ui->adsbData->setSortingEnabled(true); + QDateTime finishTime = QDateTime::currentDateTime(); + qDebug() << "Read CSV in " << startTime.secsTo(finishTime); } else { @@ -5455,6 +5324,15 @@ void ADSBDemodGUI::downloadingURL(const QString& url) } } +void ADSBDemodGUI::downloadProgress(qint64 bytesRead, qint64 totalBytes) +{ + if (m_progressDialog) + { + m_progressDialog->setMaximum(totalBytes); + m_progressDialog->setValue(bytesRead); + } +} + void ADSBDemodGUI::downloadError(const QString& error) { QMessageBox::critical(this, "ADS-B", error); @@ -5471,7 +5349,7 @@ void ADSBDemodGUI::downloadAirspaceFinished() if (m_progressDialog) { m_progressDialog->setLabelText("Reading airspaces."); } - m_airspaces = OpenAIP::readAirspaces(); + m_airspaces = OpenAIP::getAirspaces(); updateAirspaces(); m_openAIP.downloadNavAids(); } @@ -5481,7 +5359,7 @@ void ADSBDemodGUI::downloadNavAidsFinished() if (m_progressDialog) { m_progressDialog->setLabelText("Reading NAVAIDs."); } - m_navAids = OpenAIP::readNavAids(); + m_navAids = OpenAIP::getNavAids(); updateNavAids(); if (m_progressDialog) { @@ -5491,6 +5369,50 @@ void ADSBDemodGUI::downloadNavAidsFinished() } } +void ADSBDemodGUI::downloadAircraftInformationFinished() +{ + if (m_progressDialog) + { + delete m_progressDialog; + m_progressDialog = new QProgressDialog("Reading Aircraft Information.", "", 0, 1, this); + m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setWindowFlag(Qt::WindowCloseButtonHint, false); + m_progressDialog->setWindowModality(Qt::WindowModal); + m_progressDialog->show(); + QApplication::processEvents(); + } + m_aircraftInfo = OsnDB::getAircraftInformation(); + m_aircraftModel.updateAircraftInformation(m_aircraftInfo); + if (m_progressDialog) + { + m_progressDialog->close(); + delete m_progressDialog; + m_progressDialog = nullptr; + } +} + +void ADSBDemodGUI::downloadAirportInformationFinished() +{ + if (m_progressDialog) + { + delete m_progressDialog; + m_progressDialog = new QProgressDialog("Reading Airport Information.", "", 0, 1, this); + m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setWindowFlag(Qt::WindowCloseButtonHint, false); + m_progressDialog->setWindowModality(Qt::WindowModal); + m_progressDialog->show(); + QApplication::processEvents(); + } + m_airportInfo = OurAirportsDB::getAirportsById(); + updateAirports(); + if (m_progressDialog) + { + m_progressDialog->close(); + delete m_progressDialog; + m_progressDialog = nullptr; + } +} + int ADSBDemodGUI::squawkDecode(int modeA) const { int a, b, c, d; @@ -5771,16 +5693,21 @@ void ADSBDemodGUI::preferenceChanged(int elementType) Real stationLongitude = MainCore::instance()->getSettings().getLongitude(); Real stationAltitude = MainCore::instance()->getSettings().getAltitude(); - if ( (stationLatitude != m_azEl.getLocationSpherical().m_latitude) - || (stationLongitude != m_azEl.getLocationSpherical().m_longitude) - || (stationAltitude != m_azEl.getLocationSpherical().m_altitude)) + QGeoCoordinate stationPosition(stationLatitude, stationLongitude, stationAltitude); + QGeoCoordinate previousPosition(m_azEl.getLocationSpherical().m_latitude, m_azEl.getLocationSpherical().m_longitude, m_azEl.getLocationSpherical().m_altitude); + + if (stationPosition != previousPosition) { m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude); - // Update distances and what is visible - updateAirports(); - updateAirspaces(); - updateNavAids(); + // Update distances and what is visible, but only do it if position has changed significantly + if (!m_lastFullUpdatePosition.isValid() || (stationPosition.distanceTo(m_lastFullUpdatePosition) >= 1000)) + { + updateAirports(); + updateAirspaces(); + updateNavAids(); + m_lastFullUpdatePosition = stationPosition; + } // Update icon position on Map QQuickItem *item = ui->map->rootObject(); @@ -5875,3 +5802,4 @@ void ADSBDemodGUI::updateAbsoluteCenterFrequency() { setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); } + diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.h b/plugins/channelrx/demodadsb/adsbdemodgui.h index 2d0d414a1..c54f66ecd 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.h +++ b/plugins/channelrx/demodadsb/adsbdemodgui.h @@ -37,7 +37,6 @@ #include "util/messagequeue.h" #include "util/azel.h" #include "util/movingaverage.h" -#include "util/httpdownloadmanager.h" #include "util/flightinformation.h" #include "util/openaip.h" #include "util/planespotters.h" @@ -47,7 +46,7 @@ #include "SWGMapItem.h" #include "adsbdemodsettings.h" -#include "ourairportsdb.h" +#include "util/ourairportsdb.h" #include "util/osndb.h" class PluginAPI; @@ -464,7 +463,19 @@ public: allAircraftUpdated(); } - Q_INVOKABLE void findOnMap(int index); + Q_INVOKABLE void findOnMap(int index); + + void updateAircraftInformation(QSharedPointer> aircraftInfo) + { + for (auto aircraft : m_aircrafts) + { + if (aircraftInfo->contains(aircraft->m_icao)) { + aircraft->m_aircraftInfo = aircraftInfo->value(aircraft->m_icao); + } else { + aircraft->m_aircraftInfo = nullptr; + } + } + } private: QList m_aircrafts; @@ -493,7 +504,7 @@ public: { } - Q_INVOKABLE void addAirport(AirportInformation *airport, float az, float el, float distance) { + Q_INVOKABLE void addAirport(const AirportInformation *airport, float az, float el, float distance) { QString text; int rows; @@ -558,7 +569,7 @@ public: return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; } - void airportFreq(AirportInformation *airport, float az, float el, float distance, QString& text, int& rows) { + void airportFreq(const AirportInformation *airport, float az, float el, float distance, QString& text, int& rows) { // Create the text to go in the bubble next to the airport // Display name and frequencies QStringList list; @@ -567,7 +578,7 @@ public: rows = 1; for (int i = 0; i < airport->m_frequencies.size(); i++) { - AirportInformation::FrequencyInformation *frequencyInfo = airport->m_frequencies[i]; + const AirportInformation::FrequencyInformation *frequencyInfo = airport->m_frequencies[i]; list.append(QString("%1: %2 MHz").arg(frequencyInfo->m_type).arg(frequencyInfo->m_frequency)); rows++; } @@ -577,7 +588,7 @@ public: text = list.join("\n"); } - void airportUpdated(AirportInformation *airport) { + void airportUpdated(const AirportInformation *airport) { int row = m_airports.indexOf(airport); if (row >= 0) { @@ -614,7 +625,7 @@ public: private: ADSBDemodGUI *m_gui; - QList m_airports; + QList m_airports; QList m_airportDataFreq; QList m_airportDataFreqRows; QList m_showFreq; @@ -894,14 +905,15 @@ private: MessageQueue m_inputMessageQueue; QHash m_aircraft; // Hashed on ICAO - QHash *m_aircraftInfo; - QHash *m_airportInfo; // Hashed on id + QSharedPointer> m_aircraftInfo; + QSharedPointer> m_airportInfo; // Hashed on id AircraftModel m_aircraftModel; AirportModel m_airportModel; AirspaceModel m_airspaceModel; NavAidModel m_navAidModel; - QList m_airspaces; - QList m_navAids; + QSharedPointer> m_airspaces; + QSharedPointer> m_navAids; + QGeoCoordinate m_lastFullUpdatePosition; AzEl m_azEl; // Position of station Aircraft *m_trackAircraft; // Aircraft we want to track in Channel Report @@ -920,10 +932,11 @@ private: AviationWeather *m_aviationWeather; QString m_photoLink; WebAPIAdapterInterface *m_webAPIAdapterInterface; - HttpDownloadManager m_dlm; QProgressDialog *m_progressDialog; quint16 m_osmPort; OpenAIP m_openAIP; + OsnDB m_osnDB; + OurAirportsDB m_ourAirportsDB; ADSBOSMTemplateServer *m_templateServer; QRandomGenerator m_random; QHash m_3DModels; // Hashed aircraft_icao or just aircraft @@ -935,6 +948,7 @@ private: QTimer m_importTimer; QTimer m_redrawMapTimer; QNetworkAccessManager *m_networkManager; + bool m_loadingData; static const char m_idMap[]; static const QString m_categorySetA[]; @@ -957,6 +971,7 @@ private: void updatePosition(Aircraft *aircraft); bool updateLocalPosition(Aircraft *aircraft, double latitude, double longitude, bool surfacePosition); + void clearFromMap(const QString& name); void sendToMap(Aircraft *aircraft, QList *animations); Aircraft *getAircraft(int icao, bool &newAircraft); void callsignToFlight(Aircraft *aircraft); @@ -984,17 +999,8 @@ private: QString subAircraftString(Aircraft *aircraft, const QString &string); void resizeTable(); QString getDataDir(); - QString getAirportDBFilename(); - QString getAirportFrequenciesDBFilename(); - QString getOSNDBZipFilename(); - QString getOSNDBFilename(); - QString getFastDBFilename(); - qint64 fileAgeInDays(QString filename); - bool confirmDownload(QString filename); void readAirportDB(const QString& filename); void readAirportFrequenciesDB(const QString& filename); - bool readOSNDB(const QString& filename); - bool readFastDB(const QString& filename); void update3DModels(); void updateAirports(); void updateAirspaces(); @@ -1047,8 +1053,6 @@ private slots: void onMenuDialogCalled(const QPoint& p); void handleInputMessages(); void tick(); - void updateDownloadProgress(qint64 bytesRead, qint64 totalBytes); - void downloadFinished(const QString& filename, bool success); void on_device_currentIndexChanged(int index); void feedSelect(const QPoint& p); void on_displaySettings_clicked(); @@ -1057,8 +1061,11 @@ private slots: void on_logOpen_clicked(); void downloadingURL(const QString& url); void downloadError(const QString& error); + void downloadProgress(qint64 bytesRead, qint64 totalBytes); void downloadAirspaceFinished(); void downloadNavAidsFinished(); + void downloadAircraftInformationFinished(); + void downloadAirportInformationFinished(); void photoClicked(); virtual void showEvent(QShowEvent *event) override; virtual bool eventFilter(QObject *obj, QEvent *event) override; @@ -1073,3 +1080,4 @@ signals: }; #endif // INCLUDE_ADSBDEMODGUI_H + diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.ui b/plugins/channelrx/demodadsb/adsbdemodgui.ui index aa682d8e4..85846e61a 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.ui +++ b/plugins/channelrx/demodadsb/adsbdemodgui.ui @@ -844,6 +844,9 @@ QAbstractItemView::SingleSelection + + QAbstractItemView::SelectRows + ICAO ID diff --git a/plugins/channelrx/demodadsb/map/map.qml b/plugins/channelrx/demodadsb/map/map.qml index 7c3b2e0ab..78cdbe368 100644 --- a/plugins/channelrx/demodadsb/map/map.qml +++ b/plugins/channelrx/demodadsb/map/map.qml @@ -140,8 +140,8 @@ Item { Grid { horizontalItemAlignment: Grid.AlignHCenter columnSpacing: 5 - layer.enabled: true - layer.smooth: true + //layer.enabled: true + //layer.smooth: true Image { id: image source: navAidImage @@ -206,8 +206,8 @@ Item { sourceItem: Grid { columns: 1 Grid { - layer.enabled: true - layer.smooth: true + //layer.enabled: true + //layer.smooth: true horizontalItemAlignment: Grid.AlignHCenter Text { id: airspaceText @@ -239,8 +239,8 @@ Item { sourceItem: Grid { columns: 1 Grid { - layer.enabled: true - layer.smooth: true + //layer.enabled: true + //layer.smooth: true horizontalItemAlignment: Grid.AlignHCenter Image { id: image @@ -334,8 +334,8 @@ Item { columns: 1 Grid { horizontalItemAlignment: Grid.AlignHCenter - layer.enabled: true - layer.smooth: true + //layer.enabled: true + //layer.smooth: true Image { id: image source: airportImage diff --git a/plugins/channelrx/demodadsb/ourairportsdb.h b/plugins/channelrx/demodadsb/ourairportsdb.h deleted file mode 100644 index 94ddec3df..000000000 --- a/plugins/channelrx/demodadsb/ourairportsdb.h +++ /dev/null @@ -1,303 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2020 Jon Beniston, M7RCE // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// (at your option) any later version. // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_OURAIRPORTSDB_H -#define INCLUDE_OURAIRPORTSDB_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "util/csv.h" -#include "adsbdemodsettings.h" - -#define AIRPORTS_URL "https://davidmegginson.github.io/ourairports-data/airports.csv" -#define AIRPORT_FREQUENCIES_URL "https://davidmegginson.github.io/ourairports-data/airport-frequencies.csv" - -struct AirportInformation { - - struct FrequencyInformation { - QString m_type; - QString m_description; - float m_frequency; // In MHz - }; - - int m_id; - QString m_ident; - ADSBDemodSettings::AirportType m_type; - QString m_name; - float m_latitude; - float m_longitude; - float m_elevation; - QVector m_frequencies; - - ~AirportInformation() - { - qDeleteAll(m_frequencies); - } - - static QString trimQuotes(const QString s) - { - if (s.startsWith('\"') && s.endsWith('\"')) - return s.mid(1, s.size() - 2); - else - return s; - } - - // Read OurAirport's airport CSV file - // See comments for readOSNDB - static QHash *readAirportsDB(const QString &filename) - { - int cnt = 0; - QHash *airportInfo = nullptr; - - // Column numbers used for the data as of 2020/10/28 - int idCol = 0; - int identCol = 1; - int typeCol = 2; - int nameCol = 3; - int latitudeCol = 4; - int longitudeCol = 5; - int elevationCol = 6; - - qDebug() << "AirportInformation::readAirportsDB: " << filename; - - FILE *file; - QByteArray utfFilename = filename.toUtf8(); - QLocale cLocale(QLocale::C); - if ((file = fopen(utfFilename.constData(), "r")) != NULL) - { - char row[2048]; - - if (fgets(row, sizeof(row), file)) - { - airportInfo = new QHash(); - airportInfo->reserve(70000); - - // Read header - int idx = 0; - char *p = strtok(row, ","); - while (p != NULL) - { - if (!strcmp(p, "id")) - idCol = idx; - else if (!strcmp(p, "ident")) - identCol = idx; - else if (!strcmp(p, "type")) - typeCol = idx; - else if (!strcmp(p, "name")) - nameCol = idx; - else if (!strcmp(p, "latitude_deg")) - latitudeCol = idx; - else if (!strcmp(p, "longitude_deg")) - longitudeCol = idx; - else if (!strcmp(p, "elevation_ft")) - elevationCol = idx; - p = strtok(NULL, ","); - idx++; - } - // Read data - while (fgets(row, sizeof(row), file)) - { - int id = 0; - char *idString = NULL; - char *ident = NULL; - size_t identLen = 0; - char *type = NULL; - size_t typeLen = 0; - char *name = NULL; - size_t nameLen = 0; - float latitude = 0.0f; - char *latitudeString = NULL; - size_t latitudeLen = 0; - float longitude = 0.0f; - char *longitudeString = NULL; - size_t longitudeLen = 0; - float elevation = 0.0f; - char *elevationString = NULL; - size_t elevationLen = 0; - - p = strtok(row, ","); - idx = 0; - while (p != NULL) - { - // Read strings, stripping quotes - if (idx == idCol) - { - idString = p; - idString[strlen(idString)] = '\0'; - id = strtol(idString, NULL, 10); - } - else if (idx == identCol) - { - ident = p+1; - identLen = strlen(ident)-1; - ident[identLen] = '\0'; - } - else if (idx == typeCol) - { - type = p+1; - typeLen = strlen(type)-1; - type[typeLen] = '\0'; - } - else if (idx == nameCol) - { - name = p+1; - nameLen = strlen(name)-1; - name[nameLen] = '\0'; - } - else if (idx == latitudeCol) - { - latitudeString = p; - latitudeLen = strlen(latitudeString)-1; - latitudeString[latitudeLen] = '\0'; - latitude = cLocale.toFloat(latitudeString); - } - else if (idx == longitudeCol) - { - longitudeString = p; - longitudeLen = strlen(longitudeString)-1; - longitudeString[longitudeLen] = '\0'; - longitude = cLocale.toFloat(longitudeString); - } - else if (idx == elevationCol) - { - elevationString = p; - elevationLen = strlen(elevationString)-1; - elevationString[elevationLen] = '\0'; - elevation = cLocale.toFloat(elevationString); - } - p = strtok(NULL, ","); - idx++; - } - - // Only create the entry if we have some interesting data - if (((latitude != 0.0f) || (longitude != 0.0f)) && (type && strcmp(type, "closed"))) - { - AirportInformation *airport = new AirportInformation(); - airport->m_id = id; - airport->m_ident = QString(ident); - if (!strcmp(type, "small_airport")) - airport->m_type = ADSBDemodSettings::AirportType::Small; - else if (!strcmp(type, "medium_airport")) - airport->m_type = ADSBDemodSettings::AirportType::Medium; - else if (!strcmp(type, "large_airport")) - airport->m_type = ADSBDemodSettings::AirportType::Large; - else if (!strcmp(type, "heliport")) - airport->m_type = ADSBDemodSettings::AirportType::Heliport; - airport->m_name = QString(name); - airport->m_latitude = latitude; - airport->m_longitude = longitude; - airport->m_elevation = elevation; - airportInfo->insert(id, airport); - cnt++; - } - } - } - fclose(file); - } - else - qDebug() << "AirportInformation::readAirportsDB: Failed to open " << filename; - - qDebug() << "AirportInformation::readAirportsDB: Read " << cnt << " airports"; - - return airportInfo; - } - - // Read OurAirport's airport frequencies CSV file - static bool readFrequenciesDB(const QString &filename, QHash *airportInfo) - { - int cnt = 0; - - // Column numbers used for the data as of 2020/10/28 - int airportRefCol = 1; - int typeCol = 3; - int descriptionCol = 4; - int frequencyCol = 5; - - qDebug() << "AirportInformation::readFrequenciesDB: " << filename; - - QFile file(filename); - if (file.open(QIODevice::ReadOnly)) - { - QList colNames; - int idx; - - // Read header - if (!file.atEnd()) - { - QByteArray row = file.readLine().trimmed(); - colNames = row.split(','); - // Work out which columns the data is in, based on the headers - idx = colNames.indexOf("airport_ref"); - if (idx >= 0) - airportRefCol = idx; - idx = colNames.indexOf("type"); - if (idx >= 0) - typeCol = idx; - idx = colNames.indexOf("descrption"); - if (idx >= 0) - descriptionCol = idx; - idx = colNames.indexOf("frequency_mhz"); - if (idx >= 0) - frequencyCol = idx; - } - // Read data - while (!file.atEnd()) - { - QByteArray row = file.readLine(); - QList cols = row.split(','); - - bool ok = false; - int airportRef = cols[airportRefCol].toInt(&ok, 10); - if (ok) - { - if (airportInfo->contains(airportRef)) - { - QString type = trimQuotes(cols[typeCol]); - QString description = trimQuotes(cols[descriptionCol]); - float frequency = cols[frequencyCol].toFloat(); - - FrequencyInformation *frequencyInfo = new FrequencyInformation(); - frequencyInfo->m_type = type; - frequencyInfo->m_description = description; - frequencyInfo->m_frequency = frequency; - airportInfo->value(airportRef)->m_frequencies.append(frequencyInfo); - cnt++; - } - } - } - file.close(); - } - else - qDebug() << "Failed to open " << filename << " " << file.errorString(); - - qDebug() << "AirportInformation::readFrequenciesDB: - read " << cnt << " airports"; - - return airportInfo; - } - -}; - -#endif diff --git a/plugins/feature/map/CMakeLists.txt b/plugins/feature/map/CMakeLists.txt index 2b8d003ef..6e610c9e5 100644 --- a/plugins/feature/map/CMakeLists.txt +++ b/plugins/feature/map/CMakeLists.txt @@ -54,12 +54,14 @@ if(NOT SERVER_MODE) mapradiotimedialog.ui mapcolordialog.cpp mapmodel.cpp + mapitem.cpp mapwebsocketserver.cpp cesiuminterface.cpp czml.cpp map.qrc icons.qrc cesium.qrc + data.qrc ) set(map_HEADERS ${map_HEADERS} @@ -72,6 +74,7 @@ if(NOT SERVER_MODE) mapradiotimedialog.h mapcolordialog.h mapmodel.h + mapitem.h mapwebsocketserver.h cesiuminterface.h czml.h diff --git a/plugins/feature/map/cesiuminterface.cpp b/plugins/feature/map/cesiuminterface.cpp index 7be9cf9d0..a0cd030d9 100644 --- a/plugins/feature/map/cesiuminterface.cpp +++ b/plugins/feature/map/cesiuminterface.cpp @@ -231,8 +231,25 @@ void CesiumInterface::czml(QJsonObject &obj) send(obj); } -void CesiumInterface::update(MapItem *mapItem, bool isTarget, bool isSelected) +void CesiumInterface::update(ObjectMapItem *mapItem, bool isTarget, bool isSelected) { QJsonObject obj = m_czml.update(mapItem, isTarget, isSelected); czml(obj); } + +void CesiumInterface::update(PolygonMapItem *mapItem) +{ + QJsonObject obj = m_czml.update(mapItem); + czml(obj); +} + +void CesiumInterface::update(PolylineMapItem *mapItem) +{ + QJsonObject obj = m_czml.update(mapItem); + czml(obj); +} + +void CesiumInterface::setPosition(const QGeoCoordinate& position) +{ + m_czml.setPosition(position); +} diff --git a/plugins/feature/map/cesiuminterface.h b/plugins/feature/map/cesiuminterface.h index 46a4a4bdb..852f676b9 100644 --- a/plugins/feature/map/cesiuminterface.h +++ b/plugins/feature/map/cesiuminterface.h @@ -22,7 +22,9 @@ #include "czml.h" #include "SWGMapAnimation.h" -class MapItem; +class ObjectMapItem; +class PolygonMapItem; +class PolylineMapItem; class CesiumInterface : public MapWebSocketServer { @@ -72,7 +74,10 @@ public: void removeAllCZMLEntities(); void initCZML(); void czml(QJsonObject &obj); - void update(MapItem *mapItem, bool isTarget, bool isSelected); + void update(ObjectMapItem *mapItem, bool isTarget, bool isSelected); + void update(PolygonMapItem *mapItem); + void update(PolylineMapItem *mapItem); + void setPosition(const QGeoCoordinate& position); protected: diff --git a/plugins/feature/map/czml.cpp b/plugins/feature/map/czml.cpp index 8e08db6dd..b807a9081 100644 --- a/plugins/feature/map/czml.cpp +++ b/plugins/feature/map/czml.cpp @@ -28,6 +28,22 @@ CZML::CZML(const MapSettings *settings) : { } +// Set position from which distance filter is calculated +void CZML::setPosition(const QGeoCoordinate& position) +{ + m_position = position; +} + +bool CZML::filter(const MapItem *mapItem) const +{ + return ( !mapItem->m_itemSettings->m_filterName.isEmpty() + && !mapItem->m_itemSettings->m_filterNameRE.match(mapItem->m_name).hasMatch() + ) + || ( (mapItem->m_itemSettings->m_filterDistance > 0) + && (m_position.distanceTo(QGeoCoordinate(mapItem->m_latitude, mapItem->m_longitude, mapItem->m_altitude)) > mapItem->m_itemSettings->m_filterDistance) + ); +} + QJsonObject CZML::init() { QString start = QDateTime::currentDateTimeUtc().toString(Qt::ISODate); @@ -48,11 +64,150 @@ QJsonObject CZML::init() return doc; } +QJsonObject CZML::update(PolygonMapItem *mapItem) +{ + QString id = mapItem->m_name; -QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) + QJsonObject obj { + {"id", id} // id must be unique + }; + + if ( !mapItem->m_itemSettings->m_enabled + || !mapItem->m_itemSettings->m_display3DTrack + || filter(mapItem) + ) + { + // Delete obj completely (including any history) + obj.insert("delete", true); + return obj; + } + + QJsonArray positions; + for (const auto c : mapItem->m_points) + { + positions.append(c->longitude()); + positions.append(c->latitude()); + positions.append(c->altitude()); + } + + QJsonObject positionList { + {"cartographicDegrees", positions}, + }; + + QColor color = QColor::fromRgba(mapItem->m_itemSettings->m_3DTrackColor); + QJsonArray colorRGBA { + color.red(), color.green(), color.blue(), color.alpha() + }; + QJsonObject colorObj { + {"rgba", colorRGBA} + }; + + QJsonObject solidColor { + {"color", colorObj}, + }; + + QJsonObject material { + {"solidColor", solidColor} + }; + + QJsonArray outlineColorRGBA { + 0, 0, 0, 255 + }; + QJsonObject outlineColor { + {"rgba", outlineColorRGBA} + }; + + QJsonObject polygon { + {"positions", positionList}, + {"height", mapItem->m_altitude}, + {"extrudedHeight", mapItem->m_extrudedHeight}, + {"material", material}, + {"outline", true}, + {"outlineColor", outlineColor} + }; + + obj.insert("polygon", polygon); + obj.insert("description", mapItem->m_label); + + //qDebug() << "Polygon " << obj; + return obj; +} + +QJsonObject CZML::update(PolylineMapItem *mapItem) +{ + QString id = mapItem->m_name; + + QJsonObject obj { + {"id", id} // id must be unique + }; + + if ( !mapItem->m_itemSettings->m_enabled + || !mapItem->m_itemSettings->m_display3DTrack + || filter(mapItem) + ) + { + // Delete obj completely (including any history) + obj.insert("delete", true); + return obj; + } + + QJsonArray positions; + for (const auto c : mapItem->m_points) + { + positions.append(c->longitude()); + positions.append(c->latitude()); + positions.append(c->altitude()); + } + + QJsonObject positionList { + {"cartographicDegrees", positions}, + }; + + QColor color = QColor::fromRgba(mapItem->m_itemSettings->m_3DTrackColor); + QJsonArray colorRGBA { + color.red(), color.green(), color.blue(), color.alpha() + }; + QJsonObject colorObj { + {"rgba", colorRGBA} + }; + + QJsonObject solidColor { + {"color", colorObj}, + }; + + QJsonObject material { + {"solidColor", solidColor} + }; + + QJsonObject polyline { + {"positions", positionList}, + {"material", material} + }; + + obj.insert("polyline", polyline); + obj.insert("description", mapItem->m_label); + + //qDebug() << "Polyline " << obj; + return obj; +} + +QJsonObject CZML::update(ObjectMapItem *mapItem, bool isTarget, bool isSelected) { (void) isTarget; + QString id = mapItem->m_name; + + QJsonObject obj { + {"id", id} // id must be unique + }; + + if (!mapItem->m_itemSettings->m_enabled || filter(mapItem)) + { + // Delete obj completely (including any history) + obj.insert("delete", true); + return obj; + } + // Don't currently use CLIP_TO_GROUND in Cesium due to Jitter bug // https://github.com/CesiumGS/cesium/issues/4049 // Instead we implement our own clipping code in map3d.html @@ -65,8 +220,6 @@ QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) dt = QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs); } - QString id = mapItem->m_name; - // Keep a hash of the time we first saw each item bool existingId = m_ids.contains(id); if (!existingId) { @@ -77,7 +230,7 @@ QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) bool fixedPosition = mapItem->m_fixedPosition; if (mapItem->m_image == "") { - // Need to remove this from the map + // Need to remove this from the map (but history is retained) removeObj = true; } @@ -143,10 +296,10 @@ QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) hasMoved = true; m_hasMoved.insert(id, true); } - if (hasMoved) + if (hasMoved && (mapItem->m_itemSettings->m_extrapolate > 0)) { position.insert("forwardExtrapolationType", "EXTRAPOLATE"); - position.insert("forwardExtrapolationDuration", 60); + position.insert("forwardExtrapolationDuration", mapItem->m_itemSettings->m_extrapolate); // Use linear interpolation for now - other two can go crazy with aircraft on the ground //position.insert("interpolationAlgorithm", "HERMITE"); //position.insert("interpolationDegree", "2"); @@ -182,7 +335,7 @@ QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) QJsonObject orientation { {"unitQuaternion", quaternion}, {"forwardExtrapolationType", "HOLD"}, // If we extrapolate, aircraft tend to spin around - {"forwardExtrapolationDuration", 60}, + {"forwardExtrapolationDuration", mapItem->m_itemSettings->m_extrapolate}, // {"interpolationAlgorithm", "LAGRANGE"} }; QJsonObject orientationPosition { @@ -269,7 +422,10 @@ QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) // Prevent labels from being too cluttered when zoomed out // FIXME: These values should come from mapItem or mapItemSettings float displayDistanceMax = std::numeric_limits::max(); - if ((mapItem->m_group == "Beacons") || (mapItem->m_group == "AM") || (mapItem->m_group == "FM") || (mapItem->m_group == "DAB")) { + if ((mapItem->m_group == "Beacons") + || (mapItem->m_group == "AM") || (mapItem->m_group == "FM") || (mapItem->m_group == "DAB") + || (mapItem->m_group == "NavAid") + ) { displayDistanceMax = 1000000; } else if ((mapItem->m_group == "Station") || (mapItem->m_group == "Radar") || (mapItem->m_group == "Radio Time Transmitters")) { displayDistanceMax = 10000000; @@ -330,10 +486,6 @@ QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) {"verticalOrigin", "BOTTOM"} // To stop it being cut in half when zoomed out }; - QJsonObject obj { - {"id", id} // id must be unique - }; - if (!removeObj) { obj.insert("position", position); @@ -368,9 +520,11 @@ QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) } else { - QString oneMin = QDateTime::currentDateTimeUtc().addSecs(60).toString(Qt::ISODateWithMs); - QString createdToNow = QString("%1/%2").arg(m_ids[id]).arg(oneMin); // From when object was created to now - obj.insert("availability", createdToNow); + if (mapItem->m_availableUntil.isValid()) + { + QString period = QString("%1/%2").arg(m_ids[id]).arg(mapItem->m_availableUntil.toString(Qt::ISODateWithMs)); + obj.insert("availability", period); + } } } m_lastPosition.insert(id, coords); @@ -391,3 +545,4 @@ QJsonObject CZML::update(MapItem *mapItem, bool isTarget, bool isSelected) return obj; } + diff --git a/plugins/feature/map/czml.h b/plugins/feature/map/czml.h index f97be9095..ad737a1b0 100644 --- a/plugins/feature/map/czml.h +++ b/plugins/feature/map/czml.h @@ -21,9 +21,13 @@ #include #include #include +#include struct MapSettings; class MapItem; +class ObjectMapItem; +class PolygonMapItem; +class PolylineMapItem; class CZML { @@ -32,11 +36,16 @@ private: QHash m_ids; QHash m_lastPosition; QHash m_hasMoved; + QGeoCoordinate m_position; public: CZML(const MapSettings *settings); QJsonObject init(); - QJsonObject update(MapItem *mapItem, bool isTarget, bool isSelected); + QJsonObject update(ObjectMapItem *mapItem, bool isTarget, bool isSelected); + QJsonObject update(PolygonMapItem *mapItem); + QJsonObject update(PolylineMapItem *mapItem); + bool filter(const MapItem *mapItem) const; + void setPosition(const QGeoCoordinate& position); signals: void connected(); diff --git a/plugins/feature/map/data.qrc b/plugins/feature/map/data.qrc new file mode 100644 index 000000000..b864c3579 --- /dev/null +++ b/plugins/feature/map/data.qrc @@ -0,0 +1,5 @@ + + + data/transmitters.csv + + diff --git a/plugins/feature/map/data/transmitters.csv b/plugins/feature/map/data/transmitters.csv new file mode 100644 index 000000000..1640a2a93 --- /dev/null +++ b/plugins/feature/map/data/transmitters.csv @@ -0,0 +1,3478 @@ +Type,Id,Name,Frequency (Hz),Latitude,Longitude,Altitude (m),Power,TII Main,TII Sub +AM,Acacia Radio Annesley Woodhouse Annesley - Acacia Centre,Acacia Radio,1287000,53.079047,-1.250137,173,0.001,, +AM,Akash Radio Leeds Leeds Leeds - Potternewton Lane,Akash Radio Leeds,1323000,53.825157,-1.547404,113,0.03,, +AM,Anker Radio George Eliot Hospital,Anker Radio,1386000,52.511208,-1.473932,102,0.001,, +AM,Asian Sound Radio East Lancashire Ashton Moss C,Asian Sound Radio,1377000,53.491685,-2.115866,101,0.08,, +AM,Asian Sound Radio East Lancashire HASLINGDEN,Asian Sound Radio,963000,53.708491,-2.311438,336,0.2,, +AM,BBC Asian Network Midlands Freemens Common,BBC Asian Network,837000,52.61896,-1.13158,79,0.7,, +AM,BBC Asian Network Midlands Gunthorpe,BBC Asian Network,1449000,52.617188,-0.247858,3,0.15,, +AM,BBC Asian Network Midlands Langley Mill,BBC Asian Network,1458000,52.56878,-1.765371,91,5,, +AM,BBC Asian Network Midlands Sedgley,BBC Asian Network,828000,52.542856,-2.14151,160,0.2,, +AM,BBC Guernsey (AM) Guernsey Rohais,BBC Guernsey (AM),1116000,49.46174,-2.562965,28,0.5,, +AM,BBC Radio 4 (AM) Cumbria Brisco,BBC Radio 4 (AM),1485000,54.864686,-2.917634,38,0.79,, +AM,BBC Radio 4 (AM) London Crystal Palace,BBC Radio 4 (AM),720000,51.424161,-0.074944,110,0.24,, +AM,BBC Radio 4 (AM) A Enniskillen AM,BBC Radio 4 (AM),774000,54.359626,-7.642841,70,0.5,, +AM,BBC Radio 4 (AM) Northern Ireland Lisnagarvey,BBC Radio 4 (AM),720000,54.489676,-6.060423,44,10,, +AM,BBC Radio 4 (AM) Londonderry Londonderry MF,BBC Radio 4 (AM),720000,55.004653,-7.367867,175,0.25,, +AM,BBC Radio 4 (AM) Devon Plumer Barracks,BBC Radio 4 (AM),774000,50.406749,-4.125485,101,0.2,, +AM,BBC Radio 4 (AM) North East Scotland Redmoss MF,BBC Radio 4 (AM),1449000,57.114016,-2.095089,90,2,, +AM,BBC Radio 4 (AM) Cornwall Redruth MF,BBC Radio 4 (AM),756000,50.217887,-5.2124,182,2,, +AM,BBC Radio 4 (AM) Newcastle Wrekenton,BBC Radio 4 (AM),603000,54.932736,-1.572984,152,0.5,, +AM,BBC Radio 5 live Cumbria Barrow,BBC Radio 5 live,693000,54.126165,-3.198099,23,0.6,, +AM,BBC Radio 5 live Sussex Bexhill MF,BBC Radio 5 live,693000,50.837744,0.447085,15,0.4,, +AM,BBC Radio 5 live London and the South East Brookmans Park,BBC Radio 5 live,909000,51.727838,-0.176464,127,200,, +AM,BBC Radio 5 live North Scotland Burghead,BBC Radio 5 live,693000,57.69801,-3.46983,40,25,, +AM,BBC Radio 5 live A Clevedon,BBC Radio 5 live,909000,51.423652,-2.863893,5,75,, +AM,BBC Radio 5 live Dartford Tunnel,BBC Radio 5 live,909000,51.469253,0.260425,3,0.004,, +AM,BBC Radio 5 live Midlands Droitwich,BBC Radio 5 live,693000,52.298545,-2.105388,48,150,, +AM,BBC Radio 5 live A Enniskillen AM,BBC Radio 5 live,693000,54.359626,-7.642841,70,0.4,, +AM,BBC Radio 5 live Newcastle Fareham,BBC Radio 5 live,909000,50.849331,-1.226918,30,0.8,, +AM,BBC Radio 5 live South Hampshire & Isle of Wight Fern Barrow,BBC Radio 5 live,909000,50.732788,-1.902461,44,0.5,, +AM,BBC Radio 5 live Kent Folkestone MF,BBC Radio 5 live,693000,51.105014,1.219804,145,0.4,, +AM,BBC Radio 5 live Northern Ireland Lisnagarvey,BBC Radio 5 live,909000,54.489676,-6.060423,44,5,, +AM,BBC Radio 5 live Londonderry Londonderry MF,BBC Radio 5 live,909000,55.004653,-7.367867,175,0.28,, +AM,BBC Radio 5 live Northern England Moorside Edge,BBC Radio 5 live,909000,53.635238,-1.894553,340,400,, +AM,BBC Radio 5 live Exeter Pearce's Hill,BBC Radio 5 live,909000,50.683057,-3.514661,82,0.2,, +AM,BBC Radio 5 live Norfolk Postwick,BBC Radio 5 live,693000,52.626852,1.402572,26,15,, +AM,BBC Radio 5 live North East Scotland Redmoss MF,BBC Radio 5 live,693000,57.114016,-2.095089,90,0.8,, +AM,BBC Radio 5 live Cornwall Redruth MF,BBC Radio 5 live,909000,50.217887,-5.2124,182,0.4,, +AM,BBC Radio 5 live Sussex Southwick,BBC Radio 5 live,693000,50.832284,-0.24922,5,0.6,, +AM,BBC Radio 5 live Northumberland Stagshaw,BBC Radio 5 live,693000,55.0326,-2.023437,213,50,, +AM,BBC Radio 5 live South West England Start Point,BBC Radio 5 live,693000,50.228364,-3.663965,122,80,, +AM,BBC Radio 5 live Wales Tywyn,BBC Radio 5 live,990000,52.582906,-4.096237,6,0.4,, +AM,BBC Radio 5 live Central Scotland Westerglen,BBC Radio 5 live,909000,55.974427,-3.818043,155,70,, +AM,BBC Radio 5 live Cumbria Whitehaven MF,BBC Radio 5 live,909000,54.539612,-3.58734,8,0.4,, +AM,BBC Radio Cumbria (AM) Cumbria Barrow,BBC Radio Cumbria (AM),837000,54.126165,-3.198099,23,1,, +AM,BBC Radio Cumbria (AM) Cumbria Brisco,BBC Radio Cumbria (AM),756000,54.864686,-2.917634,38,1,, +AM,BBC Radio Derby (AM) Derbyshire Burnaston,BBC Radio Derby (AM),1116000,52.879237,-1.560132,60,1,, +AM,BBC Radio Gloucestershire (AM) Gloucestershire Berkeley Heath,BBC Radio Gloucestershire (AM),1413000,51.691681,-2.422387,17,0.2,, +AM,BBC Radio Jersey (AM) Jersey Trinity,BBC Radio Jersey (AM),1026000,49.2247,-2.107062,105,1,, +AM,BBC Radio Norfolk (AM) Norfolk West Lynn,BBC Radio Norfolk (AM),873000,52.742777,0.386521,3,0.25,, +AM,BBC Radio Scotland (AM) Scotland Burghead,BBC Radio Scotland (AM),810000,57.69801,-3.46983,40,100,, +AM,BBC Radio Scotland (AM) Central Scotland Westerglen,BBC Radio Scotland (AM),810000,55.974427,-3.818043,155,100,, +AM,BBC Radio Wales (AM) Wales Washford,BBC Radio Wales (AM),882000,51.161365,-3.347935,41,10,, +AM,BBC Somerset (AM) Somerset Taunton MF,BBC Somerset (AM),1566000,51.02226,-3.088245,21,1,, +AM,BFBS Bovington Bovington Camp,BFBS,1287000,50.701288,-2.239253,50,0.001,, +AM,BFBS Gurkha Radio Aldershot Aldershot Garrison - St Omer Barracks,BFBS Gurkha Radio,1278000,51.260401,-0.743088,83,0.001,, +AM,BFBS Gurkha Radio Stafford Beaconside Stafford,BFBS Gurkha Radio,1278000,52.815291,-2.091948,78,0.004,, +AM,BFBS Gurkha Radio Blandford Forum Blandford Camp,BFBS Gurkha Radio,1287000,50.875033,-2.115071,80,0.001,, +AM,BFBS Gurkha Radio Nuneaton Bramcote Barracks,BFBS Gurkha Radio,1134000,52.492879,-1.400508,111,0.001,, +AM,BFBS Gurkha Radio Brecon Brecon Barracks,BFBS Gurkha Radio,1287000,51.946758,-3.390856,133,0.001,, +AM,BFBS Gurkha Radio Gillingham Brompton Barracks,BFBS Gurkha Radio,1287000,51.39174,0.5326,38,0.001,, +AM,BFBS Gurkha Radio Hullavington Buckley Barracks,BFBS Gurkha Radio,1287000,51.530529,-2.128252,91,0.001,, +AM,BFBS Gurkha Radio Salisbury Bulford Camp,BFBS Gurkha Radio,1134000,51.18517,-1.722235,184,0.001,, +AM,BFBS Gurkha Radio Abingdon Dalton Barracks,BFBS Gurkha Radio,1134000,51.688584,-1.304137,67,0.001,, +AM,BFBS Gurkha Radio Innsworth Imjin Barracks,BFBS Gurkha Radio,1287000,51.890072,-2.200475,10,0.001,, +AM,BFBS Gurkha Radio Camberley Sandhurst,BFBS Gurkha Radio,1134000,51.346493,-0.806784,59,0.001,, +AM,BFBS Gurkha Radio Folkestone Sir John Moore Bks,BFBS Gurkha Radio,1287000,51.076852,1.130745,80,0.001,, +AM,BFBS Gurkha Radio Perham Down Swinton Barracks,BFBS Gurkha Radio,1278000,51.238702,-1.634678,132,0.001,, +AM,BFBS Gurkha Radio Catterick Vimy Barracks,BFBS Gurkha Radio,1134000,54.362774,-1.718342,186,0.001,, +AM,BFBS Gurkha Radio Warminster Warminster - BFBS Community Centre,BFBS Gurkha Radio,1287000,51.208761,-2.165146,132,0.001,, +AM,Bradford Asian Radio Bradford Bradford - St Barnabas Church,Bradford Asian Radio,1413000,53.816917,-1.783525,186,0.01,, +AM,Canterbury Hospital Radio Canterbury Kent and Canterbury Hospital,Canterbury Hospital Radio,945000,51.266026,1.086243,42,0.001,, +AM,Carillon Radio Coalville Coalville Community Hospital,Carillon Radio,1431000,52.722761,-1.351463,160,0.001,, +AM,Carillon Wellbeing Radio Coalville Coalville Town FC,Carillon Wellbeing Radio,1476000,52.722298,-1.38271,152,0.25,, +AM,CHR 1431 AM Chichester St Richard's Hospital,CHR 1431 AM,1431000,50.846129,-0.769877,20,0.001,, +AM,Clyde 2 Glasgow Dechmont Hill,Clyde 2,1152000,55.794472,-4.159643,32,3.6,, +AM,Dales Radio Yorkshire Dales Hawes MF,Dales Radio,936000,54.307766,-2.193151,230,0.15,, +AM,Desi Radio Southall Glade Lane,Desi Radio,1602000,51.50439,-0.359891,27,0.16,, +AM,Downtown Radio Belfast Knock-Breckan,Downtown Radio,1026000,54.537281,-5.882789,137,1.7,, +AM,Flame CCR Wirral Willaston,Flame CCR,1521000,53.285675,-3.009447,49,0.07,, +AM,Forth 2 Edinburgh Colinswell,Forth 2,1548000,56.061352,-3.252606,7,2.2,, +AM,Gold Manchester Ashton Moss (NGW),Gold,1458000,53.482863,-2.128802,101,5,, +AM,Gold Peterborough Gunthorpe,Gold,1332000,52.617188,-0.247858,3,0.6,, +AM,Gold Northampton Kings Heath,Gold,1557000,52.263422,-0.917137,63,0.760001,, +AM,Gold Derby Quarndon,Gold,945000,52.973416,-1.507057,125,0.2,, +AM,Gold London Saffron Green,Gold,1548000,51.66492,-0.243194,98,97.5001,, +AM,Gold Nottingham Trowell,Gold,999000,52.953184,-1.248147,69,0.25,, +AM,Greatest Hits Radio Barnsley Ardsley,Greatest Hits Radio,1305000,53.550702,-1.412685,94,0.15,, +AM,Greatest Hits Radio Doncaster Crimpsall,Greatest Hits Radio,990000,53.522412,-1.147759,12,0.25,, +AM,Greatest Hits Radio Tyne and Wear Greenside,Greatest Hits Radio,1152000,54.95869,-1.765727,122,1.8,, +AM,Greatest Hits Radio Stoke-on-Trent Sideway,Greatest Hits Radio,1170000,52.987686,-2.185565,101,0.2,, +AM,Greatest Hits Radio Sheffield and Rotherham Skew Hill,Greatest Hits Radio,1548000,53.435456,-1.509255,229,0.74,, +AM,Greatest Hits Radio Teesside Stockton,Greatest Hits Radio,1170000,54.588636,-1.349732,38,0.32,, +AM,Greatest Hits Radio Bradford Tyersal Lane,Greatest Hits Radio,1278000,53.785735,-1.702486,186,0.43,, +AM,Greatest Hits Radio Halifax and Huddersfield Vicars Lot,Greatest Hits Radio,1530000,53.651685,-1.892848,340,0.74,, +AM,Hub Radio North Bristol UWE Frenchay Campus,Hub Radio,1449000,51.499642,-2.548824,77,0.001,, +AM,Jeo Radio London Sewardstone,Jeo Radio,1584000,51.659623,-0.007147,18,0.5,, +AM,L and D Radio Luton & Dunstable Luton and Dunstable Hospital,L and D Radio,1134000,51.893859,-0.47553,136,0.001,, +AM,LBC News London Saffron Green,LBC News,1152000,51.66492,-0.243194,98,23.5,, +AM,Leicester Community Radio Leicester St. Peter's Highfield Church,Leicester Community Radio,1449000,52.629934,-1.116632,80,0.001,, +AM,Livewire Radio Norwich Colney Training Centre,Livewire Radio,1350000,52.613702,1.206812,32,0.001,, +AM,Lyca Dil Se 1035 London Glade Lane,Lyca Dil Se 1035,1035000,51.50439,-0.359891,27,2.5,, +AM,Lyca Radio 1458 London Brookmans Park,Lyca Radio 1458,1458000,51.727838,-0.176464,127,125,, +AM,Manx Radio (AM) Isle of Man FOXDALE,Manx Radio (AM),1368000,54.167479,-4.61788,164,20,, +AM,MFR 2 Inverness Tarbat Ness,MFR 2,1107000,57.831682,-3.804014,12,1.5,, +AM,Mid-Downs Radio Haywards Heath Princess Royal Hospital,Mid-Downs Radio,1350000,50.989879,-0.090688,79,0.001,, +AM,Panjab Radio Greater London Crystal Palace,Panjab Radio,558000,51.424161,-0.074944,110,2.5,, +AM,Premier Christian Radio London Bow,Premier Christian Radio,1332000,51.532918,-0.017732,1,1,, +AM,Premier Christian Radio London Chingford,Premier Christian Radio,1305000,51.650405,-0.00972,15,0.5,, +AM,Premier Christian Radio London Dartford Marshes,Premier Christian Radio,1413000,51.470819,0.235016,3,0.5,, +AM,Premier Christian Radio London Heathrow,Premier Christian Radio,1413000,51.483903,-0.446896,25,0.5,, +AM,Premier Christian Radio London North Looe,Premier Christian Radio,1305000,51.334992,-0.237316,83,0.5,, +AM,Premier Christian Radio Guildford Peasmarsh,Premier Christian Radio,1566000,51.203838,-0.592895,39,0.8,, +AM,Radio BGWS Farnborough,Radio BGWS,1179000,51.308305,-0.766169,72,0.001,, +AM,Radio Caroline Suffolk Orfordness-A,Radio Caroline,648000,52.102899,1.574156,5,4,, +AM,Radio Cavell Oldham Royal Oldham Hospital,Radio Cavell,1350000,53.55235,-2.122221,176,0.001,, +AM,Radio City Swansea Swansea Mynydd-bach-y-glo,Radio City Swansea,1386000,51.642985,-4.003012,49,0.002,, +AM,Radio Clatterbridge Clatterbridge Clatterbridge Hospital,Radio Clatterbridge,1386000,53.332267,-3.027065,27,0.001,, +AM,Radio Panj Coventry Ryton on Dunsmore,Radio Panj,1521000,52.362389,-1.428267,80,0.1,, +AM,Radio Ramadan 365 Glasgow Glasgow - Shieldhall,Radio Ramadan 365,1530000,55.86858,-4.338619,2,0.04,, +AM,Radio Redhill Redhill East Surrey Hospital,Radio Redhill,1431000,51.218538,-0.161434,66,0.001,, +AM,Radio Seerah Leicester Leicester - SIR Fabrics,Radio Seerah,1575000,52.627046,-1.106748,73,0.004,, +AM,Radio Warrington Warrington,Radio Warrington,1332000,53.376934,-2.626032,1,0.1,, +AM,Radio XL Birmingham Langley Mill B,Radio XL,1296000,52.566973,-1.760955,91,10,, +AM,RaW 1251 AM Coventry University of Warwick,RaW 1251 AM,1251000,52.379413,-1.562174,90,0.001,, +AM,Reindeer Lodge Mold Black Meadows - Mold,Reindeer Lodge,1287000,53.128628,-3.098319,149,0.001,, +AM,Sabras Radio Leicester Freemens Common,Sabras Radio,1260000,52.61896,-1.13158,79,0.29,, +AM,Salaam BCR BURY Bury - Jackson Fold Farm,Salaam BCR,1566000,53.579265,-2.264119,115,0.06,, +AM,Smooth Radio Chelmsford Bakers Wood,Smooth Radio,1359000,51.705132,0.401129,90,0.28,, +AM,Smooth Radio Eastbourne Bexhill MF,Smooth Radio,945000,50.837744,0.447085,15,0.7,, +AM,Smooth Radio Swindon Blunsdon MF,Smooth Radio,1161000,51.609004,-1.794462,147,0.16,, +AM,Smooth Radio Great Yarmouth and Norwich Brundall,Smooth Radio,1152000,52.618097,1.403665,3,0.83,, +AM,Smooth Radio Portsmouth Farlington Marshes,Smooth Radio,1170000,50.842237,-1.024216,3,0.12,, +AM,Smooth Radio Wrexham and Deeside Farndon,Smooth Radio,1260000,53.092461,-2.889935,7,0.64,, +AM,Smooth Radio Bournemouth Fern Barrow,Smooth Radio,828000,50.732788,-1.902461,44,0.27,, +AM,Smooth Radio Ipswich Foxhall Heath,Smooth Radio,1170000,52.055203,1.226159,31,0.28,, +AM,Smooth Radio Bury St Edmunds Great Barton,Smooth Radio,1251000,52.283402,0.764679,61,0.760001,, +AM,Smooth Radio Maidstone and Medway Hoo St Werburgh MF,Smooth Radio,1242000,51.427787,0.57056,20,0.32,, +AM,Smooth Radio Gloucester and Cheltenham Little Shurdington,Smooth Radio,774000,51.856009,-2.127435,69,0.14,, +AM,Smooth Radio East Kent Littlebourne,Smooth Radio,603000,51.287498,1.157969,32,0.4,, +AM,Smooth Radio West Wiltshire Naish Hill,Smooth Radio,936000,51.416202,-2.076595,175,0.18,, +AM,Smooth Radio Plymouth Plumer Barracks,Smooth Radio,1152000,50.406749,-4.125485,101,0.32,, +AM,Smooth Radio Southend Rayleigh MF,Smooth Radio,1431000,51.582733,0.639928,33,0.35,, +AM,Smooth Radio Brighton Southwick,Smooth Radio,1323000,50.832284,-0.24922,5,0.5,, +AM,Smooth Radio Southampton Veals Farm,Smooth Radio,1557000,50.883626,-1.437023,4,0.5,, +AM,Stag Radio Guildford University of Surrey,Stag Radio,1350000,51.242457,-0.588852,70,0.001,, +AM,Sunrise Radio West London Glade Lane,Sunrise Radio,972000,51.50439,-0.359891,27,1.6,, +AM,Sunrise Radio London Lea Bridge Road,Sunrise Radio,963000,51.561867,-0.038692,10,0.950001,, +AM,Sunshine Radio (AM) Ludlow Villa Farm Greete,Sunshine Radio (AM),855000,52.334295,-2.63292,92,0.15,, +AM,Talk Sport Lincs Boston MF,Talk Sport,1107000,52.985991,-0.124813,0,1,, +AM,Talk Sport London Brookmans Park,Talk Sport,1089000,51.727838,-0.176464,127,400,, +AM,Talk Sport Nottingham Clipstone,Talk Sport,1071000,53.171618,-1.128693,91,1,, +AM,Talk Sport Dartford Tunnel,Talk Sport,1089000,51.469253,0.260425,3,0.004,, +AM,Talk Sport Worcestershire Droitwich,Talk Sport,1053000,52.298545,-2.105388,48,500,, +AM,Talk Sport Dumfries Dumfries MF,Talk Sport,1053000,55.027822,-3.480171,12,10,, +AM,Talk Sport West Sussex Duxhurst,Talk Sport,1107000,51.193421,-0.200217,65,1,, +AM,Talk Sport Hampshire Fareham,Talk Sport,1107000,50.849331,-1.226918,30,1,, +AM,Talk Sport Bournemouth Fern Barrow,Talk Sport,1053000,50.732788,-1.902461,44,1,, +AM,Talk Sport Dundee Greenside Scalp,Talk Sport,1053000,56.449964,-2.924023,15,1,, +AM,Talk Sport Humberside Hull MF,Talk Sport,1053000,53.715959,-0.229947,8,1,, +AM,Talk Sport Antrim Lisnagarvey,Talk Sport,1089000,54.489676,-6.060423,44,12.5,, +AM,Talk Sport East Kent Lydd,Talk Sport,1107000,50.950918,0.91565,2,2,, +AM,Talk Sport West Yorkshire Moorside Edge,Talk Sport,1089000,53.635238,-1.894553,340,400,, +AM,Talk Sport Norfolk Postwick,Talk Sport,1053000,52.626852,1.402572,26,18,, +AM,Talk Sport Sussex Southwick,Talk Sport,1053000,50.832284,-0.24922,5,2.2,, +AM,Talk Sport Cleveland Stockton,Talk Sport,1053000,54.588636,-1.349732,38,1,, +AM,Talk Sport West Kent Tonbridge,Talk Sport,1053000,51.139442,0.224404,104,4,, +AM,Talk Sport Merseyside Wallasey,Talk Sport,1107000,53.42567,-3.046924,40,0.5,, +AM,Talk Sport Somerset Washford,Talk Sport,1089000,51.161365,-3.347935,41,80,, +AM,Talk Sport Central Scotland Westerglen,Talk Sport,1089000,55.974427,-3.818043,155,125,, +AM,Talk Sport Newcastle Wrekenton,Talk Sport,1071000,54.932736,-1.572984,152,1,, +AM,Tay 2 Perth Friarton Road,Tay 2,1584000,56.376097,-3.427597,20,0.21,, +AM,Tay 2 Dundee Greenside Scalp,Tay 2,1161000,56.449964,-2.924023,15,1.4,, +AM,University Radio York York University of York,University Radio York,1350000,53.947755,-1.053788,15,0.001,, +AM,WestSound Ayr Symington,WestSound,1035000,55.567692,-4.574968,50,0.32,, +FM,10 Radio Wiveliscombe Milverton,10 Radio,105300000,51.027561,-3.275316,148,0.025,, +FM,1055 The Point Milton Keynes Milton Keynes - Saxon Gate,1055 The Point,105500000,52.043319,-0.761199,111,0.025,, +FM,107FM East Hull Hull - Muswell Court,107FM,107400000,53.775775,-0.281912,4,0.025,, +FM,1BTN Brighton and Hove Brighton Race Course,1BTN,101400000,50.829169,-0.112873,124,0.025,, +FM,3FM Isle of Man Beary Peark,3FM,106200000,54.216063,-4.616199,289,0.26,, +FM,3FM Cronk ny Arrey,3FM,104200000,54.067672,-4.76307,159,0.05,, +FM,3FM Isle of Man DOUGLAS,3FM,105000000,54.140551,-4.493075,143,1.8,, +FM,3FM Ramsey Ramsey Town C,3FM,104200000,54.324756,-4.386402,2,0.05,, +FM,3FM Isle of Man Snaefell,3FM,106600000,54.262536,-4.462965,610,0.201,, +FM,3TFM Community Radio for Health Saltcoats,3TFM Community Radio for Health,103100000,55.646655,-4.774865,47,0.025,, +FM,60 North FM Shetland Isles Brae Marina (LRSL),60 North FM,87700000,60.392566,-1.364989,0,0.001,, +FM,60 North FM Shetland Isles Bressay and Noss Nature Reserve (LRSL),60 North FM,87700000,60.120015,-1.121929,1,0.001,, +FM,60 North FM Shetland Isles Eshares (LRSL),60 North FM,87700000,60.489627,-1.62696,58,0.001,, +FM,60 North FM Shetland Isles Haroldswick (LRSL),60 North FM,87700000,60.798307,-0.82047,33,0.001,, +FM,60 North FM Shetland Isles Sumburgh Head Nature Reserve (LRSL),60 North FM,87700000,59.854256,-1.275309,65,0.001,, +FM,60 North FM Shetland Isles Walls Marina (LRSL),60 North FM,87700000,60.22636,-1.563163,1,0.001,, +FM,Abbey 104 Sherborne,Abbey 104,104700000,50.959202,-2.514807,116,0.025,, +FM,Academy FM 105.9 Folkestone Folkestone Academy,Academy FM 105.9,105900000,51.091482,1.1653,42,0.025,, +FM,Academy FM 107.8 Thanet Ramsgate - Royal Harbour Academy,Academy FM 107.8,107800000,51.350467,1.392417,49,0.05,, +FM,AIR Weymouth,AIR,107200000,50.59912,-2.476532,64,0.1,, +FM,Aldergrove and Antrim FM Aldergrove and Antrim RAF Aldergrove,Aldergrove and Antrim FM,106500000,54.65275,-6.21226,86,0.025,, +FM,Alfred Shaftesbury Shaftesbury - Trinity Centre,Alfred,107300000,51.00592,-2.199129,218,0.025,, +FM,Alive Radio Dumfries,Alive Radio,107300000,55.065505,-3.619211,40,0.08,, +FM,ALL FM Manchester Manchester - Bickerdike Court,ALL FM,96900000,53.4542,-2.1888,56,0.05,, +FM,Amber Sound FM Belper Belper - King Street,Amber Sound FM,98400000,53.02319,-1.479655,81,0.025,, +FM,Amber Sound FM Ripley,Amber Sound FM,107200000,53.048812,-1.403566,152,0.025,, +FM,Ambur Radio Walsall Walsall - Townend House,Ambur Radio,99400000,52.586091,-1.984607,125,0.05,, +FM,Andover Radio Andover Andover - Michedever Road,Andover Radio,95900000,51.204151,-1.465333,114,0.025,, +FM,Angel Radio Portsmouth and Havant Fort Widley,Angel Radio,98600000,50.853922,-1.067587,102,0.1,, +FM,Angel Radio Isle of Wight Isle Of Wight Newport - Garretts Farm,Angel Radio Isle of Wight,91500000,50.683007,-1.275373,97,0.025,, +FM,Anker Radio Nuneaton George Eliot Hospital - maternity,Anker Radio,88900000,52.512434,-1.476864,100,0.001,, +FM,Apple FM Taunton Taunton - Musgrove Park Hospital,Apple FM,97300000,51.011891,-3.119648,20,0.025,, +FM,Argyll FM Kintyre Islay and Jura Ballygroggan,Argyll FM,107100000,55.405447,-5.746276,182,0.625,, +FM,Argyll FM Kintyre Islay and Jura Campbeltown - Baraskomill,Argyll FM,106500000,55.433038,-5.569557,92,0.5,, +FM,Argyll FM Kintyre Islay and Jura South Knapdale,Argyll FM,107700000,55.91751,-5.462223,481,0.5,, +FM,Ashdown Radio Crowborough,Ashdown Radio,94700000,51.05856,0.158875,221,0.025,, +FM,Ashdown Radio Uckfield,Ashdown Radio,105000000,50.967238,0.111767,47,0.125,, +FM,Asian Star 101.6 FM Slough Slough - Queensmere,Asian Star 101.6 FM,101600000,51.508658,-0.591451,30,0.025,, +FM,Awaaz FM Southampton Midanbury - The Castle,Awaaz FM,99800000,50.92624,-1.364941,62,0.0216,, +FM,Awaz FM Glasgow Glasgow - Dundasvale Court - Block 2,Awaz FM,107200000,55.869339,-4.259542,30,0.025,, +FM,B Radio Farnborough Farnborough - Westmead House,B Radio,106500000,51.289155,-0.757935,68,0.1,, +FM,B Radio Reading Reading - Fountain House,B Radio,95600000,51.454569,-0.977254,43,0.1,, +FM,Bailrigg FM Lancaster Lancaster University,Bailrigg FM,95300000,54.008228,-2.785769,57,0.002,, +FM,Bangor FM Bangor Bangor - SERC,Bangor FM,107900000,54.65614,-5.662282,22,0.025,, +FM,Basildon Hospital Radio (BHR) Basildon Basildon - University Hospital,Basildon Hospital Radio (BHR),87700000,51.558561,0.452552,50,5e-05,, +FM,BBC Coventry and Warwickshire Nuneaton Hartshill Quarry,BBC Coventry and Warwickshire,104000000,52.540463,-1.503661,140,0.05,, +FM,BBC Coventry and Warwickshire Coventry and Warwickshire Lark Stoke,BBC Coventry and Warwickshire,103700000,52.081613,-1.728531,260,0.7,, +FM,BBC Coventry and Warwickshire Coventry Meriden VHF,BBC Coventry and Warwickshire,94800000,52.457753,-1.624974,178,1.1,, +FM,BBC Essex (FM) Essex Benfleet,BBC Essex (FM),95300000,51.550856,0.5811,80,1.0064,, +FM,BBC Essex (FM) Dartford Tunnel,BBC Essex (FM),95300000,51.469253,0.260425,3,0,, +FM,BBC Essex (FM) Essex Great Braxted,BBC Essex (FM),103500000,51.801904,0.710885,81,6,, +FM,BBC Guernsey (FM) Alderney,BBC Guernsey (FM),99000000,49.717948,-2.189296,69,0.025,, +FM,BBC Guernsey (FM) Guernsey Les Touillets,BBC Guernsey (FM),93200000,49.457792,-2.579202,76,0.5,, +FM,BBC Hereford and Worcester (FM) Redditch Headless Cross GSC,BBC Hereford and Worcester (FM),104400000,52.294535,-1.946877,162,0.1,, +FM,BBC Hereford and Worcester (FM) Kidderminster KIDDERMINSTER,BBC Hereford and Worcester (FM),104600000,52.363252,-2.282794,82,0.25,, +FM,BBC Hereford and Worcester (FM) Worcestershire MALVERN,BBC Hereford and Worcester (FM),104000000,52.115715,-2.330146,161,1,, +FM,BBC Hereford and Worcester (FM) Herefordshire RIDGE HILL,BBC Hereford and Worcester (FM),94700000,51.997433,-2.53989,204,1,, +FM,BBC Lincolnshire (FM) Lincolnshire Belmont,BBC Lincolnshire (FM),94900000,53.335814,-0.171983,125,3,, +FM,BBC Lincolnshire (FM) Grantham,BBC Lincolnshire (FM),104700000,52.892406,-0.655971,115,0.05,, +FM,BBC London 94.9 London Crystal Palace,BBC London 94.9,94900000,51.424161,-0.074944,110,2,, +FM,BBC London 94.9 Dartford Tunnel,BBC London 94.9,94900000,51.469253,0.260425,3,0,, +FM,BBC Newcastle (FM) Northumberland CHATTON,BBC Newcastle (FM),96000000,55.531826,-1.834261,192,2.8,, +FM,BBC Newcastle (FM) Newcastle Fenham,BBC Newcastle (FM),104400000,54.978039,-1.662966,120,0.042,, +FM,BBC Newcastle (FM) Newcastle NEWTON,BBC Newcastle (FM),103700000,54.982447,-1.945593,165,0.1,, +FM,BBC Newcastle (FM) Tyneside PONTOP PIKE,BBC Newcastle (FM),95400000,54.868838,-1.771233,302,5,, +FM,BBC Oxford Oxfordshire Oxford,BBC Oxford,95200000,51.790638,-1.179183,130,2.54081,, +FM,BBC Radio 1 Aberdare,BBC Radio 1,98800000,51.702007,-3.398531,282,0.021,, +FM,BBC Radio 1 Abergavenny,BBC Radio 1,98300000,51.807795,-3.097781,433,0.02,, +FM,BBC Radio 1 Pontypool Abertillery,BBC Radio 1,98600000,51.714666,-3.12404,400,0.01,, +FM,BBC Radio 1 Argyll & Bute Ardgour,BBC Radio 1,98300000,56.712175,-5.290096,12,0.005,, +FM,BBC Radio 1 Scottish Borders Ashkirk,BBC Radio 1,98700000,55.510631,-2.840766,303,20.3208,, +FM,BBC Radio 1 Axe Valley,BBC Radio 1,99100000,50.74593,-3.016766,169,0.08,, +FM,BBC Radio 1 Argyll & Bute Ballachulish,BBC Radio 1,97700000,56.684359,-5.170394,14,0.015,, +FM,BBC Radio 1 North Antrim Ballycastle,BBC Radio 1,98400000,55.215995,-6.309339,150,0.05,, +FM,BBC Radio 1 Skipton Barnoldswick,BBC Radio 1,99300000,53.928368,-2.15728,191,0.02,, +FM,BBC Radio 1 North Devon Barnstaple,BBC Radio 1,98100000,51.040763,-4.13826,116,0.5,, +FM,BBC Radio 1 Basingstoke,BBC Radio 1,99700000,51.226848,-1.080409,176,0.02,, +FM,BBC Radio 1 Bath,BBC Radio 1,98600000,51.38779,-2.332925,175,0.041,, +FM,BBC Radio 1 Torbay Beacon Hill North,BBC Radio 1,98400000,50.447129,-3.610498,196,0.794328,, +FM,BBC Radio 1 Leeds Beecroft Hill,BBC Radio 1,99400000,53.811543,-1.641253,149,0.2,, +FM,BBC Radio 1 Lincolnshire Belmont,BBC Radio 1,98300000,53.335814,-0.171983,125,8.3,, +FM,BBC Radio 1 Stirling Ben Gullipen,BBC Radio 1,98300000,56.212308,-4.263559,415,1,, +FM,BBC Radio 1 Borders Berwick-upon-Tweed,BBC Radio 1,98200000,55.785854,-2.032822,129,0.05,, +FM,BBC Radio 1 Snowdonia Betws Y Coed,BBC Radio 1,97800000,53.108346,-3.75717,303,0.025,, +FM,BBC Radio 1 Bexhill,BBC Radio 1,99200000,50.84568,0.475913,45,0.0117,, +FM,BBC Radio 1 North Yorkshire Bilsdale - Station Tower,BBC Radio 1,98600000,54.358848,-1.149317,381,2,, +FM,BBC Radio 1 Central Scotland Black Hill,BBC Radio 1,99500000,55.860005,-3.873572,275,122.155,, +FM,BBC Radio 1 Blaenavon,BBC Radio 1,98100000,51.750968,-3.048742,373,0.01,, +FM,BBC Radio 1 Ceredigion Blaenplwyf,BBC Radio 1,98300000,52.360613,-4.102585,174,125,, +FM,BBC Radio 1 Swindon Blunsdon,BBC Radio 1,98600000,51.609363,-1.794027,148,0.2,, +FM,BBC Radio 1 Milton Keynes Bow Brickhill,BBC Radio 1,98200000,51.998806,-0.669784,169,5,, +FM,BBC Radio 1 Islay Bowmore,BBC Radio 1,97700000,55.750128,-6.274228,46,0.061,, +FM,BBC Radio 1 Mid Wales Brecon VHF,BBC Radio 1,98500000,51.959448,-3.412497,248,0.01,, +FM,BBC Radio 1 Shetland Bressay,BBC Radio 1,97900000,60.130079,-1.096281,224,25,, +FM,BBC Radio 1 Dorchester and Weymouth Bridport,BBC Radio 1,98700000,50.720805,-2.775678,64,0.2,, +FM,BBC Radio 1 Omagh and Enniskillen Brougher Mountain,BBC Radio 1,99000000,54.423191,-7.462812,305,5,, +FM,BBC Radio 1 North Derbyshire Buxton,BBC Radio 1,99600000,53.275085,-1.911935,432,0.05,, +FM,BBC Radio 1 Calne CALNE,BBC Radio 1,97800000,51.428815,-2.005417,104,0.032,, +FM,BBC Radio 1 Kirkcudbright CAMBRET HILL,BBC Radio 1,98300000,54.893698,-4.302038,343,0.065,, +FM,BBC Radio 1 South Newry Camlough,BBC Radio 1,98300000,54.160861,-6.385716,340,2,, +FM,BBC Radio 1 Kintyre Islay and Jura CAMPBELTOWN,BBC Radio 1,98000000,55.413714,-5.624241,83,0.2,, +FM,BBC Radio 1 Carmarthen,BBC Radio 1,98500000,51.867126,-4.309135,137,0.01,, +FM,BBC Radio 1 Carmarthenshire Carmel,BBC Radio 1,98000000,51.818501,-4.066216,255,1.7895,, +FM,BBC Radio 1 Newtownabbey Carnmoney Hill,BBC Radio 1,98400000,54.676355,-5.928737,207,0.02,, +FM,BBC Radio 1 Caterham Valley CATERHAM,BBC Radio 1,99300000,51.284605,-0.075623,173,0.015,, +FM,BBC Radio 1 Gloucestershire CHALFORD,BBC Radio 1,98800000,51.714525,-2.170893,174,0.1,, +FM,BBC Radio 1 Somerset Chard,BBC Radio 1,98500000,50.874213,-2.913244,173,0.05,, +FM,BBC Radio 1 Northumberland CHATTON,BBC Radio 1,99700000,55.531826,-1.834261,192,2.8,, +FM,BBC Radio 1 South Yorkshire Chesterfield,BBC Radio 1,98600000,53.283991,-1.427446,179,0.4,, +FM,BBC Radio 1 Chippenham,BBC Radio 1,98400000,51.474065,-2.12579,103,0.009,, +FM,BBC Radio 1 Gloucestershire Churchdown Hill,BBC Radio 1,98600000,51.868264,-2.175397,147,0.036,, +FM,BBC Radio 1 Cirencester,BBC Radio 1,97700000,51.717612,-1.968107,112,0.01,, +FM,BBC Radio 1 North Uist Clettraval,BBC Radio 1,97700000,57.617267,-7.44252,123,2,, +FM,BBC Radio 1 Wye Valley CLYRO,BBC Radio 1,99800000,52.08185,-3.162868,215,0.01,, +FM,BBC Radio 1 Ilfracombe Combe Martin,BBC Radio 1,98700000,51.197266,-4.031278,144,0.004,, +FM,BBC Radio 1 Conway CONWY,BBC Radio 1,98700000,53.271606,-3.828796,114,0.05,, +FM,BBC Radio 1 Calder Valley CORNHOLME,BBC Radio 1,99300000,53.734447,-2.125781,312,0.02,, +FM,BBC Radio 1 Folkestone Creteway Down,BBC Radio 1,98300000,51.099738,1.182579,166,0.1,, +FM,BBC Radio 1 Crieff CRIEFF,BBC Radio 1,98900000,56.357222,-3.920232,219,0.125,, +FM,BBC Radio 1 Croeserw,BBC Radio 1,98600000,51.644491,-3.652146,343,0.01,, +FM,BBC Radio 1 London Crystal Palace,BBC Radio 1,98500000,51.424161,-0.074944,110,4,, +FM,BBC Radio 1 Cwmafan,BBC Radio 1,98100000,51.628417,-3.737817,210,0.01,, +FM,BBC Radio 1 South Uist Daliburgh,BBC Radio 1,98900000,57.169643,-7.402558,6,1,, +FM,BBC Radio 1 Dartford Tunnel,BBC Radio 1,98800000,51.469253,0.260425,3,0,, +FM,BBC Radio 1 Ayrshire DARVEL,BBC Radio 1,99100000,55.579376,-4.289814,286,5,, +FM,BBC Radio 1 Darwen DARWEN,BBC Radio 1,99100000,53.696571,-2.443266,261,0.01,, +FM,BBC Radio 1 Gwynedd DEINIOLEN,BBC Radio 1,97700000,53.137063,-4.129256,322,0.05,, +FM,BBC Radio 1 Northern Ireland Divis A,BBC Radio 1,99700000,54.607538,-6.009471,368,61.0773,, +FM,BBC Radio 1 Snowdonia DOLGELLAU,BBC Radio 1,99700000,52.749344,-3.886853,103,0.025,, +FM,BBC Radio 1 Isle of Man DOUGLAS,BBC Radio 1,98000000,54.140551,-4.493075,143,5.7,, +FM,BBC Radio 1 Aberdeen Durris,BBC Radio 1,99000000,56.999987,-2.389944,325,1.05,, +FM,BBC Radio 1 South Wales EBBW VALE,BBC Radio 1,98000000,51.771714,-3.218938,442,0.015,, +FM,BBC Radio 1 Frome Egford Hill,BBC Radio 1,98700000,51.231585,-2.3391,132,0.06,, +FM,BBC Radio 1 Isle of Lewis Eitshal,BBC Radio 1,99400000,58.179148,-6.584974,206,2,, +FM,BBC Radio 1 Exeter Exeter (St Thomas),BBC Radio 1,98600000,50.719122,-3.562148,102,0.0275,, +FM,BBC Radio 1 Borders EYEMOUTH,BBC Radio 1,99300000,55.83228,-2.085863,197,0.1,, +FM,BBC Radio 1 Newcastle Fenham,BBC Radio 1,99400000,54.978039,-1.662966,120,0.042,, +FM,BBC Radio 1 South Wales Ferndale,BBC Radio 1,99200000,51.662873,-3.437376,386,0.01,, +FM,BBC Radio 1 Snowdonia FFESTINIOG,BBC Radio 1,97700000,52.934172,-3.921818,308,0.082081,, +FM,BBC Radio 1 Angus Forfar,BBC Radio 1,97900000,56.55718,-2.843663,206,10,, +FM,BBC Radio 1 Great Glen Fort Augustus,BBC Radio 1,98200000,57.105987,-4.70869,307,1,, +FM,BBC Radio 1 Fort William,BBC Radio 1,98900000,56.848302,-5.088621,16,2,, +FM,BBC Radio 1 Ayr GIRVAN,BBC Radio 1,98500000,55.244736,-4.814596,195,0.1,, +FM,BBC Radio 1 Isle of Mull Glengorm,BBC Radio 1,99100000,56.632166,-6.133249,253,2.5,, +FM,BBC Radio 1 Tiverton Gogwell,BBC Radio 1,99200000,50.889583,-3.469029,233,0.3,, +FM,BBC Radio 1 Grantham,BBC Radio 1,97700000,52.892406,-0.655971,115,0.05,, +FM,BBC Radio 1 Cairngorms Grantown,BBC Radio 1,99400000,57.320173,-3.656313,389,0.36,, +FM,BBC Radio 1 Guildford GUILDFORD,BBC Radio 1,97700000,51.228358,-0.605467,142,2,, +FM,BBC Radio 1 Rossendale HASLINGDEN,BBC Radio 1,99500000,53.708491,-2.311438,336,0.1,, +FM,BBC Radio 1 Hastings,BBC Radio 1,97700000,50.861622,0.566431,76,0.25,, +FM,BBC Radio 1 Pembrokeshire Haverfordwest,BBC Radio 1,98900000,51.899195,-4.86653,186,9.54993,, +FM,BBC Radio 1 Hebden Bridge HEBDEN BRIDGE,BBC Radio 1,98000000,53.737298,-2.018458,220,0.025,, +FM,BBC Radio 1 Caversham Hemdean,BBC Radio 1,99400000,51.481196,-0.978531,69,1,, +FM,BBC Radio 1 High Wycombe,BBC Radio 1,99600000,51.640531,-0.763678,156,0.025,, +FM,BBC Radio 1 Teignmouth Holcombe Down,BBC Radio 1,99000000,50.566699,-3.506408,205,0.1,, +FM,BBC Radio 1 Yorkshire and Lancashire Holme Moss,BBC Radio 1,98900000,53.533184,-1.858296,524,124.983,, +FM,BBC Radio 1 Weston-super-Mare Hutton,BBC Radio 1,99000000,51.325227,-2.918301,73,0.04,, +FM,BBC Radio 1 Bradford Idle,BBC Radio 1,98100000,53.832945,-1.752142,215,0.01,, +FM,BBC Radio 1 Bristol Ilchester Crescent,BBC Radio 1,98900000,51.427947,-2.609813,48,0.649999,, +FM,BBC Radio 1 Borders INNERLEITHEN,BBC Radio 1,99100000,55.620243,-3.07272,244,0.011,, +FM,BBC Radio 1 Isles of Scilly,BBC Radio 1,98400000,49.932504,-6.305394,32,0.03,, +FM,BBC Radio 1 Devon Ivybridge,BBC Radio 1,99500000,50.368664,-3.926486,142,0.05,, +FM,BBC Radio 1 Orkney Keelylang Hill B,BBC Radio 1,98900000,58.975283,-3.083943,220,16,, +FM,BBC Radio 1 West Yorkshire KEIGHLEY,BBC Radio 1,98500000,53.895532,-1.896639,305,1,, +FM,BBC Radio 1 South Lakes Kendal,BBC Radio 1,98600000,54.314559,-2.708127,172,0.05,, +FM,BBC Radio 1 Kenley KENLEY,BBC Radio 1,98000000,51.317089,-0.09335,152,0.025,, +FM,BBC Radio 1 North Lakes Keswick Forest,BBC Radio 1,99200000,54.608739,-3.204646,215,0,, +FM,BBC Radio 1 Kilkeel,BBC Radio 1,99000000,54.095375,-6.041723,267,0.1,, +FM,BBC Radio 1 Swansea Kilvey Hill,BBC Radio 1,99100000,51.62891,-3.919745,193,0.5,, +FM,BBC Radio 1 DartmouthDartmouth Kingswear,BBC Radio 1,99400000,50.349538,-3.565025,107,0.005,, +FM,BBC Radio 1 Cairngorms KINGUSSIE,BBC Radio 1,98700000,57.061393,-4.030507,351,0.05,, +FM,BBC Radio 1 Kinlochleven,BBC Radio 1,99300000,56.722796,-4.978914,273,0.005,, +FM,BBC Radio 1 Borders Kirkconnel,BBC Radio 1,98300000,55.412875,-3.983785,480,0.02,, +FM,BBC Radio 1 Perth Kirkton Mailer,BBC Radio 1,98600000,56.372293,-3.453361,178,0.5,, +FM,BBC Radio 1 Moray Knockmore,BBC Radio 1,97800000,57.532303,-3.135126,353,1,, +FM,BBC Radio 1 Larne,BBC Radio 1,98700000,54.862024,-5.828421,119,0.05,, +FM,BBC Radio 1 Jersey Les Platons,BBC Radio 1,97100000,49.246023,-2.1012,134,8,, +FM,BBC Radio 1 East Ayrshire LETHANHILL,BBC Radio 1,97900000,55.36421,-4.464995,300,0.11,, +FM,BBC Radio 1 Limavady,BBC Radio 1,99200000,55.109172,-6.886121,341,1.7,, +FM,BBC Radio 1 Anglesey LLANDDONA,BBC Radio 1,99400000,53.307002,-4.12825,146,10.5,, +FM,BBC Radio 1 Snowdonia LLANDECWYN,BBC Radio 1,99000000,52.914419,-4.017769,268,0.1,, +FM,BBC Radio 1 Mid Wales LLANDINAM,BBC Radio 1,99700000,52.479547,-3.399945,454,0.022,, +FM,BBC Radio 1 Llandrindod Wells,BBC Radio 1,98700000,52.261047,-3.439354,432,1.39,, +FM,BBC Radio 1 Ceredigion LLANDYFRIOG,BBC Radio 1,99700000,52.045314,-4.410045,116,0.05,, +FM,BBC Radio 1 Llanfyllin LLANFYLLIN,BBC Radio 1,98700000,52.753349,-3.259797,264,0.003972,, +FM,BBC Radio 1 Bridgend Llangeinor,BBC Radio 1,98200000,51.586117,-3.581462,306,0.01,, +FM,BBC Radio 1 Llangollen and Cheshire Llangollen VHF,BBC Radio 1,98500000,53.031048,-3.180791,556,7.80001,, +FM,BBC Radio 1 Mid Wales LLANIDLOES,BBC Radio 1,97700000,52.446933,-3.549585,244,0.025,, +FM,BBC Radio 1 Llanrhaeadr ym Mochnant LLANRHAEADR YM MOCHN,BBC Radio 1,99400000,52.825889,-3.226423,333,0.025,, +FM,BBC Radio 1 Snowdonia LLWYN ONN,BBC Radio 1,97900000,52.737496,-4.03773,277,0.25,, +FM,BBC Radio 1 Talgarth LLYSWEN,BBC Radio 1,99200000,52.016761,-3.258522,224,0.01,, +FM,BBC Radio 1 Londonderry,BBC Radio 1,98300000,55.00421,-7.368968,175,15.6,, +FM,BBC Radio 1 Welshpool LONG MOUNTAIN,BBC Radio 1,99200000,52.644306,-3.086542,400,0.024,, +FM,BBC Radio 1 Calderdale LUDDENDEN,BBC Radio 1,98300000,53.720111,-1.92874,256,0.084,, +FM,BBC Radio 1 Ludlow LUDLOW,BBC Radio 1,99200000,52.362722,-2.738327,216,0.005,, +FM,BBC Radio 1 Lyme Regis,BBC Radio 1,99300000,50.737572,-2.929856,162,0.05,, +FM,BBC Radio 1 Snowdonia MACHYNLLETH,BBC Radio 1,99000000,52.586449,-3.885603,100,0.06,, +FM,BBC Radio 1 Cambridgeshire Madingley,BBC Radio 1,98500000,52.215394,0.036667,62,0.13,, +FM,BBC Radio 1 Mallaig,BBC Radio 1,97700000,57.001499,-5.828475,71,0.02,, +FM,BBC Radio 1 Colchester and Ipswich Manningtree,BBC Radio 1,97700000,51.92387,1.086097,35,2.5,, +FM,BBC Radio 1 Marlborough MARLBOROUGH,BBC Radio 1,99700000,51.417912,-1.699977,192,0.1,, +FM,BBC Radio 1 Aberdeenshire Meldrum,BBC Radio 1,98300000,57.386674,-2.400197,245,75,, +FM,BBC Radio 1 Wester Ross Melvaig,BBC Radio 1,98700000,57.842382,-5.782182,271,17.5903,, +FM,BBC Radio 1 Membury,BBC Radio 1,98400000,51.484903,-1.558836,211,0.125,, +FM,BBC Radio 1 Mickleham MICKLEHAM,BBC Radio 1,99300000,51.272007,-0.333055,103,0.025,, +FM,BBC Radio 1 Dumbarton Millburn Muir,BBC Radio 1,97900000,55.982322,-4.600708,152,0.025,, +FM,BBC Radio 1 West Somerset Minehead,BBC Radio 1,98600000,51.19744,-3.48052,79,0.01,, +FM,BBC Radio 1 Morecambe Bay,BBC Radio 1,99600000,54.202505,-3.167346,259,5,, +FM,BBC Radio 1 Cardigan Bay Mynydd Pencarreg,BBC Radio 1,99300000,52.067402,-4.076523,411,0.2,, +FM,BBC Radio 1 Gloucestershire NAILSWORTH,BBC Radio 1,97800000,51.690257,-2.219843,114,0.1,, +FM,BBC Radio 1 Isle of Lewis Ness of Lewis,BBC Radio 1,97900000,58.461531,-6.230808,100,0.162,, +FM,BBC Radio 1 Newbury,BBC Radio 1,97800000,51.414621,-1.290472,130,0.1,, +FM,BBC Radio 1 Newhaven NEWHAVEN,BBC Radio 1,99300000,50.787726,0.035848,81,0.05,, +FM,BBC Radio 1 Newcastle NEWTON,BBC Radio 1,99000000,54.982447,-1.945593,165,0.1,, +FM,BBC Radio 1 Devon North Hessary Tor,BBC Radio 1,97700000,50.550217,-4.008413,508,80,, +FM,BBC Radio 1 Northamptonshire Northampton,BBC Radio 1,98500000,52.275355,-0.885481,127,0.0615,, +FM,BBC Radio 1 Oban and Mull Oban,BBC Radio 1,98500000,56.40396,-5.485882,122,2.5,, +FM,BBC Radio 1 Ogmore Vale,BBC Radio 1,98800000,51.593504,-3.546781,298,0.01,, +FM,BBC Radio 1 Okehampton,BBC Radio 1,98300000,50.753618,-4.005483,208,0.025,, +FM,BBC Radio 1 Scarborough OLIVERS MOUNT,BBC Radio 1,99500000,54.267351,-0.404494,151,0.125,, +FM,BBC Radio 1 Oxfordshire Oxford,BBC Radio 1,99100000,51.790638,-1.179183,130,17.5903,, +FM,BBC Radio 1 Borders PEEBLES,BBC Radio 1,98000000,55.661832,-3.227732,352,0.02,, +FM,BBC Radio 1 Bodmin Penaligon Downs,BBC Radio 1,98400000,50.481389,-4.782638,116,0.2,, +FM,BBC Radio 1 Burnley Pendle Forest,BBC Radio 1,97800000,53.841893,-2.266074,276,0.5,, +FM,BBC Radio 1 Penicuik PENICUIK,BBC Radio 1,98200000,55.819142,-3.194377,248,0.132,, +FM,BBC Radio 1 Portree Penifiler,BBC Radio 1,97700000,57.395531,-6.180316,52,0.005,, +FM,BBC Radio 1 Colwyn Bay Penmaen Rhos,BBC Radio 1,98000000,53.286941,-3.684982,125,0.1,, +FM,BBC Radio 1 Cwmbran Pennar,BBC Radio 1,99100000,51.656112,-3.144564,228,0.005,, +FM,BBC Radio 1 Huntingdonshire Peterborough,BBC Radio 1,99700000,52.507615,-0.343282,56,18.7,, +FM,BBC Radio 1 Pitlochry PITLOCHRY,BBC Radio 1,98800000,56.687307,-3.759852,401,0,, +FM,BBC Radio 1 Plymouth Plympton,BBC Radio 1,98100000,50.381346,-4.067802,113,0.04,, +FM,BBC Radio 1 Tyneside PONTOP PIKE,BBC Radio 1,98100000,54.868838,-1.771233,302,67.5,, +FM,BBC Radio 1 Pontypool,BBC Radio 1,98800000,51.685712,-3.036095,250,0.025,, +FM,BBC Radio 1 Islay PORT ELLEN,BBC Radio 1,98600000,55.627446,-6.227617,93,0.065,, +FM,BBC Radio 1 Pontypridd Porth,BBC Radio 1,98000000,51.617787,-3.403306,247,0.01,, +FM,BBC Radio 1 West Cornwall Redruth,BBC Radio 1,99300000,50.209786,-5.238489,237,8.80001,, +FM,BBC Radio 1 Neath Valley RHEOLA,BBC Radio 1,97800000,51.741661,-3.679878,409,0.01,, +FM,BBC Radio 1 Rhymney RHYMNEY,BBC Radio 1,98900000,51.730587,-3.264891,419,0.02,, +FM,BBC Radio 1 Herefordshire RIDGE HILL,BBC Radio 1,98200000,51.997433,-2.53989,204,5,, +FM,BBC Radio 1 Highland Rosemarkie,BBC Radio 1,99200000,57.633195,-4.075231,206,9.77237,, +FM,BBC Radio 1 Coupar Rosemount,BBC Radio 1,99200000,56.576982,-3.298257,81,0.032,, +FM,BBC Radio 1 Helensburgh Rosneath,BBC Radio 1,98800000,55.991937,-4.793795,107,0.025,, +FM,BBC Radio 1 South Newry Rostrevor Forest,BBC Radio 1,97900000,54.092725,-6.182015,215,0.02,, +FM,BBC Radio 1 Bute ROTHESAY,BBC Radio 1,98100000,55.878164,-4.998928,166,0.285,, +FM,BBC Radio 1 Hampshire and Isle of Wight ROWRIDGE,BBC Radio 1,98200000,50.676724,-1.370435,143,125,, +FM,BBC Radio 1 Caithness Rumster Forest,BBC Radio 1,99700000,58.328006,-3.371413,221,5,, +FM,BBC Radio 1 Greater Manchester SADDLEWORTH,BBC Radio 1,99300000,53.541535,-2.020635,347,0.1,, +FM,BBC Radio 1 Salcombe,BBC Radio 1,99100000,50.244921,-3.749115,61,0.198582,, +FM,BBC Radio 1 Salisbury SALISBURY,BBC Radio 1,99400000,51.055855,-1.806762,107,0.012619,, +FM,BBC Radio 1 Cumbria & South West Scotland Sandale,BBC Radio 1,97700000,54.749109,-3.14076,363,125,, +FM,BBC Radio 1 South Yorkshire Sheffield,BBC Radio 1,99500000,53.379385,-1.513809,247,0.16,, +FM,BBC Radio 1 Skye & Lochalsh Skriaig,BBC Radio 1,98100000,57.38642,-6.24289,390,9.68481,, +FM,BBC Radio 1 Kintyre Islay and Jura South Knapdale,BBC Radio 1,98900000,55.91751,-5.462223,481,1.1,, +FM,BBC Radio 1 Derbyshire Stanton Moor,BBC Radio 1,99400000,53.170195,-1.633756,305,0.6,, +FM,BBC Radio 1 Inveraray Strachur,BBC Radio 1,98400000,56.179137,-5.071531,175,0.01,, +FM,BBC Radio 1 Galloway STRANRAER,BBC Radio 1,99300000,54.928074,-4.949004,190,0.031,, +FM,BBC Radio 1 West Midlands SUTTON COLDFIELD,BBC Radio 1,97900000,52.600539,-1.833856,169,62.5,, +FM,BBC Radio 1 Dover Swingate,BBC Radio 1,99500000,51.137832,1.335758,122,5.5,, +FM,BBC Radio 1 Norfolk TACOLNESTON,BBC Radio 1,99300000,52.518759,1.138705,64,119.374,, +FM,BBC Radio 1 Calder Valley TODMORDEN,BBC Radio 1,98500000,53.713283,-2.065416,221,0.1,, +FM,BBC Radio 1 Rhondda Valley Ton Pentre,BBC Radio 1,98400000,51.64954,-3.504023,323,0.003,, +FM,BBC Radio 1 Tullich TULLICH,BBC Radio 1,99700000,57.07283,-3.027203,463,0.025,, +FM,BBC Radio 1 Ullapool,BBC Radio 1,97900000,57.892557,-5.135709,143,0.05,, +FM,BBC Radio 1 Neath Valley Varteg Hill,BBC Radio 1,98500000,51.754672,-3.773522,351,0.024,, +FM,BBC Radio 1 Ventnor,BBC Radio 1,99000000,50.601933,-1.199325,227,0.025,, +FM,BBC Radio 1 Calder Valley WALSDEN SOUTH,BBC Radio 1,98000000,53.690612,-2.096576,227,0.01,, +FM,BBC Radio 1 County Durham WEARDALE,BBC Radio 1,99300000,54.74117,-1.961914,404,0.09,, +FM,BBC Radio 1 Wensleydale,BBC Radio 1,97900000,54.312324,-2.013338,402,0.05,, +FM,BBC Radio 1 South Glamorgan Wenvoe,BBC Radio 1,99500000,51.459476,-3.282282,129,125,, +FM,BBC Radio 1 North Ayrshire WEST KILBRIDE,BBC Radio 1,98700000,55.695641,-4.84184,170,0.05,, +FM,BBC Radio 1 Trowbridge WESTWOOD,BBC Radio 1,97900000,51.336803,-2.264225,87,0.05,, +FM,BBC Radio 1 Weymouth,BBC Radio 1,99600000,50.59912,-2.476532,64,0.1,, +FM,BBC Radio 1 Whalley WHALLEY,BBC Radio 1,99200000,53.812989,-2.411689,172,0.01,, +FM,BBC Radio 1 West Yorkshire WHARFEDALE,BBC Radio 1,98000000,53.932231,-1.699923,212,0.02,, +FM,BBC Radio 1 Whitby WHITBY BUSINESS PARK,BBC Radio 1,99200000,54.473215,-0.595572,60,0.054,, +FM,BBC Radio 1 West Cumbria Whitehaven - VHF,BBC Radio 1,99300000,54.499453,-3.558449,125,0.13,, +FM,BBC Radio 1 Brighton WHITEHAWK HILL,BBC Radio 1,99700000,50.824954,-0.113611,120,0.25,, +FM,BBC Radio 1 Windermere WINDERMERE,BBC Radio 1,97900000,54.37436,-2.951306,216,0.032,, +FM,BBC Radio 1 Lancashire WINTER HILL,BBC Radio 1,98200000,53.625547,-2.514794,439,2,, +FM,BBC Radio 1 North Yorkshire Woolmoor,BBC Radio 1,99600000,54.287102,-1.299034,257,5,, +FM,BBC Radio 1 London and the South East Wrotham,BBC Radio 1,98800000,51.320696,0.287702,219,62.5,, +FM,BBC Radio 2 Aberdare,BBC Radio 2,89200000,51.702007,-3.398531,282,0.021,, +FM,BBC Radio 2 Abergavenny,BBC Radio 2,88700000,51.807795,-3.097781,433,0.02,, +FM,BBC Radio 2 Pontypool Abertillery,BBC Radio 2,89000000,51.714666,-3.12404,400,0.01,, +FM,BBC Radio 2 Argyll & Bute Ardgour,BBC Radio 2,88700000,56.712175,-5.290096,12,0.005,, +FM,BBC Radio 2 Scottish Borders Ashkirk,BBC Radio 2,89100000,55.510631,-2.840766,303,20.3208,, +FM,BBC Radio 2 Axe Valley,BBC Radio 2,89500000,50.74593,-3.016766,169,0.08,, +FM,BBC Radio 2 Argyll & Bute Ballachulish,BBC Radio 2,88100000,56.684359,-5.170394,14,0.015,, +FM,BBC Radio 2 North Antrim Ballycastle,BBC Radio 2,88800000,55.215995,-6.309339,150,0.05,, +FM,BBC Radio 2 Skipton Barnoldswick,BBC Radio 2,89700000,53.928368,-2.15728,191,0.02,, +FM,BBC Radio 2 North Devon Barnstaple,BBC Radio 2,88500000,51.040763,-4.13826,116,0.5,, +FM,BBC Radio 2 Basingstoke,BBC Radio 2,90100000,51.226848,-1.080409,176,0.02,, +FM,BBC Radio 2 Bath,BBC Radio 2,89000000,51.38779,-2.332925,175,0.041,, +FM,BBC Radio 2 Torbay Beacon Hill North,BBC Radio 2,88700000,50.447129,-3.610498,196,0.794328,, +FM,BBC Radio 2 Leeds Beecroft Hill,BBC Radio 2,89800000,53.811543,-1.641253,149,0.2,, +FM,BBC Radio 2 Lincolnshire Belmont,BBC Radio 2,88800000,53.335814,-0.171983,125,8.3,, +FM,BBC Radio 2 Stirling Ben Gullipen,BBC Radio 2,88700000,56.212308,-4.263559,415,1,, +FM,BBC Radio 2 Borders Berwick-upon-Tweed,BBC Radio 2,88600000,55.785854,-2.032822,129,0.05,, +FM,BBC Radio 2 Snowdonia Betws Y Coed,BBC Radio 2,88200000,53.108346,-3.75717,303,0.025,, +FM,BBC Radio 2 Bexhill,BBC Radio 2,88200000,50.84568,0.475913,45,0.0117,, +FM,BBC Radio 2 North Yorkshire Bilsdale - Station Tower,BBC Radio 2,89000000,54.358848,-1.149317,381,2,, +FM,BBC Radio 2 Central Scotland Black Hill,BBC Radio 2,89900000,55.860005,-3.873572,275,122.155,, +FM,BBC Radio 2 Blaenavon,BBC Radio 2,88500000,51.750968,-3.048742,373,0.01,, +FM,BBC Radio 2 Ceredigion Blaenplwyf,BBC Radio 2,88700000,52.360613,-4.102585,174,125,, +FM,BBC Radio 2 Swindon Blunsdon,BBC Radio 2,89000000,51.609363,-1.794027,148,0.2,, +FM,BBC Radio 2 Milton Keynes Bow Brickhill,BBC Radio 2,88600000,51.998806,-0.669784,169,5,, +FM,BBC Radio 2 Islay Bowmore,BBC Radio 2,88100000,55.750128,-6.274228,46,0.061,, +FM,BBC Radio 2 Mid Wales Brecon VHF,BBC Radio 2,88900000,51.959448,-3.412497,248,0.01,, +FM,BBC Radio 2 Shetland Bressay,BBC Radio 2,88300000,60.130079,-1.096281,224,25,, +FM,BBC Radio 2 Dorchester and Weymouth Bridport,BBC Radio 2,89100000,50.720805,-2.775678,64,0.2,, +FM,BBC Radio 2 Omagh and Enniskillen Brougher Mountain,BBC Radio 2,89400000,54.423191,-7.462812,305,5,, +FM,BBC Radio 2 North Derbyshire Buxton,BBC Radio 2,90000000,53.275085,-1.911935,432,0.05,, +FM,BBC Radio 2 Calne CALNE,BBC Radio 2,88200000,51.428815,-2.005417,104,0.032,, +FM,BBC Radio 2 Kirkcudbright CAMBRET HILL,BBC Radio 2,88700000,54.893698,-4.302038,343,0.0625,, +FM,BBC Radio 2 South Newry Camlough,BBC Radio 2,88700000,54.160861,-6.385716,340,2,, +FM,BBC Radio 2 Kintyre Islay and Jura CAMPBELTOWN,BBC Radio 2,88400000,55.413714,-5.624241,83,0.2,, +FM,BBC Radio 2 Carmarthen,BBC Radio 2,88900000,51.867126,-4.309135,137,0.01,, +FM,BBC Radio 2 Carmarthenshire Carmel,BBC Radio 2,88400000,51.818501,-4.066216,255,1.6,, +FM,BBC Radio 2 Newtownabbey Carnmoney Hill,BBC Radio 2,88800000,54.676355,-5.928737,207,0.02,, +FM,BBC Radio 2 Caterham Valley CATERHAM,BBC Radio 2,89700000,51.284605,-0.075623,173,0.015,, +FM,BBC Radio 2 Gloucestershire CHALFORD,BBC Radio 2,89200000,51.714525,-2.170893,174,0.1,, +FM,BBC Radio 2 Somerset Chard,BBC Radio 2,88900000,50.874213,-2.913244,173,0.05,, +FM,BBC Radio 2 Northumberland CHATTON,BBC Radio 2,90100000,55.531826,-1.834261,192,2.8,, +FM,BBC Radio 2 South Yorkshire Chesterfield,BBC Radio 2,89000000,53.283991,-1.427446,179,0.4,, +FM,BBC Radio 2 Chippenham,BBC Radio 2,88800000,51.474065,-2.12579,103,0.009,, +FM,BBC Radio 2 Gloucestershire Churchdown Hill,BBC Radio 2,89000000,51.868264,-2.175397,147,0.036,, +FM,BBC Radio 2 Cirencester,BBC Radio 2,88100000,51.717612,-1.968107,112,0.01,, +FM,BBC Radio 2 North Uist Clettraval,BBC Radio 2,88100000,57.617267,-7.44252,123,2,, +FM,BBC Radio 2 Wye Valley CLYRO,BBC Radio 2,88100000,52.08185,-3.162868,215,0.01,, +FM,BBC Radio 2 Ilfracombe Combe Martin,BBC Radio 2,89100000,51.197266,-4.031278,144,0.004,, +FM,BBC Radio 2 Conway CONWY,BBC Radio 2,89100000,53.271606,-3.828796,114,0.05,, +FM,BBC Radio 2 Calder Valley CORNHOLME,BBC Radio 2,89700000,53.734447,-2.125781,312,0.02,, +FM,BBC Radio 2 Folkestone Creteway Down,BBC Radio 2,88400000,51.099738,1.182579,166,0.1,, +FM,BBC Radio 2 Crieff CRIEFF,BBC Radio 2,89300000,56.357222,-3.920232,219,0.125,, +FM,BBC Radio 2 Croeserw,BBC Radio 2,89000000,51.644491,-3.652146,343,0.01,, +FM,BBC Radio 2 London Crystal Palace,BBC Radio 2,88800000,51.424161,-0.074944,110,4,, +FM,BBC Radio 2 Cwmafan,BBC Radio 2,88500000,51.628417,-3.737817,210,0.01,, +FM,BBC Radio 2 South Uist Daliburgh,BBC Radio 2,89300000,57.169643,-7.402558,6,1,, +FM,BBC Radio 2 Dartford Tunnel,BBC Radio 2,89100000,51.469253,0.260425,3,0,, +FM,BBC Radio 2 Ayrshire DARVEL,BBC Radio 2,89500000,55.579376,-4.289814,286,5,, +FM,BBC Radio 2 Darwen DARWEN,BBC Radio 2,89500000,53.696571,-2.443266,261,0.01,, +FM,BBC Radio 2 Gwynedd DEINIOLEN,BBC Radio 2,88100000,53.137063,-4.129256,322,0.05,, +FM,BBC Radio 2 Northern Ireland Divis A,BBC Radio 2,90100000,54.607538,-6.009471,368,61.0773,, +FM,BBC Radio 2 Snowdonia DOLGELLAU,BBC Radio 2,90100000,52.749344,-3.886853,103,0.025,, +FM,BBC Radio 2 Isle of Man DOUGLAS,BBC Radio 2,88400000,54.140551,-4.493075,143,5.7,, +FM,BBC Radio 2 Aberdeen Durris,BBC Radio 2,89400000,56.999987,-2.389944,325,1.05,, +FM,BBC Radio 2 South Wales EBBW VALE,BBC Radio 2,88400000,51.771714,-3.218938,442,0.015,, +FM,BBC Radio 2 Frome Egford Hill,BBC Radio 2,89100000,51.231585,-2.3391,132,0.06,, +FM,BBC Radio 2 Isle of Lewis Eitshal,BBC Radio 2,89800000,58.179148,-6.584974,206,2,, +FM,BBC Radio 2 Exeter Exeter (St Thomas),BBC Radio 2,89000000,50.719122,-3.562148,102,0.0275,, +FM,BBC Radio 2 Borders EYEMOUTH,BBC Radio 2,89700000,55.83228,-2.085863,197,0.1,, +FM,BBC Radio 2 Newcastle Fenham,BBC Radio 2,89800000,54.978039,-1.662966,120,0.042,, +FM,BBC Radio 2 South Wales Ferndale,BBC Radio 2,89600000,51.662873,-3.437376,386,0.01,, +FM,BBC Radio 2 Snowdonia FFESTINIOG,BBC Radio 2,88100000,52.934172,-3.921818,308,0.082081,, +FM,BBC Radio 2 Angus Forfar,BBC Radio 2,88300000,56.55718,-2.843663,206,10,, +FM,BBC Radio 2 Great Glen Fort Augustus,BBC Radio 2,88600000,57.105987,-4.70869,307,1,, +FM,BBC Radio 2 Fort William,BBC Radio 2,89300000,56.848302,-5.088621,16,2,, +FM,BBC Radio 2 Ayr GIRVAN,BBC Radio 2,88900000,55.244736,-4.814596,195,0.1,, +FM,BBC Radio 2 Isle of Mull Glengorm,BBC Radio 2,89500000,56.632166,-6.133249,253,2.5,, +FM,BBC Radio 2 Tiverton Gogwell,BBC Radio 2,89600000,50.889583,-3.469029,233,0.3,, +FM,BBC Radio 2 Grantham,BBC Radio 2,88100000,52.892406,-0.655971,115,0.05,, +FM,BBC Radio 2 Cairngorms Grantown,BBC Radio 2,89800000,57.320173,-3.656313,389,0.36,, +FM,BBC Radio 2 Guildford GUILDFORD,BBC Radio 2,88100000,51.228358,-0.605467,142,2,, +FM,BBC Radio 2 Rossendale HASLINGDEN,BBC Radio 2,89900000,53.708491,-2.311438,336,0.1,, +FM,BBC Radio 2 Hastings,BBC Radio 2,89600000,50.861622,0.566431,76,0.25,, +FM,BBC Radio 2 Pembrokeshire Haverfordwest,BBC Radio 2,89300000,51.899195,-4.86653,186,9.54993,, +FM,BBC Radio 2 Hebden Bridge HEBDEN BRIDGE,BBC Radio 2,88400000,53.737298,-2.018458,220,0.025,, +FM,BBC Radio 2 Caversham Hemdean,BBC Radio 2,89800000,51.481196,-0.978531,69,1,, +FM,BBC Radio 2 High Wycombe,BBC Radio 2,90000000,51.640531,-0.763678,156,0.025,, +FM,BBC Radio 2 Teignmouth Holcombe Down,BBC Radio 2,89400000,50.566699,-3.506408,205,0.1,, +FM,BBC Radio 2 Yorkshire and Lancashire Holme Moss,BBC Radio 2,89300000,53.533184,-1.858296,524,125,, +FM,BBC Radio 2 Weston-super-Mare Hutton,BBC Radio 2,89400000,51.325227,-2.918301,73,0.04,, +FM,BBC Radio 2 Bradford Idle,BBC Radio 2,88500000,53.832945,-1.752142,215,0.01,, +FM,BBC Radio 2 Bristol Ilchester Crescent,BBC Radio 2,89300000,51.427947,-2.609813,48,0.649999,, +FM,BBC Radio 2 Borders INNERLEITHEN,BBC Radio 2,89500000,55.620243,-3.07272,244,0.011,, +FM,BBC Radio 2 Isles of Scilly,BBC Radio 2,88800000,49.932504,-6.305394,32,0.03,, +FM,BBC Radio 2 Devon Ivybridge,BBC Radio 2,89900000,50.368664,-3.926486,142,0.05,, +FM,BBC Radio 2 Orkney Keelylang Hill B,BBC Radio 2,89300000,58.975283,-3.083943,220,16,, +FM,BBC Radio 2 West Yorkshire KEIGHLEY,BBC Radio 2,88900000,53.895532,-1.896639,305,1,, +FM,BBC Radio 2 South Lakes Kendal,BBC Radio 2,89000000,54.314559,-2.708127,172,0.05,, +FM,BBC Radio 2 Kenley KENLEY,BBC Radio 2,88400000,51.317089,-0.09335,152,0.025,, +FM,BBC Radio 2 North Lakes Keswick Forest,BBC Radio 2,89600000,54.608739,-3.204646,215,0,, +FM,BBC Radio 2 Kilkeel,BBC Radio 2,89400000,54.095375,-6.041723,267,0.1,, +FM,BBC Radio 2 Swansea Kilvey Hill,BBC Radio 2,89500000,51.62891,-3.919745,193,0.5,, +FM,BBC Radio 2 Dartmouth Kingswear,BBC Radio 2,89800000,50.349538,-3.565025,107,0.005,, +FM,BBC Radio 2 Cairngorms KINGUSSIE,BBC Radio 2,89100000,57.061393,-4.030507,351,0.05,, +FM,BBC Radio 2 Kinlochleven,BBC Radio 2,89700000,56.722796,-4.978914,273,0.005,, +FM,BBC Radio 2 Borders Kirkconnel,BBC Radio 2,88700000,55.412875,-3.983785,480,0.02,, +FM,BBC Radio 2 Perth Kirkton Mailer,BBC Radio 2,89000000,56.372293,-3.453361,178,0.5,, +FM,BBC Radio 2 Moray Knockmore,BBC Radio 2,88200000,57.532303,-3.135126,353,1,, +FM,BBC Radio 2 Larne,BBC Radio 2,89100000,54.862024,-5.828421,119,0.05,, +FM,BBC Radio 2 Jersey Les Platons,BBC Radio 2,89600000,49.246023,-2.1012,134,8,, +FM,BBC Radio 2 East Ayrshire LETHANHILL,BBC Radio 2,88300000,55.36421,-4.464995,300,0.11,, +FM,BBC Radio 2 Limavady,BBC Radio 2,89600000,55.109172,-6.886121,341,1.7,, +FM,BBC Radio 2 Anglesey LLANDDONA,BBC Radio 2,89800000,53.307002,-4.12825,146,10.5,, +FM,BBC Radio 2 Snowdonia LLANDECWYN,BBC Radio 2,89400000,52.914419,-4.017769,268,0.1,, +FM,BBC Radio 2 Mid Wales LLANDINAM,BBC Radio 2,90100000,52.479547,-3.399945,454,0.022,, +FM,BBC Radio 2 Llandrindod Wells,BBC Radio 2,89100000,52.261047,-3.439354,432,1.39,, +FM,BBC Radio 2 Ceredigion LLANDYFRIOG,BBC Radio 2,90100000,52.045314,-4.410045,116,0.05,, +FM,BBC Radio 2 Llanfyllin LLANFYLLIN,BBC Radio 2,89100000,52.753349,-3.259797,264,0.003972,, +FM,BBC Radio 2 Bridgend Llangeinor,BBC Radio 2,88600000,51.586117,-3.581462,306,0.01,, +FM,BBC Radio 2 Llangollen and Cheshire Llangollen VHF,BBC Radio 2,88900000,53.031048,-3.180791,556,7.80001,, +FM,BBC Radio 2 Mid Wales LLANIDLOES,BBC Radio 2,88100000,52.446933,-3.549585,244,0.025,, +FM,BBC Radio 2 Llanrhaeadr ym Mochnant LLANRHAEADR YM MOCHN,BBC Radio 2,89800000,52.825889,-3.226423,333,0.025,, +FM,BBC Radio 2 Snowdonia LLWYN ONN,BBC Radio 2,88300000,52.737496,-4.03773,277,0.25,, +FM,BBC Radio 2 Talgarth LLYSWEN,BBC Radio 2,89600000,52.016761,-3.258522,224,0.01,, +FM,BBC Radio 2 Londonderry,BBC Radio 2,88700000,55.00421,-7.368968,175,15.6,, +FM,BBC Radio 2 Welshpool LONG MOUNTAIN,BBC Radio 2,89600000,52.644306,-3.086542,400,0.024,, +FM,BBC Radio 2 Calderdale LUDDENDEN,BBC Radio 2,88700000,53.720111,-1.92874,256,0.084,, +FM,BBC Radio 2 Ludlow LUDLOW,BBC Radio 2,89600000,52.362722,-2.738327,216,0.005,, +FM,BBC Radio 2 Lyme Regis,BBC Radio 2,89700000,50.737572,-2.929856,162,0.05,, +FM,BBC Radio 2 Snowdonia MACHYNLLETH,BBC Radio 2,89400000,52.586449,-3.885603,100,0.06,, +FM,BBC Radio 2 Cambridgeshire Madingley,BBC Radio 2,88900000,52.215394,0.036667,62,0.13,, +FM,BBC Radio 2 Mallaig,BBC Radio 2,88100000,57.001499,-5.828475,71,0.02,, +FM,BBC Radio 2 Colchester and Ipswich Manningtree,BBC Radio 2,88100000,51.92387,1.086097,35,2.5,, +FM,BBC Radio 2 Marlborough MARLBOROUGH,BBC Radio 2,90100000,51.417912,-1.699977,192,0.1,, +FM,BBC Radio 2 Aberdeenshire Meldrum,BBC Radio 2,88700000,57.386674,-2.400197,245,75,, +FM,BBC Radio 2 Wester Ross Melvaig,BBC Radio 2,89100000,57.842382,-5.782182,271,17.5903,, +FM,BBC Radio 2 Membury,BBC Radio 2,88900000,51.484903,-1.558836,211,0.125,, +FM,BBC Radio 2 Mickleham MICKLEHAM,BBC Radio 2,89700000,51.272007,-0.333055,103,0.025,, +FM,BBC Radio 2 Dumbarton Millburn Muir,BBC Radio 2,88300000,55.982322,-4.600708,152,0.025,, +FM,BBC Radio 2 West Somerset Minehead,BBC Radio 2,89000000,51.19744,-3.48052,79,0.01,, +FM,BBC Radio 2 Morecambe Bay,BBC Radio 2,90000000,54.202505,-3.167346,259,5,, +FM,BBC Radio 2 Cardigan Bay Mynydd Pencarreg,BBC Radio 2,89700000,52.067402,-4.076523,411,0.2,, +FM,BBC Radio 2 Gloucestershire NAILSWORTH,BBC Radio 2,88200000,51.690257,-2.219843,114,0.1,, +FM,BBC Radio 2 Isle of Lewis Ness of Lewis,BBC Radio 2,88300000,58.461531,-6.230808,100,0.162,, +FM,BBC Radio 2 Newbury,BBC Radio 2,88200000,51.414621,-1.290472,130,0.1,, +FM,BBC Radio 2 Newhaven NEWHAVEN,BBC Radio 2,89700000,50.787726,0.035848,81,0.05,, +FM,BBC Radio 2 Newcastle NEWTON,BBC Radio 2,89400000,54.982447,-1.945593,165,0.1,, +FM,BBC Radio 2 Devon North Hessary Tor,BBC Radio 2,88100000,50.550217,-4.008413,508,80,, +FM,BBC Radio 2 Northamptonshire Northampton,BBC Radio 2,88900000,52.275355,-0.885481,127,0.0615,, +FM,BBC Radio 2 Oban and Mull Oban,BBC Radio 2,88900000,56.40396,-5.485882,122,2.5,, +FM,BBC Radio 2 Ogmore Vale,BBC Radio 2,89200000,51.593504,-3.546781,298,0.01,, +FM,BBC Radio 2 Okehampton,BBC Radio 2,88700000,50.753618,-4.005483,208,0.025,, +FM,BBC Radio 2 Scarborough OLIVERS MOUNT,BBC Radio 2,89900000,54.267351,-0.404494,151,0.125,, +FM,BBC Radio 2 Oxfordshire Oxford,BBC Radio 2,89500000,51.790638,-1.179183,130,17.5903,, +FM,BBC Radio 2 Borders PEEBLES,BBC Radio 2,88400000,55.661832,-3.227732,352,0.02,, +FM,BBC Radio 2 Bodmin Penaligon Downs,BBC Radio 2,88800000,50.481389,-4.782638,116,0.2,, +FM,BBC Radio 2 Burnley Pendle Forest,BBC Radio 2,90200000,53.841893,-2.266074,276,0.5,, +FM,BBC Radio 2 Penicuik PENICUIK,BBC Radio 2,88600000,55.819142,-3.194377,248,0.132,, +FM,BBC Radio 2 Portree Penifiler,BBC Radio 2,88100000,57.395531,-6.180316,52,0.005,, +FM,BBC Radio 2 Colwyn Bay Penmaen Rhos,BBC Radio 2,88400000,53.286941,-3.684982,125,0.1,, +FM,BBC Radio 2 Cwmbran Pennar,BBC Radio 2,89500000,51.656112,-3.144564,228,0.005,, +FM,BBC Radio 2 Huntingdonshire Peterborough,BBC Radio 2,90100000,52.507615,-0.343282,56,18.7,, +FM,BBC Radio 2 Pitlochry PITLOCHRY,BBC Radio 2,89200000,56.687307,-3.759852,401,0,, +FM,BBC Radio 2 Plymouth Plympton,BBC Radio 2,88500000,50.381346,-4.067802,113,0.04,, +FM,BBC Radio 2 Tyneside PONTOP PIKE,BBC Radio 2,88500000,54.868838,-1.771233,302,67.5,, +FM,BBC Radio 2 Pontypool,BBC Radio 2,89200000,51.685712,-3.036095,250,0.025,, +FM,BBC Radio 2 Islay PORT ELLEN,BBC Radio 2,89000000,55.627446,-6.227617,93,0.065,, +FM,BBC Radio 2 Pontypridd Porth,BBC Radio 2,88400000,51.617787,-3.403306,247,0.01,, +FM,BBC Radio 2 West Cornwall Redruth,BBC Radio 2,89700000,50.209786,-5.238489,237,8.80001,, +FM,BBC Radio 2 Neath Valley RHEOLA,BBC Radio 2,88200000,51.741661,-3.679878,409,0.01,, +FM,BBC Radio 2 Rhymney RHYMNEY,BBC Radio 2,89300000,51.730587,-3.264891,419,0.02,, +FM,BBC Radio 2 Herefordshire RIDGE HILL,BBC Radio 2,88600000,51.997433,-2.53989,204,5,, +FM,BBC Radio 2 Highland Rosemarkie,BBC Radio 2,89600000,57.633195,-4.075231,206,9.77237,, +FM,BBC Radio 2 Coupar Rosemount,BBC Radio 2,89600000,56.576982,-3.298257,81,0.032,, +FM,BBC Radio 2 Helensburgh Rosneath,BBC Radio 2,89200000,55.991937,-4.793795,107,0.025,, +FM,BBC Radio 2 South Newry Rostrevor Forest,BBC Radio 2,88300000,54.092725,-6.182015,215,0.02,, +FM,BBC Radio 2 Bute ROTHESAY,BBC Radio 2,88500000,55.878164,-4.998928,166,0.285,, +FM,BBC Radio 2 Hampshire and Isle of Wight ROWRIDGE,BBC Radio 2,88500000,50.676724,-1.370435,143,125,, +FM,BBC Radio 2 Caithness Rumster Forest,BBC Radio 2,90100000,58.328006,-3.371413,221,5,, +FM,BBC Radio 2 Greater Manchester SADDLEWORTH,BBC Radio 2,89800000,53.541535,-2.020635,347,0.1,, +FM,BBC Radio 2 Salcombe,BBC Radio 2,89500000,50.244921,-3.749115,61,0.198582,, +FM,BBC Radio 2 Salisbury SALISBURY,BBC Radio 2,89800000,51.055855,-1.806762,107,0.012619,, +FM,BBC Radio 2 Cumbria & South West Scotland Sandale,BBC Radio 2,88100000,54.749109,-3.14076,363,125,, +FM,BBC Radio 2 South Yorkshire Sheffield,BBC Radio 2,89900000,53.379385,-1.513809,247,0.16,, +FM,BBC Radio 2 Skye & Lochalsh Skriaig,BBC Radio 2,88500000,57.38642,-6.24289,390,9.68481,, +FM,BBC Radio 2 Kintyre Islay and Jura South Knapdale,BBC Radio 2,89300000,55.91751,-5.462223,481,1.1,, +FM,BBC Radio 2 Derbyshire Stanton Moor,BBC Radio 2,89800000,53.170195,-1.633756,305,0.6,, +FM,BBC Radio 2 Inveraray Strachur,BBC Radio 2,88800000,56.179137,-5.071531,175,0.01,, +FM,BBC Radio 2 Galloway STRANRAER,BBC Radio 2,89700000,54.928074,-4.949004,190,0.031,, +FM,BBC Radio 2 West Midlands SUTTON COLDFIELD,BBC Radio 2,88300000,52.600539,-1.833856,169,62.5,, +FM,BBC Radio 2 Dover Swingate,BBC Radio 2,90000000,51.137832,1.335758,122,5.5,, +FM,BBC Radio 2 Norfolk TACOLNESTON,BBC Radio 2,89700000,52.518759,1.138705,64,119.374,, +FM,BBC Radio 2 Calder Valley TODMORDEN,BBC Radio 2,88900000,53.713283,-2.065416,221,0.1,, +FM,BBC Radio 2 Rhondda Valley Ton Pentre,BBC Radio 2,88800000,51.64954,-3.504023,323,0.003,, +FM,BBC Radio 2 Tullich TULLICH,BBC Radio 2,90100000,57.07283,-3.027203,463,0.025,, +FM,BBC Radio 2 Ullapool,BBC Radio 2,88300000,57.892557,-5.135709,143,0.05,, +FM,BBC Radio 2 Neath Valley Varteg Hill,BBC Radio 2,88900000,51.754672,-3.773522,351,0.024,, +FM,BBC Radio 2 Ventnor,BBC Radio 2,89400000,50.601933,-1.199325,227,0.025,, +FM,BBC Radio 2 Calder Valley WALSDEN SOUTH,BBC Radio 2,88400000,53.690612,-2.096576,227,0.01,, +FM,BBC Radio 2 County Durham WEARDALE,BBC Radio 2,89700000,54.74117,-1.961914,404,0.09,, +FM,BBC Radio 2 Wensleydale,BBC Radio 2,88300000,54.312324,-2.013338,402,0.05,, +FM,BBC Radio 2 South Glamorgan Wenvoe,BBC Radio 2,89900000,51.459476,-3.282282,129,125,, +FM,BBC Radio 2 North Ayrshire WEST KILBRIDE,BBC Radio 2,89100000,55.695641,-4.84184,170,0.05,, +FM,BBC Radio 2 Trowbridge WESTWOOD,BBC Radio 2,88300000,51.336803,-2.264225,87,0.05,, +FM,BBC Radio 2 Weymouth,BBC Radio 2,90000000,50.59912,-2.476532,64,0.1,, +FM,BBC Radio 2 Whalley WHALLEY,BBC Radio 2,89600000,53.812989,-2.411689,172,0.01,, +FM,BBC Radio 2 West Yorkshire WHARFEDALE,BBC Radio 2,88400000,53.932231,-1.699923,212,0.02,, +FM,BBC Radio 2 Whitby WHITBY BUSINESS PARK,BBC Radio 2,89600000,54.473215,-0.595572,60,0.063,, +FM,BBC Radio 2 West Cumbria Whitehaven - VHF,BBC Radio 2,89700000,54.499453,-3.558449,125,0.13,, +FM,BBC Radio 2 Brighton WHITEHAWK HILL,BBC Radio 2,90100000,50.824954,-0.113611,120,0.25,, +FM,BBC Radio 2 Windermere WINDERMERE,BBC Radio 2,88300000,54.37436,-2.951306,216,0.032,, +FM,BBC Radio 2 Lancashire WINTER HILL,BBC Radio 2,88600000,53.625547,-2.514794,439,2,, +FM,BBC Radio 2 North Yorkshire Woolmoor,BBC Radio 2,90200000,54.287102,-1.299034,257,5,, +FM,BBC Radio 2 London and the South East Wrotham,BBC Radio 2,89100000,51.320696,0.287702,219,125,, +FM,BBC Radio 3 Aberdare,BBC Radio 3,91400000,51.702007,-3.398531,282,0.021,, +FM,BBC Radio 3 Abergavenny,BBC Radio 3,90900000,51.807795,-3.097781,433,0.02,, +FM,BBC Radio 3 Argyll & Bute Ardgour,BBC Radio 3,90900000,56.712175,-5.290096,12,0.005,, +FM,BBC Radio 3 Scottish Borders Ashkirk,BBC Radio 3,91300000,55.510631,-2.840766,303,20.3208,, +FM,BBC Radio 3 Axe Valley,BBC Radio 3,91700000,50.74593,-3.016766,169,0.08,, +FM,BBC Radio 3 Argyll & Bute Ballachulish,BBC Radio 3,90300000,56.684359,-5.170394,14,0.015,, +FM,BBC Radio 3 North Antrim Ballycastle,BBC Radio 3,91000000,55.215995,-6.309339,150,0.05,, +FM,BBC Radio 3 Skipton Barnoldswick,BBC Radio 3,91900000,53.928368,-2.15728,191,0.02,, +FM,BBC Radio 3 North Devon Barnstaple,BBC Radio 3,90700000,51.040763,-4.13826,116,0.5,, +FM,BBC Radio 3 Basingstoke,BBC Radio 3,92300000,51.226848,-1.080409,176,0.02,, +FM,BBC Radio 3 Bath,BBC Radio 3,91200000,51.38779,-2.332925,175,0.041,, +FM,BBC Radio 3 Torbay Beacon Hill North,BBC Radio 3,90900000,50.447129,-3.610498,196,0.794328,, +FM,BBC Radio 3 Leeds Beecroft Hill,BBC Radio 3,92000000,53.811543,-1.641253,149,0.2,, +FM,BBC Radio 3 Lincolnshire Belmont,BBC Radio 3,90900000,53.335814,-0.171983,125,8.3,, +FM,BBC Radio 3 Stirling Ben Gullipen,BBC Radio 3,90900000,56.212308,-4.263559,415,1,, +FM,BBC Radio 3 Borders Berwick-upon-Tweed,BBC Radio 3,90800000,55.785854,-2.032822,129,0.05,, +FM,BBC Radio 3 Bexhill,BBC Radio 3,92200000,50.84568,0.475913,45,0.0117,, +FM,BBC Radio 3 North Yorkshire Bilsdale - Station Tower,BBC Radio 3,91200000,54.358848,-1.149317,381,2,, +FM,BBC Radio 3 Central Scotland Black Hill,BBC Radio 3,92100000,55.860005,-3.873572,275,122.155,, +FM,BBC Radio 3 Blaenavon,BBC Radio 3,90700000,51.750968,-3.048742,373,0.01,, +FM,BBC Radio 3 Ceredigion Blaenplwyf,BBC Radio 3,90900000,52.360613,-4.102585,174,125,, +FM,BBC Radio 3 Swindon Blunsdon,BBC Radio 3,91200000,51.609363,-1.794027,148,0.2,, +FM,BBC Radio 3 Milton Keynes Bow Brickhill,BBC Radio 3,90800000,51.998806,-0.669784,169,5,, +FM,BBC Radio 3 Islay Bowmore,BBC Radio 3,90300000,55.750128,-6.274228,46,0.061,, +FM,BBC Radio 3 Shetland Bressay,BBC Radio 3,90500000,60.130079,-1.096281,224,25,, +FM,BBC Radio 3 Dorchester and Weymouth Bridport,BBC Radio 3,91300000,50.720805,-2.775678,64,0.2,, +FM,BBC Radio 3 Omagh and Enniskillen Brougher Mountain,BBC Radio 3,91600000,54.423191,-7.462812,305,5,, +FM,BBC Radio 3 North Derbyshire Buxton,BBC Radio 3,92200000,53.275085,-1.911935,432,0.05,, +FM,BBC Radio 3 Calne CALNE,BBC Radio 3,90400000,51.428815,-2.005417,104,0.032,, +FM,BBC Radio 3 Kirkcudbright CAMBRET HILL,BBC Radio 3,90900000,54.893698,-4.302038,343,0.065,, +FM,BBC Radio 3 South Newry Camlough,BBC Radio 3,90900000,54.160861,-6.385716,340,2,, +FM,BBC Radio 3 Kintyre Islay and Jura CAMPBELTOWN,BBC Radio 3,90600000,55.413714,-5.624241,83,0.2,, +FM,BBC Radio 3 Carmarthenshire Carmel,BBC Radio 3,90600000,51.818501,-4.066216,255,1.6,, +FM,BBC Radio 3 Newtownabbey Carnmoney Hill,BBC Radio 3,91000000,54.676355,-5.928737,207,0.02,, +FM,BBC Radio 3 Caterham Valley CATERHAM,BBC Radio 3,91900000,51.284605,-0.075623,173,0.015,, +FM,BBC Radio 3 Gloucestershire CHALFORD,BBC Radio 3,91400000,51.714525,-2.170893,174,0.1,, +FM,BBC Radio 3 Somerset Chard,BBC Radio 3,91100000,50.874213,-2.913244,173,0.05,, +FM,BBC Radio 3 Northumberland CHATTON,BBC Radio 3,92300000,55.531826,-1.834261,192,2.8,, +FM,BBC Radio 3 South Yorkshire Chesterfield,BBC Radio 3,91200000,53.283991,-1.427446,179,0.4,, +FM,BBC Radio 3 Chippenham,BBC Radio 3,91000000,51.474065,-2.12579,103,0.009,, +FM,BBC Radio 3 Gloucestershire Churchdown Hill,BBC Radio 3,91200000,51.868264,-2.175397,147,0.036,, +FM,BBC Radio 3 Cirencester,BBC Radio 3,90300000,51.717612,-1.968107,112,0.01,, +FM,BBC Radio 3 North Uist Clettraval,BBC Radio 3,90300000,57.617267,-7.44252,123,2,, +FM,BBC Radio 3 Ilfracombe Combe Martin,BBC Radio 3,91300000,51.197266,-4.031278,144,0.004,, +FM,BBC Radio 3 Calder Valley CORNHOLME,BBC Radio 3,91900000,53.734447,-2.125781,312,0.02,, +FM,BBC Radio 3 Folkestone Creteway Down,BBC Radio 3,90600000,51.099738,1.182579,166,0.1,, +FM,BBC Radio 3 Crieff CRIEFF,BBC Radio 3,91500000,56.357222,-3.920232,219,0.125,, +FM,BBC Radio 3 London Crystal Palace,BBC Radio 3,91000000,51.424161,-0.074944,110,4,, +FM,BBC Radio 3 South Uist Daliburgh,BBC Radio 3,91500000,57.169643,-7.402558,6,1,, +FM,BBC Radio 3 Dartford Tunnel,BBC Radio 3,91300000,51.469253,0.260425,3,0,, +FM,BBC Radio 3 Ayrshire DARVEL,BBC Radio 3,91700000,55.579376,-4.289814,286,5,, +FM,BBC Radio 3 Darwen DARWEN,BBC Radio 3,91700000,53.696571,-2.443266,261,0.01,, +FM,BBC Radio 3 Northern Ireland Divis A,BBC Radio 3,92300000,54.607538,-6.009471,368,61.0773,, +FM,BBC Radio 3 Isle of Man DOUGLAS,BBC Radio 3,90600000,54.140551,-4.493075,143,5.7,, +FM,BBC Radio 3 Aberdeen Durris,BBC Radio 3,91600000,56.999987,-2.389944,325,1.05,, +FM,BBC Radio 3 South Wales EBBW VALE,BBC Radio 3,90600000,51.771714,-3.218938,442,0.015,, +FM,BBC Radio 3 Frome Egford Hill,BBC Radio 3,91300000,51.231585,-2.3391,132,0.06,, +FM,BBC Radio 3 Isle of Lewis Eitshal,BBC Radio 3,92000000,58.179148,-6.584974,206,2,, +FM,BBC Radio 3 Exeter Exeter (St Thomas),BBC Radio 3,91200000,50.719122,-3.562148,102,0.0275,, +FM,BBC Radio 3 Borders EYEMOUTH,BBC Radio 3,91900000,55.83228,-2.085863,197,0.1,, +FM,BBC Radio 3 Newcastle Fenham,BBC Radio 3,92000000,54.978039,-1.662966,120,0.042,, +FM,BBC Radio 3 Angus Forfar,BBC Radio 3,90500000,56.55718,-2.843663,206,10,, +FM,BBC Radio 3 Great Glen Fort Augustus,BBC Radio 3,90800000,57.105987,-4.70869,307,1,, +FM,BBC Radio 3 Fort William,BBC Radio 3,91500000,56.848302,-5.088621,16,2,, +FM,BBC Radio 3 Ayr GIRVAN,BBC Radio 3,91100000,55.244736,-4.814596,195,0.1,, +FM,BBC Radio 3 Isle of Mull Glengorm,BBC Radio 3,91700000,56.632166,-6.133249,253,2.5,, +FM,BBC Radio 3 Tiverton Gogwell,BBC Radio 3,91800000,50.889583,-3.469029,233,0.3,, +FM,BBC Radio 3 Grantham,BBC Radio 3,90300000,52.892406,-0.655971,115,0.05,, +FM,BBC Radio 3 Cairngorms Grantown,BBC Radio 3,92000000,57.320173,-3.656313,389,0.36,, +FM,BBC Radio 3 Guildford GUILDFORD,BBC Radio 3,90300000,51.228358,-0.605467,142,2,, +FM,BBC Radio 3 Rossendale HASLINGDEN,BBC Radio 3,92100000,53.708491,-2.311438,336,0.1,, +FM,BBC Radio 3 Hastings,BBC Radio 3,91800000,50.861622,0.566431,76,0.25,, +FM,BBC Radio 3 Pembrokeshire Haverfordwest,BBC Radio 3,91500000,51.899195,-4.86653,186,9.54993,, +FM,BBC Radio 3 Hebden Bridge HEBDEN BRIDGE,BBC Radio 3,90600000,53.737298,-2.018458,220,0.025,, +FM,BBC Radio 3 Caversham Hemdean,BBC Radio 3,92000000,51.481196,-0.978531,69,1,, +FM,BBC Radio 3 High Wycombe,BBC Radio 3,92200000,51.640531,-0.763678,156,0.025,, +FM,BBC Radio 3 Teignmouth Holcombe Down,BBC Radio 3,91600000,50.566699,-3.506408,205,0.1,, +FM,BBC Radio 3 Yorkshire and Lancashire Holme Moss,BBC Radio 3,91500000,53.533184,-1.858296,524,125,, +FM,BBC Radio 3 Weston-super-Mare Hutton,BBC Radio 3,91600000,51.325227,-2.918301,73,0.04,, +FM,BBC Radio 3 Bradford Idle,BBC Radio 3,90700000,53.832945,-1.752142,215,0.01,, +FM,BBC Radio 3 Bristol Ilchester Crescent,BBC Radio 3,91500000,51.427947,-2.609813,48,0.649999,, +FM,BBC Radio 3 Borders INNERLEITHEN,BBC Radio 3,91700000,55.620243,-3.07272,244,0.011,, +FM,BBC Radio 3 Isles of Scilly,BBC Radio 3,91000000,49.932504,-6.305394,32,0.03,, +FM,BBC Radio 3 Devon Ivybridge,BBC Radio 3,92100000,50.368664,-3.926486,142,0.05,, +FM,BBC Radio 3 Orkney Keelylang Hill B,BBC Radio 3,91500000,58.975283,-3.083943,220,16,, +FM,BBC Radio 3 West Yorkshire KEIGHLEY,BBC Radio 3,91100000,53.895532,-1.896639,305,1,, +FM,BBC Radio 3 South Lakes Kendal,BBC Radio 3,91200000,54.314559,-2.708127,172,0.05,, +FM,BBC Radio 3 Kenley KENLEY,BBC Radio 3,90600000,51.317089,-0.09335,152,0.025,, +FM,BBC Radio 3 North Lakes Keswick Forest,BBC Radio 3,91800000,54.608739,-3.204646,215,0,, +FM,BBC Radio 3 Kilkeel,BBC Radio 3,91600000,54.095375,-6.041723,267,0.1,, +FM,BBC Radio 3 Swansea Kilvey Hill,BBC Radio 3,91700000,51.62891,-3.919745,193,0.5,, +FM,BBC Radio 3 Dartmouth Kingswear,BBC Radio 3,92000000,50.349538,-3.565025,107,0.005,, +FM,BBC Radio 3 Cairngorms KINGUSSIE,BBC Radio 3,91300000,57.061393,-4.030507,351,0.05,, +FM,BBC Radio 3 Kinlochleven,BBC Radio 3,91900000,56.722796,-4.978914,273,0.005,, +FM,BBC Radio 3 Borders Kirkconnel,BBC Radio 3,90900000,55.412875,-3.983785,480,0.02,, +FM,BBC Radio 3 Perth Kirkton Mailer,BBC Radio 3,91200000,56.372293,-3.453361,178,0.5,, +FM,BBC Radio 3 Moray Knockmore,BBC Radio 3,90400000,57.532303,-3.135126,353,1,, +FM,BBC Radio 3 Larne,BBC Radio 3,91300000,54.862024,-5.828421,119,0.05,, +FM,BBC Radio 3 Jersey Les Platons,BBC Radio 3,91100000,49.246023,-2.1012,134,8,, +FM,BBC Radio 3 East Ayrshire LETHANHILL,BBC Radio 3,90500000,55.36421,-4.464995,300,0.11,, +FM,BBC Radio 3 Limavady,BBC Radio 3,91800000,55.109172,-6.886121,341,1.7,, +FM,BBC Radio 3 Anglesey LLANDDONA,BBC Radio 3,92000000,53.307002,-4.12825,146,10.5,, +FM,BBC Radio 3 Londonderry,BBC Radio 3,90900000,55.00421,-7.368968,175,15.6,, +FM,BBC Radio 3 Calderdale LUDDENDEN,BBC Radio 3,90900000,53.720111,-1.92874,256,0.084,, +FM,BBC Radio 3 Ludlow LUDLOW,BBC Radio 3,91800000,52.362722,-2.738327,216,0.005,, +FM,BBC Radio 3 Lyme Regis,BBC Radio 3,91900000,50.737572,-2.929856,162,0.05,, +FM,BBC Radio 3 Cambridgeshire Madingley,BBC Radio 3,91100000,52.215394,0.036667,62,0.13,, +FM,BBC Radio 3 Mallaig,BBC Radio 3,90300000,57.001499,-5.828475,71,0.02,, +FM,BBC Radio 3 Colchester and Ipswich Manningtree,BBC Radio 3,90300000,51.92387,1.086097,35,2.5,, +FM,BBC Radio 3 Marlborough MARLBOROUGH,BBC Radio 3,92300000,51.417912,-1.699977,192,0.1,, +FM,BBC Radio 3 Aberdeenshire Meldrum,BBC Radio 3,90900000,57.386674,-2.400197,245,75,, +FM,BBC Radio 3 Wester Ross Melvaig,BBC Radio 3,91300000,57.842382,-5.782182,271,17.5903,, +FM,BBC Radio 3 Membury,BBC Radio 3,91100000,51.484903,-1.558836,211,0.125,, +FM,BBC Radio 3 Mickleham MICKLEHAM,BBC Radio 3,91900000,51.272007,-0.333055,103,0.025,, +FM,BBC Radio 3 Dumbarton Millburn Muir,BBC Radio 3,90500000,55.982322,-4.600708,152,0.025,, +FM,BBC Radio 3 West Somerset Minehead,BBC Radio 3,91200000,51.19744,-3.48052,79,0.01,, +FM,BBC Radio 3 Morecambe Bay,BBC Radio 3,92200000,54.202505,-3.167346,259,5,, +FM,BBC Radio 3 Gloucestershire NAILSWORTH,BBC Radio 3,90400000,51.690257,-2.219843,114,0.1,, +FM,BBC Radio 3 Isle of Lewis Ness of Lewis,BBC Radio 3,90500000,58.461531,-6.230808,100,0.162,, +FM,BBC Radio 3 Newbury,BBC Radio 3,90400000,51.414621,-1.290472,130,0.1,, +FM,BBC Radio 3 Newhaven NEWHAVEN,BBC Radio 3,91900000,50.787726,0.035848,81,0.05,, +FM,BBC Radio 3 Newcastle NEWTON,BBC Radio 3,91600000,54.982447,-1.945593,165,0.1,, +FM,BBC Radio 3 Devon North Hessary Tor,BBC Radio 3,90300000,50.550217,-4.008413,508,80,, +FM,BBC Radio 3 Northamptonshire Northampton,BBC Radio 3,91100000,52.275355,-0.885481,127,0.0615,, +FM,BBC Radio 3 Oban and Mull Oban,BBC Radio 3,91100000,56.40396,-5.485882,122,2.5,, +FM,BBC Radio 3 Okehampton,BBC Radio 3,90900000,50.753618,-4.005483,208,0.025,, +FM,BBC Radio 3 Scarborough OLIVERS MOUNT,BBC Radio 3,92100000,54.267351,-0.404494,151,0.125,, +FM,BBC Radio 3 Oxfordshire Oxford,BBC Radio 3,91700000,51.790638,-1.179183,130,17.5903,, +FM,BBC Radio 3 Borders PEEBLES,BBC Radio 3,90600000,55.661832,-3.227732,352,0.02,, +FM,BBC Radio 3 Bodmin Penaligon Downs,BBC Radio 3,91000000,50.481389,-4.782638,116,0.2,, +FM,BBC Radio 3 Burnley Pendle Forest,BBC Radio 3,92600000,53.841893,-2.266074,276,0.5,, +FM,BBC Radio 3 Penicuik PENICUIK,BBC Radio 3,90800000,55.819142,-3.194377,248,0.132,, +FM,BBC Radio 3 Portree Penifiler,BBC Radio 3,90300000,57.395531,-6.180316,52,0.005,, +FM,BBC Radio 3 Huntingdonshire Peterborough,BBC Radio 3,92300000,52.507615,-0.343282,56,18.7,, +FM,BBC Radio 3 Pitlochry PITLOCHRY,BBC Radio 3,91400000,56.687307,-3.759852,401,0,, +FM,BBC Radio 3 Plymouth Plympton,BBC Radio 3,90700000,50.381346,-4.067802,113,0.04,, +FM,BBC Radio 3 Tyneside PONTOP PIKE,BBC Radio 3,90700000,54.868838,-1.771233,302,67.5,, +FM,BBC Radio 3 Islay PORT ELLEN,BBC Radio 3,91200000,55.627446,-6.227617,93,0.065,, +FM,BBC Radio 3 Pontypridd Porth,BBC Radio 3,90600000,51.617787,-3.403306,247,0.01,, +FM,BBC Radio 3 West Cornwall Redruth,BBC Radio 3,91900000,50.209786,-5.238489,237,8.80001,, +FM,BBC Radio 3 Herefordshire RIDGE HILL,BBC Radio 3,90800000,51.997433,-2.53989,204,5,, +FM,BBC Radio 3 Highland Rosemarkie,BBC Radio 3,91800000,57.633195,-4.075231,206,9.77237,, +FM,BBC Radio 3 Coupar Rosemount,BBC Radio 3,91800000,56.576982,-3.298257,81,0.032,, +FM,BBC Radio 3 Helensburgh Rosneath,BBC Radio 3,91400000,55.991937,-4.793795,107,0.025,, +FM,BBC Radio 3 South Newry Rostrevor Forest,BBC Radio 3,90500000,54.092725,-6.182015,215,0.02,, +FM,BBC Radio 3 Bute ROTHESAY,BBC Radio 3,90700000,55.878164,-4.998928,166,0.285,, +FM,BBC Radio 3 Hampshire and Isle of Wight ROWRIDGE,BBC Radio 3,90700000,50.676724,-1.370435,143,125,, +FM,BBC Radio 3 Caithness Rumster Forest,BBC Radio 3,92300000,58.328006,-3.371413,221,5,, +FM,BBC Radio 3 Greater Manchester SADDLEWORTH,BBC Radio 3,91900000,53.541535,-2.020635,347,0.1,, +FM,BBC Radio 3 Salcombe,BBC Radio 3,91700000,50.244921,-3.749115,61,0.198582,, +FM,BBC Radio 3 Salisbury SALISBURY,BBC Radio 3,92000000,51.055855,-1.806762,107,0.012619,, +FM,BBC Radio 3 Cumbria & South West Scotland Sandale,BBC Radio 3,90300000,54.749109,-3.14076,363,125,, +FM,BBC Radio 3 South Yorkshire Sheffield,BBC Radio 3,92100000,53.379385,-1.513809,247,0.16,, +FM,BBC Radio 3 Skye & Lochalsh Skriaig,BBC Radio 3,90700000,57.38642,-6.24289,390,9.68481,, +FM,BBC Radio 3 Kintyre Islay and Jura South Knapdale,BBC Radio 3,91500000,55.91751,-5.462223,481,1.1,, +FM,BBC Radio 3 Derbyshire Stanton Moor,BBC Radio 3,92000000,53.170195,-1.633756,305,0.6,, +FM,BBC Radio 3 Inveraray Strachur,BBC Radio 3,91000000,56.179137,-5.071531,175,0.01,, +FM,BBC Radio 3 Galloway STRANRAER,BBC Radio 3,91900000,54.928074,-4.949004,190,0.031,, +FM,BBC Radio 3 West Midlands SUTTON COLDFIELD,BBC Radio 3,90500000,52.600539,-1.833856,169,62.5,, +FM,BBC Radio 3 Dover Swingate,BBC Radio 3,92400000,51.137832,1.335758,122,5.5,, +FM,BBC Radio 3 Norfolk TACOLNESTON,BBC Radio 3,91900000,52.518759,1.138705,64,119.374,, +FM,BBC Radio 3 Calder Valley TODMORDEN,BBC Radio 3,91100000,53.713283,-2.065416,221,0.1,, +FM,BBC Radio 3 Rhondda Valley Ton Pentre,BBC Radio 3,91000000,51.64954,-3.504023,323,0.003,, +FM,BBC Radio 3 Tullich TULLICH,BBC Radio 3,92300000,57.07283,-3.027203,463,0.025,, +FM,BBC Radio 3 Ullapool,BBC Radio 3,90500000,57.892557,-5.135709,143,0.05,, +FM,BBC Radio 3 Neath Valley Varteg Hill,BBC Radio 3,91100000,51.754672,-3.773522,351,0.024,, +FM,BBC Radio 3 Ventnor,BBC Radio 3,91700000,50.601933,-1.199325,227,0.025,, +FM,BBC Radio 3 Calder Valley WALSDEN SOUTH,BBC Radio 3,90600000,53.690612,-2.096576,227,0.01,, +FM,BBC Radio 3 County Durham WEARDALE,BBC Radio 3,91900000,54.74117,-1.961914,404,0.09,, +FM,BBC Radio 3 Wensleydale,BBC Radio 3,90500000,54.312324,-2.013338,402,0.05,, +FM,BBC Radio 3 South Glamorgan Wenvoe,BBC Radio 3,92100000,51.459476,-3.282282,129,125,, +FM,BBC Radio 3 North Ayrshire WEST KILBRIDE,BBC Radio 3,91300000,55.695641,-4.84184,170,0.05,, +FM,BBC Radio 3 Trowbridge WESTWOOD,BBC Radio 3,90500000,51.336803,-2.264225,87,0.05,, +FM,BBC Radio 3 Weymouth,BBC Radio 3,92200000,50.59912,-2.476532,64,0.1,, +FM,BBC Radio 3 Whalley WHALLEY,BBC Radio 3,91800000,53.812989,-2.411689,172,0.01,, +FM,BBC Radio 3 West Yorkshire WHARFEDALE,BBC Radio 3,90600000,53.932231,-1.699923,212,0.02,, +FM,BBC Radio 3 Whitby WHITBY BUSINESS PARK,BBC Radio 3,91800000,54.473215,-0.595572,60,0.062,, +FM,BBC Radio 3 West Cumbria Whitehaven - VHF,BBC Radio 3,91900000,54.499453,-3.558449,125,0.13,, +FM,BBC Radio 3 Brighton WHITEHAWK HILL,BBC Radio 3,92300000,50.824954,-0.113611,120,0.25,, +FM,BBC Radio 3 Windermere WINDERMERE,BBC Radio 3,90500000,54.37436,-2.951306,216,0.032,, +FM,BBC Radio 3 Lancashire WINTER HILL,BBC Radio 3,90800000,53.625547,-2.514794,439,2,, +FM,BBC Radio 3 North Yorkshire Woolmoor,BBC Radio 3,92200000,54.287102,-1.299034,257,5,, +FM,BBC Radio 3 London and the South East Wrotham,BBC Radio 3,91300000,51.320696,0.287702,219,125,, +FM,BBC Radio 4 (FM) Aberdare,BBC Radio 4 (FM),104700000,51.702007,-3.398531,282,0.021,, +FM,BBC Radio 4 (FM) Abergavenny,BBC Radio 4 (FM),93100000,51.807795,-3.097781,433,0.02,, +FM,BBC Radio 4 (FM) Pontypool Abertillery,BBC Radio 4 (FM),93400000,51.714666,-3.12404,400,0.01,, +FM,BBC Radio 4 (FM) Argyll & Bute Ardgour,BBC Radio 4 (FM),95100000,56.712175,-5.290096,12,0.005,, +FM,BBC Radio 4 (FM) Scottish Borders Ashkirk,BBC Radio 4 (FM),103900000,55.510631,-2.840766,303,20.3208,, +FM,BBC Radio 4 (FM) Axe Valley,BBC Radio 4 (FM),93900000,50.74593,-3.016766,169,0.08,, +FM,BBC Radio 4 (FM) Argyll & Bute Ballachulish,BBC Radio 4 (FM),94700000,56.684359,-5.170394,14,0.015,, +FM,BBC Radio 4 (FM) North Antrim Ballycastle,BBC Radio 4 (FM),93200000,55.215995,-6.309339,150,0.05,, +FM,BBC Radio 4 (FM) Skipton Barnoldswick,BBC Radio 4 (FM),94100000,53.928368,-2.15728,191,0.02,, +FM,BBC Radio 4 (FM) North Devon Barnstaple,BBC Radio 4 (FM),92900000,51.040763,-4.13826,116,0.5,, +FM,BBC Radio 4 (FM) Basingstoke,BBC Radio 4 (FM),94500000,51.226848,-1.080409,176,0.02,, +FM,BBC Radio 4 (FM) Bath,BBC Radio 4 (FM),93400000,51.38779,-2.332925,175,0.041,, +FM,BBC Radio 4 (FM) Torbay Beacon Hill North,BBC Radio 4 (FM),93100000,50.447129,-3.610498,196,0.794328,, +FM,BBC Radio 4 (FM) Leeds Beecroft Hill,BBC Radio 4 (FM),94200000,53.811543,-1.641253,149,0.2,, +FM,BBC Radio 4 (FM) Lincolnshire Belmont,BBC Radio 4 (FM),93100000,53.335814,-0.171983,125,8.3,, +FM,BBC Radio 4 (FM) Stirling Ben Gullipen,BBC Radio 4 (FM),104900000,56.212308,-4.263559,415,1,, +FM,BBC Radio 4 (FM) Borders Berwick-upon-Tweed,BBC Radio 4 (FM),93000000,55.785854,-2.032822,129,0.05,, +FM,BBC Radio 4 (FM) Snowdonia Betws Y Coed,BBC Radio 4 (FM),104900000,53.108346,-3.75717,303,0.025,, +FM,BBC Radio 4 (FM) Bexhill,BBC Radio 4 (FM),94600000,50.84568,0.475913,45,0.0117,, +FM,BBC Radio 4 (FM) North Yorkshire Bilsdale - Station Tower,BBC Radio 4 (FM),93400000,54.358848,-1.149317,381,2,, +FM,BBC Radio 4 (FM) Central Scotland Black Hill,BBC Radio 4 (FM),95800000,55.860005,-3.873572,275,97.7237,, +FM,BBC Radio 4 (FM) Blaenavon,BBC Radio 4 (FM),92900000,51.750968,-3.048742,373,0.01,, +FM,BBC Radio 4 (FM) Ceredigion Blaenplwyf,BBC Radio 4 (FM),104000000,52.360613,-4.102585,174,125,, +FM,BBC Radio 4 (FM) Swindon Blunsdon,BBC Radio 4 (FM),93400000,51.609363,-1.794027,148,0.2,, +FM,BBC Radio 4 (FM) Milton Keynes Bow Brickhill,BBC Radio 4 (FM),93000000,51.998806,-0.669784,169,5,, +FM,BBC Radio 4 (FM) Islay Bowmore,BBC Radio 4 (FM),95700000,55.750128,-6.274228,46,0.061,, +FM,BBC Radio 4 (FM) Mid Wales Brecon VHF,BBC Radio 4 (FM),104700000,51.959448,-3.412497,248,0.01,, +FM,BBC Radio 4 (FM) Shetland Bressay,BBC Radio 4 (FM),94900000,60.130079,-1.096281,224,25,, +FM,BBC Radio 4 (FM) Dorchester and Weymouth Bridport,BBC Radio 4 (FM),93500000,50.720805,-2.775678,64,0.2,, +FM,BBC Radio 4 (FM) Omagh and Enniskillen Brougher Mountain,BBC Radio 4 (FM),95600000,54.423191,-7.462812,305,5,, +FM,BBC Radio 4 (FM) North Derbyshire Buxton,BBC Radio 4 (FM),94400000,53.275085,-1.911935,432,0.05,, +FM,BBC Radio 4 (FM) Calne CALNE,BBC Radio 4 (FM),92600000,51.428815,-2.005417,104,0.032,, +FM,BBC Radio 4 (FM) Kirkcudbright CAMBRET HILL,BBC Radio 4 (FM),95300000,54.893698,-4.302038,343,0.065,, +FM,BBC Radio 4 (FM) South Newry Camlough,BBC Radio 4 (FM),104600000,54.160861,-6.385716,340,2,, +FM,BBC Radio 4 (FM) Kintyre Islay and Jura CAMPBELTOWN,BBC Radio 4 (FM),95200000,55.413714,-5.624241,83,0.2,, +FM,BBC Radio 4 (FM) Carmarthen,BBC Radio 4 (FM),95500000,51.867126,-4.309135,137,0.01,, +FM,BBC Radio 4 (FM) Carmarthenshire Carmel,BBC Radio 4 (FM),92800000,51.818501,-4.066216,255,1.6,, +FM,BBC Radio 4 (FM) Newtownabbey Carnmoney Hill,BBC Radio 4 (FM),93200000,54.676355,-5.928737,207,0.02,, +FM,BBC Radio 4 (FM) Caterham Valley CATERHAM,BBC Radio 4 (FM),94100000,51.284605,-0.075623,173,0.015,, +FM,BBC Radio 4 (FM) Gloucestershire CHALFORD,BBC Radio 4 (FM),93600000,51.714525,-2.170893,174,0.1,, +FM,BBC Radio 4 (FM) Somerset Chard,BBC Radio 4 (FM),93300000,50.874213,-2.913244,173,0.05,, +FM,BBC Radio 4 (FM) Northumberland CHATTON,BBC Radio 4 (FM),94500000,55.531826,-1.834261,192,2.8,, +FM,BBC Radio 4 (FM) South Yorkshire Chesterfield,BBC Radio 4 (FM),93400000,53.283991,-1.427446,179,0.4,, +FM,BBC Radio 4 (FM) Chippenham,BBC Radio 4 (FM),93200000,51.474065,-2.12579,103,0.009,, +FM,BBC Radio 4 (FM) Gloucestershire Churchdown Hill,BBC Radio 4 (FM),93400000,51.868264,-2.175397,147,0.036,, +FM,BBC Radio 4 (FM) Cirencester,BBC Radio 4 (FM),92500000,51.717612,-1.968107,112,0.01,, +FM,BBC Radio 4 (FM) North Uist Clettraval,BBC Radio 4 (FM),95100000,57.617267,-7.44252,123,2,, +FM,BBC Radio 4 (FM) Wye Valley CLYRO,BBC Radio 4 (FM),104900000,52.08185,-3.162868,215,0.01,, +FM,BBC Radio 4 (FM) Ilfracombe Combe Martin,BBC Radio 4 (FM),93500000,51.197266,-4.031278,144,0.004,, +FM,BBC Radio 4 (FM) Conway CONWY,BBC Radio 4 (FM),104400000,53.271606,-3.828796,114,0.05,, +FM,BBC Radio 4 (FM) Calder Valley CORNHOLME,BBC Radio 4 (FM),94100000,53.734447,-2.125781,312,0.02,, +FM,BBC Radio 4 (FM) Folkestone Creteway Down,BBC Radio 4 (FM),93100000,51.099738,1.182579,166,0.1,, +FM,BBC Radio 4 (FM) Crieff CRIEFF,BBC Radio 4 (FM),95300000,56.357222,-3.920232,219,0.125,, +FM,BBC Radio 4 (FM) Croeserw,BBC Radio 4 (FM),103600000,51.644491,-3.652146,343,0.01,, +FM,BBC Radio 4 (FM) London Crystal Palace,BBC Radio 4 (FM),93200000,51.424161,-0.074944,110,4,, +FM,BBC Radio 4 (FM) Cwmafan,BBC Radio 4 (FM),92900000,51.628417,-3.737817,210,0.01,, +FM,BBC Radio 4 (FM) South Uist Daliburgh,BBC Radio 4 (FM),95900000,57.169643,-7.402558,6,1,, +FM,BBC Radio 4 (FM) Dartford Tunnel,BBC Radio 4 (FM),93500000,51.469253,0.260425,3,0,, +FM,BBC Radio 4 (FM) Ayrshire DARVEL,BBC Radio 4 (FM),104300000,55.579376,-4.289814,286,5,, +FM,BBC Radio 4 (FM) Darwen DARWEN,BBC Radio 4 (FM),93900000,53.696571,-2.443266,261,0.01,, +FM,BBC Radio 4 (FM) Gwynedd DEINIOLEN,BBC Radio 4 (FM),104100000,53.137063,-4.129256,322,0.05,, +FM,BBC Radio 4 (FM) Northern Ireland Divis A,BBC Radio 4 (FM),96000000,54.607538,-6.009471,368,61.0773,, +FM,BBC Radio 4 (FM) Snowdonia DOLGELLAU,BBC Radio 4 (FM),103600000,52.749344,-3.886853,103,0.025,, +FM,BBC Radio 4 (FM) Isle of Man DOUGLAS,BBC Radio 4 (FM),92800000,54.140551,-4.493075,143,5.7,, +FM,BBC Radio 4 (FM) Aberdeen Durris,BBC Radio 4 (FM),95900000,56.999987,-2.389944,325,1.05,, +FM,BBC Radio 4 (FM) South Wales EBBW VALE,BBC Radio 4 (FM),92800000,51.771714,-3.218938,442,0.015,, +FM,BBC Radio 4 (FM) Frome Egford Hill,BBC Radio 4 (FM),93500000,51.231585,-2.3391,132,0.06,, +FM,BBC Radio 4 (FM) Isle of Lewis Eitshal,BBC Radio 4 (FM),95100000,58.179148,-6.584974,206,2,, +FM,BBC Radio 4 (FM) Exeter Exeter (St Thomas),BBC Radio 4 (FM),93400000,50.719122,-3.562148,102,0.0275,, +FM,BBC Radio 4 (FM) Borders EYEMOUTH,BBC Radio 4 (FM),104600000,55.83228,-2.085863,197,0.1,, +FM,BBC Radio 4 (FM) Newcastle Fenham,BBC Radio 4 (FM),94200000,54.978039,-1.662966,120,0.042,, +FM,BBC Radio 4 (FM) South Wales Ferndale,BBC Radio 4 (FM),94000000,51.662873,-3.437376,386,0.01,, +FM,BBC Radio 4 (FM) Snowdonia FFESTINIOG,BBC Radio 4 (FM),103500000,52.934172,-3.921818,308,0.082081,, +FM,BBC Radio 4 (FM) Angus Forfar,BBC Radio 4 (FM),94900000,56.55718,-2.843663,206,10,, +FM,BBC Radio 4 (FM) Great Glen Fort Augustus,BBC Radio 4 (FM),95200000,57.105987,-4.70869,307,1,, +FM,BBC Radio 4 (FM) Fort William,BBC Radio 4 (FM),95900000,56.848302,-5.088621,16,2,, +FM,BBC Radio 4 (FM) Ayr GIRVAN,BBC Radio 4 (FM),95300000,55.244736,-4.814596,195,0.1,, +FM,BBC Radio 4 (FM) Isle of Mull Glengorm,BBC Radio 4 (FM),96100000,56.632166,-6.133249,253,2.5,, +FM,BBC Radio 4 (FM) Tiverton Gogwell,BBC Radio 4 (FM),94000000,50.889583,-3.469029,233,0.3,, +FM,BBC Radio 4 (FM) Grantham,BBC Radio 4 (FM),92500000,52.892406,-0.655971,115,0.05,, +FM,BBC Radio 4 (FM) Cairngorms Grantown,BBC Radio 4 (FM),96100000,57.320173,-3.656313,389,0.36,, +FM,BBC Radio 4 (FM) Guildford GUILDFORD,BBC Radio 4 (FM),92500000,51.228358,-0.605467,142,2,, +FM,BBC Radio 4 (FM) Rossendale HASLINGDEN,BBC Radio 4 (FM),94300000,53.708491,-2.311438,336,0.1,, +FM,BBC Radio 4 (FM) Hastings,BBC Radio 4 (FM),94200000,50.861622,0.566431,76,0.25,, +FM,BBC Radio 4 (FM) Pembrokeshire Haverfordwest,BBC Radio 4 (FM),104900000,51.899195,-4.86653,186,9.54993,, +FM,BBC Radio 4 (FM) Hebden Bridge HEBDEN BRIDGE,BBC Radio 4 (FM),92800000,53.737298,-2.018458,220,0.025,, +FM,BBC Radio 4 (FM) Caversham Hemdean,BBC Radio 4 (FM),94200000,51.481196,-0.978531,69,1,, +FM,BBC Radio 4 (FM) High Wycombe,BBC Radio 4 (FM),94400000,51.640531,-0.763678,156,0.025,, +FM,BBC Radio 4 (FM) Teignmouth Holcombe Down,BBC Radio 4 (FM),93800000,50.566699,-3.506408,205,0.1,, +FM,BBC Radio 4 (FM) Yorkshire and Lancashire Holme Moss,BBC Radio 4 (FM),93700000,53.533184,-1.858296,524,125,, +FM,BBC Radio 4 (FM) Weston-super-Mare Hutton,BBC Radio 4 (FM),93800000,51.325227,-2.918301,73,0.04,, +FM,BBC Radio 4 (FM) Bradford Idle,BBC Radio 4 (FM),92900000,53.832945,-1.752142,215,0.01,, +FM,BBC Radio 4 (FM) Bristol Ilchester Crescent,BBC Radio 4 (FM),93700000,51.427947,-2.609813,48,0.649999,, +FM,BBC Radio 4 (FM) Borders INNERLEITHEN,BBC Radio 4 (FM),96100000,55.620243,-3.07272,244,0.011,, +FM,BBC Radio 4 (FM) Isles of Scilly,BBC Radio 4 (FM),93200000,49.932504,-6.305394,32,0.03,, +FM,BBC Radio 4 (FM) Devon Ivybridge,BBC Radio 4 (FM),94300000,50.368664,-3.926486,142,0.05,, +FM,BBC Radio 4 (FM) Orkney Keelylang Hill B,BBC Radio 4 (FM),96000000,58.975283,-3.083943,220,16,, +FM,BBC Radio 4 (FM) West Yorkshire KEIGHLEY,BBC Radio 4 (FM),93300000,53.895532,-1.896639,305,1,, +FM,BBC Radio 4 (FM) South Lakes Kendal,BBC Radio 4 (FM),93400000,54.314559,-2.708127,172,0.05,, +FM,BBC Radio 4 (FM) Kenley KENLEY,BBC Radio 4 (FM),92800000,51.317089,-0.09335,152,0.025,, +FM,BBC Radio 4 (FM) North Lakes Keswick Forest,BBC Radio 4 (FM),94000000,54.608739,-3.204646,215,0,, +FM,BBC Radio 4 (FM) Kilkeel,BBC Radio 4 (FM),103900000,54.095375,-6.041723,267,0.1,, +FM,BBC Radio 4 (FM) Swansea Kilvey Hill,BBC Radio 4 (FM),94600000,51.62891,-3.919745,193,0.5,, +FM,BBC Radio 4 (FM) Dartmouth Kingswear,BBC Radio 4 (FM),94200000,50.349538,-3.565025,107,0.005,, +FM,BBC Radio 4 (FM) Cairngorms KINGUSSIE,BBC Radio 4 (FM),95700000,57.061393,-4.030507,351,0.05,, +FM,BBC Radio 4 (FM) Kinlochleven,BBC Radio 4 (FM),95600000,56.722796,-4.978914,273,0.005,, +FM,BBC Radio 4 (FM) Borders Kirkconnel,BBC Radio 4 (FM),95300000,55.412875,-3.983785,480,0.02,, +FM,BBC Radio 4 (FM) Perth Kirkton Mailer,BBC Radio 4 (FM),94600000,56.372293,-3.453361,178,0.5,, +FM,BBC Radio 4 (FM) Moray Knockmore,BBC Radio 4 (FM),94800000,57.532303,-3.135126,353,1,, +FM,BBC Radio 4 (FM) Larne,BBC Radio 4 (FM),103500000,54.862024,-5.828421,119,0.05,, +FM,BBC Radio 4 (FM) Jersey Les Platons,BBC Radio 4 (FM),94800000,49.246023,-2.1012,134,8,, +FM,BBC Radio 4 (FM) East Ayrshire LETHANHILL,BBC Radio 4 (FM),94900000,55.36421,-4.464995,300,0.11,, +FM,BBC Radio 4 (FM) Limavady,BBC Radio 4 (FM),94000000,55.109172,-6.886121,341,1.7,, +FM,BBC Radio 4 (FM) Anglesey LLANDDONA,BBC Radio 4 (FM),103600000,53.307002,-4.12825,146,10.5,, +FM,BBC Radio 4 (FM) Snowdonia LLANDECWYN,BBC Radio 4 (FM),104900000,52.914419,-4.017769,268,0.1,, +FM,BBC Radio 4 (FM) Mid Wales LLANDINAM,BBC Radio 4 (FM),94500000,52.479547,-3.399945,454,0.022,, +FM,BBC Radio 4 (FM) Llandrindod Wells,BBC Radio 4 (FM),103800000,52.261047,-3.439354,432,1.35,, +FM,BBC Radio 4 (FM) Ceredigion LLANDYFRIOG,BBC Radio 4 (FM),104400000,52.045314,-4.410045,116,0.05,, +FM,BBC Radio 4 (FM) Llanfyllin LLANFYLLIN,BBC Radio 4 (FM),93500000,52.753349,-3.259797,264,0.003972,, +FM,BBC Radio 4 (FM) Bridgend Llangeinor,BBC Radio 4 (FM),93000000,51.586117,-3.581462,306,0.01,, +FM,BBC Radio 4 (FM) Llangollen and Cheshire Llangollen VHF,BBC Radio 4 (FM),93300000,53.031048,-3.180791,556,7.80001,, +FM,BBC Radio 4 (FM) Mid Wales LLANIDLOES,BBC Radio 4 (FM),104800000,52.446933,-3.549585,244,0.025,, +FM,BBC Radio 4 (FM) Llanrhaeadr ym Mochnant LLANRHAEADR YM MOCHN,BBC Radio 4 (FM),94200000,52.825889,-3.226423,333,0.025,, +FM,BBC Radio 4 (FM) Snowdonia LLWYN ONN,BBC Radio 4 (FM),104800000,52.737496,-4.03773,277,0.25,, +FM,BBC Radio 4 (FM) Talgarth LLYSWEN,BBC Radio 4 (FM),104400000,52.016761,-3.258522,224,0.01,, +FM,BBC Radio 4 (FM) Londonderry,BBC Radio 4 (FM),94900000,55.00421,-7.368968,175,5,, +FM,BBC Radio 4 (FM) Welshpool LONG MOUNTAIN,BBC Radio 4 (FM),94000000,52.644306,-3.086542,400,0.024,, +FM,BBC Radio 4 (FM) Calderdale LUDDENDEN,BBC Radio 4 (FM),93100000,53.720111,-1.92874,256,0.084,, +FM,BBC Radio 4 (FM) Ludlow LUDLOW,BBC Radio 4 (FM),94000000,52.362722,-2.738327,216,0.005,, +FM,BBC Radio 4 (FM) Lyme Regis,BBC Radio 4 (FM),94100000,50.737572,-2.929856,162,0.05,, +FM,BBC Radio 4 (FM) Snowdonia MACHYNLLETH,BBC Radio 4 (FM),103600000,52.586449,-3.885603,100,0.06,, +FM,BBC Radio 4 (FM) Cambridgeshire Madingley,BBC Radio 4 (FM),93300000,52.215394,0.036667,62,0.13,, +FM,BBC Radio 4 (FM) Mallaig,BBC Radio 4 (FM),94700000,57.001499,-5.828475,71,0.02,, +FM,BBC Radio 4 (FM) Colchester and Ipswich Manningtree,BBC Radio 4 (FM),92500000,51.92387,1.086097,35,2.5,, +FM,BBC Radio 4 (FM) Marlborough MARLBOROUGH,BBC Radio 4 (FM),94500000,51.417912,-1.699977,192,0.1,, +FM,BBC Radio 4 (FM) Aberdeenshire Meldrum,BBC Radio 4 (FM),95300000,57.386674,-2.400197,245,75,, +FM,BBC Radio 4 (FM) Wester Ross Melvaig,BBC Radio 4 (FM),95700000,57.842382,-5.782182,271,17.5903,, +FM,BBC Radio 4 (FM) Membury,BBC Radio 4 (FM),93300000,51.484903,-1.558836,211,0.125,, +FM,BBC Radio 4 (FM) Mickleham MICKLEHAM,BBC Radio 4 (FM),94100000,51.272007,-0.333055,103,0.025,, +FM,BBC Radio 4 (FM) Dumbarton Millburn Muir,BBC Radio 4 (FM),104100000,55.982322,-4.600708,152,0.025,, +FM,BBC Radio 4 (FM) West Somerset Minehead,BBC Radio 4 (FM),93400000,51.19744,-3.48052,79,0.01,, +FM,BBC Radio 4 (FM) Morecambe Bay,BBC Radio 4 (FM),94400000,54.202505,-3.167346,259,5,, +FM,BBC Radio 4 (FM) Cardigan Bay Mynydd Pencarreg,BBC Radio 4 (FM),103700000,52.067402,-4.076523,411,0.2,, +FM,BBC Radio 4 (FM) Gloucestershire NAILSWORTH,BBC Radio 4 (FM),92600000,51.690257,-2.219843,114,0.1,, +FM,BBC Radio 4 (FM) Isle of Lewis Ness of Lewis,BBC Radio 4 (FM),96100000,58.461531,-6.230808,100,0.162,, +FM,BBC Radio 4 (FM) Newbury,BBC Radio 4 (FM),92600000,51.414621,-1.290472,130,0.1,, +FM,BBC Radio 4 (FM) Newhaven NEWHAVEN,BBC Radio 4 (FM),94100000,50.787726,0.035848,81,0.05,, +FM,BBC Radio 4 (FM) Newcastle NEWTON,BBC Radio 4 (FM),93800000,54.982447,-1.945593,165,0.1,, +FM,BBC Radio 4 (FM) Devon North Hessary Tor,BBC Radio 4 (FM),92500000,50.550217,-4.008413,508,80,, +FM,BBC Radio 4 (FM) Northamptonshire Northampton,BBC Radio 4 (FM),93300000,52.275355,-0.885481,127,0.0615,, +FM,BBC Radio 4 (FM) Oban and Mull Oban,BBC Radio 4 (FM),95300000,56.40396,-5.485882,122,2.5,, +FM,BBC Radio 4 (FM) Ogmore Vale,BBC Radio 4 (FM),93600000,51.593504,-3.546781,298,0.01,, +FM,BBC Radio 4 (FM) Okehampton,BBC Radio 4 (FM),93100000,50.753618,-4.005483,208,0.025,, +FM,BBC Radio 4 (FM) Scarborough OLIVERS MOUNT,BBC Radio 4 (FM),94300000,54.267351,-0.404494,151,0.125,, +FM,BBC Radio 4 (FM) Oxfordshire Oxford,BBC Radio 4 (FM),93900000,51.790638,-1.179183,130,17.5903,, +FM,BBC Radio 4 (FM) Borders PEEBLES,BBC Radio 4 (FM),95000000,55.661832,-3.227732,352,0.02,, +FM,BBC Radio 4 (FM) Bodmin Penaligon Downs,BBC Radio 4 (FM),93200000,50.481389,-4.782638,116,0.2,, +FM,BBC Radio 4 (FM) Burnley Pendle Forest,BBC Radio 4 (FM),94600000,53.841893,-2.266074,276,0.5,, +FM,BBC Radio 4 (FM) Penicuik PENICUIK,BBC Radio 4 (FM),95500000,55.819142,-3.194377,248,0.132,, +FM,BBC Radio 4 (FM) Portree Penifiler,BBC Radio 4 (FM),96100000,57.395531,-6.180316,52,0.005,, +FM,BBC Radio 4 (FM) Colwyn Bay Penmaen Rhos,BBC Radio 4 (FM),104600000,53.286941,-3.684982,125,0.1,, +FM,BBC Radio 4 (FM) Cwmbran Pennar,BBC Radio 4 (FM),93900000,51.656112,-3.144564,228,0.005,, +FM,BBC Radio 4 (FM) Huntingdonshire Peterborough,BBC Radio 4 (FM),94500000,52.507615,-0.343282,56,18.7,, +FM,BBC Radio 4 (FM) Pitlochry PITLOCHRY,BBC Radio 4 (FM),103900000,56.687307,-3.759852,401,0,, +FM,BBC Radio 4 (FM) Plymouth Plympton,BBC Radio 4 (FM),92900000,50.381346,-4.067802,113,0.04,, +FM,BBC Radio 4 (FM) Tyneside PONTOP PIKE,BBC Radio 4 (FM),92900000,54.868838,-1.771233,302,67.5,, +FM,BBC Radio 4 (FM) Pontypool,BBC Radio 4 (FM),104800000,51.685712,-3.036095,250,0.025,, +FM,BBC Radio 4 (FM) Islay PORT ELLEN,BBC Radio 4 (FM),94700000,55.627446,-6.227617,93,0.065,, +FM,BBC Radio 4 (FM) Pontypridd Porth,BBC Radio 4 (FM),92800000,51.617787,-3.403306,247,0.01,, +FM,BBC Radio 4 (FM) West Cornwall Redruth,BBC Radio 4 (FM),94100000,50.209786,-5.238489,237,8.80001,, +FM,BBC Radio 4 (FM) Neath Valley RHEOLA,BBC Radio 4 (FM),104800000,51.741661,-3.679878,409,0.01,, +FM,BBC Radio 4 (FM) Rhymney RHYMNEY,BBC Radio 4 (FM),93700000,51.730587,-3.264891,419,0.02,, +FM,BBC Radio 4 (FM) Herefordshire RIDGE HILL,BBC Radio 4 (FM),93000000,51.997433,-2.53989,204,5,, +FM,BBC Radio 4 (FM) Highland Rosemarkie,BBC Radio 4 (FM),103600000,57.633195,-4.075231,206,9.77237,, +FM,BBC Radio 4 (FM) Coupar Rosemount,BBC Radio 4 (FM),95500000,56.576982,-3.298257,81,0.032,, +FM,BBC Radio 4 (FM) Helensburgh Rosneath,BBC Radio 4 (FM),103800000,55.991937,-4.793795,107,0.025,, +FM,BBC Radio 4 (FM) South Newry Rostrevor Forest,BBC Radio 4 (FM),103900000,54.092725,-6.182015,215,0.02,, +FM,BBC Radio 4 (FM) Bute ROTHESAY,BBC Radio 4 (FM),95100000,55.878164,-4.998928,166,0.285,, +FM,BBC Radio 4 (FM) Hampshire and Isle of Wight ROWRIDGE,BBC Radio 4 (FM),92900000,50.676724,-1.370435,143,125,, +FM,BBC Radio 4 (FM) Caithness Rumster Forest,BBC Radio 4 (FM),95600000,58.328006,-3.371413,221,5,, +FM,BBC Radio 4 (FM) Greater Manchester SADDLEWORTH,BBC Radio 4 (FM),94100000,53.541535,-2.020635,347,0.1,, +FM,BBC Radio 4 (FM) Salcombe,BBC Radio 4 (FM),93900000,50.244921,-3.749115,61,0.198582,, +FM,BBC Radio 4 (FM) Salisbury SALISBURY,BBC Radio 4 (FM),94200000,51.055855,-1.806762,107,0.012619,, +FM,BBC Radio 4 (FM) Cumbria & South West Scotland Sandale,BBC Radio 4 (FM),92500000,54.749109,-3.14076,363,125,, +FM,BBC Radio 4 (FM) South Yorkshire Sheffield,BBC Radio 4 (FM),94300000,53.379385,-1.513809,247,0.16,, +FM,BBC Radio 4 (FM) Skye & Lochalsh Skriaig,BBC Radio 4 (FM),94800000,57.38642,-6.24289,390,9.68481,, +FM,BBC Radio 4 (FM) Kintyre Islay and Jura South Knapdale,BBC Radio 4 (FM),95600000,55.91751,-5.462223,481,1.1,, +FM,BBC Radio 4 (FM) Derbyshire Stanton Moor,BBC Radio 4 (FM),94200000,53.170195,-1.633756,305,0.6,, +FM,BBC Radio 4 (FM) Inveraray Strachur,BBC Radio 4 (FM),95100000,56.179137,-5.071531,175,0.01,, +FM,BBC Radio 4 (FM) Galloway STRANRAER,BBC Radio 4 (FM),103600000,54.928074,-4.949004,190,0.031,, +FM,BBC Radio 4 (FM) West Midlands SUTTON COLDFIELD,BBC Radio 4 (FM),92700000,52.600539,-1.833856,169,62.5,, +FM,BBC Radio 4 (FM) Dover Swingate,BBC Radio 4 (FM),94400000,51.137832,1.335758,122,5.5,, +FM,BBC Radio 4 (FM) Norfolk TACOLNESTON,BBC Radio 4 (FM),94100000,52.518759,1.138705,64,119.374,, +FM,BBC Radio 4 (FM) Calder Valley TODMORDEN,BBC Radio 4 (FM),93300000,53.713283,-2.065416,221,0.1,, +FM,BBC Radio 4 (FM) Rhondda Valley Ton Pentre,BBC Radio 4 (FM),104300000,51.64954,-3.504023,323,0.003,, +FM,BBC Radio 4 (FM) Tullich TULLICH,BBC Radio 4 (FM),104500000,57.07283,-3.027203,463,0.025,, +FM,BBC Radio 4 (FM) Ullapool,BBC Radio 4 (FM),96100000,57.892557,-5.135709,143,0.05,, +FM,BBC Radio 4 (FM) Neath Valley Varteg Hill,BBC Radio 4 (FM),103500000,51.754672,-3.773522,351,0.024,, +FM,BBC Radio 4 (FM) Ventnor,BBC Radio 4 (FM),93800000,50.601933,-1.199325,227,0.025,, +FM,BBC Radio 4 (FM) Calder Valley WALSDEN SOUTH,BBC Radio 4 (FM),92800000,53.690612,-2.096576,227,0.01,, +FM,BBC Radio 4 (FM) County Durham WEARDALE,BBC Radio 4 (FM),94100000,54.74117,-1.961914,404,0.09,, +FM,BBC Radio 4 (FM) Wensleydale,BBC Radio 4 (FM),92700000,54.312324,-2.013338,402,0.05,, +FM,BBC Radio 4 (FM) South Glamorgan Wenvoe,BBC Radio 4 (FM),94300000,51.459476,-3.282282,129,125,, +FM,BBC Radio 4 (FM) North Ayrshire WEST KILBRIDE,BBC Radio 4 (FM),103500000,55.695641,-4.84184,170,0.05,, +FM,BBC Radio 4 (FM) Trowbridge WESTWOOD,BBC Radio 4 (FM),92700000,51.336803,-2.264225,87,0.05,, +FM,BBC Radio 4 (FM) Weymouth,BBC Radio 4 (FM),94400000,50.59912,-2.476532,64,0.1,, +FM,BBC Radio 4 (FM) Whalley WHALLEY,BBC Radio 4 (FM),94000000,53.812989,-2.411689,172,0.01,, +FM,BBC Radio 4 (FM) West Yorkshire WHARFEDALE,BBC Radio 4 (FM),92800000,53.932231,-1.699923,212,0.02,, +FM,BBC Radio 4 (FM) Whitby WHITBY BUSINESS PARK,BBC Radio 4 (FM),94000000,54.473215,-0.595572,60,0.056,, +FM,BBC Radio 4 (FM) West Cumbria Whitehaven - VHF,BBC Radio 4 (FM),94100000,54.499453,-3.558449,125,0.13,, +FM,BBC Radio 4 (FM) Brighton WHITEHAWK HILL,BBC Radio 4 (FM),94500000,50.824954,-0.113611,120,0.25,, +FM,BBC Radio 4 (FM) Windermere WINDERMERE,BBC Radio 4 (FM),92700000,54.37436,-2.951306,216,0.032,, +FM,BBC Radio 4 (FM) Lancashire WINTER HILL,BBC Radio 4 (FM),93000000,53.625547,-2.514794,439,2,, +FM,BBC Radio 4 (FM) North Yorkshire Woolmoor,BBC Radio 4 (FM),94400000,54.287102,-1.299034,257,5,, +FM,BBC Radio 4 (FM) London and the South East Wrotham,BBC Radio 4 (FM),93500000,51.320696,0.287702,219,125,, +FM,BBC Radio Berkshire Berkshire HANNINGTON,BBC Radio Berkshire,104100000,51.307873,-1.244777,220,2,, +FM,BBC Radio Berkshire Berkshire HENLEY,BBC Radio Berkshire,94600000,51.533409,-0.877019,109,0.125,, +FM,BBC Radio Berkshire Reading Reading - Fountain House,BBC Radio Berkshire,104400000,51.454569,-0.977254,43,0.7978,, +FM,BBC Radio Berkshire Windsor Windsor Castle,BBC Radio Berkshire,95400000,51.483228,-0.607933,38,0.5,, +FM,BBC Radio Bristol (FM) Bath,BBC Radio Bristol (FM),104600000,51.38779,-2.332925,175,0.041,, +FM,BBC Radio Bristol (FM) Bristol East Dundry,BBC Radio Bristol (FM),94900000,51.396006,-2.613844,198,0.5,, +FM,BBC Radio Bristol (FM) Weston-super-Mare Hutton,BBC Radio Bristol (FM),103600000,51.325227,-2.918301,73,0.1,, +FM,BBC Radio Cambridgeshire (FM) Cambridgeshire Madingley,BBC Radio Cambridgeshire (FM),96000000,52.215394,0.036667,62,0.4,, +FM,BBC Radio Cambridgeshire (FM) Huntingdonshire Peterborough,BBC Radio Cambridgeshire (FM),95700000,52.507615,-0.343282,56,2.6,, +FM,BBC Radio Cornwall (FM) East Cornwall Caradon Hill,BBC Radio Cornwall (FM),95200000,50.511364,-4.43683,369,2.5,, +FM,BBC Radio Cornwall (FM) Isles of Scilly,BBC Radio Cornwall (FM),96000000,49.932504,-6.305394,32,0.03,, +FM,BBC Radio Cornwall (FM) West Cornwall Redruth,BBC Radio Cornwall (FM),103900000,50.209786,-5.238489,237,8.9,, +FM,BBC Radio Cumbria (FM) South Lakes Kendal,BBC Radio Cumbria (FM),95200000,54.314559,-2.708127,172,0.1,, +FM,BBC Radio Cumbria (FM) North Lakes Keswick Forest,BBC Radio Cumbria (FM),104100000,54.608739,-3.204646,215,0,, +FM,BBC Radio Cumbria (FM) Morecambe Bay,BBC Radio Cumbria (FM),96100000,54.202505,-3.167346,259,1.6,, +FM,BBC Radio Cumbria (FM) Cumbria Sandale,BBC Radio Cumbria (FM),95600000,54.749109,-3.14076,363,7.5,, +FM,BBC Radio Cumbria (FM) West Cumbria Whitehaven - VHF,BBC Radio Cumbria (FM),104100000,54.499453,-3.558449,125,0.967164,, +FM,BBC Radio Cumbria (FM) Windermere WINDERMERE,BBC Radio Cumbria (FM),104200000,54.37436,-2.951306,216,0.032,, +FM,BBC Radio Cymru Aberdare,BBC Radio Cymru,93600000,51.702007,-3.398531,282,0.021,, +FM,BBC Radio Cymru Abergavenny,BBC Radio Cymru,103500000,51.807795,-3.097781,433,0.02,, +FM,BBC Radio Cymru Pontypool Abertillery,BBC Radio Cymru,104300000,51.714666,-3.12404,400,0.01,, +FM,BBC Radio Cymru Snowdonia Betws Y Coed,BBC Radio Cymru,92600000,53.108346,-3.75717,303,0.025,, +FM,BBC Radio Cymru Blaenavon,BBC Radio Cymru,104100000,51.750968,-3.048742,373,0.01,, +FM,BBC Radio Cymru Ceredigion Blaenplwyf,BBC Radio Cymru,93100000,52.360613,-4.102585,174,125,, +FM,BBC Radio Cymru Mid Wales Brecon VHF,BBC Radio Cymru,93300000,51.959448,-3.412497,248,0.01,, +FM,BBC Radio Cymru Carmarthen,BBC Radio Cymru,93300000,51.867126,-4.309135,137,0.01,, +FM,BBC Radio Cymru Carmarthenshire Carmel,BBC Radio Cymru,104600000,51.818501,-4.066216,255,1.6,, +FM,BBC Radio Cymru Wye Valley CLYRO,BBC Radio Cymru,92400000,52.08185,-3.162868,215,0.01,, +FM,BBC Radio Cymru Conway CONWY,BBC Radio Cymru,93500000,53.271606,-3.828796,114,0.05,, +FM,BBC Radio Cymru Croeserw,BBC Radio Cymru,93400000,51.644491,-3.652146,343,0.01,, +FM,BBC Radio Cymru Cwmafan,BBC Radio Cymru,104500000,51.628417,-3.737817,210,0.01,, +FM,BBC Radio Cymru Gwynedd DEINIOLEN,BBC Radio Cymru,92500000,53.137063,-4.129256,322,0.05,, +FM,BBC Radio Cymru Snowdonia DOLGELLAU,BBC Radio Cymru,94500000,52.749344,-3.886853,103,0.025,, +FM,BBC Radio Cymru South Wales EBBW VALE,BBC Radio Cymru,104600000,51.771714,-3.218938,442,0.015,, +FM,BBC Radio Cymru South Wales Ferndale,BBC Radio Cymru,104900000,51.662873,-3.437376,386,0.01,, +FM,BBC Radio Cymru Snowdonia FFESTINIOG,BBC Radio Cymru,92500000,52.934172,-3.921818,308,0.09,, +FM,BBC Radio Cymru Pembrokeshire Haverfordwest,BBC Radio Cymru,93700000,51.899195,-4.86653,186,9.54993,, +FM,BBC Radio Cymru Dee Estuary Holywell,BBC Radio Cymru,104700000,53.284128,-3.231408,130,0.25,, +FM,BBC Radio Cymru Swansea Kilvey Hill,BBC Radio Cymru,104200000,51.62891,-3.919745,193,0.5,, +FM,BBC Radio Cymru Anglesey LLANDDONA,BBC Radio Cymru,94200000,53.307002,-4.12825,146,10.5,, +FM,BBC Radio Cymru Snowdonia LLANDECWYN,BBC Radio Cymru,93800000,52.914419,-4.017769,268,0.1,, +FM,BBC Radio Cymru Mid Wales LLANDINAM,BBC Radio Cymru,96100000,52.479547,-3.399945,454,0.022,, +FM,BBC Radio Cymru Llandrindod Wells,BBC Radio Cymru,93500000,52.261047,-3.439354,432,1.35,, +FM,BBC Radio Cymru Ceredigion LLANDYFRIOG,BBC Radio Cymru,94500000,52.045314,-4.410045,116,0.05,, +FM,BBC Radio Cymru Llanfyllin LLANFYLLIN,BBC Radio Cymru,95700000,52.753349,-3.259797,264,0.005,, +FM,BBC Radio Cymru Bridgend Llangeinor,BBC Radio Cymru,104600000,51.586117,-3.581462,306,0.01,, +FM,BBC Radio Cymru Llangollen and Cheshire Llangollen VHF,BBC Radio Cymru,104300000,53.031048,-3.180791,556,7.80001,, +FM,BBC Radio Cymru Mid Wales LLANIDLOES,BBC Radio Cymru,92500000,52.446933,-3.549585,244,0.025,, +FM,BBC Radio Cymru Llanrhaeadr ym Mochnant LLANRHAEADR YM MOCHN,BBC Radio Cymru,103800000,52.825889,-3.226423,333,0.025,, +FM,BBC Radio Cymru Snowdonia LLWYN ONN,BBC Radio Cymru,92700000,52.737496,-4.03773,277,0.25,, +FM,BBC Radio Cymru Talgarth LLYSWEN,BBC Radio Cymru,94000000,52.016761,-3.258522,224,0.01,, +FM,BBC Radio Cymru Welshpool LONG MOUNTAIN,BBC Radio Cymru,103600000,52.644306,-3.086542,400,0.024,, +FM,BBC Radio Cymru Snowdonia MACHYNLLETH,BBC Radio Cymru,93800000,52.586449,-3.885603,100,0.06,, +FM,BBC Radio Cymru Cardigan Bay Mynydd Pencarreg,BBC Radio Cymru,94100000,52.067402,-4.076523,411,0.2,, +FM,BBC Radio Cymru Ogmore Vale,BBC Radio Cymru,95000000,51.593504,-3.546781,298,0.01,, +FM,BBC Radio Cymru Colwyn Bay Penmaen Rhos,BBC Radio Cymru,92800000,53.286941,-3.684982,125,0.1,, +FM,BBC Radio Cymru Cwmbran Pennar,BBC Radio Cymru,94700000,51.656112,-3.144564,228,0.005,, +FM,BBC Radio Cymru Pontypool,BBC Radio Cymru,93600000,51.685712,-3.036095,250,0.025,, +FM,BBC Radio Cymru Pontypridd Porth,BBC Radio Cymru,104500000,51.617787,-3.403306,247,0.01,, +FM,BBC Radio Cymru Neath Valley RHEOLA,BBC Radio Cymru,92600000,51.741661,-3.679878,409,0.01,, +FM,BBC Radio Cymru Rhymney RHYMNEY,BBC Radio Cymru,104900000,51.730587,-3.264891,419,0.02,, +FM,BBC Radio Cymru Rhondda Valley Ton Pentre,BBC Radio Cymru,93200000,51.64954,-3.504023,323,0.003,, +FM,BBC Radio Cymru Neath Valley Varteg Hill,BBC Radio Cymru,93300000,51.754672,-3.773522,351,0.024,, +FM,BBC Radio Cymru South Glamorgan Wenvoe,BBC Radio Cymru,96800000,51.459476,-3.282282,129,150,, +FM,BBC Radio Derby (FM) North Derbyshire Buxton,BBC Radio Derby (FM),96000000,53.275085,-1.911935,432,0.05,, +FM,BBC Radio Derby (FM) Derbyshire Drum Hill,BBC Radio Derby (FM),104500000,52.975288,-1.442404,156,2.2,, +FM,BBC Radio Derby (FM) Derbyshire Stanton Moor,BBC Radio Derby (FM),95300000,53.170195,-1.633756,305,0.6,, +FM,BBC Radio Devon (FM) Torbay Beacon Hill North,BBC Radio Devon (FM),104300000,50.447129,-3.610498,196,1,, +FM,BBC Radio Devon (FM) Exeter Exeter (St Thomas),BBC Radio Devon (FM),95800000,50.719122,-3.562148,102,0.226,, +FM,BBC Radio Devon (FM) North Devon Huntshaw Cross,BBC Radio Devon (FM),94800000,50.979244,-4.098818,200,0.5,, +FM,BBC Radio Devon (FM) Devon North Hessary Tor,BBC Radio Devon (FM),103400000,50.550217,-4.008413,508,7.5,, +FM,BBC Radio Devon (FM) Okehampton,BBC Radio Devon (FM),96000000,50.753618,-4.005483,208,0.05,, +FM,BBC Radio Devon (FM) Plymouth Plympton,BBC Radio Devon (FM),95700000,50.381346,-4.067802,113,1,, +FM,BBC Radio Gloucestershire (FM) Gloucestershire Churchdown Hill,BBC Radio Gloucestershire (FM),104700000,51.868264,-2.175397,147,1,, +FM,BBC Radio Gloucestershire (FM) Cirencester CIRENCESTER UHF,BBC Radio Gloucestershire (FM),95800000,51.750794,-1.994303,184,0.08,, +FM,BBC Radio Gloucestershire (FM) Gloucestershire STROUD,BBC Radio Gloucestershire (FM),95000000,51.768084,-2.238625,223,0.05,, +FM,BBC Radio Humberside (FM) Humberside High Hunsley,BBC Radio Humberside (FM),95900000,53.803052,-0.565371,164,5,, +FM,BBC Radio Jersey (FM) Jersey Les Platons,BBC Radio Jersey (FM),88800000,49.246023,-2.1012,134,1.9,, +FM,BBC Radio Kent (FM) Folkestone Creteway Down,BBC Radio Kent (FM),97600000,51.099738,1.182579,166,0.1,, +FM,BBC Radio Kent (FM) Dartford Tunnel,BBC Radio Kent (FM),96700000,51.469253,0.260425,3,0,, +FM,BBC Radio Kent (FM) Dover Swingate,BBC Radio Kent (FM),104200000,51.137832,1.335758,122,5,, +FM,BBC Radio Kent (FM) London and the South East Wrotham,BBC Radio Kent (FM),96700000,51.320696,0.287702,219,4.35,, +FM,BBC Radio Lancashire (FM) Burnley Hameldon Hill,BBC Radio Lancashire (FM),95500000,53.755909,-2.291465,397,0.8,, +FM,BBC Radio Lancashire (FM) Lancashire LANCASTER,BBC Radio Lancashire (FM),104500000,54.089336,-2.779963,88,1.05,, +FM,BBC Radio Lancashire (FM) Lancashire WINTER HILL,BBC Radio Lancashire (FM),103900000,53.625547,-2.514794,439,0.909999,, +FM,BBC Radio Leeds (FM) Leeds Beecroft Hill,BBC Radio Leeds (FM),103900000,53.811543,-1.641253,149,0.1,, +FM,BBC Radio Leeds (FM) West Yorkshire Holme Moss,BBC Radio Leeds (FM),92400000,53.533184,-1.858296,524,2.6,, +FM,BBC Radio Leeds (FM) West Yorkshire KEIGHLEY,BBC Radio Leeds (FM),102700000,53.895532,-1.896639,305,0.5,, +FM,BBC Radio Leeds (FM) Calderdale LUDDENDEN,BBC Radio Leeds (FM),95300000,53.720111,-1.92874,256,0.065929,, +FM,BBC Radio Leeds (FM) West Yorkshire WHARFEDALE,BBC Radio Leeds (FM),95300000,53.932231,-1.699923,212,0.02,, +FM,BBC Radio Leicester Leicestershire Copt Oak,BBC Radio Leicester,104900000,52.710153,-1.285042,240,4,, +FM,BBC Radio Manchester Greater Manchester Holme Moss,BBC Radio Manchester,95100000,53.533184,-1.858296,524,2.6,, +FM,BBC Radio Manchester Greater Manchester SADDLEWORTH,BBC Radio Manchester,104600000,53.541535,-2.020635,347,0.1,, +FM,BBC Radio Merseyside (FM) Merseyside Allerton Park,BBC Radio Merseyside (FM),95800000,53.373318,-2.884808,69,3.75,, +FM,BBC Radio nan Gaidheal (FM) Argyll & Bute Ardgour,BBC Radio nan Gaidheal (FM),104900000,56.712175,-5.290096,12,0.005,, +FM,BBC Radio nan Gaidheal (FM) Argyll & Bute Ballachulish,BBC Radio nan Gaidheal (FM),103700000,56.684359,-5.170394,14,0.015,, +FM,BBC Radio nan Gaidheal (FM) Central Scotland Black Hill,BBC Radio nan Gaidheal (FM),104700000,55.860005,-3.873572,275,4.88619,, +FM,BBC Radio nan Gaidheal (FM) Islay Bowmore,BBC Radio nan Gaidheal (FM),103600000,55.750128,-6.274228,46,0.061,, +FM,BBC Radio nan Gaidheal (FM) North Uist Clettraval,BBC Radio nan Gaidheal (FM),103700000,57.617267,-7.44252,123,2,, +FM,BBC Radio nan Gaidheal (FM) A CRAIGKELLY,BBC Radio nan Gaidheal (FM),104100000,56.071791,-3.233186,181,2.5,, +FM,BBC Radio nan Gaidheal (FM) South Uist Daliburgh,BBC Radio nan Gaidheal (FM),104200000,57.169643,-7.402558,6,1,, +FM,BBC Radio nan Gaidheal (FM) Isle of Lewis Eitshal,BBC Radio nan Gaidheal (FM),104300000,58.179148,-6.584974,206,2,, +FM,BBC Radio nan Gaidheal (FM) Angus Forfar,BBC Radio nan Gaidheal (FM),103700000,56.55718,-2.843663,206,2.5,, +FM,BBC Radio nan Gaidheal (FM) Great Glen Fort Augustus,BBC Radio nan Gaidheal (FM),104700000,57.105987,-4.70869,307,1,, +FM,BBC Radio nan Gaidheal (FM) Fort William,BBC Radio nan Gaidheal (FM),104200000,56.848302,-5.088621,16,2,, +FM,BBC Radio nan Gaidheal (FM) Isle of Mull Glengorm,BBC Radio nan Gaidheal (FM),103500000,56.632166,-6.133249,253,2.5,, +FM,BBC Radio nan Gaidheal (FM) Cairngorms Grantown,BBC Radio nan Gaidheal (FM),104700000,57.320173,-3.656313,389,0.36,, +FM,BBC Radio nan Gaidheal (FM) Cairngorms KINGUSSIE,BBC Radio nan Gaidheal (FM),104000000,57.061393,-4.030507,351,0.05,, +FM,BBC Radio nan Gaidheal (FM) Kinlochleven,BBC Radio nan Gaidheal (FM),104400000,56.722796,-4.978914,273,0.005,, +FM,BBC Radio nan Gaidheal (FM) Perth Kirkton Mailer,BBC Radio nan Gaidheal (FM),104500000,56.372293,-3.453361,178,0.5,, +FM,BBC Radio nan Gaidheal (FM) Mallaig,BBC Radio nan Gaidheal (FM),104300000,57.001499,-5.828475,71,0.02,, +FM,BBC Radio nan Gaidheal (FM) Aberdeenshire Meldrum,BBC Radio nan Gaidheal (FM),104200000,57.386674,-2.400197,245,75,, +FM,BBC Radio nan Gaidheal (FM) Wester Ross Melvaig,BBC Radio nan Gaidheal (FM),103900000,57.842382,-5.782182,271,17.5903,, +FM,BBC Radio nan Gaidheal (FM) Isle of Lewis Ness of Lewis,BBC Radio nan Gaidheal (FM),104900000,58.461531,-6.230808,100,0.162,, +FM,BBC Radio nan Gaidheal (FM) Oban and Mull Oban,BBC Radio nan Gaidheal (FM),104600000,56.40396,-5.485882,122,2.5,, +FM,BBC Radio nan Gaidheal (FM) Penicuik PENICUIK,BBC Radio nan Gaidheal (FM),104400000,55.819142,-3.194377,248,0.132,, +FM,BBC Radio nan Gaidheal (FM) Portree Penifiler,BBC Radio nan Gaidheal (FM),104300000,57.395531,-6.180316,52,0.005,, +FM,BBC Radio nan Gaidheal (FM) Islay PORT ELLEN,BBC Radio nan Gaidheal (FM),104900000,55.627446,-6.227617,93,0.065,, +FM,BBC Radio nan Gaidheal (FM) Highland Rosemarkie,BBC Radio nan Gaidheal (FM),104900000,57.633195,-4.075231,206,9.77237,, +FM,BBC Radio nan Gaidheal (FM) Bute ROTHESAY,BBC Radio nan Gaidheal (FM),104000000,55.878164,-4.998928,166,0.285,, +FM,BBC Radio nan Gaidheal (FM) Caithness Rumster Forest,BBC Radio nan Gaidheal (FM),104600000,58.328006,-3.371413,221,5,, +FM,BBC Radio nan Gaidheal (FM) Skye & Lochalsh Skriaig,BBC Radio nan Gaidheal (FM),104700000,57.38642,-6.24289,390,9.68481,, +FM,BBC Radio nan Gaidheal (FM) Kintyre Islay and Jura South Knapdale,BBC Radio nan Gaidheal (FM),103700000,55.91751,-5.462223,481,1.1,, +FM,BBC Radio nan Gaidheal (FM) Inveraray Strachur,BBC Radio nan Gaidheal (FM),104200000,56.179137,-5.071531,175,0.01,, +FM,BBC Radio nan Gaidheal (FM) Ullapool,BBC Radio nan Gaidheal (FM),104900000,57.892557,-5.135709,143,0.05,, +FM,BBC Radio Norfolk (FM) West Norfolk Massingham,BBC Radio Norfolk (FM),104400000,52.774139,0.649933,92,2.2,, +FM,BBC Radio Norfolk (FM) Great Yarmouth and Norwich Stoke Holy Cross,BBC Radio Norfolk (FM),95100000,52.574817,1.331664,65,2,, +FM,BBC Radio Norfolk (FM) North Norfolk WEST RUNTON,BBC Radio Norfolk (FM),95600000,52.924381,1.251171,99,0.125594,, +FM,BBC Radio Northampton North Northamptonshire Geddington,BBC Radio Northampton,103600000,52.445531,-0.666816,118,0.41,, +FM,BBC Radio Northampton Northamptonshire Northampton,BBC Radio Northampton,104200000,52.275355,-0.885481,127,2,, +FM,BBC Radio Nottingham (FM) Mansfield Fishpond Hill,BBC Radio Nottingham (FM),95500000,53.140513,-1.232922,168,1,, +FM,BBC Radio Nottingham (FM) Nottingham Mapperley Ridge,BBC Radio Nottingham (FM),103800000,52.976309,-1.132626,122,0.5,, +FM,BBC Radio Nottingham (FM) Newark,BBC Radio Nottingham (FM),95100000,53.075237,-0.787915,45,0.2,, +FM,BBC Radio Scotland (FM) Argyll & Bute Ardgour,BBC Radio Scotland (FM),93100000,56.712175,-5.290096,12,0.005,, +FM,BBC Radio Scotland (FM) Scottish Borders Ashkirk,BBC Radio Scotland (FM),93500000,55.510631,-2.840766,303,20.3208,, +FM,BBC Radio Scotland (FM) Argyll & Bute Ballachulish,BBC Radio Scotland (FM),92500000,56.684359,-5.170394,14,0.015,, +FM,BBC Radio Scotland (FM) Stirling Ben Gullipen,BBC Radio Scotland (FM),93100000,56.212308,-4.263559,415,1,, +FM,BBC Radio Scotland (FM) Central Scotland Black Hill,BBC Radio Scotland (FM),94300000,55.860005,-3.873572,275,122.155,, +FM,BBC Radio Scotland (FM) A Blair Atholl,BBC Radio Scotland (FM),93100000,56.770409,-3.810867,390,0.1,, +FM,BBC Radio Scotland (FM) Islay Bowmore,BBC Radio Scotland (FM),92500000,55.750128,-6.274228,46,0.061,, +FM,BBC Radio Scotland (FM) Shetland Bressay,BBC Radio Scotland (FM),92700000,60.130079,-1.096281,224,25,, +FM,BBC Radio Scotland (FM) Kirkcudbright CAMBRET HILL,BBC Radio Scotland (FM),93100000,54.893698,-4.302038,343,0.065,, +FM,BBC Radio Scotland (FM) Kintyre Islay and Jura CAMPBELTOWN,BBC Radio Scotland (FM),92800000,55.413714,-5.624241,83,0.2,, +FM,BBC Radio Scotland (FM) North Uist Clettraval,BBC Radio Scotland (FM),92500000,57.617267,-7.44252,123,2,, +FM,BBC Radio Scotland (FM) Crieff CRIEFF,BBC Radio Scotland (FM),93700000,56.357222,-3.920232,219,0.125,, +FM,BBC Radio Scotland (FM) A Crubenmore,BBC Radio Scotland (FM),93000000,56.984905,-4.196689,514,0.2,, +FM,BBC Radio Scotland (FM) South Uist Daliburgh,BBC Radio Scotland (FM),93700000,57.169643,-7.402558,6,1,, +FM,BBC Radio Scotland (FM) A Dalnacardoch Wood,BBC Radio Scotland (FM),94200000,56.816408,-4.098008,388,0.025,, +FM,BBC Radio Scotland (FM) Ayrshire DARVEL,BBC Radio Scotland (FM),93900000,55.579376,-4.289814,286,5,, +FM,BBC Radio Scotland (FM) Aberdeen Durris,BBC Radio Scotland (FM),93800000,56.999987,-2.389944,325,1.05,, +FM,BBC Radio Scotland (FM) Isle of Lewis Eitshal,BBC Radio Scotland (FM),94200000,58.179148,-6.584974,206,2,, +FM,BBC Radio Scotland (FM) Borders EYEMOUTH,BBC Radio Scotland (FM),94100000,55.83228,-2.085863,197,0.1,, +FM,BBC Radio Scotland (FM) Angus Forfar,BBC Radio Scotland (FM),92700000,56.55718,-2.843663,206,10,, +FM,BBC Radio Scotland (FM) Great Glen Fort Augustus,BBC Radio Scotland (FM),93000000,57.105987,-4.70869,307,1,, +FM,BBC Radio Scotland (FM) Fort William,BBC Radio Scotland (FM),93700000,56.848302,-5.088621,16,2,, +FM,BBC Radio Scotland (FM) Ayr GIRVAN,BBC Radio Scotland (FM),93300000,55.244736,-4.814596,195,0.1,, +FM,BBC Radio Scotland (FM) Isle of Mull Glengorm,BBC Radio Scotland (FM),93900000,56.632166,-6.133249,253,2.5,, +FM,BBC Radio Scotland (FM) Cairngorms Grantown,BBC Radio Scotland (FM),94200000,57.320173,-3.656313,389,0.36,, +FM,BBC Radio Scotland (FM) Borders INNERLEITHEN,BBC Radio Scotland (FM),93900000,55.620243,-3.07272,244,0.011,, +FM,BBC Radio Scotland (FM) Orkney Keelylang Hill B,BBC Radio Scotland (FM),93700000,58.975283,-3.083943,220,16,, +FM,BBC Radio Scotland (FM) Cairngorms KINGUSSIE,BBC Radio Scotland (FM),93500000,57.061393,-4.030507,351,0.05,, +FM,BBC Radio Scotland (FM) Kinlochleven,BBC Radio Scotland (FM),94100000,56.722796,-4.978914,273,0.005,, +FM,BBC Radio Scotland (FM) Borders Kirkconnel,BBC Radio Scotland (FM),93100000,55.412875,-3.983785,480,0.02,, +FM,BBC Radio Scotland (FM) Perth Kirkton Mailer,BBC Radio Scotland (FM),93400000,56.372293,-3.453361,178,0.5,, +FM,BBC Radio Scotland (FM) Moray Knockmore,BBC Radio Scotland (FM),92600000,57.532303,-3.135126,353,1,, +FM,BBC Radio Scotland (FM) East Ayrshire LETHANHILL,BBC Radio Scotland (FM),92700000,55.36421,-4.464995,300,0.11,, +FM,BBC Radio Scotland (FM) Mallaig,BBC Radio Scotland (FM),92500000,57.001499,-5.828475,71,0.02,, +FM,BBC Radio Scotland (FM) Aberdeenshire Meldrum,BBC Radio Scotland (FM),93100000,57.386674,-2.400197,245,75,, +FM,BBC Radio Scotland (FM) Wester Ross Melvaig,BBC Radio Scotland (FM),93500000,57.842382,-5.782182,271,17.5903,, +FM,BBC Radio Scotland (FM) Dumbarton Millburn Muir,BBC Radio Scotland (FM),92700000,55.982322,-4.600708,152,0.025,, +FM,BBC Radio Scotland (FM) Isle of Lewis Ness of Lewis,BBC Radio Scotland (FM),92700000,58.461531,-6.230808,100,0.162,, +FM,BBC Radio Scotland (FM) Oban and Mull Oban,BBC Radio Scotland (FM),93300000,56.40396,-5.485882,122,2.5,, +FM,BBC Radio Scotland (FM) Borders PEEBLES,BBC Radio Scotland (FM),92800000,55.661832,-3.227732,352,0.02,, +FM,BBC Radio Scotland (FM) Penicuik PENICUIK,BBC Radio Scotland (FM),93000000,55.819142,-3.194377,248,0.132,, +FM,BBC Radio Scotland (FM) Portree Penifiler,BBC Radio Scotland (FM),92500000,57.395531,-6.180316,52,0.005,, +FM,BBC Radio Scotland (FM) Pitlochry PITLOCHRY,BBC Radio Scotland (FM),93600000,56.687307,-3.759852,401,0,, +FM,BBC Radio Scotland (FM) Islay PORT ELLEN,BBC Radio Scotland (FM),93400000,55.627446,-6.227617,93,0.065,, +FM,BBC Radio Scotland (FM) Highland Rosemarkie,BBC Radio Scotland (FM),94000000,57.633195,-4.075231,206,9.77237,, +FM,BBC Radio Scotland (FM) Coupar Rosemount,BBC Radio Scotland (FM),94000000,56.576982,-3.298257,81,0.032,, +FM,BBC Radio Scotland (FM) Helensburgh Rosneath,BBC Radio Scotland (FM),93600000,55.991937,-4.793795,107,0.025,, +FM,BBC Radio Scotland (FM) Bute ROTHESAY,BBC Radio Scotland (FM),92900000,55.878164,-4.998928,166,0.285,, +FM,BBC Radio Scotland (FM) Caithness Rumster Forest,BBC Radio Scotland (FM),94500000,58.328006,-3.371413,221,5,, +FM,BBC Radio Scotland (FM) Cumbria & South West Scotland Sandale,BBC Radio Scotland (FM),94700000,54.749109,-3.14076,363,125,, +FM,BBC Radio Scotland (FM) Skye & Lochalsh Skriaig,BBC Radio Scotland (FM),92900000,57.38642,-6.24289,390,9.68481,, +FM,BBC Radio Scotland (FM) Kintyre Islay and Jura South Knapdale,BBC Radio Scotland (FM),93700000,55.91751,-5.462223,481,1.1,, +FM,BBC Radio Scotland (FM) Inveraray Strachur,BBC Radio Scotland (FM),93200000,56.179137,-5.071531,175,0.01,, +FM,BBC Radio Scotland (FM) Galloway STRANRAER,BBC Radio Scotland (FM),94100000,54.928074,-4.949004,190,0.031,, +FM,BBC Radio Scotland (FM) Tullich TULLICH,BBC Radio Scotland (FM),94500000,57.07283,-3.027203,463,0.025,, +FM,BBC Radio Scotland (FM) Ullapool,BBC Radio Scotland (FM),92700000,57.892557,-5.135709,143,0.05,, +FM,BBC Radio Scotland (FM) North Ayrshire WEST KILBRIDE,BBC Radio Scotland (FM),93500000,55.695641,-4.84184,170,0.05,, +FM,BBC Radio Sheffield (FM) South Yorkshire Chesterfield,BBC Radio Sheffield (FM),94700000,53.283991,-1.427446,179,0.4,, +FM,BBC Radio Sheffield (FM) South Yorkshire Holme Moss,BBC Radio Sheffield (FM),104100000,53.533184,-1.858296,524,2,, +FM,BBC Radio Sheffield (FM) South Yorkshire Sheffield,BBC Radio Sheffield (FM),88600000,53.379385,-1.513809,247,0.167,, +FM,BBC Radio Shropshire Shropshire CLUN,BBC Radio Shropshire,104100000,52.413167,-2.994548,413,0.04,, +FM,BBC Radio Shropshire Church Stretton HAZLER HILL,BBC Radio Shropshire,90000000,52.531128,-2.790828,343,0.01,, +FM,BBC Radio Shropshire Ludlow LUDLOW,BBC Radio Shropshire,95000000,52.362722,-2.738327,216,0.005,, +FM,BBC Radio Shropshire Shropshire and Telford The Wrekin,BBC Radio Shropshire,96000000,52.670935,-2.550228,396,2.4,, +FM,BBC Radio Solent (FM) Dorset Bincombe Hill,BBC Radio Solent (FM),103800000,50.66283,-2.443645,160,0.7,, +FM,BBC Radio Solent (FM) Hampshire and Isle of Wight ROWRIDGE,BBC Radio Solent (FM),96100000,50.676724,-1.370435,143,5,, +FM,BBC Radio Stoke (FM) Staffordshire Alsagers Bank,BBC Radio Stoke (FM),94600000,53.027231,-2.28071,220,3.1,, +FM,BBC Radio Stoke (FM) Staffordshire Stafford,BBC Radio Stoke (FM),104100000,52.806371,-2.115367,76,0.075,, +FM,BBC Radio Suffolk Suffolk Coast Aldeburgh,BBC Radio Suffolk,95900000,52.180735,1.570158,21,2,, +FM,BBC Radio Suffolk Bury St Edmunds Great Barton,BBC Radio Suffolk,104600000,52.283402,0.764679,61,0.7,, +FM,BBC Radio Suffolk Colchester and Ipswich Manningtree,BBC Radio Suffolk,103900000,51.92387,1.086097,35,2.5,, +FM,BBC Radio Suffolk Suffolk Oulton,BBC Radio Suffolk,95500000,52.486385,1.715554,8,2,, +FM,BBC Radio Ulster/Foyle (FM) North Antrim Ballycastle,BBC Radio Ulster/Foyle (FM),95100000,55.215995,-6.309339,150,0.05,, +FM,BBC Radio Ulster/Foyle (FM) Omagh and Enniskillen Brougher Mountain,BBC Radio Ulster/Foyle (FM),93800000,54.423191,-7.462812,305,5,, +FM,BBC Radio Ulster/Foyle (FM) South Newry Camlough,BBC Radio Ulster/Foyle (FM),93100000,54.160861,-6.385716,340,2,, +FM,BBC Radio Ulster/Foyle (FM) Newtownabbey Carnmoney Hill,BBC Radio Ulster/Foyle (FM),95300000,54.676355,-5.928737,207,0.02,, +FM,BBC Radio Ulster/Foyle (FM) Northern Ireland Divis A,BBC Radio Ulster/Foyle (FM),94500000,54.607538,-6.009471,368,61.0773,, +FM,BBC Radio Ulster/Foyle (FM) Kilkeel,BBC Radio Ulster/Foyle (FM),93800000,54.095375,-6.041723,267,0.1,, +FM,BBC Radio Ulster/Foyle (FM) Larne,BBC Radio Ulster/Foyle (FM),93500000,54.862024,-5.828421,119,0.016,, +FM,BBC Radio Ulster/Foyle (FM) Limavady,BBC Radio Ulster/Foyle (FM),95400000,55.109172,-6.886121,341,1.7,, +FM,BBC Radio Ulster/Foyle (FM) Londonderry,BBC Radio Ulster/Foyle (FM),93100000,55.00421,-7.368968,175,15.6,, +FM,BBC Radio Ulster/Foyle (FM) South Newry Rostrevor Forest,BBC Radio Ulster/Foyle (FM),92700000,54.092725,-6.182015,215,0.02,, +FM,BBC Radio Wales Aberdare,BBC Radio Wales,95800000,51.702007,-3.398531,282,0.021,, +FM,BBC Radio Wales Abergavenny,BBC Radio Wales,95200000,51.807795,-3.097781,433,0.02,, +FM,BBC Radio Wales Pontypool Abertillery,BBC Radio Wales,91200000,51.714666,-3.12404,400,0.01,, +FM,BBC Radio Wales Snowdonia Betws Y Coed,BBC Radio Wales,90400000,53.108346,-3.75717,303,0.025,, +FM,BBC Radio Wales Blaenavon,BBC Radio Wales,95100000,51.750968,-3.048742,373,0.01,, +FM,BBC Radio Wales Ceredigion Blaenplwyf,BBC Radio Wales,95300000,52.360613,-4.102585,174,60,, +FM,BBC Radio Wales Mid Wales Brecon VHF,BBC Radio Wales,91100000,51.959448,-3.412497,248,0.01,, +FM,BBC Radio Wales Carmarthen,BBC Radio Wales,91100000,51.867126,-4.309135,137,0.01,, +FM,BBC Radio Wales Carmarthenshire Carmel,BBC Radio Wales,95100000,51.818501,-4.066216,255,1.6,, +FM,BBC Radio Wales A Christchurch,BBC Radio Wales,95900000,51.601588,-2.935417,94,0.25,, +FM,BBC Radio Wales Wye Valley CLYRO,BBC Radio Wales,90200000,52.08185,-3.162868,215,0.01,, +FM,BBC Radio Wales Conway CONWY,BBC Radio Wales,91300000,53.271606,-3.828796,114,0.05,, +FM,BBC Radio Wales Croeserw,BBC Radio Wales,91200000,51.644491,-3.652146,343,0.01,, +FM,BBC Radio Wales Cwmafan,BBC Radio Wales,90700000,51.628417,-3.737817,210,0.01,, +FM,BBC Radio Wales Gwynedd DEINIOLEN,BBC Radio Wales,90300000,53.137063,-4.129256,322,0.05,, +FM,BBC Radio Wales Snowdonia DOLGELLAU,BBC Radio Wales,92300000,52.749344,-3.886853,103,0.025,, +FM,BBC Radio Wales South Wales EBBW VALE,BBC Radio Wales,95000000,51.771714,-3.218938,442,0.015,, +FM,BBC Radio Wales South Wales Ferndale,BBC Radio Wales,91800000,51.662873,-3.437376,386,0.01,, +FM,BBC Radio Wales Snowdonia FFESTINIOG,BBC Radio Wales,90300000,52.934172,-3.921818,308,0.082081,, +FM,BBC Radio Wales Pembrokeshire Haverfordwest,BBC Radio Wales,95900000,51.899195,-4.86653,186,9.54993,, +FM,BBC Radio Wales Swansea Kilvey Hill,BBC Radio Wales,93900000,51.62891,-3.919745,193,0.5,, +FM,BBC Radio Wales Anglesey LLANDDONA,BBC Radio Wales,94800000,53.307002,-4.12825,146,5,, +FM,BBC Radio Wales Snowdonia LLANDECWYN,BBC Radio Wales,91600000,52.914419,-4.017769,268,0.1,, +FM,BBC Radio Wales Mid Wales LLANDINAM,BBC Radio Wales,92300000,52.479547,-3.399945,454,0.022,, +FM,BBC Radio Wales Llandrindod Wells,BBC Radio Wales,91300000,52.261047,-3.439354,432,1.39,, +FM,BBC Radio Wales Ceredigion LLANDYFRIOG,BBC Radio Wales,92300000,52.045314,-4.410045,116,0.05,, +FM,BBC Radio Wales Llanfyllin LLANFYLLIN,BBC Radio Wales,91300000,52.753349,-3.259797,264,0.003972,, +FM,BBC Radio Wales Bridgend Llangeinor,BBC Radio Wales,90800000,51.586117,-3.581462,306,0.01,, +FM,BBC Radio Wales Llangollen and Cheshire Llangollen VHF,BBC Radio Wales,91100000,53.031048,-3.180791,556,7.80001,, +FM,BBC Radio Wales Mid Wales LLANIDLOES,BBC Radio Wales,90300000,52.446933,-3.549585,244,0.025,, +FM,BBC Radio Wales Llanrhaeadr ym Mochnant LLANRHAEADR YM MOCHN,BBC Radio Wales,92000000,52.825889,-3.226423,333,0.025,, +FM,BBC Radio Wales Snowdonia LLWYN ONN,BBC Radio Wales,90500000,52.737496,-4.03773,277,0.25,, +FM,BBC Radio Wales Talgarth LLYSWEN,BBC Radio Wales,91800000,52.016761,-3.258522,224,0.01,, +FM,BBC Radio Wales Welshpool LONG MOUNTAIN,BBC Radio Wales,91800000,52.644306,-3.086542,400,0.024,, +FM,BBC Radio Wales Snowdonia MACHYNLLETH,BBC Radio Wales,91600000,52.586449,-3.885603,100,0.06,, +FM,BBC Radio Wales Merthyr Tydfil,BBC Radio Wales,96100000,51.749853,-3.367124,249,0.025,, +FM,BBC Radio Wales Cardigan Bay Mynydd Pencarreg,BBC Radio Wales,91900000,52.067402,-4.076523,411,0.2,, +FM,BBC Radio Wales Ogmore Vale,BBC Radio Wales,91400000,51.593504,-3.546781,298,0.01,, +FM,BBC Radio Wales Colwyn Bay Penmaen Rhos,BBC Radio Wales,90600000,53.286941,-3.684982,125,0.1,, +FM,BBC Radio Wales Cwmbran Pennar,BBC Radio Wales,91700000,51.656112,-3.144564,228,0.005,, +FM,BBC Radio Wales Pontypool,BBC Radio Wales,91400000,51.685712,-3.036095,250,0.025,, +FM,BBC Radio Wales Pontypridd Porth,BBC Radio Wales,94600000,51.617787,-3.403306,247,0.01,, +FM,BBC Radio Wales Neath Valley RHEOLA,BBC Radio Wales,90400000,51.741661,-3.679878,409,0.01,, +FM,BBC Radio Wales Rhymney RHYMNEY,BBC Radio Wales,91500000,51.730587,-3.264891,419,0.02,, +FM,BBC Radio Wales Rhondda Valley Ton Pentre,BBC Radio Wales,94800000,51.64954,-3.504023,323,0.003,, +FM,BBC Radio Wales Neath Valley Varteg Hill,BBC Radio Wales,95500000,51.754672,-3.773522,351,0.024,, +FM,BBC Radio Wales South Glamorgan Wenvoe,BBC Radio Wales,103900000,51.459476,-3.282282,129,18.6651,, +FM,BBC Radio Wales North Wales Wrexham Rhos,BBC Radio Wales,95400000,53.076278,-3.044994,210,0.7,, +FM,BBC Radio York (FM) North Yorkshire Acklam Wold,BBC Radio York (FM),103700000,54.046924,-0.786852,224,2,, +FM,BBC Radio York (FM) Scarborough OLIVERS MOUNT,BBC Radio York (FM),95500000,54.267351,-0.404494,151,0.125,, +FM,BBC Radio York (FM) North Yorkshire Woolmoor,BBC Radio York (FM),104300000,54.287102,-1.299034,257,0.5,, +FM,BBC Somerset (FM) Somerset MENDIP,BBC Somerset (FM),95500000,51.236969,-2.625476,303,2.5,, +FM,BBC Surrey/Sussex (FM) South Downs Burton Down,BBC Surrey/Sussex (FM),104800000,50.909654,-0.627813,245,2,, +FM,BBC Surrey/Sussex (FM) Surrey GUILDFORD,BBC Surrey/Sussex (FM),104600000,51.228358,-0.605467,142,2,, +FM,BBC Surrey/Sussex (FM) East Sussex Heathfield,BBC Surrey/Sussex (FM),104500000,50.976724,0.230437,158,5,, +FM,BBC Surrey/Sussex (FM) Horsham,BBC Surrey/Sussex (FM),95100000,51.064034,-0.322554,52,0.016,, +FM,BBC Surrey/Sussex (FM) Newhaven NEWHAVEN,BBC Surrey/Sussex (FM),95000000,50.787726,0.035848,81,0.05,, +FM,BBC Surrey/Sussex (FM) Surrey REIGATE,BBC Surrey/Sussex (FM),104000000,51.254494,-0.200986,234,2,, +FM,BBC Surrey/Sussex (FM) Brighton WHITEHAWK HILL,BBC Surrey/Sussex (FM),95300000,50.824954,-0.113611,120,0.5,, +FM,BBC Tees Darlington Darlington - Harrowgate Hill,BBC Tees,104000000,54.555795,-1.560849,72,0.25,, +FM,BBC Tees Teesside Eston Nab,BBC Tees,95000000,54.556455,-1.120934,237,0.3,, +FM,BBC Tees Whitby WHITBY BUSINESS PARK,BBC Tees,95800000,54.473215,-0.595572,60,0.054,, +FM,BBC Three Counties Radio (FM) Milton Keynes Bow Brickhill,BBC Three Counties Radio (FM),104500000,51.998806,-0.669784,169,1.1,, +FM,BBC Three Counties Radio (FM) Hertfordshire Epping Green,BBC Three Counties Radio (FM),90400000,51.744172,-0.128729,122,0.1,, +FM,BBC Three Counties Radio (FM) Hertfordshire Hemel Hempstead (Pimlico),BBC Three Counties Radio (FM),92100000,51.728571,-0.426217,142,0.05,, +FM,BBC Three Counties Radio (FM) High Wycombe,BBC Three Counties Radio (FM),98000000,51.640531,-0.763678,156,0.1,, +FM,BBC Three Counties Radio (FM) Aylesbury Quainton Hill,BBC Three Counties Radio (FM),94700000,51.885386,-0.910988,186,0.4,, +FM,BBC Three Counties Radio (FM) Bedfordshire SANDY HEATH,BBC Three Counties Radio (FM),95500000,52.130132,-0.241462,54,0.6,, +FM,BBC Three Counties Radio (FM) Luton Zouches Farm,BBC Three Counties Radio (FM),103800000,51.877958,-0.483622,207,0.388,, +FM,BBC Wiltshire (FM) Swindon Blunsdon,BBC Wiltshire (FM),103600000,51.609363,-1.794027,148,0.25,, +FM,BBC Wiltshire (FM) Marlborough MARLBOROUGH,BBC Wiltshire (FM),104900000,51.417912,-1.699977,192,0.1,, +FM,BBC Wiltshire (FM) Wiltshire Naish Hill,BBC Wiltshire (FM),104300000,51.416202,-2.076595,175,0.3,, +FM,BBC Wiltshire (FM) Wiltshire Newton Barrow,BBC Wiltshire (FM),103500000,51.117705,-1.85908,152,1,, +FM,BBC WM West Midlands SUTTON COLDFIELD,BBC WM,95600000,52.600539,-1.833856,169,5.7,, +FM,BCB 106.6 FM Bradford Idle,BCB 106.6 FM,106600000,53.832945,-1.752142,215,0.1,, +FM,Beat Radio Preston Preston - Guild Tower,Beat Radio,103200000,53.759726,-2.695723,37,0.025,, +FM,Belfast 89FM Belfast Belfast - Europa Hotel,Belfast 89FM,89300000,54.59479,-5.935047,11,0.075,, +FM,Beverley FM Beverley Beverley Race Course,Beverley FM,107800000,53.843546,-0.460172,45,0.025,, +FM,Beyond Radio Lancaster Carnforth - Lancaster,Beyond Radio,107500000,54.130311,-2.76321,37,0.01,, +FM,Beyond Radio Lancaster Lancaster - Ashton Memorial,Beyond Radio,103500000,54.045283,-2.782039,105,0.05,, +FM,BFBS Aldershot Aldershot - Centre for Health,BFBS,102500000,51.254436,-0.765605,107,0.025,, +FM,BFBS Blandford Blandford Garrison,BFBS,89300000,50.870624,-2.118471,106,0.025,, +FM,BFBS Bulford Bulford Camp,BFBS,106800000,51.18517,-1.722235,184,0.025,, +FM,BFBS Inverness Cameron Barracks Inverness (LRSL),BFBS,87700000,57.477715,-4.204681,18,5e-05,, +FM,BFBS Catterick Catterick Garrison,BFBS,106900000,54.380761,-1.723761,152,0.025,, +FM,BFBS Colchester Garrison,BFBS,107000000,51.880018,0.889961,32,0.025,, +FM,BFBS Edinburgh South Dreghorn Barracks,BFBS,98500000,55.901107,-3.23816,160,0.025,, +FM,BFBS Inverness Fort George Inverness (LRSL),BFBS,87700000,57.583316,-4.070549,6,0.0005,, +FM,BFBS Edinburgh South Glencorse Barracks,BFBS,94000000,55.848416,-3.205497,183,0.005,, +FM,BFBS Blandford (Bovington) Bovington Bovington Camp - FM,BFBS Blandford (Bovington),100800000,50.699487,-2.240659,44,0.0005,, +FM,BFBS Brize Norton Brize Norton Carterton - RAF Brize Norton,BFBS Brize Norton,106100000,51.756175,-1.584595,87,0.025,, +FM,BFBS Gibraltar O'Haras Battery,BFBS Gibraltar,97800000,36.124006,-5.343083,415,0.5,, +FM,BFBS Gibraltar Oyster Cottage,BFBS Gibraltar,93500000,36.153572,-5.350287,10,1,, +FM,BFBS Gurkha Radio Dover Dover Community Centre,BFBS Gurkha Radio,90800000,51.138863,1.323536,123,0.0005,, +FM,BFBS Lisburn FM Lisburn BFBS Lisburn,BFBS Lisburn FM,100600000,54.52375,-6.050621,73,0.025,, +FM,BFBS Radio (Fort George) Inverness Fort George Inverness (LRSL),BFBS Radio (Fort George),87700000,57.583316,-4.070549,6,0.0005,, +FM,BFBS Radio 2 O'Haras Battery,BFBS Radio 2,99500000,36.124006,-5.343083,415,0.5,, +FM,BFBS Radio 2 Oyster Cottage,BFBS Radio 2,89400000,36.153572,-5.350287,10,0.5,, +FM,BFBS Shorncliffe Shorncliffe Camp Shorncliffe MoD - Tower Theatre,BFBS Shorncliffe,105400000,51.079275,1.134336,74,0.025,, +FM,BGFM Brynmawr,BGFM,97300000,51.802578,-3.181482,414,0.025,, +FM,Big City Radio Birmingham Aston Birmingham - Victor Tower,Big City Radio,89100000,52.494597,-1.872256,108,0.025,, +FM,Biggles FM Biggleswade Potton,Biggles FM,104800000,52.126108,-0.224966,47,0.05,, +FM,Bishop FM 105.9 South West Durham High Etherley - Community Centre,Bishop FM 105.9,105900000,54.648533,-1.748295,201,0.05,, +FM,Black Cat Radio St Neots Paxton Hill,Black Cat Radio,102500000,52.248446,-0.23459,46,0.1,, +FM,Black Country Radio Stourbridge Brierley Hill - St Michaels,Black Country Radio,102500000,52.479497,-2.124668,162,0.05,, +FM,Black Country Radio Dudley Dudley - King Street,Black Country Radio,92200000,52.508028,-2.08762,202,0.03,, +FM,Black Diamond Midlothian Halkerston Farm,Black Diamond,100700000,55.813657,-3.046918,263,0.025,, +FM,Black Diamond FM Midlothian Newtongrange - Newbattle MC,Black Diamond FM,107800000,55.867368,-3.049481,138,0.05,, +FM,Blackburn's 102.2FM Blackburn Blackburn - Dukes Cars,Blackburn's 102.2FM,102200000,53.754839,-2.505,197,0.05,, +FM,Blast 106 Belfast Belfast - Europa Hotel,Blast 106,106400000,54.59479,-5.935047,11,0.025,, +FM,Blast106 Coleraine and up to Portstewart Coleraine - Beresford Biz Centre,Blast106,106400000,55.128079,-6.666744,4,0.1,, +FM,Bolton FM Bolton Bolton - Dove Mill,Bolton FM,96500000,53.565454,-2.46137,140,0.1,, +FM,Bradley Stoke Radio Bradley Stoke,Bradley Stoke Radio,103400000,51.540136,-2.561134,67,0.025,, +FM,Branch FM Dewsbury,Branch FM,101800000,53.702187,-1.62128,133,0.025,, +FM,BRFM 95.6 FM Sheppey Minster,BRFM 95.6 FM,95600000,51.423502,0.830556,57,0.025,, +FM,Bridge FM Bridgend Mynydd Baedan,Bridge FM,106300000,51.556793,-3.628192,244,0.5,, +FM,Bridge FM Dundee Ninewells Hospital Dundee,Bridge FM,87700000,56.460854,-2.991471,43,5e-05,, +FM,Brill Oldies Radio Brill,Brill Oldies Radio,104700000,51.818986,-1.051142,181,5e-05,, +FM,Bristol Community FM Bristol Barton Hill,Bristol Community FM,93200000,51.454979,-2.562536,25,0.025,, +FM,BRO Radio Barry Barry - Awbery House,BRO Radio,98100000,51.410121,-3.281189,82,0.05,, +FM,BRO Radio Barry Llantwit Major Rugby Club,BRO Radio,100200000,51.407511,-3.47982,46,0.05,, +FM,BRO Radio Penarth,BRO Radio,106100000,51.42835,-3.180864,26,0.015,, +FM,BRO Radio St Athan St Athan - Community Centre,BRO Radio,98400000,51.40142,-3.419818,38,0.025,, +FM,Buchan Radio Peterhead Peterhead - Wilson Street,Buchan Radio,107900000,57.510991,-1.781674,13,0.025,, +FM,Bute Island Radio Isle of Bute Rothesay Town,Bute Island Radio,96500000,55.836375,-5.053216,9,0.025,, +FM,Cabin FM Herne Bay Herne Bay - Council Office,Cabin FM,94600000,51.370251,1.127739,6,0.025,, +FM,Caithness FM Caithness Ben Dorrery,Caithness FM,106500000,58.473372,-3.608383,244,0.630001,, +FM,Calon FM Wrexham Wrexham - Ty Pawb,Calon FM,105000000,53.046449,-2.990571,80,0.025,, +FM,Cam FM Cambridge Cambridge University Library,Cam FM,97200000,52.205053,0.108347,9,0.025,, +FM,Cambridge 105 Radio Cambridge,Cambridge 105 Radio,105000000,52.198956,0.127374,12,0.025,, +FM,CamGlen Radio Cambuslang and Rutherglen Rutherglen,CamGlen Radio,107900000,55.828534,-4.210231,23,0.025,, +FM,Canalside Radio 102.8 FM Bollington - Macclesfield Bollington - Clarence Mill,Canalside Radio 102.8 FM,102800000,53.300333,-2.100342,153,0.05,, +FM,Cando FM Barrow-in-Furness,Cando FM,106300000,54.111664,-3.227816,11,0.015,, +FM,Cando FM Barrow-in-Furness Ulverston - St Mary's Hospice,Cando FM,107300000,54.200466,-3.087573,37,0.025,, +FM,Cannock Chase Radio Burntwood,Cannock Chase Radio,89800000,52.68154,-1.925998,170,0.05,, +FM,Cannock Chase Radio Cannock,Cannock Chase Radio,94000000,52.692526,-2.029252,154,0.025,, +FM,Cannock Chase Radio Rugeley RUGELEY,Cannock Chase Radio,89600000,52.758593,-1.949725,100,0.05,, +FM,Capital Caernarfon Arfon,Capital,103000000,53.01985,-4.273475,300,2.5,, +FM,Capital Birmingham Birmingham - Metropolitan House,Capital,102200000,52.473153,-1.919722,152,0.5,, +FM,Capital Central Scotland Black Hill,Capital,106100000,55.860005,-3.873572,275,10,, +FM,Capital Blackburn Blackburn - Royal Blackburn Hospital,Capital,107000000,53.736137,-2.462328,201,0.25,, +FM,Capital North East England Burnhope,Capital,105300000,54.8219,-1.714848,240,4.2,, +FM,Capital South East Staffordshire Burton,Capital,102400000,52.801463,-1.607194,122,0.05,, +FM,Capital Chorley Chorley - St George's Church,Capital,102800000,53.652054,-2.629496,87,0.025,, +FM,Capital Newport Christchurch,Capital,97400000,51.601588,-2.935417,94,0.25,, +FM,Capital Central Scotland CRAIGKELLY,Capital,105700000,56.071791,-3.233186,181,5,, +FM,Capital London Croydon,Capital,95800000,51.40986,-0.085755,114,1.9998,, +FM,Capital Dartford Tunnel,Capital,95800000,51.469253,0.260425,3,0,, +FM,Capital Derby Drum Hill,Capital,102800000,52.975288,-1.442404,156,0.575,, +FM,Capital Yorkshire Emley Moor,Capital,105100000,53.611985,-1.66456,256,2.5,, +FM,Capital North East England Eston Nab,Capital,106400000,54.556455,-1.120934,237,0.3,, +FM,Capital Banbury Farthinghoe,Capital,107600000,52.044582,-1.224699,157,0.1,, +FM,Capital North East England Fenham,Capital,105600000,54.978039,-1.662966,120,0.05,, +FM,Capital Mansfield Fishpond Hill,Capital,96500000,53.140513,-1.232922,168,0.05,, +FM,Capital North Wales Coast Great Ormes Head,Capital,96300000,53.332716,-3.853487,200,1,, +FM,Capital North Humberside High Hunsley,Capital,105800000,53.803052,-0.565371,164,5,, +FM,Capital Bradford Idle,Capital,105600000,53.832945,-1.752142,215,0.25,, +FM,Capital Stratford Lark Stoke,Capital,102000000,52.081613,-1.728531,260,1.44,, +FM,Capital Warwick LEAMINGTON SPA,Capital,107300000,52.294288,-1.519026,90,0.1,, +FM,Capital South East Staffordshire Lichfield,Capital,101600000,52.63655,-1.759098,145,0.05,, +FM,Capital Liverpool Liverpool Cathedral,Capital,107600000,53.397439,-2.973289,40,0.17825,, +FM,Capital Manchester Manchester - City Tower,Capital,102000000,53.480177,-2.23864,43,0.5,, +FM,Capital Nottingham Mapperley Ridge,Capital,96200000,52.976309,-1.132626,122,0.5,, +FM,Capital Hexham NEWTON,Capital,105800000,54.982447,-1.945593,165,0.1,, +FM,Capital Burnley Pendle Forest,Capital,99800000,53.841893,-2.266074,276,0.5,, +FM,Capital Preston Preston - Bee Lane,Capital,106500000,53.733667,-2.694534,31,0.1,, +FM,Capital Rugby Rugby - Art Gallery,Capital,107100000,52.371554,-1.264669,113,0.1,, +FM,Capital Coventry Samuel Vale House,Capital,96200000,52.413654,-1.513171,91,0.08,, +FM,Capital Sheffield,Capital,105600000,53.379385,-1.513809,247,0.125,, +FM,Capital Leicester Skeffington,Capital,105400000,52.624763,-0.909129,210,4,, +FM,Capital Deeside Storeton,Capital,97100000,53.349848,-3.031394,61,0.5,, +FM,Capital Cardiff Wenallt,Capital,103200000,51.544539,-3.223384,226,1,, +FM,Capital Wrexham Wrexham Rhos,Capital,103400000,53.076278,-3.044994,210,0.7,, +FM,Capital FM Brighton WHITEHAWK HILL,Capital FM,107200000,50.824954,-0.113611,120,0.1,, +FM,Capital South Coast Southampton Chillerton Down,Capital South Coast,103200000,50.649245,-1.328934,166,1,, +FM,Capital Xtra North London Alexandra Palace,Capital Xtra,107100000,51.594459,-0.129257,92,0.1,, +FM,Capital Xtra Brixton Crystal Palace,Capital Xtra,96900000,51.424161,-0.074944,110,0.03,, +FM,Capital/Heart Winchester Crabwood Farm,Capital/Heart,96700000,51.063167,-1.360216,158,0.225,, +FM,Capital/Heart Portsmouth Fort Widley,Capital/Heart,97500000,50.853922,-1.067587,102,0.425,, +FM,Caroline Community Radio Maldon Maldon - Blue Boar Hotel,Caroline Community Radio,94700000,51.732016,0.675995,32,0.1,, +FM,Castledown Radio Ludgershall,Castledown Radio,104700000,51.2513,-1.63773,141,0.05,, +FM,Castledown Radio Tidworth Tidworth - Beech Hill Road,Castledown Radio,107600000,51.241283,-1.655572,127,0.025,, +FM,Celtic Music Radio Glasgow Glasgow - Grafton Place,Celtic Music Radio,95000000,55.864198,-4.245819,40,0.05,, +FM,Central FM Stirling Earls Hill,Central FM,103100000,56.070378,-4.059694,432,0.25,, +FM,CFM West Cumbria Broughton Moor,CFM,102200000,54.682913,-3.463248,125,0.5,, +FM,CFM Carlisle Caldbeck,CFM,96400000,54.773382,-3.091075,289,1,, +FM,CFM Penrith Penrith - Beacon Hill,CFM,102500000,54.674729,-2.728805,263,0.05,, +FM,CFM West Cumbria WHITEHAVEN,CFM,103400000,54.496676,-3.557726,133,0.2,, +FM,Channel 103 Jersey Fremont Point,Channel 103,103700000,49.25148,-2.131167,106,2,, +FM,CHBN Truro Treliske,CHBN,100800000,50.266723,-5.090217,94,0.025,, +FM,Chelmsford Community Radio Chelmsford Chelmsford - Soax House,Chelmsford Community Radio,104400000,51.735001,0.469917,28,0.1,, +FM,Chiltern Voice Amersham and Chesham Amersham - Beacon School,Chiltern Voice,107400000,51.687607,-0.614982,162,0.05,, +FM,Cinque Ports Radio Romney Marsh Ivychurch,Cinque Ports Radio,100200000,51.01255,0.889573,3,0.075,, +FM,Classic FM Tayside Angus,Classic FM,100100000,56.555053,-2.986125,312,8.2,, +FM,Classic FM North West Wales Arfon,Classic FM,100700000,53.01985,-4.273475,300,15,, +FM,Classic FM Bath,Classic FM,100200000,51.38779,-2.332925,175,0.1,, +FM,Classic FM Leeds Beecroft Hill,Classic FM,101600000,53.811543,-1.641253,149,0.5,, +FM,Classic FM Lincolnshire Belmont,Classic FM,100500000,53.335814,-0.171983,125,3.1,, +FM,Classic FM Glasgow Black Hill,Classic FM,101700000,55.860005,-3.873572,275,122.155,, +FM,Classic FM Cardigan Bay Blaenplwyf,Classic FM,101100000,52.360613,-4.102585,174,8,, +FM,Classic FM Swindon Blunsdon,Classic FM,100800000,51.609363,-1.794027,148,0.36,, +FM,Classic FM Bedford Bow Brickhill,Classic FM,100400000,51.998806,-0.669784,169,5,, +FM,Classic FM London Crystal Palace,Classic FM,100600000,51.424161,-0.074944,110,2,, +FM,Classic FM Dartford Tunnel,Classic FM,100900000,51.469253,0.260425,3,0,, +FM,Classic FM Ayrshire DARVEL,Classic FM,101300000,55.579376,-4.289814,286,4,, +FM,Classic FM Northern Ireland Divis A,Classic FM,101900000,54.607538,-6.009471,368,122.155,, +FM,Classic FM Isle of Man DOUGLAS,Classic FM,100200000,54.140551,-4.493075,143,0.68,, +FM,Classic FM Kent DOVER,Classic FM,101800000,51.11163,1.247272,133,4.2,, +FM,Classic FM Teesside Eston Nab,Classic FM,101600000,54.556455,-1.120934,237,0.3,, +FM,Classic FM Newcastle Fenham,Classic FM,101000000,54.978039,-1.662966,120,0.05,, +FM,Classic FM North Wales Great Ormes Head,Classic FM,101600000,53.332716,-3.853487,200,2,, +FM,Classic FM Reading Hemdean,Classic FM,101800000,51.481196,-0.978531,69,0.5,, +FM,Classic FM West Yorkshire Holme Moss,Classic FM,101100000,53.533184,-1.858296,524,125,, +FM,Classic FM Bradford Idle,Classic FM,100300000,53.832945,-1.752142,215,0.25,, +FM,Classic FM West Glamorgan Kilvey Hill,Classic FM,101300000,51.62891,-3.919745,193,0.5,, +FM,Classic FM Londonderry,Classic FM,100500000,55.00421,-7.368968,175,15.5,, +FM,Classic FM Grampian Meldrum,Classic FM,100500000,57.386674,-2.400197,245,75,, +FM,Classic FM Morecambe Bay,Classic FM,101800000,54.202505,-3.167346,259,3.2,, +FM,Classic FM Moray Firth Mounteagle,Classic FM,101400000,57.591626,-4.27683,212,8.80001,, +FM,Classic FM Devon North Hessary Tor,Classic FM,100000000,50.550217,-4.008413,508,80,, +FM,Classic FM Oxfordshire Oxford,Classic FM,101300000,51.790638,-1.179183,130,22.4765,, +FM,Classic FM Cambridgeshire Peterborough,Classic FM,101900000,52.507615,-0.343282,56,20,, +FM,Classic FM Durham PONTOP PIKE,Classic FM,100300000,54.868838,-1.771233,302,64.9999,, +FM,Classic FM South West Wales Presely,Classic FM,100500000,51.944404,-4.661027,323,5.7,, +FM,Classic FM Bristol Pur Down,Classic FM,101400000,51.48519,-2.562764,91,0.1,, +FM,Classic FM Cornwall Redruth,Classic FM,101500000,50.209786,-5.238489,237,8.1,, +FM,Classic FM Hereford RIDGE HILL,Classic FM,100400000,51.997433,-2.53989,204,3.9,, +FM,Classic FM Isle of Wight ROWRIDGE,Classic FM,100300000,50.676724,-1.370435,143,125,, +FM,Classic FM Cumbria Sandale,Classic FM,99900000,54.749109,-3.14076,363,125,, +FM,Classic FM Selkirk SELKIRK,Classic FM,100900000,55.555786,-2.793221,290,5.4,, +FM,Classic FM South Yorkshire Sheffield,Classic FM,101700000,53.379385,-1.513809,247,0.25,, +FM,Classic FM West Midlands SUTTON COLDFIELD,Classic FM,100100000,52.600539,-1.833856,169,125,, +FM,Classic FM Norfolk TACOLNESTON,Classic FM,101500000,52.518759,1.138705,64,119.374,, +FM,Classic FM South Glamorgan Wenvoe,Classic FM,101700000,51.459476,-3.282282,129,125,, +FM,Classic FM Brighton WHITEHAWK HILL,Classic FM,101900000,50.824954,-0.113611,120,0.2,, +FM,Classic FM London Wrotham,Classic FM,100900000,51.320696,0.287702,219,125,, +FM,Classic Hits Forest Gold Epping Epping - St Margaret's Hospital,Classic Hits Forest Gold,99300000,51.70488,0.123306,113,0.001,, +FM,Clyde 1 Glasgow Black Hill,Clyde 1,102500000,55.860005,-3.873572,275,13,, +FM,Clyde 1 Vale of Leven Millburn Muir,Clyde 1,97000000,55.982322,-4.600708,152,0.05,, +FM,Clyde 1 Rosneath,Clyde 1,103300000,55.991937,-4.793795,107,0.05,, +FM,Clyde 1 Rothesay ROTHESAY,Clyde 1,102300000,55.878164,-4.998928,166,0.3,, +FM,Coagh Baptist Drive-In Cookstown, NI Coagh Baptist Church,Coagh Baptist Drive-In,104200000,54.645163,-6.620914,33,5e-05,, +FM,Coast and County Radio Scarborough Oliver's Mount B,Coast and County Radio,97400000,54.267627,-0.404944,151,0.05,, +FM,Coast and County Radio Whitby Whitby - Football Club,Coast and County Radio,105500000,54.489577,-0.627277,47,0.025,, +FM,Coast FM St Just Lands End Radio Station,Coast FM,97200000,50.117779,-5.669653,156,0.1,, +FM,Coast FM Penzance Penzance Cricket Club,Coast FM,96500000,50.124239,-5.545881,64,0.025,, +FM,Coast Radio Ballygalley,Coast Radio,106400000,54.896089,-5.849348,64,0.1,, +FM,Colne Radio Wivenhoe Wivenhoe Town CC,Colne Radio,106600000,51.86508,0.966141,29,0.025,, +FM,Community Voice FM Middlesbrough,Community Voice FM,104500000,54.568152,-1.228488,7,0.025,, +FM,Cool FM/Downtown Radio Belfast Black Mountain,Cool FM/Downtown Radio,97400000,54.586989,-6.022076,301,1.85,, +FM,Cool FM/Downtown Radio Omagh and Enniskillen Brougher Mountain,Cool FM/Downtown Radio,96600000,54.423191,-7.462812,305,5,, +FM,Cool FM/Downtown Radio South Newry Camlough,Cool FM/Downtown Radio,103100000,54.160861,-6.385716,340,0.900001,, +FM,Cool FM/Downtown Radio Newtownabbey Carnmoney Hill,Cool FM/Downtown Radio,103400000,54.676355,-5.928737,207,0.01,, +FM,Cool FM/Downtown Radio Larne,Cool FM/Downtown Radio,97100000,54.862024,-5.828421,119,0.04,, +FM,Cool FM/Downtown Radio Limavady,Cool FM/Downtown Radio,96400000,55.109172,-6.886121,341,1,, +FM,Cool FM/Downtown Radio Londonderry,Cool FM/Downtown Radio,102400000,55.00421,-7.368968,175,5,, +FM,Cool FM/Downtown Radio Newcastle,Cool FM/Downtown Radio,103400000,54.203198,-5.913247,251,0.1005,, +FM,Cool FM/Downtown Radio Ballymena Portglenone,Cool FM/Downtown Radio,102300000,54.863112,-6.429581,207,0.4,, +FM,Corby Radio Corby,Corby Radio,96300000,52.487381,-0.703107,115,0.025,, +FM,Crescent Radio Rochdale Stoneyfield,Crescent Radio,97000000,53.610283,-2.157454,143,0.05,, +FM,Cross Counties Radio Blaby Town Blaby,Cross Counties Radio,95400000,52.562594,-1.169426,76,0.1,, +FM,Cross Counties Radio Lutterworth & Blaby Lutterworth - Magna Park,Cross Counties Radio,92000000,52.466091,-1.243959,125,0.0959,, +FM,Cross Rhythms City Radio Newcastle under Lyme Hanchurch - Duke Lodge,Cross Rhythms City Radio,96600000,52.957473,-2.24081,218,0.025,, +FM,Cross Rhythms City Radio Stoke On Trent Stoke-on-Trent,Cross Rhythms City Radio,101800000,53.043768,-2.123907,213,0.1,, +FM,Cross Rhythms Plymouth Plymouth Mannamead,Cross Rhythms Plymouth,96300000,50.388056,-4.129573,76,0.05,, +FM,Croydon FM Croydon,Croydon FM,97800000,51.40986,-0.085755,114,0.025,, +FM,Crystal FM Midlothian Penicuik Cricket Club,Crystal FM,107400000,55.829332,-3.218157,205,0.015,, +FM,Cumbernauld FM Cumbernauld Cumbernauld - Tay Walk,Cumbernauld FM,106800000,55.947051,-3.99036,140,0.0287,, +FM,Dales Radio Yorkshire Dales Giggleswick,Dales Radio,104900000,54.075664,-2.303636,204,0.05,, +FM,Dales Radio Settle Grassington - Spring House,Dales Radio,104900000,54.079193,-1.988349,298,0.05,, +FM,Dales Radio Ingleton,Dales Radio,103000000,54.146933,-2.471488,120,0.1,, +FM,Dales Radio Leyburn,Dales Radio,104900000,54.314104,-1.838569,239,0.03,, +FM,Dean Radio Bream,Dean Radio,95700000,51.751011,-2.573595,154,0.025,, +FM,Dean Radio Cinderford Cinderford - Belle Vue,Dean Radio,105600000,51.823198,-2.497178,214,0.025,, +FM,Dee 106.3 Chester Chester - Steam Mill,Dee 106.3,106300000,53.193393,-2.88005,25,0.1,, +FM,Deveron FM Banff and Macduff Banff (Battery Green),Deveron FM,107400000,57.67024,-2.526196,20,0.1,, +FM,Deveron FM Banff and Macduff Portsoy,Deveron FM,105900000,57.681488,-2.673424,65,0.025,, +FM,Deveron FM Banff and Macduff Turriff,Deveron FM,105300000,57.534604,-2.481317,56,0.025,, +FM,Digital Hits One North Somerset Fry's Hill,Digital Hits One,100500000,51.297615,-2.809603,238,0.1,, +FM,Diverse FM Luton Luton - Farley Hill,Diverse FM,102800000,51.878444,-0.438278,167,0.2,, +FM,Dover Community Radio Dover Guston,Dover Community Radio,104900000,51.144582,1.316654,126,0.05,, +FM,Down FM Downpatrick,Down FM,105000000,54.324166,-5.697297,62,0.025,, +FM,Drive 105 FM Londonderry Londonderry - Corrody Road,Drive 105 FM,105300000,54.979578,-7.315472,145,0.1,, +FM,Drive in Films (Banbury) Banbury DCS Stadium,Drive in Films (Banbury),95800000,52.034827,-1.319185,112,5e-05,, +FM,Drive in Films (Derby) Derby Mickleover Sports FC,Drive in Films (Derby),87700000,52.922995,-1.54059,103,5e-05,, +FM,Drive-In Theatres (Poole) Poole Farmer Palmer's Farm Park,Drive-In Theatres (Poole),87700000,50.733704,-2.088098,9,5e-05,, +FM,Drystone Radio Ilkley Ilkley - Upper Austby Farm,Drystone Radio,102000000,53.948055,-1.845316,220,0.035,, +FM,Drystone Radio Sutton in Craven Sutton in Craven - Valley Farm,Drystone Radio,103500000,53.886677,-1.981403,272,0.075,, +FM,Dunoon Community Radio Dunoon Dunoon - Argyll Street,Dunoon Community Radio,97400000,55.951328,-4.928325,16,0.025,, +FM,East Coast FM East Lothian Garleton Hills - Lothian Broadband,East Coast FM,107600000,55.974039,-2.781251,179,0.025,, +FM,East Devon Radio East Devon District Aylesbeare,East Devon Radio,94600000,50.706037,-3.349844,152,0.025,, +FM,East Devon Radio Ottery St Mary Ottery St Mary - Finnimore Ind. Estate,East Devon Radio,106100000,50.750811,-3.287199,40,0,, +FM,East Devon Radio Sidmouth Sidmouth Golf Club,East Devon Radio,95000000,50.677602,-3.254765,81,0.025,, +FM,East Devon Radio Exmouth Withycombe Raleigh Common,East Devon Radio,106400000,50.64666,-3.367095,127,0.1,, +FM,EAVA FM Leicester Leicester - Belgrave,EAVA FM,102500000,52.653973,-1.125121,52,0.025,, +FM,Eden FM Penrith Penrith - Newton Rigg,Eden FM,107500000,54.672038,-2.788379,169,0.05,, +FM,Embrace Northampton Northampton - Fire Station,Embrace,104700000,52.241724,-0.894379,88,0.05,, +FM,Endeavour FM Boston Boston - Blackfriars Theatre,Endeavour FM,107000000,52.976151,-0.022467,1,0.05,, +FM,Energy Radio Isle of Man Ballasaig,Energy Radio,105200000,54.290529,-4.348618,189,0.04,, +FM,Energy Radio Isle of Man Beary Peark,Energy Radio,102400000,54.216063,-4.616199,289,0.175,, +FM,Energy Radio Isle of Man DOUGLAS,Energy Radio,98600000,54.140551,-4.493075,143,1.1,, +FM,Energy Radio Isle of Man Jurby Control Tower,Energy Radio,93400000,54.356338,-4.521985,27,0.6,, +FM,Energy Radio Isle of Man Mull Hill,Energy Radio,105200000,54.071137,-4.768804,158,0.025,, +FM,Energy Radio Isle of Man Ramsey Town B,Energy Radio,98400000,54.322428,-4.38596,2,0.014,, +FM,Energy Radio Isle of Man Snaefell,Energy Radio,91200000,54.262536,-4.462965,610,1,, +FM,Erewash Sound Ilkeston,Erewash Sound,96800000,52.970098,-1.309798,93,0.025,, +FM,Erewash Sound Long Eaton Risley,Erewash Sound,103500000,52.931208,-1.331542,131,0.012,, +FM,Express FM Portsmouth Portsmouth - Ladywood House,Express FM,93700000,50.795443,-1.086912,4,0.025,, +FM,Fantasy Radio Devizes,Fantasy Radio,97000000,51.352297,-1.996361,129,0.025,, +FM,Felixstowe Radio Felixstowe Felixstowe - Academy,Felixstowe Radio,107500000,51.973009,1.332237,23,0.025,, +FM,Fever FM Leeds (Harehills&Chapeltown) Leeds - Potternewton Heights,Fever FM,107300000,53.825224,-1.541327,104,0.025,, +FM,Fiesta FM Southampton Midanbury - The Castle,Fiesta FM,95000000,50.92624,-1.364941,62,0.025,, +FM,First FM Oxford Oxford - Windrush Tower,First FM,105100000,51.721028,-1.202737,62,0.1467,, +FM,Flex FM London Wandsworth Wandsworth,Flex FM,101400000,51.447973,-0.215843,42,0.1,, +FM,Forest FM Verwood Cranevalley Golf Club,Forest FM,92300000,50.880448,-1.906134,58,0.025,, +FM,Forest FM Verwood Ferndown,Forest FM,98900000,50.80545,-1.904297,27,0.025,, +FM,Forth 1 Edinburgh Black Hill,Forth 1,97600000,55.860005,-3.873572,275,0.1,, +FM,Forth 1 Edinburgh CRAIGKELLY,Forth 1,97300000,56.071791,-3.233186,181,4.9,, +FM,Forth 1 Penicuik PENICUIK,Forth 1,102200000,55.819142,-3.194377,248,0.25,, +FM,Fosse 107 Hinckley,Fosse 107,107900000,52.546486,-1.371022,131,0.1,, +FM,Fosse 107 Loughborough Loughborough - University,Fosse 107,107000000,52.766045,-1.223955,48,0.08,, +FM,Free Radio Kidderminster KIDDERMINSTER,Free Radio,96700000,52.363252,-2.282794,82,0.05,, +FM,Free Radio Leamington Spa LEAMINGTON SPA,Free Radio,102900000,52.294288,-1.519026,90,0.025,, +FM,Free Radio Worcester MALVERN,Free Radio,102800000,52.115715,-2.330146,161,0.5,, +FM,Free Radio Hereford RIDGE HILL,Free Radio,97600000,51.997433,-2.53989,204,0.4,, +FM,Free Radio Coventry Shilton,Free Radio,97000000,52.450069,-1.397116,106,1,, +FM,Free Radio Birmingham SUTTON COLDFIELD,Free Radio,96400000,52.600539,-1.833856,169,5,, +FM,Free Radio Shrewsbury and Telford The Wrekin,Free Radio,103100000,52.670935,-2.550228,396,1.35,, +FM,Free Radio Wolverhampton Turners Hill B,Free Radio,97200000,52.496363,-2.049153,270,1,, +FM,Fresh FM Barnstaple Barnstaple - North Devon college,Fresh FM,87700000,51.072691,-4.068213,49,5e-05,, +FM,Frome FM Frome Frome - Memorial Theatre,Frome FM,96600000,51.22956,-2.324191,99,0.025,, +FM,Funky SX Southend Southend University Hospital,Funky SX,103700000,51.553907,0.689473,26,0.025,, +FM,fUSe FM Ballymoney Ballymoney - Baptist Church,fUSe FM,107500000,55.065952,-6.485513,65,0.025,, +FM,Future Radio Norwich Norwich - Markham Tower,Future Radio,107800000,52.65073,1.270152,25,0.05,, +FM,Gateway 97.8 Basildon Basildon - University Hospital,Gateway 97.8,97800000,51.558561,0.452552,50,0.075,, +FM,Gaydio Manchester Manchester One,Gaydio,88400000,53.478111,-2.238327,40,0.025,, +FM,Gaydio (Brighton) Brighton and Hove Brighton Race Course,Gaydio (Brighton),97800000,50.829169,-0.112873,124,0.025,, +FM,GBC Radio Gibraltar North Mole,GBC Radio Gibraltar,91300000,36.148333,-5.365833,10,0.2,, +FM,GBC Radio Gibraltar O'Haras Battery,GBC Radio Gibraltar,92600000,36.124006,-5.343083,415,1,, +FM,GEM 106 East Midlands Copt Oak,GEM 106,106000000,52.710153,-1.285042,240,4,, +FM,Glastonbury FM Glastonbury,Glastonbury FM,107100000,51.150542,-2.706801,82,0.025,, +FM,Gloucester FM Gloucester Gloucester - Clapham Court,Gloucester FM,96600000,51.869138,-2.240322,14,0.025,, +FM,Great Driffield Radio Driffield Driffield - Wold Farm,Great Driffield Radio,107200000,54.042204,-0.453755,96,0.0958,, +FM,Greatest Hits Stoke-on-Trent Alsagers Bank,Greatest Hits,102600000,53.027231,-2.28071,220,2,, +FM,Greatest Hits Stafford Pye Green,Greatest Hits,96900000,52.728576,-2.0198,234,0.1,, +FM,Greatest Hits Congleton Sutton Common,Greatest Hits,96400000,53.206041,-2.10072,401,0.125,, +FM,Greatest Hits Radio York Acklam Wold,Greatest Hits Radio,104700000,54.046924,-0.786852,224,2,, +FM,Greatest Hits Radio Liverpool Allerton Park,Greatest Hits Radio,105900000,53.373318,-2.884808,69,4,, +FM,Greatest Hits Radio Andover,Greatest Hits Radio,106400000,51.198771,-1.468544,121,0.1,, +FM,Greatest Hits Radio Barnsley Ardsley,Greatest Hits Radio,102000000,53.550702,-1.412685,94,0.2,, +FM,Greatest Hits Radio Ashbourne Ashbourne - Windmill Lane,Greatest Hits Radio,96700000,53.022497,-1.732059,167,0.2,, +FM,Greatest Hits Radio North Norfolk Aylmerton,Greatest Hits Radio,103200000,52.920542,1.253413,94,0.25,, +FM,Greatest Hits Radio Basingstoke Basingstoke - Fanum House,Greatest Hits Radio,107600000,51.269037,-1.070967,87,0.1,, +FM,Greatest Hits Radio Bath,Greatest Hits Radio,107900000,51.38779,-2.332925,175,0.1,, +FM,Greatest Hits Radio Torbay Beacon Hill,Greatest Hits Radio,105500000,50.446404,-3.610896,188,0.802201,, +FM,Greatest Hits Radio Wigan Billinge Hill,Greatest Hits Radio,102400000,53.509257,-2.71981,170,0.05,, +FM,Greatest Hits Radio Dorchester and Weymouth Bincombe Hill,Greatest Hits Radio,97200000,50.66283,-2.443645,160,0.7,, +FM,Greatest Hits Radio Blackpool Blackpool Tower,Greatest Hits Radio,96500000,53.815794,-3.055258,11,0.2,, +FM,Greatest Hits Radio Blandford Blandford - Tin Pot Lane,Greatest Hits Radio,96600000,50.868862,-2.16252,79,0.1,, +FM,Greatest Hits Radio Swindon Blunsdon,Greatest Hits Radio,107700000,51.609363,-1.794027,148,0.1,, +FM,Greatest Hits Radio Southwold Blythburgh Water Tower,Greatest Hits Radio,97400000,52.311386,1.598136,22,0.2,, +FM,Greatest Hits Radio Bridgwater Bridgwater - Westfield House,Greatest Hits Radio,107400000,51.125924,-3.010084,12,0.1,, +FM,Greatest Hits Radio Dorchester and Weymouth Bridport,Greatest Hits Radio,96000000,50.720805,-2.775678,64,0.1,, +FM,Greatest Hits Radio Alton Brockham Hill,Greatest Hits Radio,102000000,51.180141,-0.968029,213,0.05,, +FM,Greatest Hits Radio Bridlington Buckton Barn,Greatest Hits Radio,102400000,54.124979,-0.218986,105,0.1,, +FM,Greatest Hits Radio North Norfolk Bunkers Hill,Greatest Hits Radio,103200000,52.913141,0.829776,71,0.25,, +FM,Greatest Hits Radio Rutland Burley WT,Greatest Hits Radio,107200000,52.691584,-0.681529,146,0.063546,, +FM,Greatest Hits Radio Buxton,Greatest Hits Radio,106400000,53.275085,-1.911935,432,0.25,, +FM,Greatest Hits Radio Salisbury Camp Hill,Greatest Hits Radio,102000000,51.102938,-1.8427,139,1,, +FM,Greatest Hits Radio Buxton Chapel-en-le-Frith - Quentin Rd,Greatest Hits Radio,106600000,53.32452,-1.90808,221,0.04,, +FM,Greatest Hits Radio Yeovil Charlock Hill,Greatest Hits Radio,105600000,50.959935,-2.551266,143,0.25,, +FM,Greatest Hits Radio Cheltenham,Greatest Hits Radio,107500000,51.894084,-2.076391,65,0.1,, +FM,Greatest Hits Radio Chesterfield,Greatest Hits Radio,107400000,53.283991,-1.427446,179,0.1,, +FM,Greatest Hits Radio Tendring CLACTON,Greatest Hits Radio,100200000,51.803409,1.165049,7,1,, +FM,Greatest Hits Radio London Crystal Palace,Greatest Hits Radio,105800000,51.424161,-0.074944,110,1.732,, +FM,Greatest Hits Radio Dartford Tunnel,Greatest Hits Radio,105800000,51.469253,0.260425,3,0,, +FM,Greatest Hits Radio Doncaster Doncaster - Silverwood House,Greatest Hits Radio,107100000,53.515238,-1.137497,16,0.25,, +FM,Greatest Hits Radio North Norfolk Fakenham WT,Greatest Hits Radio,96200000,52.835379,0.858868,51,0.01,, +FM,Greatest Hits Radio Plymouth Fort Staddon,Greatest Hits Radio,106700000,50.346611,-4.113802,121,0.5,, +FM,Greatest Hits Radio Four Marks Four Marks WT,Greatest Hits Radio,101600000,51.119609,-1.040247,220,0.05,, +FM,Greatest Hits Radio Buxton GLOSSOP,Greatest Hits Radio,106400000,53.455242,-1.960506,262,0.25,, +FM,Greatest Hits Radio Kings Lynn Great Massingham,Greatest Hits Radio,96700000,52.773873,0.649768,92,2,, +FM,Greatest Hits Radio Great Yarmouth Great Yarmouth - Havenbridge House,Greatest Hits Radio,97400000,52.607707,1.721838,1,0.05,, +FM,Greatest Hits Radio Grimsby Grimsby- ATE,Greatest Hits Radio,96400000,53.567838,-0.079989,4,0.1,, +FM,Greatest Hits Radio Guildford GUILDFORD,Greatest Hits Radio,96400000,51.228358,-0.605467,142,1.5,, +FM,Greatest Hits Radio Littlehampton Hammerpot,Greatest Hits Radio,102300000,50.839815,-0.47846,40,0.25,, +FM,Greatest Hits Radio Harrogate Harlow Hill,Greatest Hits Radio,97200000,53.983038,-1.561859,176,0.5,, +FM,Greatest Hits Radio Haslemere,Greatest Hits Radio,97100000,51.091179,-0.736114,172,0.25,, +FM,Greatest Hits Radio Telford Heath Hill,Greatest Hits Radio,107400000,52.666946,-2.474912,198,0.1,, +FM,Greatest Hits Radio Warrington High Warren Reservoir,Greatest Hits Radio,107200000,53.354058,-2.581526,105,0.1,, +FM,Greatest Hits Radio Hindhead,Greatest Hits Radio,101600000,51.114323,-0.730911,256,0.065,, +FM,Greatest Hits Radio Buxton Hope Valley,Greatest Hits Radio,103300000,53.351313,-1.733309,196,0.035,, +FM,Greatest Hits Radio Barnsley Hoylandswaine,Greatest Hits Radio,97100000,53.536407,-1.609935,275,0.05,, +FM,Greatest Hits Radio Hungerford,Greatest Hits Radio,107400000,51.405422,-1.514458,128,0.015,, +FM,Greatest Hits Radio Kidderminster KIDDERMINSTER,Greatest Hits Radio,107200000,52.363252,-2.282794,82,0.1,, +FM,Greatest Hits Radio Midhurst MIDHURST,Greatest Hits Radio,106600000,51.017054,-0.70092,185,0.2,, +FM,Greatest Hits Radio West Somerset Minehead North,Greatest Hits Radio,102400000,51.215281,-3.484815,169,2,, +FM,Greatest Hits Radio Newbury Newbury - Water Tower,Greatest Hits Radio,105600000,51.380344,-1.349196,126,0.1,, +FM,Greatest Hits Radio Northallerton,Greatest Hits Radio,103500000,54.342393,-1.440224,36,0.2,, +FM,Greatest Hits Radio Oldham Oldham Civic Centre,Greatest Hits Radio,96200000,53.542378,-2.11676,203,0.1,, +FM,Greatest Hits Radio Scarborough OLIVERS MOUNT,Greatest Hits Radio,96200000,54.267351,-0.404494,151,0.5,, +FM,Greatest Hits Radio Great Yarmouth and Lowestoft Oulton,Greatest Hits Radio,103400000,52.486385,1.715554,8,1,, +FM,Greatest Hits Radio Pateley Bridge,Greatest Hits Radio,107100000,54.080259,-1.784452,292,0.05,, +FM,Greatest Hits Radio Petersfield,Greatest Hits Radio,101800000,51.004418,-0.936586,61,0.1,, +FM,Greatest Hits Radio West Somerset Porlock,Greatest Hits Radio,100800000,51.20432,-3.599983,160,0.1,, +FM,Greatest Hits Radio Skipton Procter Heights,Greatest Hits Radio,107800000,53.911534,-2.098304,361,0.5,, +FM,Greatest Hits Radio Bristol Pur Down,Greatest Hits Radio,107200000,51.48519,-2.562764,91,0.5,, +FM,Greatest Hits Radio Aylesbury Quainton Hill,Greatest Hits Radio,96200000,51.885386,-0.910988,186,0.5,, +FM,Greatest Hits Radio Reading Reading - Tilehurst Water Tower,Greatest Hits Radio,107000000,51.451561,-1.04712,105,0.1,, +FM,Greatest Hits Radio Oswestry Rhosfach Farm,Greatest Hits Radio,107100000,52.878444,-3.091941,305,0.05,, +FM,Greatest Hits Radio Rotherham,Greatest Hits Radio,96100000,53.416904,-1.351035,115,0.2,, +FM,Greatest Hits Radio Shaftesbury,Greatest Hits Radio,97400000,51.007936,-2.186951,218,0.1,, +FM,Greatest Hits Radio Shrewsbury Shelton,Greatest Hits Radio,106500000,52.716753,-2.793442,91,0.25,, +FM,Greatest Hits Radio Skipton Town Skipton Town - Otley Road,Greatest Hits Radio,107100000,53.961815,-2.010633,118,0.015,, +FM,Greatest Hits Radio Stamford Stamford - New College,Greatest Hits Radio,97400000,52.65786,-0.471118,41,0.025,, +FM,Greatest Hits Radio Matlock Stanton Moor,Greatest Hits Radio,102000000,53.170195,-1.633756,305,0.05,, +FM,Greatest Hits Radio Stockport Stockport - Ratcliffe Towers,Greatest Hits Radio,104900000,53.404991,-2.15549,72,0.32,, +FM,Greatest Hits Radio North Norfolk Stody,Greatest Hits Radio,96200000,52.857485,1.078719,65,1.9,, +FM,Greatest Hits Radio Norwich Stoke Holy Cross,Greatest Hits Radio,99900000,52.574817,1.331664,65,0.25,, +FM,Greatest Hits Radio West Midlands SUTTON COLDFIELD,Greatest Hits Radio,105200000,52.600539,-1.833856,169,5.5,, +FM,Greatest Hits Radio Chichester The Trundle,Greatest Hits Radio,96600000,50.89247,-0.755575,194,0.47,, +FM,Greatest Hits Radio Thirsk Thirsk - Calverts Carpets,Greatest Hits Radio,102300000,54.231543,-1.34385,36,0.1,, +FM,Greatest Hits Radio Leeds Tingley,Greatest Hits Radio,96300000,53.735659,-1.57823,136,2,, +FM,Greatest Hits Radio Bolton Tottington,Greatest Hits Radio,107400000,53.605175,-2.358734,226,0.1001,, +FM,Greatest Hits Radio Uttoxeter,Greatest Hits Radio,101800000,52.923623,-1.834558,152,0.05,, +FM,Greatest Hits Radio Wakefield Wakefield House Flats,Greatest Hits Radio,106800000,53.685368,-1.496211,44,0.5,, +FM,Greatest Hits Radio Warminster,Greatest Hits Radio,107500000,51.215032,-2.18149,204,0.1,, +FM,Greatest Hits Radio Buxton Whalley Bridge - Hawkhurst Farm,Greatest Hits Radio,103300000,53.329589,-1.998009,262,0.2,, +FM,Greatest Hits Radio Whitby WHITBY BUSINESS PARK,Greatest Hits Radio,103100000,54.473215,-0.595572,60,0.06,, +FM,Greatest Hits Radio Ilkley Windsover Farm Middleton,Greatest Hits Radio,107100000,53.946319,-1.82445,231,0.05,, +FM,Greatest Hits Radio Chard Windwhistle,Greatest Hits Radio,106600000,50.882767,-2.876735,216,0.25,, +FM,Greatest Hits Radio Wirksworth,Greatest Hits Radio,101800000,53.072948,-1.558311,254,0.045,, +FM,Greatest Hits Radio Wolverhampton Wolverhampton - Mander House,Greatest Hits Radio,107700000,52.585123,-2.128215,154,0.0849,, +FM,Greatest Hits Radio Worksop Worksop Golf Course,Greatest Hits Radio,107900000,53.291829,-1.108097,62,0.1,, +FM,Greatest Hits Radio Weston-Super-Mare Worlebury Hill,Greatest Hits Radio,107700000,51.359245,-2.970542,105,0.1,, +FM,Groove City Radio GLASGOW Glasgow - Middlesex Street,Groove City Radio,88600000,55.850935,-4.282758,9,0.027,, +FM,GTFM Aberdare Aberdare - Leisure Centre,GTFM,107100000,51.7131,-3.440416,121,0.025,, +FM,GTFM Mountain Ash Mountain Ash GC,GTFM,100700000,51.692996,-3.39261,205,0.023,, +FM,GTFM Pontypridd Pontypridd - Bryn Tail,GTFM,107900000,51.601239,-3.310241,285,0.05,, +FM,Gulshan Radio Wolverhampton Wolverhampton - Blakenhall,Gulshan Radio,106900000,52.571453,-2.133487,168,0.0412,, +FM,Hailsham FM hailsham Hailsham,Hailsham FM,95900000,50.86223,0.258648,26,0.025,, +FM,Hallam FM Barnsley Ardsley,Hallam FM,102900000,53.550702,-1.412685,94,0.2,, +FM,Hallam FM Doncaster Clifton,Hallam FM,103400000,53.457744,-1.220893,138,1,, +FM,Hallam FM Sheffield,Hallam FM,97400000,53.379385,-1.513809,247,0.2,, +FM,Halton Community Radio Halton,Halton Community Radio,92300000,53.331059,-2.696684,79,0.025,, +FM,Harborough FM (Hfm) Market Harborough Little Oxendon Farm,Harborough FM (Hfm),102300000,52.44938,-0.930682,156,0.025,, +FM,Harbour Radio Great Yarmouth Great Yarmouth - King Street,Harbour Radio,107400000,52.604326,1.729234,1,0.032,, +FM,Harrogate Hospital Radio Harrogate Hospital Harrogate District Hospital,Harrogate Hospital Radio,95300000,53.993114,-1.517643,109,0.001,, +FM,Hayes FM London Hayes St Anselms Church,Hayes FM,91800000,51.504667,-0.41939,32,0.025,, +FM,HCR FM Huntingdon,HCR FM,104000000,52.337998,-0.169522,21,0.025,, +FM,Heart Abergavenny,Heart,105200000,51.807795,-3.097781,433,0.022,, +FM,Heart Caernarfon Arfon,Heart,107200000,53.01985,-4.273475,300,2.5,, +FM,Heart Chelmsford Bakers Wood,Heart,102600000,51.705132,0.401129,90,0.9893,, +FM,Heart Bargoed,Heart,107300000,51.701289,-3.238171,292,0.1,, +FM,Heart Bath,Heart,103000000,51.38779,-2.332925,175,0.04,, +FM,Heart Torbay Beacon Hill,Heart,96400000,50.446404,-3.610896,188,0.8,, +FM,Heart Southend Benfleet,Heart,96300000,51.550856,0.5811,80,0.5644,, +FM,Heart Central Scotland Black Hill,Heart,100300000,55.860005,-3.873572,275,10,, +FM,Heart Cardigan Bay Blaenplwyf,Heart,107700000,52.360613,-4.102585,174,10,, +FM,Heart Maidstone and Medway Bluebell Hill (FM),Heart,103100000,51.324198,0.52012,192,2,, +FM,Heart Swindon Blunsdon,Heart,97200000,51.609363,-1.794027,148,0.35,, +FM,Heart Milton Keynes Bow Brickhill,Heart,103300000,51.998806,-0.669784,169,1,, +FM,Heart North East England Burnhope,Heart,101800000,54.8219,-1.714848,240,4.25,, +FM,Heart East Cornwall Caradon Hill,Heart,105100000,50.511364,-4.43683,369,2,, +FM,Heart Carmarthen Carmarthen A,Heart,106000000,51.86652,-4.307942,122,0.01,, +FM,Heart Carmarthenshire Carmel,Heart,105200000,51.818501,-4.066216,255,1.5105,, +FM,Heart Yeovil Chedington,Heart,97100000,50.842173,-2.710226,250,0.2,, +FM,Heart Newport Christchurch,Heart,105900000,51.601588,-2.935417,94,0.5,, +FM,Heart Gloucester and Cheltenham Churchdown Hill,Heart,102400000,51.868264,-2.175397,147,1,, +FM,Heart Central Scotland CRAIGKELLY,Heart,101100000,56.071791,-3.233186,181,4.8,, +FM,Heart London Croydon,Heart,106200000,51.40986,-0.085755,114,2,, +FM,Heart Dartford Tunnel,Heart,106200000,51.469253,0.260425,3,0,, +FM,Heart Dartmouth Dartmouth - Academy,Heart,100800000,50.346257,-3.594714,146,0.1,, +FM,Heart East Kent DOVER,Heart,97000000,51.11163,1.247272,133,0.25,, +FM,Heart Bristol Dundry,Heart,96300000,51.399606,-2.646667,222,0.944061,, +FM,Heart East Kent (Canterbury) Dunkirk,Heart,102800000,51.292731,0.979008,122,0.5,, +FM,Heart Ebbw Vale EBBW VALE,Heart,106100000,51.771714,-3.218938,442,0.012,, +FM,Heart South Wales Eglwysilan,Heart,102300000,51.611393,-3.302735,381,0.25,, +FM,Heart South West Yorkshire Emley Moor,Heart,106200000,53.611985,-1.66456,256,2.5,, +FM,Heart North East England Eston Nab,Heart,100700000,54.556455,-1.120934,237,0.3,, +FM,Heart Exeter Exeter (St Thomas),Heart,97000000,50.719122,-3.562148,102,0.5,, +FM,Heart Banbury Farthinghoe,Heart,97400000,52.044582,-1.224699,157,0.15,, +FM,Heart Fenham,Heart,96200000,54.978039,-1.662966,120,0.05,, +FM,Heart South Wales Fishguard,Heart,106200000,52.012591,-4.996935,123,0.5,, +FM,Heart Ipswich Foxhall Heath,Heart,97100000,52.055203,1.226159,31,2,, +FM,Heart Bury St Edmunds Great Barton,Heart,96400000,52.283402,0.764679,61,1,, +FM,Heart Colwyn Bay Great Ormes Head,Heart,105700000,53.332716,-3.853487,200,1,, +FM,Heart Peterborough Gunthorpe,Heart,102700000,52.617188,-0.247858,3,2,, +FM,Heart Rhyl Gwaenysgor,Heart,107300000,53.32441,-3.386164,226,0.035,, +FM,Heart Basingstoke and Andover HANNINGTON,Heart,102900000,51.307873,-1.244777,220,1.7,, +FM,Heart Harlow Harlow - Rye Hill,Heart,101700000,51.739903,0.097485,110,0.05,, +FM,Heart Hastings,Heart,102000000,50.861622,0.566431,76,0.1,, +FM,Heart Haverhill Haverhill Water Tower,Heart,97400000,52.078154,0.422852,106,0.01,, +FM,Heart Eastbourne Heathfield,Heart,102400000,50.976724,0.230437,158,4.1,, +FM,Heart St Albans Hemel Hempstead (Pimlico),Heart,96600000,51.728571,-0.426217,142,0.5,, +FM,Heart Sunderland Hendon,Heart,101200000,54.893895,-1.363068,10,0.05,, +FM,Heart Henley HENLEY,Heart,103400000,51.533409,-0.877019,109,0.05,, +FM,Heart Aberdare Heolgerrig,Heart,105900000,51.740421,-3.419414,451,0.025,, +FM,Heart Reigate and Crawley Horsham,Heart,97500000,51.064034,-0.322554,52,0.015,, +FM,Heart Barnstaple Huntshaw Cross,Heart,96200000,50.979244,-4.098818,200,2,, +FM,Heart Bradford Idle,Heart,107600000,53.832945,-1.752142,215,0.1,, +FM,Heart Ilfracombe,Heart,97300000,51.197967,-4.138233,203,0.05,, +FM,Heart Ivybridge,Heart,101900000,50.368664,-3.926486,142,0.25,, +FM,Heart Swansea Kilvey Hill,Heart,106000000,51.62891,-3.919745,193,0.5,, +FM,Heart Kingsbridge,Heart,101200000,50.274442,-3.794967,93,1,, +FM,Heart Powys LLANDINAM,Heart,106000000,52.479547,-3.399945,454,0.022,, +FM,Heart Welshpool LONG MOUNTAIN,Heart,102800000,52.644306,-3.086542,400,0.1,, +FM,Heart Cambridge Madingley,Heart,103000000,52.215394,0.036667,62,0.4,, +FM,Heart Marlborough MARLBOROUGH,Heart,96500000,51.417912,-1.699977,192,0.03,, +FM,Heart Somerset MENDIP,Heart,102600000,51.236969,-2.625476,303,2,, +FM,Heart North West England Mersey Tunnel,Heart,105400000,53.404457,-2.994207,3,0.001,, +FM,Heart Vale of Leven Millburn Muir,Heart,100000000,55.982322,-4.600708,152,0.05,, +FM,Heart N. Wales MOEL Y PARC,Heart,106900000,53.220944,-3.31452,336,0.445,, +FM,Heart West Wiltshire Naish Hill,Heart,102200000,51.416202,-2.076595,175,0.24,, +FM,Heart Brighton NEWHAVEN,Heart,96900000,50.787726,0.035848,81,0.05,, +FM,Heart Newmarket Newmarket - Icewell Hill,Heart,97400000,52.24549,0.401489,31,0.004,, +FM,Heart Hexham NEWTON,Heart,101200000,54.982447,-1.945593,165,0.1,, +FM,Heart Bournemouth Nine Barrow Down,Heart,102300000,50.629952,-1.987364,196,1.6,, +FM,Heart Northampton,Heart,96600000,52.275355,-0.885481,127,2,, +FM,Heart Oxford,Heart,102600000,51.790638,-1.179183,130,4.39757,, +FM,Heart Penicuik PENICUIK,Heart,103300000,55.819142,-3.194377,248,0.25,, +FM,Heart Plymouth Plympton,Heart,97000000,50.381346,-4.067802,113,1,, +FM,Heart South Wales Presely,Heart,105700000,51.944404,-4.661027,323,7.5,, +FM,Heart Reading Reading - Fountain House,Heart,97000000,51.454569,-0.977254,43,0.4,, +FM,Heart West Cornwall Redruth,Heart,107000000,50.209786,-5.238489,237,8.54,, +FM,Heart Reigate and Crawley REIGATE,Heart,102700000,51.254494,-0.200986,234,1.8,, +FM,Heart Rosneath,Heart,101100000,55.991937,-4.793795,107,0.1,, +FM,Heart Bedford SANDY HEATH,Heart,96900000,52.130132,-0.241462,54,0.450001,, +FM,Heart Sheffield,Heart,107700000,53.379385,-1.513809,247,0.1,, +FM,Heart Southend Town SOUTHEND TE,Heart,97500000,51.540835,0.698653,33,0.05,, +FM,Heart Cardiff St Hilary,Heart,105400000,51.457374,-3.402986,126,2.4883,, +FM,Heart East Devon Stockland Hill,Heart,103000000,50.807088,-3.104951,227,0.5,, +FM,Heart Great Yarmouth and Norwich Stoke Holy Cross,Heart,102400000,52.574817,1.331664,65,1.65,, +FM,Heart Gloucester and Cheltenham STROUD,Heart,103000000,51.768084,-2.238625,223,0.05,, +FM,Heart West Midlands SUTTON COLDFIELD,Heart,100700000,52.600539,-1.833856,169,5.5,, +FM,Heart Taunton Taunton MF,Heart,96500000,51.02226,-3.088245,21,0.05,, +FM,Heart Tavistock,Heart,96600000,50.524794,-4.137982,167,0.02,, +FM,Heart East Kent Thanet,Heart,95900000,51.36004,1.397292,49,0.135,, +FM,Heart Totnes Totnes - Harpers Hill,Heart,100500000,50.425305,-3.696905,150,0.25,, +FM,Heart Brighton WHITEHAWK HILL,Heart,103500000,50.824954,-0.113611,120,0.450001,, +FM,Heart North West England WINTER HILL,Heart,105400000,53.625547,-2.514794,439,2.5,, +FM,Heart Colchester Wivenhoe Park FM,Heart,96100000,51.877841,0.945039,26,0.25,, +FM,Heart Weston-Super-Mare Worlebury Hill,Heart,103000000,51.359245,-2.970542,105,0.05,, +FM,Heart Wrexham Wrexham Rhos,Heart,88000000,53.076278,-3.044994,210,0.7,, +FM,Heart East Kent (Ashford) WYE,Heart,96100000,51.187004,0.955865,98,0.1,, +FM,Heart Luton Zouches Farm,Heart,97600000,51.877958,-0.483622,207,0.5,, +FM,Heart (Morecambe Bay) Kendal,Heart (Morecambe Bay),103200000,54.314559,-2.708127,172,0.0497,, +FM,Heart (Morecambe Bay) Morecambe Bay,Heart (Morecambe Bay),96900000,54.202505,-3.167346,259,1.6,, +FM,Heart (Morecambe Bay) Windermere WINDERMERE,Heart (Morecambe Bay),102300000,54.37436,-2.951306,216,0.032,, +FM,Heart Hertfordshire Hertford Cole Green,Heart Hertfordshire,106900000,51.787539,-0.135924,71,0.25,, +FM,Heart Hertfordshire Hitchin and Letchworth Letchworth - Briar Patch Lane,Heart Hertfordshire,106900000,51.967745,-0.241566,97,0.05,, +FM,Heart Hertfordshire Stevenage Old Knebworth,Heart Hertfordshire,106700000,51.872155,-0.211306,121,0.1,, +FM,Heartland FM Pitlochry and Aberfeldy Fàire Mhòr,Heartland FM,97500000,56.705122,-3.646339,480,0.2,, +FM,Heritage CR Manchester South Manchester - Duffield Court,Heritage CR,90600000,53.463992,-2.241562,36,0.05,, +FM,Hermitage FM Coalville Coalville - Hoo Ash Farm,Hermitage FM,99200000,52.731179,-1.396357,161,0.025,, +FM,Hitmix Radio Newcastle Under Lyme Alsagers Bank (High Lane),Hitmix Radio,107500000,53.029744,-2.282367,212,0.025,, +FM,Hits Radio Bristol East Dundry,Hits Radio,106500000,51.396006,-2.613844,198,0.5,, +FM,Hits Radio Bournemouth Poole - West Howe,Hits Radio,107600000,50.757093,-1.938987,65,0.5,, +FM,Hits Radio Manchester SADDLEWORTH,Hits Radio,103000000,53.541535,-2.020635,347,2,, +FM,Holywood FM Holywood Palace Barracks,Holywood FM,101000000,54.628269,-5.845388,24,0.025,, +FM,Home Radio Cumbernauld Kilsyth - Corrie Farm,Home Radio,100800000,55.987001,-4.101109,257,0.1,, +FM,Hope FM Bournemouth Poole - Poole House,Hope FM,90100000,50.743305,-1.897054,50,0.075,, +FM,Hospital Radio Medway Gillingham Medway Maritime Hospital,Hospital Radio Medway,87900000,51.379876,0.540568,65,0.0005,, +FM,Hospital Radio Plymouth Plymouth Derriford Hospital,Hospital Radio Plymouth,107300000,50.416131,-4.114081,93,0.001,, +FM,Hot Radio 102.8 Poole CANFORD HEATH,Hot Radio 102.8,102800000,50.744958,-1.949066,63,0.05,, +FM,In2beats FM Bedford Bedford - Murdock Road,In2beats FM,106500000,52.153525,-0.475153,74,0.025,, +FM,Insanity Radio Egham,Insanity Radio,103200000,51.426938,-0.563327,51,0.025,, +FM,Inspiration FM Northampton Northampton - Fire Station,Inspiration FM,107800000,52.241724,-0.894379,88,0.01,, +FM,Inspire FM Luton Luton - Farley Hill,Inspire FM,105100000,51.878444,-0.438278,167,0.06,, +FM,Ipswich Community Radio Ipswich Ipswich - Chantry Academy,Ipswich Community Radio,105700000,52.04551,1.128753,45,0.025,, +FM,Irvine Beat FM Irvine Irvine - Cunninghame House,Irvine Beat FM,107200000,55.613121,-4.674028,4,0.025,, +FM,Island FM Alderney Fort Albert,Island FM,93700000,49.725692,-2.183499,52,0.01,, +FM,Island FM Guernsey Les Touillets,Island FM,104700000,49.457792,-2.579202,76,1,, +FM,Islands FM Isles of Scilly Isles of Scilly - Marine and Coastguard Agency,Islands FM,107900000,49.929237,-6.303709,49,0.1,, +FM,Isle of Wight Radio Isle of Wight Chillerton Down,Isle of Wight Radio,107000000,50.649245,-1.328934,166,0.08,, +FM,Isle of Wight Radio Cowes Cowes (GKN),Isle of Wight Radio,102000000,50.759894,-1.289782,1,0.007,, +FM,Isle of Wight Radio Ryde Ryde Pier,Isle of Wight Radio,102000000,50.73925,-1.160281,0,0.02,, +FM,Isle of Wight Radio Ventnor,Isle of Wight Radio,102000000,50.601933,-1.199325,227,0.025,, +FM,Isles FM Isle of Lewis Eitshal - B,Isles FM,103000000,58.180639,-6.586018,220,2,, +FM,IUR FM Newry Newry GC,IUR FM,101400000,54.151598,-6.351943,159,0.025,, +FM,Jack 2 Oxford Boars Hill A,Jack 2,107900000,51.723637,-1.302007,162,0.1,, +FM,Jack FM Bicester,Jack FM,106400000,51.903204,-1.140941,71,0.03,, +FM,Jack FM Oxford Boars Hill A,Jack FM,106800000,51.723637,-1.302007,162,0.25,, +FM,Jack FM Wallingford,Jack FM,106400000,51.607161,-1.110148,45,0.03,, +FM,Jack FM Wantage,Jack FM,106400000,51.587288,-1.427363,95,0.03,, +FM,Jack FM Witney,Jack FM,106400000,51.78673,-1.489501,80,0.023,, +FM,Jorvik Radio York York - Askrigg House,Jorvik Radio,94800000,53.958123,-1.116954,29,0.1,, +FM,Juice FM Belfast Belfast Belfast - Conway Mill,Juice FM Belfast,103800000,54.599372,-5.950909,19,0.025,, +FM,K107 FM Kirkcaldy Kirkcaldy - Glamis Road,K107 FM,107000000,56.124363,-3.195777,111,0.025,, +FM,Kane FM Guildford GUILDFORD,Kane FM,103700000,51.228358,-0.605467,142,0.025,, +FM,KCC Live Knowsley,KCC Live,99800000,53.411748,-2.840923,31,0.025,, +FM,KCR Moray Tor Sliasg,KCR,107700000,57.609887,-2.965824,293,0.47,, +FM,KeeP 106 Dorchester Bincombe Barn,KeeP 106,106300000,50.671048,-2.457873,165,0.0483,, +FM,Kemet Radio Nottingham Nottingham - Pine View,Kemet Radio,97500000,52.95996,-1.172106,54,0.025,, +FM,Kennet Radio Newbury Newbury East,Kennet Radio,106700000,51.409277,-1.298894,91,0.085,, +FM,Kingdom FM Fife Allanhill Farm,Kingdom FM,105400000,56.316831,-2.777568,96,0.1,, +FM,Kingdom FM Fife East Neuk,Kingdom FM,106300000,56.269954,-2.698467,98,0.15,, +FM,Kingdom FM Kirkcaldy Kirkcaldy - Ravens Craig,Kingdom FM,96600000,56.12053,-3.145152,32,0.01,, +FM,Kingdom FM Dunfermline Knock Hill,Kingdom FM,95200000,56.126954,-3.523569,355,0.1,, +FM,Kingdom FM Glenrothes Purin Hill,Kingdom FM,96100000,56.23998,-3.207285,337,0.25,, +FM,Kiss London Croydon,Kiss,100000000,51.40986,-0.085755,114,2,, +FM,Kiss Peterborough Gunthorpe,Kiss,107700000,52.617188,-0.247858,3,0.1,, +FM,Kiss Cambridge Madingley,Kiss,105600000,52.215394,0.036667,62,0.5,, +FM,Kiss Severn Estuary MENDIP,Kiss,101000000,51.236969,-2.625476,303,20,, +FM,Kiss Ipswich Mendlesham,Kiss,106400000,52.234496,1.107319,64,10,, +FM,Kiss Bristol Pur Down,Kiss,97200000,51.48519,-2.562764,91,0.15,, +FM,Kiss Norwich Stoke Holy Cross,Kiss,106100000,52.574817,1.331664,65,2,, +FM,KMFM Ashford Ashford - Charter House,KMFM,107600000,51.150169,0.874855,52,0.25,, +FM,KMFM Thanet Broadstairs,KMFM,107200000,51.355569,1.408741,48,0.1,, +FM,KMFM Maidstone Coxheath,KMFM,105600000,51.230029,0.495203,117,0.075,, +FM,KMFM Folkestone Creteway Down,KMFM,96400000,51.099738,1.182579,166,0.2,, +FM,KMFM Medway Gillingham,KMFM,100400000,51.371461,0.551166,78,0.15,, +FM,KMFM Dover Guston,KMFM,106800000,51.144582,1.316654,126,0.1,, +FM,KMFM Medway Hoo St Werburgh VHF,KMFM,107900000,51.429038,0.550344,61,0.3,, +FM,KMFM Canterbury Rough Common,KMFM,106000000,51.297298,1.04616,74,0.1,, +FM,KMFM Tonbridge TUNBRIDGE WELLS,KMFM,96200000,51.172557,0.297815,124,0.15,, +FM,KMFM Sevenoaks Wrotham,KMFM,101600000,51.320696,0.287702,219,0.2,, +FM,Koast Radio Ashington,Koast Radio,106600000,55.173328,-1.557073,29,0.15,, +FM,Kohinoor FM Leicester Leicester East,Kohinoor FM,97300000,52.633552,-1.099227,64,0.025,, +FM,KTCRfm Keynsham Keynsham - Burnett Business Park,KTCRfm,105800000,51.392682,-2.478266,95,0.025,, +FM,LBC 97.3 London Croydon,LBC 97.3,97300000,51.40986,-0.085755,114,2,, +FM,LCR1 Leicestershire St. Peter's Highfield Church,LCR1,94100000,52.629934,-1.116632,80,0.002,, +FM,Leeds Dance Community Radio Leeds Leeds - Burnsall Grange,Leeds Dance Community Radio,97800000,53.797363,-1.591578,77,0.0489,, +FM,Legacy 90.1 Hulme,Legacy 90.1,90100000,53.462071,-2.257667,33,0.025,, +FM,Lincoln City Radio Lincoln Lincoln Cathedral,Lincoln City Radio,103600000,53.234314,-0.536361,60,0.05,, +FM,Lincs FM Lincoln Belmont,Lincs FM,102200000,53.335814,-0.171983,125,3.2,, +FM,Lincs FM Grantham,Lincs FM,96700000,52.892406,-0.655971,115,0.035,, +FM,Lincs FM Scunthorpe Scunthorpe - Trent View House,Lincs FM,97600000,53.57127,-0.670181,42,0.025,, +FM,Link FM Sheffield Sheffield - School Road,Link FM,96700000,53.38365,-1.501733,186,0.025,, +FM,Lionheart Radio Alnwick Alnwick Moor,Lionheart Radio,107300000,55.407804,-1.722334,133,0.022,, +FM,Lisburn's 98FM Lisburn,Lisburn's 98FM,98800000,54.512999,-6.041404,35,0.025,, +FM,Liverpool Community Radio Liverpool Liverpool - Holt Road,Liverpool Community Radio,106700000,53.409869,-2.947697,57,0.1,, +FM,Lochbroom FM Ullapool Polbain,Lochbroom FM,96800000,58.044513,-5.392429,150,0.5,, +FM,Lochbroom FM Ullapool,Lochbroom FM,102200000,57.892557,-5.135709,143,0.7,, +FM,London Greek Radio Haringey Highgate - Cholmeley Lodge,London Greek Radio,103300000,51.570602,-0.144523,117,0.1,, +FM,Magic 105.4 London Croydon,Magic 105.4,105400000,51.40986,-0.085755,114,2,, +FM,Magic 105.4 Dartford Tunnel,Magic 105.4,105400000,51.469253,0.260425,3,0,, +FM,Mansfield 103.2 Mansfield Fishpond Hill,Mansfield 103.2,103200000,53.140513,-1.232922,168,0.1,, +FM,Manx Radio (FM) Isle of Man DOUGLAS,Manx Radio (FM),97200000,54.140551,-4.493075,143,5.65999,, +FM,Manx Radio (FM) Isle of Man JURBY,Manx Radio (FM),103700000,54.3611,-4.517812,27,1.95,, +FM,Manx Radio (FM) Isle of Man Peel,Manx Radio (FM),89500000,54.217653,-4.706962,96,0.05,, +FM,Manx Radio (FM) Ramsey Ramsey Town,Manx Radio (FM),89500000,54.322598,-4.386431,2,0.05,, +FM,Manx Radio (FM) Isle of Man Snaefell,Manx Radio (FM),89000000,54.262536,-4.462965,610,0.93,, +FM,Maritime Radio Greenwich Woolwich - Shrewsbury House,Maritime Radio,96500000,51.473349,0.072851,120,0.025,, +FM,Marlow FM Marlow Handy Cross Farm,Marlow FM,97500000,51.596236,-0.766902,105,0.025,, +FM,Mearns FM Inverbervie,Mearns FM,106200000,56.836148,-2.283512,41,0.1,, +FM,Mearns FM Laurencekirk,Mearns FM,107300000,56.829397,-2.416189,247,0.1,, +FM,Mearns FM Porthlethen,Mearns FM,105100000,57.059909,-2.127266,85,0.05,, +FM,Mearns FM Stonehaven,Mearns FM,105700000,56.952633,-2.206963,68,0.15,, +FM,Meridian FM East Grinstead East Grinstead VHF,Meridian FM,107000000,51.129409,-0.001901,126,0.025,, +FM,Metro Radio Tyne and Wear Burnhope,Metro Radio,97100000,54.8219,-1.714848,240,4,, +FM,Metro Radio Tyne and Wear Fenham,Metro Radio,103000000,54.978039,-1.662966,120,0.05,, +FM,Metro Radio Hexham NEWTON,Metro Radio,103200000,54.982447,-1.945593,165,0.1,, +FM,Metro Radio Alnwick Shilbottle,Metro Radio,102600000,55.366418,-1.700379,171,0.1,, +FM,Metro Radio Tyne Tunnel,Metro Radio,97100000,54.987484,-1.485827,1,0.015,, +FM,Mighty Radio Southport Southport - Holy Trinity Church,Mighty Radio,107900000,53.650278,-2.996805,6,0.025,, +FM,Mix 92.6 St Albans St Albans - St Peters Church),Mix 92.6,92600000,51.755459,-0.335019,121,0.075,, +FM,MKFM Bletchley Bletchley - MK Stadium,MKFM,102100000,52.009052,-0.734754,77,0.05,, +FM,MKFM Milton Keynes Milton Keynes - Saxon Gate,MKFM,106300000,52.043319,-0.761199,111,0.05,, +FM,MKFM Wolverton Wolverton - Stratford Road,MKFM,95000000,52.06252,-0.818579,79,0.05,, +FM,MônFM Anglesey Amlwch Nebo,MônFM,102500000,53.390547,-4.301313,160,0.2,, +FM,MônFM Anglesey Gwalchmai,MônFM,102100000,53.263035,-4.416069,97,0.1,, +FM,MônFM Anglesey Penmynydd,MônFM,96800000,53.248889,-4.228493,102,0.2,, +FM,Moonbeamers Drive-in Billericay Barleylands Craft Village,Moonbeamers Drive-in,106800000,51.600426,0.445999,25,5e-05,, +FM,Moorlands Radio Biddulph Biddulph Moor - Rails Farm,Moorlands Radio,103700000,53.123677,-2.127723,328,0.0253,, +FM,Moorlands Radio Leek Leek - Stockwell Villas,Moorlands Radio,97300000,53.107922,-2.024009,187,0.025,, +FM,Moray Firth Radio FM Caithness Ben Dorrery,Moray Firth Radio FM,102500000,58.473372,-3.608383,244,0.6004,, +FM,Moray Firth Radio FM Speyside Cairn Gorm,Moray Firth Radio FM,96600000,57.123819,-3.646048,1085,0.175,, +FM,Moray Firth Radio FM Fraserburgh Mormond Hill DAB,Moray Firth Radio FM,96700000,57.602976,-2.029937,225,0.05,, +FM,Moray Firth Radio FM Inverness Mounteagle,Moray Firth Radio FM,97400000,57.591626,-4.27683,212,5,, +FM,Moray Firth Radio FM Wick Newton Wick,Moray Firth Radio FM,96700000,58.431247,-3.118201,46,0.01,, +FM,Moray Firth Radio FM Keith Tor Sliasg,Moray Firth Radio FM,102800000,57.609887,-2.965824,293,0.506499,, +FM,More Radio Eastbourne Butts Brow,More Radio,107500000,50.791712,0.240347,184,0.1,, +FM,More Radio Worthing Findon,More Radio,107700000,50.853924,-0.410233,124,0.125,, +FM,More Radio Hastings,More Radio,107800000,50.861622,0.566431,76,0.1,, +FM,More Radio Haywards Heath,More Radio,106400000,50.99144,-0.092619,91,0.24,, +FM,More Radio Lewes Lewes County Hall,More Radio,106800000,50.871877,0.001136,40,0.05,, +FM,MSR 103.8 Burgess Hill Burgess Hill - Tower House,MSR 103.8,103800000,50.953117,-0.125228,60,0.025,, +FM,Nation Radio Cardigan Bay Blaenplwyf,Nation Radio,103300000,52.360613,-4.102585,174,4.6,, +FM,Nation Radio Swansea Carmel,Nation Radio,102900000,51.818501,-4.066216,255,1.6,, +FM,Nation Radio Solent Chillerton Down,Nation Radio,106000000,50.649245,-1.328934,166,2,, +FM,Nation Radio Winchester Crabwood Farm B,Nation Radio,106600000,51.06398,-1.360918,152,0.01,, +FM,Nation Radio Kingston-Upon-Hull Humber Bridge - North Pier,Nation Radio,99800000,53.714254,-0.450805,0,0.5,, +FM,Nation Radio Swansea Kilvey Hill,Nation Radio,107300000,51.62891,-3.919745,193,1,, +FM,Nation Radio Cardigan Bay Mynydd Pencarreg,Nation Radio,96600000,52.067402,-4.076523,411,0.2,, +FM,Nation Radio Cardigan Bay Penwaun,Nation Radio,97400000,52.065055,-4.69417,182,0.2,, +FM,Nation Radio Presely,Nation Radio,107100000,51.944404,-4.661027,323,2.0079,, +FM,Nation Radio Ipswich Warren Heath,Nation Radio,102000000,52.037726,1.200836,32,2,, +FM,Nation Radio Cardiff Wenvoe,Nation Radio,106800000,51.459476,-3.282282,129,2.5,, +FM,Nation Radio Scotland Glasgow Cathkin (S),Nation Radio Scotland,96300000,55.798001,-4.193822,206,2,, +FM,Nation Radio Scotland Helensburgh Helensburgh - East Princess St,Nation Radio Scotland,106900000,56.002997,-4.729464,8,0.025,, +FM,Nation's Easy Radio Southampton Chilworth,Nation's Easy Radio,107800000,50.960084,-1.423285,85,0.5,, +FM,Nation's Easy Radio Winchester Crabwood Farm B,Nation's Easy Radio,107200000,51.06398,-1.360918,152,0.1,, +FM,Nation's Easy Radio Portsmouth Fort Southwick,Nation's Easy Radio,107400000,50.858847,-1.110965,124,0.1,, +FM,Nation's Easy Radio Swansea Kilvey Hill,Nation's Easy Radio,102100000,51.62891,-3.919745,193,1,, +FM,Nations Radio Poole Poole - West Howe,Nations Radio,106600000,50.757093,-1.938987,65,0.25,, +FM,Nevis Radio Skye/Mallaig Cnoc Malagan,Nevis Radio,102300000,57.103288,-5.874998,185,0.8,, +FM,Nevis Radio Fort William Creag a' Chàil,Nevis Radio,96600000,56.827212,-5.054422,269,0.3,, +FM,Nevis Radio Loch Leven Glenachulish,Nevis Radio,102400000,56.681764,-5.211986,255,0.8,, +FM,Nevis Radio Glencoe,Nevis Radio,97000000,56.623839,-4.836427,680,0.2,, +FM,New Style Radio 98.7 FM Birmingham Birmingham - Cambridge Tower,New Style Radio 98.7 FM,98700000,52.480787,-1.909401,137,0.016,, +FM,Ninesprings FM Yeovil Cricket St Thomas GC,Ninesprings FM,107600000,50.880198,-2.895308,222,0.025,, +FM,Ninesprings FM Yeovil Wincanton - Racecourse,Ninesprings FM,103300000,51.065979,-2.414666,112,0.025,, +FM,Ninesprings FM Yeovil Yeovil - Huish Park,Ninesprings FM,104500000,50.950212,-2.673293,94,0.1,, +FM,NLive Northampton Northampton - Fire Station,NLive,106900000,52.241724,-0.894379,88,0.025,, +FM,Nomad Radio Hammersmith Hammersmith - Kings St,Nomad Radio,92200000,51.492361,-0.231397,6,0.1,, +FM,North Manchester FM Manchester Manchester - Kentmere Court,North Manchester FM,106600000,53.528173,-2.189733,102,0.05,, +FM,Northsound 1 Aberdeen Balgownie,Northsound 1,97600000,57.184868,-2.122071,74,0.025,, +FM,Northsound 1 Aberdeen Durris,Northsound 1,96900000,56.999987,-2.389944,325,5.1,, +FM,Northsound 1 Peterhead Stirling Hill,Northsound 1,103000000,57.460172,-1.794644,81,0.174,, +FM,Nova Radio North East 102.5 FM Newcastle Upon Tyne Newcastle upon Tyne - Westgate Community College,Nova Radio North East 102.5 FM,102500000,54.977313,-1.660472,120,0.025,, +FM,Nu Sound Radio Newham Stratford New Town,Nu Sound Radio,92000000,51.550148,-0.005011,5,0.025,, +FM,Oban FM Oban,Oban FM,103300000,56.40396,-5.485882,122,0.2364,, +FM,Oldham Community Radio Oldham Oldham Civic Centre,Oldham Community Radio,99700000,53.542378,-2.11676,203,0.025,, +FM,Original 106 Aberdeen Balgownie,Original 106,106300000,57.184868,-2.122071,74,0.025,, +FM,Original 106 Aberdeen Durris,Original 106,106800000,56.999987,-2.389944,325,9.00001,, +FM,Original 106 Peterhead Peterhead FC,Original 106,106300000,57.511465,-1.796526,26,0.175,, +FM,Park Radio Diss,Park Radio,107600000,52.379033,1.106883,42,0.2,, +FM,Park Radio Harleston,Park Radio,105200000,52.397642,1.30594,39,0.025,, +FM,Pendle Community Radio Nelson Brierfield,Pendle Community Radio,103100000,53.822137,-2.212023,265,0.025,, +FM,Penistone FM Penistone Hoylandswaine (B),Penistone FM,95700000,53.536589,-1.610386,275,0.025,, +FM,Peterborough Community Radio Peterborough Peterborough - Cumberland House,Peterborough Community Radio,103200000,52.574323,-0.237171,8,0.05,, +FM,Phoenix FM Brentwood Brentwood - Gibraltar House,Phoenix FM,98000000,51.602337,0.298078,113,0.025,, +FM,Phoenix FM Halifax,Phoenix FM,96700000,53.713832,-1.846175,233,0.025,, +FM,Phonic FM Exeter Exeter - Pheonix Arts Centre,Phonic FM,106800000,50.725287,-3.531325,45,0.025,, +FM,Pirate FM East Cornwall Caradon Hill,Pirate FM,102200000,50.511364,-4.43683,369,2,, +FM,Pirate FM West Cornwall Redruth,Pirate FM,102800000,50.209786,-5.238489,237,8.3,, +FM,Platform B Brighton Sussex Heights,Platform B,105500000,50.822557,-0.149203,19,0.025,, +FM,Pride FM NEWCASTLE Newcastle - Shieldfield House,Pride FM,89200000,54.978297,-1.599687,41,0.05,, +FM,Pulse 1 Bradford Idle,Pulse 1,97500000,53.832945,-1.752142,215,0.25,, +FM,Pulse 1 Halifax and Huddersfield Vicars Lot,Pulse 1,102500000,53.651685,-1.892848,340,1,, +FM,Pulse Community Radio Barrhead Barrhead - St Lukes School,Pulse Community Radio,98400000,55.789931,-4.385746,103,0.025,, +FM,Purbeck Coast FM Swanage Nine Barrow Down,Purbeck Coast FM,101200000,50.629952,-1.987364,196,0.05,, +FM,Pure Radio Dundee Dundee Law,Pure Radio,102000000,56.470214,-2.989443,174,0.1,, +FM,Pure Radio Perth Kirkton Mailer,Pure Radio,106600000,56.372293,-3.453361,178,0.2528,, +FM,Q 102.9 Londonderry Foyle Hill,Q 102.9,102900000,54.993579,-7.380227,183,5,, +FM,Q Radio 96.7/102.5FM Bangor,Q Radio 96.7/102.5FM,102500000,54.661435,-5.675928,21,0.04,, +FM,Q Radio 96.7/102.5FM Belfast Black Mountain,Q Radio 96.7/102.5FM,96700000,54.586989,-6.022076,301,0.3,, +FM,Q Radio 96.7/102.5FM Newtownabbey Carnmoney Hill,Q Radio 96.7/102.5FM,102500000,54.676355,-5.928737,207,0.02,, +FM,Q100.5 Armagh Armagh - City Hotel,Q100.5,107600000,54.344707,-6.650706,54,0.15,, +FM,Q100.5 Newry Camlough,Q100.5,100500000,54.160861,-6.385716,340,0.5,, +FM,Q100.5 Kilkeel,Q100.5,101100000,54.095375,-6.041723,267,0.217,, +FM,Q100.5 Newcastle Tullybrannigan Raod,Q100.5,101100000,54.217544,-5.916663,45,0.1,, +FM,Q101.2 Omagh and Enniskillen Brougher Mountain B,Q101.2,101200000,54.424515,-7.457403,293,5,, +FM,Q101.2 Enniskillen Coles Hill,Q101.2,102100000,54.342771,-7.654519,64,0.03,, +FM,Q106/7 Dungannon,Q106/7,107200000,54.505165,-6.768771,84,0.25,, +FM,Q106/7 Maghera Seefin Hill,Q106/7,106300000,54.866046,-6.726181,196,0.025,, +FM,Q106/7 Cookstown Tulnagee Quarry,Q106/7,106000000,54.728374,-6.721965,270,0.5,, +FM,Q107 Larne Gransha,Q107,107600000,54.800061,-5.698616,126,0.15,, +FM,Q107 Ballymena Portglenone,Q107,107000000,54.863112,-6.429581,207,0.5,, +FM,Q97.2 Ballycastle Drumeeny,Q97.2,97600000,55.192111,-6.23419,86,0.025,, +FM,Q97.2 Coleraine Maddybenny More,Q97.2,97200000,55.178615,-6.671493,62,0.25,, +FM,Quality Radio Paisley Paisley - Oliphant Court,Quality Radio,107500000,55.824656,-4.466108,75,0.05,, +FM,Quay FM Alderney Fort Albert,Quay FM,107100000,49.725692,-2.183499,52,0.025,, +FM,Raaj FM Sandwell West Bromwich Sandwell,Raaj FM,91300000,52.515701,-1.989789,162,0.025,, +FM,Radio Ashford Ashford Ashford - William Harvey Hospital,Radio Ashford,107100000,51.142455,0.917557,63,0.02,, +FM,Radio Borders Borders Berwick-upon-Tweed,Radio Borders,102300000,55.785854,-2.032822,129,0.01,, +FM,Radio Borders Borders EYEMOUTH,Radio Borders,103400000,55.83228,-2.085863,197,0.5,, +FM,Radio Borders Borders PEEBLES,Radio Borders,103100000,55.661832,-3.227732,352,0.035,, +FM,Radio Borders Borders SELKIRK,Radio Borders,96800000,55.555786,-2.793221,290,5,, +FM,Radio Bronglais Aberystwyth Bronglais Hospital,Radio Bronglais,87800000,52.416008,-4.071692,20,0.0005,, +FM,Radio Cardiff Cardiff Cardiff - Nelson House,Radio Cardiff,98700000,51.470082,-3.171,4,0.025,, +FM,Radio Carmarthenshire Carmarthen,Radio Carmarthenshire,97500000,51.867126,-4.309135,137,0.005,, +FM,Radio Carmarthenshire Carmarthenshire Carmel,Radio Carmarthenshire,97100000,51.818501,-4.066216,255,1.5105,, +FM,Radio Carmarthenshire Llanelli LLANELLI,Radio Carmarthenshire,97500000,51.699961,-4.157337,111,0.2,, +FM,Radio City Liverpool Allerton Park,Radio City,96700000,53.373318,-2.884808,69,4.1,, +FM,Radio City Mersey Tunnel,Radio City,96700000,53.404457,-2.994207,3,0.001,, +FM,Radio Dawn Nottingham Mapperley,Radio Dawn,107600000,52.979731,-1.133451,125,0.05,, +FM,Radio Essex Chelmsford Church Green,Radio Essex,107700000,51.715584,0.574257,110,0.325,, +FM,Radio Essex Southend SOUTHEND TE,Radio Essex,105100000,51.540835,0.698653,33,0.2378,, +FM,Radio Exe Exeter Exeter (St Thomas),Radio Exe,107300000,50.719122,-3.562148,102,1,, +FM,Radio Faza 97.1 FM Nottingham Mapperley,Radio Faza 97.1 FM,97100000,52.979731,-1.133451,125,0.05,, +FM,Radio Gibraltar Plus Upper Rock,Radio Gibraltar Plus,100500000,36.133162,-5.345733,400,0.2,, +FM,Radio Glangwili Carmarthen Glangwili General Hospital,Radio Glangwili,87700000,51.868925,-4.28613,24,5e-05,, +FM,Radio Hartlepool Hartlepool,Radio Hartlepool,102400000,54.686616,-1.216936,12,0.025,, +FM,Radio Ikhlas Derby Normanton,Radio Ikhlas,107800000,52.906966,-1.502458,95,0.025,, +FM,Radio Jackie Kingston Tolworth Tower,Radio Jackie,107800000,51.379884,-0.281001,29,0.4,, +FM,Radio LaB Luton Luton - Farley Hill,Radio LaB,97100000,51.878444,-0.438278,167,0.025,, +FM,Radio Leyland Leyland Leyland - Farington,Radio Leyland,104800000,53.702614,-2.6866,43,0.05,, +FM,Radio MAC Bradford Bradford - Richmond Building,Radio MAC,107100000,53.791802,-1.76301,127,0.025,, +FM,Radio Mount Vernon London Mount Vernon,Radio Mount Vernon,95100000,51.615389,-0.448479,105,0.0005,, +FM,Radio Newark Newark Newark - St Mary Magdalene Church,Radio Newark,107800000,53.076705,-0.808623,18,0.025,, +FM,Radio Newquay Newquay Newquay - Lane Theatre,Radio Newquay,106100000,50.400677,-5.055861,61,0.1,, +FM,Radio North Angus Arbroath Arbroath Infirmary,Radio North Angus,96600000,56.554563,-2.597638,17,0.2,, +FM,Radio North Angus Carnoustie Carnoustie High School,Radio North Angus,107500000,56.506001,-2.724898,26,0.025,, +FM,Radio North Angus Arbroath Monifieth - High School,Radio North Angus,105900000,56.47904,-2.840142,21,0.025,, +FM,Radio North Angus FM Brechin High School,Radio North Angus FM,87700000,56.736949,-2.672732,80,5e-05,, +FM,Radio North Angus FM Montrose Montrose Academy,Radio North Angus FM,87700000,56.70939,-2.463211,2,5e-05,, +FM,Radio North Angus FM Whitehills Forfar Whitehills Health Centre,Radio North Angus FM,87700000,56.651326,-2.870882,75,5e-05,, +FM,Radio Panj Coventry William Batchelor House,Radio Panj,99600000,52.413553,-1.510526,92,0.01,, +FM,Radio Pembrokeshire Pembrokeshire Fishguard,Radio Pembrokeshire,107500000,52.012591,-4.996935,123,0.09,, +FM,Radio Pembrokeshire Pembrokeshire Haverfordwest,Radio Pembrokeshire,102500000,51.899195,-4.86653,186,9.54993,, +FM,Radio Pembrokeshire Pembrokeshire Tenby VHF,Radio Pembrokeshire,107500000,51.679343,-4.701725,52,0.07,, +FM,Radio Plus Coventry Coventry - Mercia House,Radio Plus,101500000,52.408177,-1.514849,76,0.025,, +FM,Radio Redhill East Surrey East Surrey Hospital,Radio Redhill,100400000,51.218538,-0.161434,66,0.001,, +FM,Radio Reverb Brighton & Hove Brighton Race Course,Radio Reverb,97200000,50.829169,-0.112873,124,0.07,, +FM,Radio Saltire Musselburgh Carberry - Hillhead Farm,Radio Saltire,106700000,55.917198,-3.000107,152,0.025,, +FM,Radio Saltire Tranent,Radio Saltire,107200000,55.94425,-2.954051,86,0.025,, +FM,Radio Sangam Huddersfield Huddersfield - Royal Infirmary,Radio Sangam,107900000,53.655545,-1.815067,187,0.02,, +FM,Radio Scarborough Scarborough Oliver's Mount B,Radio Scarborough,107600000,54.267627,-0.404944,151,0.025,, +FM,Radio Skye Skye & Lochalsh Portree,Radio Skye,106200000,57.41693,-6.193925,51,0.03,, +FM,Radio Skye Skye & Lochalsh Sabhal Mòr Ostaig,Radio Skye,106200000,57.086557,-5.881012,42,0.1,, +FM,Radio Skye Skye & Lochalsh Skriaig,Radio Skye,102700000,57.38642,-6.24289,390,3.65,, +FM,Radio Skye Skye & Lochalsh Staffin - caravan & camping site,Radio Skye,107200000,57.62189,-6.196103,88,0.1,, +FM,Radio St Austell Bay St Austell St Austell RFC,Radio St Austell Bay,105600000,50.32788,-4.777309,90,0.025,, +FM,Radio Tamworth Tamworth Tamworth - Strode House,Radio Tamworth,106800000,52.633266,-1.698832,63,0.025,, +FM,Radio Tircoed Swansea North-West Tircoed,Radio Tircoed,106500000,51.682376,-3.997518,67,0.025,, +FM,Radio Tyneside Newcastle-Upon-Tyne Newcastle - Royal Victoria Infirmary,Radio Tyneside,93600000,54.980525,-1.622165,70,0.05,, +FM,Radio Wimborne Wimborne,Radio Wimborne,94600000,50.784535,-1.981933,42,0.025,, +FM,Radio Winchcombe Winchcombe Winchcombe - Encounter Church,Radio Winchcombe,107100000,51.955961,-1.967212,94,0.025,, +FM,Radio Wyvern Worcester Worcester - Perry Wood School,Radio Wyvern,106700000,52.193696,-2.193793,73,0.1,, +FM,Radio X London Crystal Palace,Radio X,104900000,51.424161,-0.074944,110,1.9,, +FM,Radio X Manchester Manchester - City Tower,Radio X,97700000,53.480177,-2.23864,43,0.5,, +FM,Radio2Funky Leicester Leicester - Granby Street,Radio2Funky,95000000,52.632511,-1.128357,67,0.025,, +FM,Raidió Fáilte Belfast Belfast - Divis Flats,Raidió Fáilte,107100000,54.599944,-5.942214,14,0.29,, +FM,Rainbow Radio SE_London Crystal Palace,Rainbow Radio,92400000,51.424161,-0.074944,110,0.03,, +FM,Red Kite Radio Haddenham and Thame Haddenham,Red Kite Radio,107200000,51.769341,-0.914507,71,0.04,, +FM,Redroad FM Rother Valley Wales Sheffield,Redroad FM,102400000,53.338861,-1.284487,119,0.025,, +FM,Reprezent 107.3 FM Lewisham Honor Oak - Greystead Road,Reprezent 107.3 FM,107300000,51.447582,-0.055538,88,0.08,, +FM,Resonance FM London Guys Hospital Tower,Resonance FM,104400000,51.503766,-0.087153,3,0.025,, +FM,Revival FM Glasgow Glasgow - Dundasvale Court - Block 22,Revival FM,93000000,55.867219,-4.257501,29,0.05,, +FM,Revive FM Newham Forest Gate - Mosque,Revive FM,94000000,51.54622,0.024816,7,0.1,, +FM,Revolution Radio Northampton Northampton - St James,Revolution Radio,96100000,52.238473,-0.921991,62,0.01,, +FM,Rhondda Radio Rhondda Valley Ferndale Shooting Club,Rhondda Radio,97500000,51.663145,-3.43724,392,0.0245,, +FM,Rhondda Radio Rhondda Ystrad - Nant y Gwyddon landfill,Rhondda Radio,106100000,51.637868,-3.474302,312,0.025,, +FM,Ribble FM Ribble Clitheroe,Ribble FM,106700000,53.87373,-2.39008,91,0.05,, +FM,Rinse FM London City East Peregrine House,Rinse FM,106800000,51.529704,-0.100628,22,0.025,, +FM,Riviera FM Torbay Torquay Town,Riviera FM,107900000,50.463334,-3.529328,67,0.17,, +FM,RNA FM Scotland Angus - Webster's High School,RNA FM,107900000,56.670235,-3.006984,131,0.0007,, +FM,RNIB Connect Radio West Glasgow Glasgow west - Anniesland Cort,RNIB Connect Radio,101000000,55.891042,-4.324777,28,0.025,, +FM,Rock FM Preston and Blackpool WINTER HILL,Rock FM,97400000,53.625547,-2.514794,439,1,, +FM,Rossendale Radio Rossendale Rawtenstall - Hardmans Business Centre,Rossendale Radio,104700000,53.696842,-2.297569,157,0.05,, +FM,RWS FM 103.3 Bury St Edmunds Bury St Edmunds - West Suffolk Hospital,RWS FM 103.3,103300000,52.231722,0.709179,57,0.075,, +FM,Sabras Sound FM Leicester Leicester - Corah Works,Sabras Sound FM,91000000,52.643163,-1.134352,52,0.1,, +FM,Sabras Sound FM Loughborough Loughborough - University,Sabras Sound FM,102100000,52.766045,-1.223955,48,0.1,, +FM,Salaam Radio Peterborough Peterborough - Cumberland House,Salaam Radio,106200000,52.574323,-0.237171,8,0.025,, +FM,Salford City Radio Salford Swinton Civic Centre,Salford City Radio,94400000,53.510582,-2.339991,68,0.025,, +FM,Scout Radio Chingford Gilwell Park,Scout Radio,99600000,51.649824,0.00221,75,0.001,, +FM,Seaforde - Drive in Church Downpatrick, NI Seaforde (drive in movie),Seaforde - Drive in Church,107200000,54.306741,-5.848547,57,5e-05,, +FM,Seahaven FM Eastbourne Butts Brow,Seahaven FM,95600000,50.791712,0.240347,184,0.025,, +FM,Seahaven FM Newhaven Newhaven MCA,Seahaven FM,96300000,50.782266,0.049797,50,0.1,, +FM,Seaside FM 105.3 Hornsea and District Hornsea,Seaside FM 105.3,103500000,53.898863,-0.174128,21,0.08,, +FM,Seaside FM 105.3 Withernsea,Seaside FM 105.3,105300000,53.731283,0.033575,6,0.1,, +FM,Sedgemoor FM Bridgwater Bridgwater - Westfield House,Sedgemoor FM,104200000,51.125924,-3.010084,12,0.07,, +FM,Select Radio Dulwich Dulwich - Countisbury House,Select Radio,94400000,51.433323,-0.068804,106,0.05,, +FM,SFM 106.9 Sittingbourne Sittingbourne - Swale House,SFM 106.9,106900000,51.339728,0.741529,10,0.1,, +FM,Sheffield Live 93.2 FM West Sheffield Sheffield,Sheffield Live 93.2 FM,93200000,53.379385,-1.513809,247,0.025,, +FM,Sheppey FM Sheerness,Sheppey FM,92200000,51.44156,0.7636,3,0.025,, +FM,shmu FM Aberdeen Aberdeen - Stewart Park Court,shmu FM,99800000,57.16473,-2.137712,90,0.025,, +FM,SIBC Shetland Bressay,SIBC,96200000,60.130079,-1.096281,224,4,, +FM,SIBC Shetland Lerwick,SIBC,102200000,60.155463,-1.146383,22,0.025,, +FM,Silk FM Macclesfield Sutton Common,Silk FM,106900000,53.206041,-2.10072,401,0.15,, +FM,Sine FM Doncaster Doncaster - Civic Centre,Sine FM,102600000,53.520399,-1.130303,16,0.1,, +FM,Siren FM Lincoln Lincoln University,Siren FM,107300000,53.228811,-0.549432,4,0.025,, +FM,Skylark Buckfastleigh Holne - Higher Mill Leat Farm,Skylark,107600000,50.506305,-3.812489,184,0.1,, +FM,Skylark Princetown,Skylark,105800000,50.549887,-4.001482,464,0.1,, +FM,Skyline Gold 102.5 Hedge End,Skyline Gold 102.5,102500000,50.913384,-1.317748,41,0.025,, +FM,Smooth Radio Glasgow Black Hill,Smooth Radio,105200000,55.860005,-3.873572,275,15,, +FM,Smooth Radio North East England Burnhope,Smooth Radio,97500000,54.8219,-1.714848,240,4.5,, +FM,Smooth Radio London Croydon,Smooth Radio,102200000,51.40986,-0.085755,114,2,, +FM,Smooth Radio Derby Drum Hill,Smooth Radio,101400000,52.975288,-1.442404,156,0.125,, +FM,Smooth Radio North East England Eston Nab,Smooth Radio,107700000,54.556455,-1.120934,237,2.5,, +FM,Smooth Radio North East England Fenham,Smooth Radio,107500000,54.978039,-1.662966,120,0.05,, +FM,Smooth Radio Kettering Geddington,Smooth Radio,107400000,52.445531,-0.666816,118,0.2,, +FM,Smooth Radio Peterborough Gunthorpe,Smooth Radio,106800000,52.617188,-0.247858,3,0.1,, +FM,Smooth Radio Wellingborough Irchester,Smooth Radio,97200000,52.272441,-0.64153,90,0.1,, +FM,Smooth Radio Kendal,Smooth Radio,100100000,54.314559,-2.708127,172,0.1,, +FM,Smooth Radio Kendal Keswick Forest,Smooth Radio,101400000,54.608739,-3.204646,215,0,, +FM,Smooth Radio North East England NEWTON,Smooth Radio,96400000,54.982447,-1.945593,165,0.1,, +FM,Smooth Radio West Midlands SUTTON COLDFIELD,Smooth Radio,105700000,52.600539,-1.833856,169,5.5,, +FM,Smooth Radio East Midlands WALTHAM,Smooth Radio,106600000,52.801451,-0.80088,138,6.2,, +FM,Smooth Radio Windermere WINDERMERE,Smooth Radio,100800000,54.37436,-2.951306,216,0.1,, +FM,Smooth Radio North West England WINTER HILL,Smooth Radio,100400000,53.625547,-2.514794,439,2.5,, +FM,Somer Valley FM Midsomer Norton Clandown,Somer Valley FM,97500000,51.305362,-2.458279,157,0.025,, +FM,Sound Radio Towyn & Rhyl Towyn,Sound Radio,103100000,53.301565,-3.540892,2,0.05,, +FM,Soundart Radio Totnes Dartington Hall,Soundart Radio,102500000,50.452961,-3.693809,62,0.05,, +FM,Spark FM Sunderland Monkswearmouth Sunderland,Spark FM,107000000,54.914812,-1.376309,21,0.025,, +FM,Speysound Radio Aviemore Cairn Gorm,Speysound Radio,107100000,57.123819,-3.646048,1085,0.068,, +FM,Spice FM Newcastle upon Tyne Newcastle upon Tyne - The Beacon,Spice FM,98800000,54.974313,-1.648312,110,0.025,, +FM,Stafford FM Stafford Stafford - Guildhall Shopping Centre,Stafford FM,107300000,52.807267,-2.118633,78,0.0248,, +FM,Star Radio Ely Ely Cathedral,Star Radio,107100000,52.398758,0.262657,20,0.1,, +FM,Star Radio Haverhill,Star Radio,107900000,52.094644,0.443018,105,0.01,, +FM,Star Radio Cambridge Madingley,Star Radio,100700000,52.215394,0.036667,62,0.3379,, +FM,Star Radio Saffron Walden,Star Radio,107300000,52.018807,0.236288,63,0.02,, +FM,Stoke Mandeville Hospital Radio Aylesbury Stoke Mandeville Hospital,Stoke Mandeville Hospital Radio,101800000,51.797803,-0.799261,87,0.0015,, +FM,Storm FM Bangor University of Wales Bangor,Storm FM,87700000,53.226864,-4.130115,15,5e-05,, +FM,Sun FM Darlington Darlington - Harrowgate Hill,Sun FM,103200000,54.555795,-1.560849,72,0.165,, +FM,Sun FM Sunderland Haining,Sun FM,103400000,54.851532,-1.447373,162,0.15,, +FM,Sun FM Bishop Auckland Middlestone,Sun FM,106800000,54.678457,-1.611325,189,0.025,, +FM,Sun FM Richmond Richmond - Mercury Road,Sun FM,102600000,54.411911,-1.748975,212,0.05,, +FM,Sun FM Durham Sacriston,Sun FM,102800000,54.813552,-1.619989,180,0.1648,, +FM,Sunny Govan Radio Glasgow Glasgow - Govan,Sunny Govan Radio,103500000,55.846502,-4.336973,35,0.025,, +FM,Sunrise FM Bradford Idle,Sunrise FM,103200000,53.832945,-1.752142,215,0.25,, +FM,Sunset Drive-in Cinema Portsmouth Pier Road (Car Park),Sunset Drive-in Cinema,92000000,50.786694,-1.098659,1,5e-05,, +FM,Sunshine East Belfast Belfast - Lower Braniel Road,Sunshine,104900000,54.578225,-5.850659,67,0.025,, +FM,Sunshine Radio Monmouthshire Abergavenny,Sunshine Radio,107800000,51.807795,-3.097781,433,0.02,, +FM,Sunshine Radio Ludlow Clee Hill,Sunshine Radio,107800000,52.378266,-2.596676,427,0.125,, +FM,Sunshine Radio Monmouth MONMOUTH,Sunshine Radio,107000000,51.811533,-2.688667,194,0.5,, +FM,Sunshine Radio Hereford RIDGE HILL,Sunshine Radio,106200000,51.997433,-2.53989,204,0.8,, +FM,Sunshine Radio (FM) Ludlow Woofferton,Sunshine Radio (FM),105900000,52.318073,-2.718365,81,0.5,, +FM,Susy Radio Redhill & Reigate Reigate Hill - Fort Lodge,Susy Radio,103400000,51.254634,-0.198401,226,0.05,, +FM,Swindon 105.5 Swindon Swindon - Brunel Tower,Swindon 105.5,105500000,51.561066,-1.786888,100,0.025,, +FM,Switch Radio 107.5 North East Birmingham Castle Vale,Switch Radio 107.5,107500000,52.520827,-1.794217,89,0.025,, +FM,SWUFM Bristol Bristol - Croydon House,SWUFM,103700000,51.459262,-2.569353,20,0.05,, +FM,Takeover Radio Leicester Leicester - Gorse Hill City Farm,Takeover Radio,103200000,52.65099,-1.160066,81,0.025,, +FM,Takeover Radio 106.9 Sutton in Ashfield,Takeover Radio 106.9,106900000,53.1237,-1.260867,160,0.025,, +FM,Tameside Radio Tameside Harrop Edge,Tameside Radio,103600000,53.464054,-2.026622,301,0.05,, +FM,Tay FM Dundee Angus,Tay FM,102800000,56.555053,-2.986125,312,4,, +FM,Tay FM Perth PERTH,Tay FM,96400000,56.375183,-3.444404,123,0.3,, +FM,Tay FM Dundee Tay Bridge,Tay FM,96400000,56.444566,-2.925027,100,0.05,, +FM,TD1 Radio Central Borders Galashiels - Golf Club,TD1 Radio,106500000,55.62095,-2.804223,190,0.02,, +FM,Tempo 107.4 FM Wetherby Collingham,Tempo 107.4 FM,107400000,53.897122,-1.415753,96,0.025,, +FM,TFM Radio Teeside ESTON NAB,TFM Radio,96600000,54.555831,-1.121721,234,0.3,, +FM,The Beat London 103.6FM Harlesden Stonebridge,The Beat London 103.6FM,103600000,51.541357,-0.260646,35,0.023,, +FM,The Cat Crewe & Nantwich Crewe,The Cat,107900000,53.088897,-2.45491,51,0.05,, +FM,The Eye Vale of Belvoir White Lodge Farm,The Eye,103000000,52.807355,-0.929488,167,0.042,, +FM,The Flash Waterlooville Waterlooville - Library,The Flash,104300000,50.879962,-1.029683,51,0.1,, +FM,The Hillz FM Coventry Coventry - Pioneer House,The Hillz FM,98600000,52.41396,-1.500377,87,0.05,, +FM,The Source Falmouth & Penryn Penryn - Tremough,The Source,96100000,50.170903,-5.127727,121,0.025,, +FM,The Voice Barnstaple Barnstaple - North Devon college,The Voice,106100000,51.072691,-4.068213,49,0.05,, +FM,The Voice Bideford Homlacott,The Voice,107800000,51.039847,-4.134223,116,0.05,, +FM,The Voice Ilfracombe Ilfracombe Holiday Park,The Voice,107800000,51.201277,-4.11448,130,0.0343,, +FM,The Wave Swansea Kilvey Hill,The Wave,96400000,51.62891,-3.919745,193,1,, +FM,Thornbury Radio Olveston,Thornbury Radio,107500000,51.582306,-2.561076,75,0.008,, +FM,Thornbury Radio Thornbury and District Thornbury,Thornbury Radio,105100000,51.608616,-2.488331,99,0.0511,, +FM,Time 107.5 Havering Romford - Mercury House,Time 107.5,107500000,51.57906,0.184321,18,0.4065,, +FM,TMCR Thorne-Moorends Thorne - Bridge Street,TMCR,95300000,53.610359,-0.959319,2,0.0199,, +FM,Tone FM Taunton Taunton - Market House,Tone FM,107800000,51.014569,-3.102891,19,0.025,, +FM,Torbay Hospital Radio Devon Torbay Hospital,Torbay Hospital Radio,95900000,50.482428,-3.553751,72,0.001,, +FM,Two Lochs Radio Loch Ewe Cliff Hill,Two Lochs Radio,106600000,57.757467,-5.614524,225,2,, +FM,Two Lochs Radio Gairloch Port Henderson,Two Lochs Radio,106000000,57.700504,-5.75527,64,0.6,, +FM,U105 Belfast Black Mountain,U105,105800000,54.586989,-6.022076,301,1,, +FM,Ujima Radio Bristol Bristol - Rawnsley House,Ujima Radio,98000000,51.463564,-2.572286,13,0.025,, +FM,Unity 101 Southampton Midanbury - Broadway,Unity 101,101100000,50.925696,-1.364237,61,0.075,, +FM,Unity FM Birmingham East Birmingham - Pritchett Tower,Unity FM,93500000,52.472029,-1.869083,129,0.075,, +FM,Unity Radio Manchester Manchester One,Unity Radio,92800000,53.478111,-2.238327,40,0.025,, +FM,University Radio York York University of York,University Radio York,88300000,53.947755,-1.053788,15,0.002,, +FM,UWS Radio Ayr Ayr University,UWS Radio,87700000,55.45949,-4.607931,20,5e-05,, +FM,Vanny Radio Coventry William Batchelor House,Vanny Radio,106300000,52.413553,-1.510526,92,0.01,, +FM,Vectis Radio Newport (IoW) Newport Golf Course,Vectis Radio,104600000,50.683114,-1.278202,104,0.075,, +FM,Vibe 107.6 FM Watford Watford YMCA,Vibe 107.6 FM,107600000,51.65704,-0.396312,74,0.1,, +FM,Viking FM Humberside High Hunsley,Viking FM,96900000,53.803052,-0.565371,164,5,, +FM,Vixen 101 Market Weighton,Vixen 101,101800000,53.866896,-0.628886,120,0.025,, +FM,Vixen 101 Pocklington Pocklington - Judsons Wine Bar,Vixen 101,103100000,53.930003,-0.779584,35,0.02,, +FM,Voice FM Southampton Southampton - Solent University,Voice FM,103900000,50.907544,-1.400609,9,0.05,, +FM,Wallingford Radio Wallingford and District Wallingford - Ayres Ind Est,Wallingford Radio,107300000,51.602015,-1.13133,48,0.025,, +FM,Wave 105/Greatest Hits Radio Solent Chillerton Down,Wave 105/Greatest Hits Radio,105200000,50.649245,-1.328934,166,5,, +FM,Wave 105/Greatest Hits Radio Poole POOLE,Wave 105/Greatest Hits Radio,105800000,50.729221,-1.948658,64,0.5,, +FM,Waves Radio Peterhead and Fraserburgh Mormond Hill A,Waves Radio,101200000,57.602975,-2.03228,229,1,, +FM,WCR Warminster Warminster Town,WCR,105500000,51.205499,-2.182169,117,0.025,, +FM,WCR FM Wolverhampton Wolverhampton - Mander House,WCR FM,101800000,52.585123,-2.128215,154,0.0125,, +FM,West FM Ayr DARVEL,West FM,96700000,55.579376,-4.289814,286,1.1,, +FM,West FM Ayr GIRVAN,West FM,97500000,55.244736,-4.814596,195,0.075,, +FM,West FM Rothesay ROTHESAY,West FM,106700000,55.878164,-4.998928,166,0.3,, +FM,West Hull FM West Hull Hull - Royal Infirmary,West Hull FM,106900000,53.743955,-0.359032,2,0.05,, +FM,West Kent Radio Kent Bidborough,West Kent Radio,95500000,51.16973,0.234874,121,0.015,, +FM,West Kent Radio Kent Tunbridge Wells - Sankeys,West Kent Radio,106700000,51.135332,0.260515,123,0.05,, +FM,West Somerset Radio Minehead Minehead North,West Somerset Radio,104400000,51.215281,-3.484815,169,0.05,, +FM,Westside 89.6 FM Southall Rutherford Tower,Westside 89.6 FM,89600000,51.518659,-0.364279,31,0.007,, +FM,Westsound FM Stranraer Cairn Pat,Westsound FM,96500000,54.86339,-5.049018,173,0.1,, +FM,Westsound FM Kirkcudbright CAMBRET HILL,Westsound FM,103000000,54.893698,-4.302038,343,0.532,, +FM,Westsound FM Dumfries Riddings Hill,Westsound FM,97000000,55.082733,-3.719548,230,1,, +FM,Wey Valley Radio Alton Alton - Thedden Grange,Wey Valley Radio,101100000,51.147701,-1.022937,182,0.05,, +FM,Winchester Radio Winchester Winchester - RHCH,Winchester Radio,94700000,51.061296,-1.331131,95,0.025,, +FM,Witney Radio Chilson Ascott-under-Wychwood,Witney Radio,105300000,51.86963,-1.581517,131,0.025,, +FM,Witney Radio Chipping Norton,Witney Radio,107400000,51.937095,-1.542053,220,0.025,, +FM,Witney Radio Eynsham,Witney Radio,105300000,51.782234,-1.377497,70,0.025,, +FM,Witney Radio Faringdon Faringdon Leisure Centre,Witney Radio,107100000,51.648114,-1.588473,129,0.02,, +FM,Witney Radio Stonesfield Stonesfield Sports and Social Club,Witney Radio,90200000,51.855404,-1.427162,122,0.05,, +FM,Witney Radio Witney Witney West,Witney Radio,99900000,51.791789,-1.516557,107,0.15,, +FM,Wycombe Sound High Wycombe High Wycombe (Wycombe Sound),Wycombe Sound,106600000,51.625688,-0.771594,151,0.05,, +FM,Wythenshawe FM Manchester Wythenshawe,Wythenshawe FM,97200000,53.381442,-2.258683,60,0.05,, +FM,XS Manchester Manchester Manchester - City Tower,XS Manchester,106100000,53.480177,-2.23864,43,0.5,, +FM,YO1 Radio Selby Selby Abbey,YO1 Radio,90000000,53.784006,-1.067189,2,0.2,, +FM,YO1 Radio York City York Hospital,YO1 Radio,102800000,53.970545,-1.083457,13,0.1,, +FM,Your FM Stockport Stockport - Ratcliffe Towers,Your FM,107800000,53.404991,-2.15549,72,0.025,, +FM,Your Radio Dumbarton,Your Radio,103000000,55.945232,-4.577878,8,0.1,, +FM,YourFM Portadown,YourFM,100200000,54.43016,-6.408277,63,0.025,, +FM,Zack FM 105.3 Forest Heath Mildenhall St Mary's Church,Zack FM 105.3,105300000,52.34271,0.508941,8,0.05,, +FM,Zetland FM Redcar Dunsdale - Park Farm,Zetland FM,105000000,54.570459,-1.070671,110,0.0258,, +DAB,Aberdeen 3E07,Aberdeen,220352000,56.999987,-2.389944,325,2,3E,07 +DAB,Aberdeen 3E06,Aberdeen,220352000,57.386674,-2.400197,245,8.51001,3E,06 +DAB,Aberdeen 3E01,Aberdeen,220352000,57.602976,-2.029937,225,1,3E,01 +DAB,Aberdeen 3E13,Aberdeen,220352000,57.113656,-2.096244,87,1.2,3E,13 +DAB,Ayr 400E,Ayr,218640000,55.409586,-4.699754,273,4,40,0E +DAB,Ayr 400A,Ayr,218640000,55.579376,-4.289814,286,0.760001,40,0A +DAB,Ayr 4004,Ayr,218640000,55.244736,-4.814596,195,2,40,04 +DAB,Ayr 4007,Ayr,218640000,55.695641,-4.84184,170,1.51,40,07 +DAB,Basingstoke small-scale 0308,Basingstoke small-scale,197648000,51.226848,-1.080409,176,0.25,03,08 +DAB,BBC National DAB 2412,BBC National DAB,225648000,51.702007,-3.398531,282,0.2,24,12 +DAB,BBC National DAB 2405,BBC National DAB,225648000,51.807795,-3.097781,433,0.488619,24,05 +DAB,BBC National DAB 2415,BBC National DAB,225648000,51.714666,-3.12404,400,1,24,15 +DAB,BBC National DAB 2E0D,BBC National DAB,225648000,54.046924,-0.786852,224,2,2E,0D +DAB,BBC National DAB 3A0A,BBC National DAB,225648000,53.674328,-1.813774,257,0.6,3A,0A +DAB,BBC National DAB 3111,BBC National DAB,225648000,52.180735,1.570158,21,1.8,31,11 +DAB,BBC National DAB 0B02,BBC National DAB,225648000,51.594459,-0.129257,92,3.2,0B,02 +DAB,BBC National DAB 3502,BBC National DAB,225648000,53.027231,-2.28071,220,2.5,35,02 +DAB,BBC National DAB 0C13,BBC National DAB,225648000,51.142291,-0.968873,148,0.05,0C,13 +DAB,BBC National DAB 0516,BBC National DAB,225648000,53.390547,-4.301313,160,0.6,05,16 +DAB,BBC National DAB 3C08,BBC National DAB,225648000,56.555053,-2.986125,312,10,3C,08 +DAB,BBC National DAB 3C03,BBC National DAB,225648000,56.711856,-2.671353,130,1,3C,03 +DAB,BBC National DAB 0502,BBC National DAB,225648000,53.01985,-4.273475,300,3.90895,05,02 +DAB,BBC National DAB 1908,BBC National DAB,225648000,54.342402,-6.629562,109,5,19,08 +DAB,BBC National DAB 2001,BBC National DAB,225648000,53.011257,-1.730341,170,0.5,20,01 +DAB,BBC National DAB 0E17,BBC National DAB,225648000,50.505425,-3.752519,156,0.3,0E,17 +DAB,BBC National DAB 4315,BBC National DAB,225648000,55.974965,-2.776943,175,1,43,15 +DAB,BBC National DAB 1606,BBC National DAB,225648000,51.819509,-0.811742,81,0.6,16,06 +DAB,BBC National DAB 2904,BBC National DAB,225648000,52.924963,-3.535217,309,0.3,29,04 +DAB,BBC National DAB 3E0D,BBC National DAB,225648000,57.184868,-2.122071,74,0.3,3E,0D +DAB,BBC National DAB 1912,BBC National DAB,225648000,55.191644,-6.24536,109,0.1,19,12 +DAB,BBC National DAB 0E05,BBC National DAB,225648000,51.003284,-3.473759,226,0.6,0E,05 +DAB,BBC National DAB 1914,BBC National DAB,225648000,54.661435,-5.675928,21,0.4,19,14 +DAB,BBC National DAB 0712,BBC National DAB,225648000,54.126165,-3.198099,23,0.6,07,12 +DAB,BBC National DAB 4210,BBC National DAB,225648000,54.934919,-3.857934,178,2,42,10 +DAB,BBC National DAB 0308,BBC National DAB,225648000,51.226848,-1.080409,176,1,03,08 +DAB,BBC National DAB 230E,BBC National DAB,225648000,51.38779,-2.332925,175,1.95447,23,0E +DAB,BBC National DAB 0E07,BBC National DAB,225648000,50.447129,-3.610498,196,4.66627,0E,07 +DAB,BBC National DAB 3305,BBC National DAB,225648000,52.449252,1.557261,26,0.05,33,05 +DAB,BBC National DAB 3A09,BBC National DAB,225648000,53.811543,-1.641253,149,1.85675,3A,09 +DAB,BBC National DAB 0E11,BBC National DAB,225648000,50.701549,-3.091423,93,0.05,0E,11 +DAB,BBC National DAB 3202,BBC National DAB,225648000,53.335814,-0.171983,125,4.45625,32,02 +DAB,BBC National DAB 3D14,BBC National DAB,225648000,56.212308,-4.263559,415,2,3D,14 +DAB,BBC National DAB 0514,BBC National DAB,225648000,53.108346,-3.75717,303,0.6,05,14 +DAB,BBC National DAB 4407,BBC National DAB,225648000,55.576525,-3.56198,325,0.6,44,07 +DAB,BBC National DAB 3B02,BBC National DAB,225648000,54.358848,-1.149317,381,2,3B,02 +DAB,BBC National DAB 0D03,BBC National DAB,225648000,50.66283,-2.443645,160,0.977237,0D,03 +DAB,BBC National DAB 2B08,BBC National DAB,225648000,53.372188,-1.95923,313,0.05,2B,08 +DAB,BBC National DAB 2C07,BBC National DAB,225648000,53.809005,-3.05038,6,0.12,2C,07 +DAB,BBC National DAB 280D,BBC National DAB,225648000,52.360613,-4.102585,174,4.66627,28,0D +DAB,BBC National DAB 0104,BBC National DAB,225648000,51.324006,0.520684,192,6.30001,01,04 +DAB,BBC National DAB 1A0B,BBC National DAB,225648000,51.609363,-1.794027,148,4,1A,0B +DAB,BBC National DAB 3107,BBC National DAB,225648000,52.311386,1.598136,22,1.2,31,07 +DAB,BBC National DAB 1203,BBC National DAB,225648000,51.723271,-1.300854,162,1.2,12,03 +DAB,BBC National DAB 200C,BBC National DAB,225648000,53.094354,-1.561526,315,0.3,20,0C +DAB,BBC National DAB 3203,BBC National DAB,225648000,52.962367,-0.015354,3,0.3,32,03 +DAB,BBC National DAB 1609,BBC National DAB,225648000,51.998806,-0.669784,169,1.82402,16,09 +DAB,BBC National DAB 4312,BBC National DAB,225648000,55.912262,-3.200598,202,0.977237,43,12 +DAB,BBC National DAB 060C,BBC National DAB,225648000,51.865628,0.576571,62,0.1,06,0C +DAB,BBC National DAB 310C,BBC National DAB,225648000,52.447068,0.594193,21,1.2,31,0C +DAB,BBC National DAB 280A,BBC National DAB,225648000,51.959448,-3.412497,248,0.5,28,0A +DAB,BBC National DAB 4501,BBC National DAB,225648000,60.130079,-1.096281,224,4.5,45,01 +DAB,BBC National DAB 0E0D,BBC National DAB,225648000,50.720805,-2.775678,64,0.2,0E,0D +DAB,BBC National DAB 0E0A,BBC National DAB,225648000,50.395927,-3.518996,50,0.3,0E,0A +DAB,BBC National DAB 1C04,BBC National DAB,225648000,52.355115,-2.078214,147,1.95447,1C,04 +DAB,BBC National DAB 1903,BBC National DAB,225648000,54.423191,-7.462812,305,3.2,19,03 +DAB,BBC National DAB 070F,BBC National DAB,225648000,54.682913,-3.463248,125,1.3,07,0F +DAB,BBC National DAB 400E,BBC National DAB,225648000,55.409586,-4.699754,273,2.4,40,0E +DAB,BBC National DAB 0817,BBC National DAB,225648000,51.521504,-0.138879,27,0.8,08,17 +DAB,BBC National DAB 2F0C,BBC National DAB,225648000,54.124979,-0.218986,105,1.5,2F,0C +DAB,BBC National DAB 040A,BBC National DAB,225648000,50.82768,-4.530383,47,0.293171,04,0A +DAB,BBC National DAB 0E13,BBC National DAB,225648000,50.634311,-3.354151,102,0.6,0E,13 +DAB,BBC National DAB 310B,BBC National DAB,225648000,52.440322,1.445862,34,0.05,31,0B +DAB,BBC National DAB 3308,BBC National DAB,225648000,52.952591,0.671702,60,0.977237,33,08 +DAB,BBC National DAB 0A02,BBC National DAB,225648000,50.909654,-0.627813,245,0.122155,0A,02 +DAB,BBC National DAB 200F,BBC National DAB,225648000,53.275085,-1.911935,432,0.977237,20,0F +DAB,BBC National DAB 330C,BBC National DAB,225648000,52.659164,1.715858,17,0.025,33,0C +DAB,BBC National DAB 3415,BBC National DAB,225648000,54.969789,-1.608675,15,0.025,34,15 +DAB,BBC National DAB 2007,BBC National DAB,225648000,53.265177,-1.653635,275,1,20,07 +DAB,BBC National DAB 420C,BBC National DAB,225648000,54.893698,-4.302038,343,2.4,42,0C +DAB,BBC National DAB 190A,BBC National DAB,225648000,54.160861,-6.385716,340,3,19,0A +DAB,BBC National DAB 3D09,BBC National DAB,225648000,55.413714,-5.624241,83,0.6,3D,09 +DAB,BBC National DAB 0405,BBC National DAB,225648000,50.511364,-4.43683,369,2.38748,04,05 +DAB,BBC National DAB 2708,BBC National DAB,225648000,51.867126,-4.309135,137,0.6,27,08 +DAB,BBC National DAB 2707,BBC National DAB,225648000,51.818501,-4.066216,255,4.88619,27,07 +DAB,BBC National DAB 1909,BBC National DAB,225648000,54.676355,-5.928737,207,1,19,09 +DAB,BBC National DAB 080D,BBC National DAB,225648000,51.263565,-0.086822,226,2.4,08,0D +DAB,BBC National DAB 390E,BBC National DAB,225648000,55.825353,-4.290679,67,0.01,39,0E +DAB,BBC National DAB 2104,BBC National DAB,225648000,50.874213,-2.913244,173,0.6,21,04 +DAB,BBC National DAB 0103,BBC National DAB,225648000,51.21959,0.812581,193,2,01,03 +DAB,BBC National DAB 010B,BBC National DAB,225648000,51.265673,1.013529,67,1,01,0B +DAB,BBC National DAB 340C,BBC National DAB,225648000,55.531826,-1.834261,192,3.2,34,0C +DAB,BBC National DAB 0316,BBC National DAB,225648000,51.6119,-0.734849,142,0.6,03,16 +DAB,BBC National DAB 1604,BBC National DAB,225648000,51.697895,-0.618141,127,0.1,16,04 +DAB,BBC National DAB 2D12,BBC National DAB,225648000,53.283991,-1.427446,179,1,2D,12 +DAB,BBC National DAB 2404,BBC National DAB,225648000,51.601588,-2.935417,94,2,24,04 +DAB,BBC National DAB 1B11,BBC National DAB,225648000,51.868264,-2.175397,147,2,1B,11 +DAB,BBC National DAB 0601,BBC National DAB,225648000,51.803409,1.165049,7,0.012,06,01 +DAB,BBC National DAB 3D04,BBC National DAB,225648000,57.617267,-7.44252,123,1.95447,3D,04 +DAB,BBC National DAB 2D05,BBC National DAB,225648000,53.457744,-1.220893,138,2,2D,05 +DAB,BBC National DAB 3705,BBC National DAB,225648000,52.413167,-2.994548,413,0.6,37,05 +DAB,BBC National DAB 2804,BBC National DAB,225648000,52.08185,-3.162868,215,1.2,28,04 +DAB,BBC National DAB 2116,BBC National DAB,225648000,50.916513,-2.700119,134,2,21,16 +DAB,BBC National DAB 330F,BBC National DAB,225648000,52.8029,0.84086,80,0.244309,33,0F +DAB,BBC National DAB 0513,BBC National DAB,225648000,53.271606,-3.828796,114,0.5,05,13 +DAB,BBC National DAB 0314,BBC National DAB,225648000,51.414004,-0.796112,90,0.977237,03,14 +DAB,BBC National DAB 4111,BBC National DAB,225648000,52.710153,-1.285042,240,1.5,41,11 +DAB,BBC National DAB 3D01,BBC National DAB,225648000,56.814742,-5.093559,283,1,3D,01 +DAB,BBC National DAB 0210,BBC National DAB,225648000,51.064004,-1.358677,152,0,02,10 +DAB,BBC National DAB 3F02,BBC National DAB,225648000,56.071791,-3.233186,181,5,3F,02 +DAB,BBC National DAB 0105,BBC National DAB,225648000,51.099738,1.182579,166,0.25,01,05 +DAB,BBC National DAB 3C0B,BBC National DAB,225648000,56.357222,-3.920232,219,0.6,3C,0B +DAB,BBC National DAB 1D11,BBC National DAB,225648000,51.184826,-2.177079,160,0.5,1D,11 +DAB,BBC National DAB 4406,BBC National DAB,225648000,55.40857,-2.811432,239,1,44,06 +DAB,BBC National DAB 0B01,BBC National DAB,225648000,51.424161,-0.074944,110,9.54993,0B,01 +DAB,BBC National DAB 3310,BBC National DAB,225648000,52.652502,0.872498,85,1.2,33,10 +DAB,BBC National DAB 0616,BBC National DAB,225648000,51.719492,0.58056,105,2,06,16 +DAB,BBC National DAB ,BBC National DAB,225648000,51.469253,0.260425,3,1e-05,, +DAB,BBC National DAB 400A,BBC National DAB,225648000,55.579376,-4.289814,286,9.54993,40,0A +DAB,BBC National DAB 2C02,BBC National DAB,225648000,53.696571,-2.443266,261,0.1,2C,02 +DAB,BBC National DAB 1702,BBC National DAB,225648000,52.253028,-1.139914,199,9.54993,17,02 +DAB,BBC National DAB 050E,BBC National DAB,225648000,53.137063,-4.129256,322,0.3,05,0E +DAB,BBC National DAB 1901,BBC National DAB,225648000,54.607538,-6.009471,368,9.54993,19,01 +DAB,BBC National DAB 0512,BBC National DAB,225648000,52.749344,-3.886853,103,0.649999,05,12 +DAB,BBC National DAB 2D06,BBC National DAB,225648000,53.531884,-1.091294,7,0.022,2D,06 +DAB,BBC National DAB 0C15,BBC National DAB,225648000,51.221643,-0.326426,127,0.2,0C,15 +DAB,BBC National DAB 090B,BBC National DAB,225648000,54.140551,-4.493075,143,5,09,0B +DAB,BBC National DAB 0102,BBC National DAB,225648000,51.11163,1.247272,133,1.90999,01,02 +DAB,BBC National DAB 3311,BBC National DAB,225648000,52.608286,0.367383,5,0.3,33,11 +DAB,BBC National DAB 3C17,BBC National DAB,225648000,56.308188,-2.874532,210,1.2,3C,17 +DAB,BBC National DAB 4208,BBC National DAB,225648000,55.051018,-3.613774,12,1,42,08 +DAB,BBC National DAB 010D,BBC National DAB,225648000,51.292731,0.979008,122,2,01,0D +DAB,BBC National DAB 3E07,BBC National DAB,225648000,56.999987,-2.389944,325,10,3E,07 +DAB,BBC National DAB 2306,BBC National DAB,225648000,51.665695,-2.307343,247,0.25,23,06 +DAB,BBC National DAB 3F06,BBC National DAB,225648000,56.071792,-4.055753,410,2,3F,06 +DAB,BBC National DAB 0A0C,BBC National DAB,225648000,51.107066,-0.020722,136,0.649999,0A,0C +DAB,BBC National DAB 0A01,BBC National DAB,225648000,50.764511,0.288682,11,0.3,0A,01 +DAB,BBC National DAB 2413,BBC National DAB,225648000,51.771714,-3.218938,442,0.5,24,13 +DAB,BBC National DAB 2402,BBC National DAB,225648000,51.611393,-3.302735,381,1.2,24,02 +DAB,BBC National DAB 3D05,BBC National DAB,225648000,58.179148,-6.584974,206,5,3D,05 +DAB,BBC National DAB 2E14,BBC National DAB,225648000,53.611985,-1.66456,256,7.4131,2E,14 +DAB,BBC National DAB 190B,BBC National DAB,225648000,54.359541,-7.642326,61,0.5,19,0B +DAB,BBC National DAB 1605,BBC National DAB,225648000,51.744172,-0.128729,122,2,16,05 +DAB,BBC National DAB 3B0A,BBC National DAB,225648000,54.556455,-1.120934,237,1,3B,0A +DAB,BBC National DAB 0E09,BBC National DAB,225648000,50.719122,-3.562148,102,4,0E,09 +DAB,BBC National DAB 4414,BBC National DAB,225648000,55.83228,-2.085863,197,2,44,14 +DAB,BBC National DAB 1201,BBC National DAB,225648000,52.044582,-1.224699,157,1.2,12,01 +DAB,BBC National DAB 3102,BBC National DAB,225648000,51.951883,1.331834,2,0.719999,31,02 +DAB,BBC National DAB 3403,BBC National DAB,225648000,54.978039,-1.662966,120,1.99526,34,03 +DAB,BBC National DAB 0A12,BBC National DAB,225648000,50.853924,-0.410233,124,0.28,0A,12 +DAB,BBC National DAB 2803,BBC National DAB,225648000,52.012591,-4.996935,123,0.195447,28,03 +DAB,BBC National DAB 300A,BBC National DAB,225648000,53.140513,-1.232922,168,1,30,0A +DAB,BBC National DAB 2714,BBC National DAB,225648000,51.627893,-3.760915,361,1,27,14 +DAB,BBC National DAB 0208,BBC National DAB,225648000,50.853922,-1.067587,102,1,02,08 +DAB,BBC National DAB 0213,BBC National DAB,225648000,50.877178,-1.278479,50,0.033,02,13 +DAB,BBC National DAB 3E11,BBC National DAB,225648000,57.381625,-2.756233,416,1.7,3E,11 +DAB,BBC National DAB 1705,BBC National DAB,225648000,52.445531,-0.666816,118,5,17,05 +DAB,BBC National DAB 4004,BBC National DAB,225648000,55.244736,-4.814596,195,0.6,40,04 +DAB,BBC National DAB 390B,BBC National DAB,225648000,55.886844,-4.294621,26,0.01,39,0B +DAB,BBC National DAB 3902,BBC National DAB,225648000,55.861436,-4.268991,16,0.3,39,02 +DAB,BBC National DAB 2B09,BBC National DAB,225648000,53.455242,-1.960506,262,0.5,2B,09 +DAB,BBC National DAB 3206,BBC National DAB,225648000,52.918371,-0.592549,124,0.8,32,06 +DAB,BBC National DAB 380A,BBC National DAB,225648000,57.320173,-3.656313,389,1.2,38,0A +DAB,BBC National DAB 3309,BBC National DAB,225648000,52.773873,0.649768,92,5,33,09 +DAB,BBC National DAB 3303,BBC National DAB,225648000,52.602996,1.722916,1,0.5,33,03 +DAB,BBC National DAB 2811,BBC National DAB,225648000,51.674549,-5.002613,71,1,28,11 +DAB,BBC National DAB 0C16,BBC National DAB,225648000,51.228358,-0.605467,142,4.88619,0C,16 +DAB,BBC National DAB 0404,BBC National DAB,225648000,50.13053,-5.53431,62,0.013,04,04 +DAB,BBC National DAB 030C,BBC National DAB,225648000,51.307873,-1.244777,220,5,03,0C +DAB,BBC National DAB 060B,BBC National DAB,225648000,51.739903,0.097485,110,1,06,0B +DAB,BBC National DAB 2E06,BBC National DAB,225648000,53.995727,-1.592234,150,1.2,2E,06 +DAB,BBC National DAB 1814,BBC National DAB,225648000,52.540463,-1.503661,140,0.5,18,14 +DAB,BBC National DAB 0C09,BBC National DAB,225648000,51.091179,-0.736114,172,0.630001,0C,09 +DAB,BBC National DAB 2C15,BBC National DAB,225648000,53.708491,-2.311438,336,1,2C,15 +DAB,BBC National DAB 0A06,BBC National DAB,225648000,50.861622,0.566431,76,3,0A,06 +DAB,BBC National DAB 2801,BBC National DAB,225648000,51.899195,-4.86653,186,1,28,01 +DAB,BBC National DAB 3407,BBC National DAB,225648000,54.961693,-2.298886,212,0.3,34,07 +DAB,BBC National DAB 3701,BBC National DAB,225648000,52.531128,-2.790828,343,0.649999,37,01 +DAB,BBC National DAB 3304,BBC National DAB,225648000,52.893823,0.496359,20,0.6,33,04 +DAB,BBC National DAB 1301,BBC National DAB,225648000,52.294535,-1.946877,162,0.0152,13,01 +DAB,BBC National DAB 0A07,BBC National DAB,225648000,50.976724,0.230437,158,5,0A,07 +DAB,BBC National DAB 3A0E,BBC National DAB,225648000,53.737298,-2.018458,220,0.2,3A,0E +DAB,BBC National DAB 0416,BBC National DAB,225648000,50.101857,-5.285607,71,1,04,16 +DAB,BBC National DAB 030D,BBC National DAB,225648000,51.481196,-0.978531,69,0.5,03,0D +DAB,BBC National DAB 1612,BBC National DAB,225648000,51.728571,-0.426217,142,4,16,12 +DAB,BBC National DAB 3409,BBC National DAB,225648000,54.893895,-1.363068,10,0.8,34,09 +DAB,BBC National DAB 2411,BBC National DAB,225648000,51.740421,-3.419414,451,1,24,11 +DAB,BBC National DAB 2E03,BBC National DAB,225648000,54.063816,-1.740687,298,0.25,2E,03 +DAB,BBC National DAB 2F07,BBC National DAB,225648000,53.803052,-0.565371,164,2,2F,07 +DAB,BBC National DAB 1610,BBC National DAB,225648000,51.640531,-0.763678,156,0.2,16,10 +DAB,BBC National DAB 0E0C,BBC National DAB,225648000,50.566699,-3.506408,205,0.5,0E,0C +DAB,BBC National DAB 3A04,BBC National DAB,225648000,53.533184,-1.858296,524,2,3A,04 +DAB,BBC National DAB 0506,BBC National DAB,225648000,53.307315,-4.683071,135,1,05,06 +DAB,BBC National DAB 2A09,BBC National DAB,225648000,53.265968,-3.22279,214,0.3,2A,09 +DAB,BBC National DAB 0A09,BBC National DAB,225648000,51.064289,-0.321546,53,0.024,0A,09 +DAB,BBC National DAB 0C01,BBC National DAB,225648000,51.234232,-0.820719,179,0.08,0C,01 +DAB,BBC National DAB 0E08,BBC National DAB,225648000,50.979244,-4.098818,200,2.44309,0E,08 +DAB,BBC National DAB 230C,BBC National DAB,225648000,51.325227,-2.918301,73,0.6,23,0C +DAB,BBC National DAB 1B05,BBC National DAB,225648000,51.904177,-1.707798,241,1,1B,05 +DAB,BBC National DAB 2E0B,BBC National DAB,225648000,53.832945,-1.752142,215,0.3,2E,0B +DAB,BBC National DAB 4303,BBC National DAB,225648000,55.620243,-3.07272,244,0.3,43,03 +DAB,BBC National DAB 2208,BBC National DAB,225648000,50.368664,-3.926486,142,0.25,22,08 +DAB,BBC National DAB 4402,BBC National DAB,225648000,55.494186,-2.53763,111,0.1,44,02 +DAB,BBC National DAB 4504,BBC National DAB,225648000,58.975283,-3.083943,220,10,45,04 +DAB,BBC National DAB 3A0C,BBC National DAB,225648000,53.895532,-1.896639,305,2,3A,0C +DAB,BBC National DAB 0707,BBC National DAB,225648000,54.314559,-2.708127,172,3.2,07,07 +DAB,BBC National DAB 0B14,BBC National DAB,225648000,51.317089,-0.09335,152,0.05,0B,14 +DAB,BBC National DAB 3411,BBC National DAB,225648000,55.001052,-1.665743,120,0.01,34,11 +DAB,BBC National DAB 070A,BBC National DAB,225648000,54.5916,-3.117626,178,1,07,0A +DAB,BBC National DAB 1C06,BBC National DAB,225648000,52.363252,-2.282794,82,0.092,1C,06 +DAB,BBC National DAB 2703,BBC National DAB,225648000,51.62891,-3.919745,193,4.1,27,03 +DAB,BBC National DAB 3313,BBC National DAB,225648000,52.824325,0.487473,51,0.6,33,13 +DAB,BBC National DAB 220D,BBC National DAB,225648000,50.274442,-3.794967,93,0.5,22,0D +DAB,BBC National DAB 0E10,BBC National DAB,225648000,50.349538,-3.565025,107,0.4,0E,10 +DAB,BBC National DAB 3808,BBC National DAB,225648000,57.061393,-4.030507,351,0.586342,38,08 +DAB,BBC National DAB 3F01,BBC National DAB,225648000,55.852721,-3.826093,277,9.54993,3F,01 +DAB,BBC National DAB 3207,BBC National DAB,225648000,52.832469,-0.431001,73,1.2,32,07 +DAB,BBC National DAB 4202,BBC National DAB,225648000,55.412875,-3.983785,480,1,42,02 +DAB,BBC National DAB 3C09,BBC National DAB,225648000,56.372293,-3.453361,178,3.98107,3C,09 +DAB,BBC National DAB 3805,BBC National DAB,225648000,57.532303,-3.135126,353,5,38,05 +DAB,BBC National DAB 0711,BBC National DAB,225648000,54.382063,-2.589348,349,1,07,11 +DAB,BBC National DAB 2005,BBC National DAB,225648000,53.306661,-1.960342,404,0.251189,20,05 +DAB,BBC National DAB 2C0E,BBC National DAB,225648000,54.089336,-2.779963,88,4.88619,2C,0E +DAB,BBC National DAB 4204,BBC National DAB,225648000,55.137967,-3.008447,271,0.5,42,04 +DAB,BBC National DAB 1808,BBC National DAB,225648000,52.081613,-1.728531,260,3,18,08 +DAB,BBC National DAB 190F,BBC National DAB,225648000,54.862024,-5.828421,119,0.2,19,0F +DAB,BBC National DAB 1806,BBC National DAB,225648000,52.294288,-1.519026,90,0.1,18,06 +DAB,BBC National DAB 0C0F,BBC National DAB,225648000,51.319591,-0.372374,60,0.05,0C,0F +DAB,BBC National DAB 3512,BBC National DAB,225648000,53.102442,-2.00205,265,0.6,35,12 +DAB,BBC National DAB 4108,BBC National DAB,225648000,52.637434,-1.125451,57,0.3,41,08 +DAB,BBC National DAB 1001,BBC National DAB,225648000,49.246023,-2.1012,134,2,10,01 +DAB,BBC National DAB 1102,BBC National DAB,225648000,49.457792,-2.579202,76,0.475,11,02 +DAB,BBC National DAB 160D,BBC National DAB,225648000,51.981709,-0.201702,82,0.6,16,0D +DAB,BBC National DAB 1302,BBC National DAB,225648000,52.375278,-2.013764,280,1,13,02 +DAB,BBC National DAB 1907,BBC National DAB,225648000,55.109172,-6.886121,341,6.30001,19,07 +DAB,BBC National DAB 3209,BBC National DAB,225648000,53.205578,-0.546174,15,0.6,32,09 +DAB,BBC National DAB 0A08,BBC National DAB,225648000,51.13246,-0.23632,92,1.17268,0A,08 +DAB,BBC National DAB 2B17,BBC National DAB,225648000,53.646225,-2.076355,229,0.6,2B,17 +DAB,BBC National DAB 0501,BBC National DAB,225648000,53.307002,-4.12825,146,5,05,01 +DAB,BBC National DAB 0509,BBC National DAB,225648000,52.914419,-4.017769,268,0.5,05,09 +DAB,BBC National DAB 050B,BBC National DAB,225648000,52.479547,-3.399945,454,2,05,0B +DAB,BBC National DAB 2810,BBC National DAB,225648000,52.261047,-3.439354,432,5,28,10 +DAB,BBC National DAB 280B,BBC National DAB,225648000,52.045314,-4.410045,116,1,28,0B +DAB,BBC National DAB 2709,BBC National DAB,225648000,51.699961,-4.157337,111,0.6,27,09 +DAB,BBC National DAB 290B,BBC National DAB,225648000,52.954525,-3.117972,390,0.4,29,0B +DAB,BBC National DAB 290A,BBC National DAB,225648000,53.031048,-3.180791,556,5,29,0A +DAB,BBC National DAB 0503,BBC National DAB,225648000,52.446933,-3.549585,244,0.3,05,03 +DAB,BBC National DAB 1904,BBC National DAB,225648000,55.00421,-7.368968,175,6.30001,19,04 +DAB,BBC National DAB 0511,BBC National DAB,225648000,52.644306,-3.086542,400,1,05,11 +DAB,BBC National DAB 3A11,BBC National DAB,225648000,53.720111,-1.92874,256,0.3,3A,11 +DAB,BBC National DAB 3703,BBC National DAB,225648000,52.362722,-2.738327,216,1.2,37,03 +DAB,BBC National DAB 0E06,BBC National DAB,225648000,50.737572,-2.929856,162,0.4,0E,06 +DAB,BBC National DAB 0508,BBC National DAB,225648000,52.586449,-3.885603,100,0.5,05,08 +DAB,BBC National DAB 190C,BBC National DAB,225648000,55.178615,-6.671493,62,1.5,19,0C +DAB,BBC National DAB 1506,BBC National DAB,225648000,52.215394,0.036667,62,4,15,06 +DAB,BBC National DAB 2704,BBC National DAB,225648000,51.608486,-3.6738,252,0.3,27,04 +DAB,BBC National DAB 030A,BBC National DAB,225648000,51.548667,-0.775255,85,1,03,0A +DAB,BBC National DAB 1C15,BBC National DAB,225648000,52.115715,-2.330146,161,5,1C,15 +DAB,BBC National DAB 2B06,BBC National DAB,225648000,53.480177,-2.23864,43,0.5,2B,06 +DAB,BBC National DAB 060F,BBC National DAB,225648000,51.92387,1.086097,35,5,06,0F +DAB,BBC National DAB 3008,BBC National DAB,225648000,52.976309,-1.132626,122,1,30,08 +DAB,BBC National DAB 3707,BBC National DAB,225648000,52.905093,-2.493571,100,0.033884,37,07 +DAB,BBC National DAB 3E06,BBC National DAB,225648000,57.386674,-2.400197,245,10,3E,06 +DAB,BBC National DAB 3D07,BBC National DAB,225648000,57.842382,-5.782182,271,1.5,3D,07 +DAB,BBC National DAB 1A12,BBC National DAB,225648000,51.484903,-1.558836,211,5,1A,12 +DAB,BBC National DAB 2302,BBC National DAB,225648000,51.236969,-2.625476,303,5.86342,23,02 +DAB,BBC National DAB 310E,BBC National DAB,225648000,52.234496,1.107319,64,4.3,31,0E +DAB,BBC National DAB 0A0A,BBC National DAB,225648000,51.017054,-0.70092,185,6.01646,0A,0A +DAB,BBC National DAB 390F,BBC National DAB,225648000,55.982322,-4.600708,152,0.4,39,0F +DAB,BBC National DAB 2903,BBC National DAB,225648000,53.220944,-3.31452,336,10,29,03 +DAB,BBC National DAB 4201,BBC National DAB,225648000,55.340908,-3.474167,270,0.3,42,01 +DAB,BBC National DAB 2403,BBC National DAB,225648000,51.811533,-2.688667,194,0.23,24,03 +DAB,BBC National DAB 0705,BBC National DAB,225648000,54.202505,-3.167346,259,5,07,05 +DAB,BBC National DAB 3E01,BBC National DAB,225648000,57.602976,-2.029937,225,2,3E,01 +DAB,BBC National DAB 340E,BBC National DAB,225648000,55.171858,-1.659136,60,1.1,34,0E +DAB,BBC National DAB 3803,BBC National DAB,225648000,57.591626,-4.27683,212,10,38,03 +DAB,BBC National DAB 3510,BBC National DAB,225648000,53.116187,-2.211069,325,2,35,10 +DAB,BBC National DAB 2705,BBC National DAB,225648000,51.556793,-3.628192,244,0.75,27,05 +DAB,BBC National DAB 2417,BBC National DAB,225648000,51.604177,-3.122175,360,1,24,17 +DAB,BBC National DAB 2806,BBC National DAB,225648000,52.067402,-4.076523,411,1,28,06 +DAB,BBC National DAB 280C,BBC National DAB,225648000,51.750918,-4.154115,279,1.2,28,0C +DAB,BBC National DAB 1D09,BBC National DAB,225648000,51.416202,-2.076595,175,1.90999,1D,09 +DAB,BBC National DAB 1910,BBC National DAB,225648000,54.203198,-5.913247,251,2,19,10 +DAB,BBC National DAB 0A03,BBC National DAB,225648000,50.787726,0.035848,81,1.26064,0A,03 +DAB,BBC National DAB 0414,BBC National DAB,225648000,50.402798,-5.053886,62,0.5,04,14 +DAB,BBC National DAB 340F,BBC National DAB,225648000,54.982447,-1.945593,165,1,34,0F +DAB,BBC National DAB 1913,BBC National DAB,225648000,54.590668,-5.677949,20,0.450001,19,13 +DAB,BBC National DAB 0D08,BBC National DAB,225648000,50.629952,-1.987364,196,1.5,0D,08 +DAB,BBC National DAB 220F,BBC National DAB,225648000,50.550217,-4.008413,508,3.2,22,0F +DAB,BBC National DAB 330A,BBC National DAB,225648000,52.82694,1.381376,27,0.07,33,0A +DAB,BBC National DAB 170F,BBC National DAB,225648000,52.275355,-0.885481,127,2,17,0F +DAB,BBC National DAB 3006,BBC National DAB,225648000,52.986825,-1.251436,129,0.032,30,06 +DAB,BBC National DAB 3D06,BBC National DAB,225648000,56.40396,-5.485882,122,1.17268,3D,06 +DAB,BBC National DAB 270F,BBC National DAB,225648000,51.593504,-3.546781,298,0.6,27,0F +DAB,BBC National DAB 0E02,BBC National DAB,225648000,50.753618,-4.005483,208,0.6,0E,02 +DAB,BBC National DAB 2E01,BBC National DAB,225648000,54.267351,-0.404494,151,2,2E,01 +DAB,BBC National DAB 3301,BBC National DAB,225648000,52.486385,1.715554,8,0.950001,33,01 +DAB,BBC National DAB 120E,BBC National DAB,225648000,51.790638,-1.179183,130,9.54993,12,0E +DAB,BBC National DAB 4305,BBC National DAB,225648000,55.661832,-3.227732,352,0.3,43,05 +DAB,BBC National DAB 0413,BBC National DAB,225648000,50.481389,-4.782638,116,1.2,04,13 +DAB,BBC National DAB 2C0D,BBC National DAB,225648000,53.841893,-2.266074,276,4.88619,2C,0D +DAB,BBC National DAB 3F0B,BBC National DAB,225648000,55.819142,-3.194377,248,1,3F,0B +DAB,BBC National DAB 050C,BBC National DAB,225648000,53.286941,-3.684982,125,0.6,05,0C +DAB,BBC National DAB 0706,BBC National DAB,225648000,54.674729,-2.728805,263,4,07,06 +DAB,BBC National DAB 1E01,BBC National DAB,225648000,52.507615,-0.343282,56,4.88619,1E,01 +DAB,BBC National DAB 1614,BBC National DAB,225648000,51.915442,-0.184286,133,1.2,16,14 +DAB,BBC National DAB 3C0C,BBC National DAB,225648000,56.687307,-3.759852,401,1,3C,0C +DAB,BBC National DAB 2204,BBC National DAB,225648000,50.381346,-4.067802,113,1.95447,22,04 +DAB,BBC National DAB 3401,BBC National DAB,225648000,54.868838,-1.771233,302,7.63994,34,01 +DAB,BBC National DAB 2409,BBC National DAB,225648000,51.685712,-3.036095,250,0.5,24,09 +DAB,BBC National DAB 0D07,BBC National DAB,225648000,50.729221,-1.948658,64,1.95447,0D,07 +DAB,BBC National DAB 3D0A,BBC National DAB,225648000,55.627446,-6.227617,93,1,3D,0A +DAB,BBC National DAB 0904,BBC National DAB,225648000,54.074773,-4.743515,69,0.4,09,04 +DAB,BBC National DAB 2805,BBC National DAB,225648000,51.944404,-4.661027,323,5,28,05 +DAB,BBC National DAB 230F,BBC National DAB,225648000,51.48519,-2.562764,91,1,23,0F +DAB,BBC National DAB 310A,BBC National DAB,225648000,52.290839,0.777315,69,2,31,0A +DAB,BBC National DAB 3513,BBC National DAB,225648000,52.728576,-2.0198,234,1.75,35,13 +DAB,BBC National DAB 2004,BBC National DAB,225648000,52.973416,-1.507057,125,3,20,04 +DAB,BBC National DAB 0912,BBC National DAB,225648000,54.312725,-4.381093,134,0.2,09,12 +DAB,BBC National DAB 3E13,BBC National DAB,225648000,57.113656,-2.096244,87,1.2,3E,13 +DAB,BBC National DAB 0403,BBC National DAB,225648000,50.209786,-5.238489,237,1.95447,04,03 +DAB,BBC National DAB 0B05,BBC National DAB,225648000,51.254494,-0.200986,234,0.954993,0B,05 +DAB,BBC National DAB 270E,BBC National DAB,225648000,51.741661,-3.679878,409,0.6,27,0E +DAB,BBC National DAB 2406,BBC National DAB,225648000,51.633901,-3.460735,316,1,24,06 +DAB,BBC National DAB 3702,BBC National DAB,225648000,52.878444,-3.091941,305,0.25,37,02 +DAB,BBC National DAB 2410,BBC National DAB,225648000,51.730587,-3.264891,419,1,24,10 +DAB,BBC National DAB 1C01,BBC National DAB,225648000,51.997433,-2.53989,204,10,1C,01 +DAB,BBC National DAB 3B05,BBC National DAB,225648000,54.593159,-2.041753,352,1,3B,05 +DAB,BBC National DAB 390C,BBC National DAB,225648000,55.991937,-4.793795,107,1.8,39,0C +DAB,BBC National DAB 390D,BBC National DAB,225648000,55.878164,-4.998928,166,1,39,0D +DAB,BBC National DAB 020D,BBC National DAB,225648000,50.676724,-1.370435,143,5,02,0D +DAB,BBC National DAB 3802,BBC National DAB,225648000,58.328006,-3.371413,221,10,38,02 +DAB,BBC National DAB 0A0D,BBC National DAB,225648000,50.946708,0.709647,44,0.2,0A,0D +DAB,BBC National DAB 2B12,BBC National DAB,225648000,53.541535,-2.020635,347,0.6,2B,12 +DAB,BBC National DAB 1D06,BBC National DAB,225648000,51.055855,-1.806762,107,2,1D,06 +DAB,BBC National DAB 180A,BBC National DAB,225648000,52.413654,-1.513171,91,0.5,18,0A +DAB,BBC National DAB 0702,BBC National DAB,225648000,54.749109,-3.14076,363,9.54993,07,02 +DAB,BBC National DAB 1603,BBC National DAB,225648000,52.130132,-0.241462,54,4.88619,16,03 +DAB,BBC National DAB 4502,BBC National DAB,225648000,60.140298,-1.284513,72,0.1,45,02 +DAB,BBC National DAB 3204,BBC National DAB,225648000,53.57127,-0.670181,42,0.6,32,04 +DAB,BBC National DAB 3708,BBC National DAB,225648000,52.547739,-2.115424,225,0.006,37,08 +DAB,BBC National DAB 440D,BBC National DAB,225648000,55.555786,-2.793221,290,9.77237,44,0D +DAB,BBC National DAB 3909,BBC National DAB,225648000,55.80577,-4.466669,230,1,39,09 +DAB,BBC National DAB 1517,BBC National DAB,225648000,52.029722,0.290628,120,1,15,17 +DAB,BBC National DAB 0D15,BBC National DAB,225648000,51.025199,-2.188304,244,2,0D,15 +DAB,BBC National DAB 2D03,BBC National DAB,225648000,53.379385,-1.513809,247,4,2D,03 +DAB,BBC National DAB 4105,BBC National DAB,225648000,52.763046,-1.275729,91,0.06,41,05 +DAB,BBC National DAB 340B,BBC National DAB,225648000,55.366418,-1.700379,171,0.950001,34,0B +DAB,BBC National DAB 0E01,BBC National DAB,225648000,50.684407,-3.223662,112,0.1,0E,01 +DAB,BBC National DAB 2310,BBC National DAB,225648000,51.467762,-2.478188,70,0.018197,23,10 +DAB,BBC National DAB 3205,BBC National DAB,225648000,53.191837,0.178307,60,2,32,05 +DAB,BBC National DAB 3B07,BBC National DAB,225648000,54.563232,-0.895147,69,0.3,3B,07 +DAB,BBC National DAB 2E07,BBC National DAB,225648000,53.961373,-2.140639,162,1.6,2E,07 +DAB,BBC National DAB 3D10,BBC National DAB,225648000,57.38642,-6.24289,390,5,3D,10 +DAB,BBC National DAB 2212,BBC National DAB,225648000,50.263014,-3.662366,98,0.3,22,12 +DAB,BBC National DAB 3D08,BBC National DAB,225648000,55.91751,-5.462223,481,5,3D,08 +DAB,BBC National DAB 0613,BBC National DAB,225648000,51.540835,0.698653,33,0.024,06,13 +DAB,BBC National DAB 1E09,BBC National DAB,225648000,52.773292,-0.143159,3,0.069,1E,09 +DAB,BBC National DAB 0401,BBC National DAB,225648000,50.348174,-4.801267,188,0.900001,04,01 +DAB,BBC National DAB 0D01,BBC National DAB,225648000,50.759634,-1.799193,42,0.6,0D,01 +DAB,BBC National DAB 0411,BBC National DAB,225648000,50.171587,-5.44349,18,0.1,04,11 +DAB,BBC National DAB 2A04,BBC National DAB,225648000,53.406267,-2.981914,10,0.5,2A,04 +DAB,BBC National DAB 0410,BBC National DAB,225648000,50.140528,-5.664396,199,0.6,04,10 +DAB,BBC National DAB 0113,BBC National DAB,225648000,51.11386,0.259324,144,0.02,01,13 +DAB,BBC National DAB 0415,BBC National DAB,225648000,50.168461,-5.016083,81,0.5,04,15 +DAB,BBC National DAB 1E03,BBC National DAB,225648000,52.662748,-0.501852,58,0.15,1E,03 +DAB,BBC National DAB 200D,BBC National DAB,225648000,53.170195,-1.633756,305,1.5,20,0D +DAB,BBC National DAB 1B16,BBC National DAB,225648000,51.775824,-2.234753,250,1.2,1B,16 +DAB,BBC National DAB 0E0B,BBC National DAB,225648000,50.807088,-3.104951,227,5,0E,0B +DAB,BBC National DAB 2D02,BBC National DAB,225648000,53.48869,-1.586409,301,1.2,2D,02 +DAB,BBC National DAB 3302,BBC National DAB,225648000,52.574817,1.331664,65,4.88619,33,02 +DAB,BBC National DAB 1905,BBC National DAB,225648000,54.799414,-7.388644,274,1.6,19,05 +DAB,BBC National DAB 420D,BBC National DAB,225648000,54.928074,-4.949004,190,0.8,42,0D +DAB,BBC National DAB 0610,BBC National DAB,225648000,52.004239,0.784592,71,2.4,06,10 +DAB,BBC National DAB 1312,BBC National DAB,225648000,52.600539,-1.833856,169,10,13,12 +DAB,BBC National DAB 330E,BBC National DAB,225648000,52.634975,0.72369,50,4,33,0E +DAB,BBC National DAB 0114,BBC National DAB,225648000,51.137832,1.335758,122,1,01,14 +DAB,BBC National DAB 330D,BBC National DAB,225648000,52.518759,1.138705,64,3.53973,33,0D +DAB,BBC National DAB 2110,BBC National DAB,225648000,51.058123,-3.070536,130,1,21,10 +DAB,BBC National DAB 3C16,BBC National DAB,225648000,56.444566,-2.925027,100,0.6,3C,16 +DAB,BBC National DAB 2802,BBC National DAB,225648000,51.662111,-4.735117,85,0.6,28,02 +DAB,BBC National DAB 010A,BBC National DAB,225648000,51.36004,1.397292,49,0.668495,01,0A +DAB,BBC National DAB 3709,BBC National DAB,225648000,52.670935,-2.550228,396,4.88619,37,09 +DAB,BBC National DAB 3306,BBC National DAB,225648000,52.422601,0.741906,39,0.25,33,06 +DAB,BBC National DAB 4205,BBC National DAB,225648000,55.183241,-3.798481,324,0.6,42,05 +DAB,BBC National DAB 350B,BBC National DAB,225648000,53.003549,-2.055691,265,1.95447,35,0B +DAB,BBC National DAB 370E,BBC National DAB,225648000,52.397256,-2.592523,494,2,37,0E +DAB,BBC National DAB 0E0E,BBC National DAB,225648000,50.903183,-3.509706,142,0.2,0E,0E +DAB,BBC National DAB 2C05,BBC National DAB,225648000,53.713283,-2.065416,221,1,2C,05 +DAB,BBC National DAB 0204,BBC National DAB,225648000,50.961044,-1.454599,84,1,02,04 +DAB,BBC National DAB 2203,BBC National DAB,225648000,50.353472,-4.242037,108,0.6,22,03 +DAB,BBC National DAB 0A04,BBC National DAB,225648000,50.882048,-0.257307,211,1.8,0A,04 +DAB,BBC National DAB 0402,BBC National DAB,225648000,50.258036,-5.037597,58,0.5,04,02 +DAB,BBC National DAB 3E12,BBC National DAB,225648000,57.07283,-3.027203,463,0.6,3E,12 +DAB,BBC National DAB 1911,BBC National DAB,225648000,54.838485,-6.190049,208,0.6,19,11 +DAB,BBC National DAB 0110,BBC National DAB,225648000,51.172557,0.297815,124,3.1,01,10 +DAB,BBC National DAB 130F,BBC National DAB,225648000,52.496364,-2.048417,267,9.54993,13,0F +DAB,BBC National DAB 0111,BBC National DAB,225648000,51.068688,1.072375,1,0.1,01,11 +DAB,BBC National DAB 270D,BBC National DAB,225648000,51.754672,-3.773522,351,0.6,27,0D +DAB,BBC National DAB 020E,BBC National DAB,225648000,50.601933,-1.199325,227,0.6,02,0E +DAB,BBC National DAB 4110,BBC National DAB,225648000,52.801451,-0.80088,138,4.77496,41,10 +DAB,BBC National DAB 3103,BBC National DAB,225648000,52.037726,1.200836,32,1.2,31,03 +DAB,BBC National DAB 3404,BBC National DAB,225648000,54.74117,-1.961914,404,0.8,34,04 +DAB,BBC National DAB 1706,BBC National DAB,225648000,52.297367,-0.675082,43,0.017,17,06 +DAB,BBC National DAB 3314,BBC National DAB,225648000,52.941952,0.953868,32,2,33,14 +DAB,BBC National DAB 2401,BBC National DAB,225648000,51.459476,-3.282282,129,7.8179,24,01 +DAB,BBC National DAB 3312,BBC National DAB,225648000,52.743618,0.384937,4,0.6,33,12 +DAB,BBC National DAB 3307,BBC National DAB,225648000,52.924381,1.251171,99,1,33,07 +DAB,BBC National DAB 2C06,BBC National DAB,225648000,53.812989,-2.411689,172,0.3,2C,06 +DAB,BBC National DAB 3A16,BBC National DAB,225648000,53.932231,-1.699923,212,1,3A,16 +DAB,BBC National DAB 2E05,BBC National DAB,225648000,54.473215,-0.595572,60,0.933254,2E,05 +DAB,BBC National DAB 0704,BBC National DAB,225648000,54.496676,-3.557726,133,2,07,04 +DAB,BBC National DAB 0A0E,BBC National DAB,225648000,50.824954,-0.113611,120,2,0A,0E +DAB,BBC National DAB 3405,BBC National DAB,225648000,55.035277,-1.453767,40,0.01,34,05 +DAB,BBC National DAB 2C03,BBC National DAB,225648000,53.67893,-2.17406,335,0.1,2C,03 +DAB,BBC National DAB 3108,BBC National DAB,225648000,52.190371,0.547028,125,10,31,08 +DAB,BBC National DAB 1B02,BBC National DAB,225648000,51.957393,-1.947856,148,0.1,1B,02 +DAB,BBC National DAB 070B,BBC National DAB,225648000,54.37436,-2.951306,216,0.977237,07,0B +DAB,BBC National DAB 2B11,BBC National DAB,225648000,53.625547,-2.514794,439,10,2B,11 +DAB,BBC National DAB 0D05,BBC National DAB,225648000,50.845187,-2.230756,157,0.6,0D,05 +DAB,BBC National DAB 1E0D,BBC National DAB,225648000,52.655393,0.160854,4,0.1,1E,0D +DAB,BBC National DAB 3106,BBC National DAB,225648000,52.100123,1.315423,32,0.5,31,06 +DAB,BBC National DAB 2906,BBC National DAB,225648000,53.076278,-3.044994,210,1,29,06 +DAB,BBC National DAB 0107,BBC National DAB,225648000,51.320696,0.287702,219,10,01,07 +DAB,BBC National DAB 0109,BBC National DAB,225648000,51.187004,0.955865,98,0.5,01,09 +DAB,BBC National DAB 160E,BBC National DAB,225648000,51.877958,-0.483622,207,4.00667,16,0E +DAB,Berkshire and North Hampshire 0308,Berkshire and North Hampshire,229072000,51.226848,-1.080409,176,1,03,08 +DAB,Berkshire and North Hampshire 0314,Berkshire and North Hampshire,229072000,51.414004,-0.796112,90,0.977237,03,14 +DAB,Berkshire and North Hampshire 0310,Berkshire and North Hampshire,229072000,51.325875,-0.81306,95,0.3,03,10 +DAB,Berkshire and North Hampshire 030C,Berkshire and North Hampshire,229072000,51.307873,-1.244777,220,1,03,0C +DAB,Berkshire and North Hampshire 030D,Berkshire and North Hampshire,229072000,51.481196,-0.978531,69,0.98,03,0D +DAB,Berkshire and North Hampshire 0301,Berkshire and North Hampshire,229072000,51.278623,-1.489559,215,0.4,03,01 +DAB,Berkshire and North Hampshire 030A,Berkshire and North Hampshire,229072000,51.548667,-0.775255,85,1,03,0A +DAB,Berkshire and North Hampshire 030E,Berkshire and North Hampshire,229072000,51.484903,-1.558836,211,1,03,0E +DAB,Berkshire and North Hampshire 030B,Berkshire and North Hampshire,229072000,51.414621,-1.290472,130,1,03,0B +DAB,Birmingham 1303,Birmingham,220352000,52.473153,-1.919722,152,0.3,13,03 +DAB,Birmingham 1301,Birmingham,220352000,52.294535,-1.946877,162,0.3,13,01 +DAB,Birmingham 1305,Birmingham,220352000,52.63655,-1.759098,145,2.5,13,05 +DAB,Birmingham 1302,Birmingham,220352000,52.375278,-2.013764,280,1,13,02 +DAB,Birmingham 130B,Birmingham,220352000,52.547739,-2.115424,225,0.3,13,0B +DAB,Birmingham 130F,Birmingham,220352000,52.496364,-2.048417,267,2,13,0F +DAB,Blackpool small-scale ,Blackpool small-scale,197648000,53.815794,-3.055258,11,0.1,, +DAB,Bournemouth 0D03,Bournemouth,218640000,50.66283,-2.443645,160,0.977237,0D,03 +DAB,Bournemouth 0D08,Bournemouth,218640000,50.629952,-1.987364,196,1,0D,08 +DAB,Bournemouth 0D07,Bournemouth,218640000,50.729221,-1.948658,64,0.693838,0D,07 +DAB,Bournemouth 0D15,Bournemouth,218640000,51.025199,-2.188304,244,0.5,0D,15 +DAB,Bournemouth 0D01,Bournemouth,218640000,50.759634,-1.799193,42,1,0D,01 +DAB,Bournemouth 0D05,Bournemouth,218640000,50.845187,-2.230756,157,1.20226,0D,05 +DAB,Bradford small-scale 3A06,Bradford small-scale,197648000,53.844699,-1.778397,108,0.05,3A,06 +DAB,Bradford small-scale 3A17,Bradford small-scale,197648000,53.820579,-1.728063,210,0.035,3A,17 +DAB,Bradford small-scale 3A15,Bradford small-scale,197648000,53.802804,-1.73744,183,0.1,3A,15 +DAB,Bradfrd&Huddersf 3A0A,Bradfrd&Huddersf,218640000,53.674328,-1.813774,257,1,3A,0A +DAB,Bradfrd&Huddersf 2E14,Bradfrd&Huddersf,218640000,53.611985,-1.66456,256,0.069994,2E,14 +DAB,Bradfrd&Huddersf 3A04,Bradfrd&Huddersf,218640000,53.533184,-1.858296,524,0.199526,3A,04 +DAB,Bradfrd&Huddersf 3A08,Bradfrd&Huddersf,218640000,53.832945,-1.752142,215,0.3,3A,08 +DAB,Bradfrd&Huddersf 3A0C,Bradfrd&Huddersf,218640000,53.895532,-1.896639,305,1,3A,0C +DAB,Bradfrd&Huddersf 3A11,Bradfrd&Huddersf,218640000,53.720111,-1.92874,256,1,3A,11 +DAB,Bradfrd&Huddersf 3A13,Bradfrd&Huddersf,218640000,53.761891,-1.692037,220,1.61,3A,13 +DAB,Bristol 2303,Bristol,218640000,51.441961,-2.722947,96,0.3,23,03 +DAB,Bristol 230E,Bristol,218640000,51.38779,-2.332925,175,0.977237,23,0E +DAB,Bristol 230B,Bristol,218640000,51.494699,-2.65363,90,0.3,23,0B +DAB,Bristol 230D,Bristol,218640000,51.392229,-2.630897,213,4,23,0D +DAB,Bristol 230C,Bristol,218640000,51.325227,-2.918301,73,2,23,0C +DAB,Bristol 2307,Bristol,218640000,51.608719,-2.485155,106,1.20226,23,07 +DAB,Bristol 230F,Bristol,218640000,51.48519,-2.562764,91,1,23,0F +DAB,Bristol 2310,Bristol,218640000,51.467762,-2.478188,70,0.6,23,10 +DAB,Cambridge 150F,Cambridge,220352000,52.213666,0.462135,110,2.4,15,0F +DAB,Cambridge 1507,Cambridge,220352000,52.412282,0.279524,22,1,15,07 +DAB,Cambridge 1506,Cambridge,220352000,52.215394,0.036667,62,2,15,06 +DAB,Cambridge 150B,Cambridge,220352000,52.130132,-0.241462,54,1.2,15,0B +DAB,Cambridge 1517,Cambridge,220352000,52.029722,0.290628,120,1,15,17 +DAB,Cambridge small-scale ,Cambridge small-scale,206352000,52.209429,0.14983,10,0.1,, +DAB,Cambridge small-scale ,Cambridge small-scale,206352000,52.158186,0.178647,72,0.075,, +DAB,Cardiff small-scale 240D,Cardiff small-scale,215072000,51.410121,-3.281189,82,0.07,24,0D +DAB,Cardiff small-scale 240E,Cardiff small-scale,215072000,51.50502,-3.165988,56,0.07,24,0E +DAB,Cardiff small-scale 2417,Cardiff small-scale,215072000,51.604177,-3.122175,360,0.025,24,17 +DAB,Central Scotland 3F0F,Central Scotland,222064000,55.912262,-3.200598,202,0.977237,3F,0F +DAB,Central Scotland 390E,Central Scotland,222064000,55.825353,-4.290679,67,0.01,39,0E +DAB,Central Scotland 3F02,Central Scotland,222064000,56.071791,-3.233186,181,0.780001,3F,02 +DAB,Central Scotland 3F05,Central Scotland,222064000,55.579376,-4.289814,286,0.5,3F,05 +DAB,Central Scotland 3F06,Central Scotland,222064000,56.071792,-4.055753,410,0.73,3F,06 +DAB,Central Scotland 390B,Central Scotland,222064000,55.886844,-4.294621,26,0.01,39,0B +DAB,Central Scotland 3F13,Central Scotland,222064000,55.861436,-4.268991,16,0.3,3F,13 +DAB,Central Scotland 3F01,Central Scotland,222064000,55.852721,-3.826093,277,1.79539,3F,01 +DAB,Central Scotland 3F03,Central Scotland,222064000,55.80577,-4.466669,230,0.947999,3F,03 +DAB,Channel Islands 1F01,Channel Islands,223936000,49.726408,-2.185861,52,0.2,1F,01 +DAB,Channel Islands 1001,Channel Islands,223936000,49.246023,-2.1012,134,2,10,01 +DAB,Channel Islands 1102,Channel Islands,223936000,49.457792,-2.579202,76,0.5,11,02 +DAB,Clevedon Avonmouth and Filton small-scale 2411,Clevedon Avonmouth and Filton small-scale,229072000,51.501345,-2.549924,75,0.1,24,11 +DAB,Clevedon Avonmouth and Filton small-scale 2412,Clevedon Avonmouth and Filton small-scale,229072000,51.494699,-2.65363,90,0.079816,24,12 +DAB,Cornwall 040A,Cornwall,218640000,50.82768,-4.530383,47,0.293171,04,0A +DAB,Cornwall 0405,Cornwall,218640000,50.511364,-4.43683,369,5,04,05 +DAB,Cornwall 0404,Cornwall,218640000,50.13053,-5.53431,62,0.3,04,04 +DAB,Cornwall 0416,Cornwall,218640000,50.101857,-5.285607,71,1,04,16 +DAB,Cornwall 0414,Cornwall,218640000,50.402798,-5.053886,62,0.5,04,14 +DAB,Cornwall 040B,Cornwall,218640000,50.550217,-4.008413,508,3.2,04,0B +DAB,Cornwall 0413,Cornwall,218640000,50.481389,-4.782638,116,1.2,04,13 +DAB,Cornwall 0403,Cornwall,218640000,50.209786,-5.238489,237,4.88619,04,03 +DAB,Cornwall 0401,Cornwall,218640000,50.348174,-4.801267,188,0.900001,04,01 +DAB,Cornwall 0410,Cornwall,218640000,50.140528,-5.664396,199,0.6,04,10 +DAB,Cornwall 0415,Cornwall,218640000,50.168461,-5.016083,81,0.5,04,15 +DAB,Cornwall 0402,Cornwall,218640000,50.258036,-5.037597,58,0.5,04,02 +DAB,Coventry 180D,Coventry,229072000,52.568941,-1.334553,125,0.5031,18,0D +DAB,Coventry 1803,Coventry,229072000,52.253028,-1.139914,199,1,18,03 +DAB,Coventry 1814,Coventry,229072000,52.540463,-1.503661,140,0.5,18,14 +DAB,Coventry 1817,Coventry,229072000,52.081402,-1.715399,228,2,18,17 +DAB,Coventry 1806,Coventry,229072000,52.294288,-1.519026,90,0.5,18,06 +DAB,Coventry 180C,Coventry,229072000,52.455227,-1.6222,184,0.5,18,0C +DAB,Coventry 180A,Coventry,229072000,52.413654,-1.513171,91,0.5,18,0A +DAB,Coventry 1807,Coventry,229072000,52.450069,-1.397116,106,0.5,18,07 +DAB,Coventry small-scale ,Coventry small-scale,204640000,52.413553,-1.510526,92,0.06,, +DAB,D1 National 0B02,D1 National,222064000,51.594459,-0.129257,92,2,0B,02 +DAB,D1 National 3502,D1 National,222064000,53.027231,-2.28071,220,2,35,02 +DAB,D1 National 3C08,D1 National,223936000,56.555053,-2.986125,312,10,3C,08 +DAB,D1 National 3C03,D1 National,223936000,56.711856,-2.671353,130,0.045,3C,03 +DAB,D1 National 0502,D1 National,222064000,53.01985,-4.273475,300,1.85675,05,02 +DAB,D1 National 1908,D1 National,222064000,54.342402,-6.629562,109,5,19,08 +DAB,D1 National 1606,D1 National,222064000,51.819509,-0.811742,81,0.03,16,06 +DAB,D1 National 1914,D1 National,222064000,54.661435,-5.675928,21,0.024,19,14 +DAB,D1 National 0308,D1 National,222064000,51.226848,-1.080409,176,1,03,08 +DAB,D1 National 230E,D1 National,222064000,51.38779,-2.332925,175,0.977237,23,0E +DAB,D1 National 0E07,D1 National,222064000,50.447129,-3.610498,196,2.89309,0E,07 +DAB,D1 National 3A09,D1 National,222064000,53.811543,-1.641253,149,0.977237,3A,09 +DAB,D1 National 3202,D1 National,222064000,53.335814,-0.171983,125,4.45625,32,02 +DAB,D1 National 0614,D1 National,222064000,51.550856,0.5811,80,0.089125,06,14 +DAB,D1 National 3B02,D1 National,222064000,54.358848,-1.149317,381,2,3B,02 +DAB,D1 National 0D03,D1 National,222064000,50.66283,-2.443645,160,1.56358,0D,03 +DAB,D1 National 2C07,D1 National,222064000,53.809005,-3.05038,6,0.036308,2C,07 +DAB,D1 National 280D,D1 National,222064000,52.360613,-4.102585,174,1.4,28,0D +DAB,D1 National 0115,D1 National,222064000,51.324006,0.520684,192,8.2,01,15 +DAB,D1 National 1A0B,D1 National,222064000,51.609363,-1.794027,148,3.98107,1A,0B +DAB,D1 National 3107,D1 National,222064000,52.311386,1.598136,22,0.1,31,07 +DAB,D1 National 3203,D1 National,222064000,52.962367,-0.015354,3,0.03,32,03 +DAB,D1 National 1609,D1 National,222064000,51.998806,-0.669784,169,2.37123,16,09 +DAB,D1 National 4312,D1 National,223936000,55.912262,-3.200598,202,0.977237,43,12 +DAB,D1 National 0E0A,D1 National,222064000,50.395927,-3.518996,50,0.03,0E,0A +DAB,D1 National 1C04,D1 National,222064000,52.355115,-2.078214,147,1.46585,1C,04 +DAB,D1 National 0B0A,D1 National,222064000,51.727838,-0.176464,127,1.29,0B,0A +DAB,D1 National 1903,D1 National,222064000,54.423191,-7.462812,305,3.2,19,03 +DAB,D1 National 400E,D1 National,223936000,55.409586,-4.699754,273,2.4,40,0E +DAB,D1 National 0817,D1 National,222064000,51.521504,-0.138879,27,0.8,08,17 +DAB,D1 National 2F0C,D1 National,222064000,54.124979,-0.218986,105,1.2,2F,0C +DAB,D1 National 0A02,D1 National,222064000,50.909654,-0.627813,245,0.126575,0A,02 +DAB,D1 National 330C,D1 National,222064000,52.659164,1.715858,17,0.025,33,0C +DAB,D1 National 0709,D1 National,222064000,54.773382,-3.091075,289,2.7819,07,09 +DAB,D1 National 3415,D1 National,222064000,54.969789,-1.608675,15,0.025,34,15 +DAB,D1 National 190A,D1 National,222064000,54.160861,-6.385716,340,3,19,0A +DAB,D1 National 0405,D1 National,222064000,50.511364,-4.43683,369,2,04,05 +DAB,D1 National 2707,D1 National,222064000,51.818501,-4.066216,255,1,27,07 +DAB,D1 National 1909,D1 National,222064000,54.676355,-5.928737,207,1,19,09 +DAB,D1 National 080D,D1 National,222064000,51.263565,-0.086822,226,0.14,08,0D +DAB,D1 National 390E,D1 National,223936000,55.825353,-4.290679,67,0.01,39,0E +DAB,D1 National 010B,D1 National,222064000,51.265673,1.013529,67,0.4,01,0B +DAB,D1 National 0316,D1 National,222064000,51.6119,-0.734849,142,0.6,03,16 +DAB,D1 National 1604,D1 National,222064000,51.697895,-0.618141,127,0.1,16,04 +DAB,D1 National 2D12,D1 National,222064000,53.283991,-1.427446,179,1,2D,12 +DAB,D1 National 150F,D1 National,222064000,52.213666,0.462135,110,0.1,15,0F +DAB,D1 National 0211,D1 National,222064000,50.649245,-1.328934,166,5,02,11 +DAB,D1 National 2404,D1 National,222064000,51.601588,-2.935417,94,2,24,04 +DAB,D1 National 1B11,D1 National,222064000,51.868264,-2.175397,147,3.06,1B,11 +DAB,D1 National 1B0A,D1 National,222064000,51.750794,-1.994303,184,0.035,1B,0A +DAB,D1 National 0601,D1 National,222064000,51.803409,1.165049,7,0.012,06,01 +DAB,D1 National 2D0A,D1 National,222064000,53.346243,-0.886897,62,0.07,2D,0A +DAB,D1 National 2116,D1 National,222064000,50.916513,-2.700119,134,2,21,16 +DAB,D1 National 0605,D1 National,222064000,51.917174,0.925798,45,0.4437,06,05 +DAB,D1 National 0808,D1 National,222064000,51.58316,-0.247792,46,0.3,08,08 +DAB,D1 National 0314,D1 National,222064000,51.414004,-0.796112,90,0.488619,03,14 +DAB,D1 National 4111,D1 National,222064000,52.710153,-1.285042,240,1.5,41,11 +DAB,D1 National 0210,D1 National,222064000,51.063167,-1.360216,158,0.6,02,10 +DAB,D1 National 3F02,D1 National,223936000,56.071791,-3.233186,181,6.75,3F,02 +DAB,D1 National 0B01,D1 National,222064000,51.424161,-0.074944,110,6.15971,0B,01 +DAB,D1 National 0616,D1 National,222064000,51.719492,0.58056,105,2,06,16 +DAB,D1 National ,D1 National,222064000,51.469253,0.260425,3,1e-05,, +DAB,D1 National 400A,D1 National,223936000,55.579376,-4.289814,286,7,40,0A +DAB,D1 National 2C02,D1 National,222064000,53.696571,-2.443266,261,0.028184,2C,02 +DAB,D1 National 1702,D1 National,222064000,52.253028,-1.139914,199,9.26343,17,02 +DAB,D1 National 1901,D1 National,222064000,54.607538,-6.009471,368,9.54993,19,01 +DAB,D1 National 2D06,D1 National,222064000,53.531884,-1.091294,7,0.022,2D,06 +DAB,D1 National 0102,D1 National,222064000,51.11163,1.247272,133,1.44544,01,02 +DAB,D1 National 3311,D1 National,222064000,52.608286,0.367383,5,0.0337,33,11 +DAB,D1 National 230D,D1 National,222064000,51.392229,-2.630897,213,2,23,0D +DAB,D1 National 010D,D1 National,222064000,51.292731,0.979008,122,2,01,0D +DAB,D1 National 3416,D1 National,222064000,54.775175,-1.590656,100,0.03,34,16 +DAB,D1 National 3E07,D1 National,223936000,56.999987,-2.389944,325,10,3E,07 +DAB,D1 National 3F06,D1 National,223936000,56.071792,-4.055753,410,2,3F,06 +DAB,D1 National 0A01,D1 National,222064000,50.764511,0.288682,11,1,0A,01 +DAB,D1 National 2402,D1 National,222064000,51.611393,-3.302735,381,0.6,24,02 +DAB,D1 National 1507,D1 National,222064000,52.412282,0.279524,22,0.04,15,07 +DAB,D1 National 2E14,D1 National,222064000,53.611985,-1.66456,256,6.0256,2E,14 +DAB,D1 National 0811,D1 National,222064000,51.361981,-0.349183,24,0.3,08,11 +DAB,D1 National 3B,D1 National,222064000,54.556455,-1.120934,237,0.8,3B, +DAB,D1 National 0E09,D1 National,222064000,50.719122,-3.562148,102,3.75,0E,09 +DAB,D1 National 010C,D1 National,222064000,51.305892,0.873532,33,0.691831,01,0C +DAB,D1 National 3403,D1 National,222064000,54.978039,-1.662966,120,1.4,34,03 +DAB,D1 National 300A,D1 National,222064000,53.140513,-1.232922,168,1,30,0A +DAB,D1 National 0208,D1 National,222064000,50.853922,-1.067587,102,0.5,02,08 +DAB,D1 National 0213,D1 National,222064000,50.877178,-1.278479,50,0.03,02,13 +DAB,D1 National 390B,D1 National,223936000,55.886844,-4.294621,26,0.01,39,0B +DAB,D1 National 3902,D1 National,223936000,55.861436,-4.268991,16,0.3,39,02 +DAB,D1 National 2B09,D1 National,222064000,53.455242,-1.960506,262,0.050119,2B,09 +DAB,D1 National 3309,D1 National,222064000,52.773873,0.649768,92,1.25,33,09 +DAB,D1 National 3303,D1 National,222064000,52.602996,1.722916,1,0.4,33,03 +DAB,D1 National 0C16,D1 National,222064000,51.228358,-0.605467,142,4.88619,0C,16 +DAB,D1 National 0404,D1 National,222064000,50.13053,-5.53431,62,0.013,04,04 +DAB,D1 National 030C,D1 National,222064000,51.307873,-1.244777,220,5,03,0C +DAB,D1 National 060B,D1 National,222064000,51.739903,0.097485,110,0.25,06,0B +DAB,D1 National 0803,D1 National,222064000,51.622949,-0.356487,125,0.3,08,03 +DAB,D1 National 0A06,D1 National,222064000,50.861622,0.566431,76,1,0A,06 +DAB,D1 National 2801,D1 National,222064000,51.899195,-4.86653,186,1,28,01 +DAB,D1 National 3304,D1 National,222064000,52.893823,0.496359,20,0.06,33,04 +DAB,D1 National 1301,D1 National,222064000,52.294535,-1.946877,162,0.011,13,01 +DAB,D1 National 0A07,D1 National,222064000,50.976724,0.230437,158,2.2,0A,07 +DAB,D1 National 030D,D1 National,222064000,51.481196,-0.978531,69,1,03,0D +DAB,D1 National 1612,D1 National,222064000,51.728571,-0.426217,142,3.12716,16,12 +DAB,D1 National 3409,D1 National,222064000,54.893895,-1.363068,10,0.794328,34,09 +DAB,D1 National 2F07,D1 National,222064000,53.803052,-0.565371,164,2,2F,07 +DAB,D1 National 0E0C,D1 National,222064000,50.566699,-3.506408,205,0.5,0E,0C +DAB,D1 National 3A04,D1 National,222064000,53.533184,-1.858296,524,4.68,3A,04 +DAB,D1 National 0A09,D1 National,222064000,51.064289,-0.321546,53,0.025,0A,09 +DAB,D1 National 4115,D1 National,222064000,52.63314,-1.002896,153,1.2,41,15 +DAB,D1 National 0C01,D1 National,222064000,51.234232,-0.820719,179,1,0C,01 +DAB,D1 National 0E08,D1 National,222064000,50.979244,-4.098818,200,4.55,0E,08 +DAB,D1 National 2E0B,D1 National,222064000,53.832945,-1.752142,215,1,2E,0B +DAB,D1 National 3A0C,D1 National,222064000,53.895532,-1.896639,305,3,3A,0C +DAB,D1 National 0707,D1 National,222064000,54.314559,-2.708127,172,2.9,07,07 +DAB,D1 National 3411,D1 National,222064000,55.001052,-1.665743,120,0.01,34,11 +DAB,D1 National 1C06,D1 National,222064000,52.363252,-2.282794,82,0.087,1C,06 +DAB,D1 National 2703,D1 National,222064000,51.62891,-3.919745,193,1,27,03 +DAB,D1 National 3F01,D1 National,223936000,55.852721,-3.826093,277,4.77496,3F,01 +DAB,D1 National 3C09,D1 National,223936000,56.372293,-3.453361,178,1.90561,3C,09 +DAB,D1 National 2C0E,D1 National,222064000,54.089336,-2.779963,88,1.95447,2C,0E +DAB,D1 National 1808,D1 National,222064000,52.081613,-1.728531,260,3.23594,18,08 +DAB,D1 National 0812,D1 National,222064000,51.319591,-0.372374,60,1.5,08,12 +DAB,D1 National 4108,D1 National,222064000,52.637434,-1.125451,57,0.03,41,08 +DAB,D1 National 160D,D1 National,222064000,51.981709,-0.201702,82,0.025,16,0D +DAB,D1 National 1907,D1 National,222064000,55.109172,-6.886121,341,6.30001,19,07 +DAB,D1 National 3209,D1 National,222064000,53.205578,-0.546174,15,0.06,32,09 +DAB,D1 National 0501,D1 National,222064000,53.307002,-4.12825,146,0.977237,05,01 +DAB,D1 National 1904,D1 National,222064000,55.00421,-7.368968,175,6.2,19,04 +DAB,D1 National 1506,D1 National,222064000,52.215394,0.036667,62,1,15,06 +DAB,D1 National 030A,D1 National,222064000,51.548667,-0.775255,85,0.025,03,0A +DAB,D1 National 1A05,D1 National,222064000,51.591795,-2.089739,91,0.02,1A,05 +DAB,D1 National 2B06,D1 National,222064000,53.480177,-2.23864,43,0.5,2B,06 +DAB,D1 National 060F,D1 National,222064000,51.92387,1.086097,35,1,06,0F +DAB,D1 National 3008,D1 National,222064000,52.976309,-1.132626,122,1,30,08 +DAB,D1 National 3707,D1 National,222064000,52.905093,-2.493571,100,0.033884,37,07 +DAB,D1 National 1A13,D1 National,222064000,51.417912,-1.699977,192,0.2,1A,13 +DAB,D1 National 2302,D1 National,222064000,51.236969,-2.625476,303,4.88619,23,02 +DAB,D1 National 310E,D1 National,222064000,52.234496,1.107319,64,1,31,0E +DAB,D1 National 0A0A,D1 National,222064000,51.017054,-0.70092,185,1.8,0A,0A +DAB,D1 National 2903,D1 National,222064000,53.220944,-3.31452,336,9.50001,29,03 +DAB,D1 National 0705,D1 National,222064000,54.202505,-3.167346,259,2.8,07,05 +DAB,D1 National 3A10,D1 National,222064000,53.736807,-1.572457,120,1,3A,10 +DAB,D1 National 0B0F,D1 National,222064000,51.615389,-0.448479,105,0.1,0B,0F +DAB,D1 National 3803,D1 National,223936000,57.591626,-4.27683,212,10,38,03 +DAB,D1 National 1D09,D1 National,222064000,51.416202,-2.076595,175,1.90999,1D,09 +DAB,D1 National 0A03,D1 National,222064000,50.787726,0.035848,81,0.977237,0A,03 +DAB,D1 National 1913,D1 National,222064000,54.590668,-5.677949,20,0.015,19,13 +DAB,D1 National 0D08,D1 National,222064000,50.629952,-1.987364,196,1,0D,08 +DAB,D1 National 220F,D1 National,222064000,50.550217,-4.008413,508,3.2,22,0F +DAB,D1 National 3006,D1 National,222064000,52.986825,-1.251436,129,0.03,30,06 +DAB,D1 National 0C05,D1 National,222064000,51.242524,-0.945288,115,1,0C,05 +DAB,D1 National 2E01,D1 National,222064000,54.267351,-0.404494,151,2,2E,01 +DAB,D1 National 3301,D1 National,222064000,52.486385,1.715554,8,0.501187,33,01 +DAB,D1 National 120E,D1 National,222064000,51.790638,-1.179183,130,7.4012,12,0E +DAB,D1 National 2C0D,D1 National,222064000,53.841893,-2.266074,276,2.029,2C,0D +DAB,D1 National 0706,D1 National,222064000,54.674729,-2.728805,263,2,07,06 +DAB,D1 National 1E01,D1 National,222064000,52.507615,-0.343282,56,4.88619,1E,01 +DAB,D1 National 1614,D1 National,222064000,51.915442,-0.184286,133,0.06,16,14 +DAB,D1 National 2204,D1 National,222064000,50.381346,-4.067802,113,1.95447,22,04 +DAB,D1 National 3401,D1 National,222064000,54.868838,-1.771233,302,6.01646,34,01 +DAB,D1 National 2805,D1 National,222064000,51.944404,-4.661027,323,1.69824,28,05 +DAB,D1 National 230F,D1 National,222064000,51.48519,-2.562764,91,1,23,0F +DAB,D1 National 310A,D1 National,222064000,52.290839,0.777315,69,1.8,31,0A +DAB,D1 National 3E13,D1 National,223936000,57.113656,-2.096244,87,1.2,3E,13 +DAB,D1 National 0403,D1 National,222064000,50.209786,-5.238489,237,1.28995,04,03 +DAB,D1 National 0B05,D1 National,222064000,51.254494,-0.200986,234,0.954993,0B,05 +DAB,D1 National 0813,D1 National,222064000,51.451704,-0.297446,40,0.3,08,13 +DAB,D1 National 1C01,D1 National,222064000,51.997433,-2.53989,204,5,1C,01 +DAB,D1 National 390C,D1 National,223936000,55.991937,-4.793795,107,0.6,39,0C +DAB,D1 National 2B12,D1 National,222064000,53.541535,-2.020635,347,0.6,2B,12 +DAB,D1 National 1D06,D1 National,222064000,51.055855,-1.806762,107,1.9,1D,06 +DAB,D1 National 180A,D1 National,222064000,52.413654,-1.513171,91,0.5,18,0A +DAB,D1 National 1603,D1 National,222064000,52.130132,-0.241462,54,4.59302,16,03 +DAB,D1 National 3204,D1 National,222064000,53.57127,-0.670181,42,0.077,32,04 +DAB,D1 National 3708,D1 National,222064000,52.547739,-2.115424,225,0.6,37,08 +DAB,D1 National 440D,D1 National,223936000,55.555786,-2.793221,290,9.77237,44,0D +DAB,D1 National 3909,D1 National,223936000,55.80577,-4.466669,230,0.913,39,09 +DAB,D1 National 1517,D1 National,222064000,52.029722,0.290628,120,1,15,17 +DAB,D1 National 2D03,D1 National,222064000,53.379385,-1.513809,247,2.69154,2D,03 +DAB,D1 National 4105,D1 National,222064000,52.763046,-1.275729,91,0.06,41,05 +DAB,D1 National 0E01,D1 National,222064000,50.684407,-3.223662,112,0.0302,0E,01 +DAB,D1 National 2310,D1 National,222064000,51.467762,-2.478188,70,0.02,23,10 +DAB,D1 National 0613,D1 National,222064000,51.540835,0.698653,33,0.024,06,13 +DAB,D1 National 1E09,D1 National,222064000,52.773292,-0.143159,3,0.07,1E,09 +DAB,D1 National 2A04,D1 National,222064000,53.406267,-2.981914,10,0.5,2A,04 +DAB,D1 National 0113,D1 National,222064000,51.11386,0.259324,144,0.02,01,13 +DAB,D1 National 080B,D1 National,222064000,51.43569,-0.508094,16,0.3,08,0B +DAB,D1 National 1E03,D1 National,222064000,52.662748,-0.501852,58,0.036,1E,03 +DAB,D1 National 0E0B,D1 National,222064000,50.807088,-3.104951,227,2,0E,0B +DAB,D1 National 3302,D1 National,222064000,52.574817,1.331664,65,1.07496,33,02 +DAB,D1 National 1905,D1 National,222064000,54.799414,-7.388644,274,1.6,19,05 +DAB,D1 National 0610,D1 National,222064000,52.004239,0.784592,71,2.39883,06,10 +DAB,D1 National 1312,D1 National,222064000,52.600539,-1.833856,169,8.73,13,12 +DAB,D1 National 330E,D1 National,222064000,52.634975,0.72369,50,0.17,33,0E +DAB,D1 National 0114,D1 National,222064000,51.137832,1.335758,122,1,01,14 +DAB,D1 National 330D,D1 National,222064000,52.518759,1.138705,64,2.83178,33,0D +DAB,D1 National 2110,D1 National,222064000,51.058123,-3.070536,130,1,21,10 +DAB,D1 National 010A,D1 National,222064000,51.36004,1.397292,49,0.381997,01,0A +DAB,D1 National 3709,D1 National,222064000,52.670935,-2.550228,396,7.8179,37,09 +DAB,D1 National 0204,D1 National,222064000,50.961044,-1.454599,84,0.5,02,04 +DAB,D1 National 2203,D1 National,222064000,50.353472,-4.242037,108,0.6,22,03 +DAB,D1 National 0A04,D1 National,222064000,50.882048,-0.257307,211,1.8,0A,04 +DAB,D1 National 0110,D1 National,222064000,51.172557,0.297815,124,1.46,01,10 +DAB,D1 National 130F,D1 National,222064000,52.496364,-2.048417,267,9.54993,13,0F +DAB,D1 National 0111,D1 National,222064000,51.068688,1.072375,1,0.01,01,11 +DAB,D1 National 4110,D1 National,222064000,52.801451,-0.80088,138,8.40394,41,10 +DAB,D1 National 3103,D1 National,222064000,52.037726,1.200836,32,1.2,31,03 +DAB,D1 National 1706,D1 National,222064000,52.297367,-0.675082,43,0.02,17,06 +DAB,D1 National 2401,D1 National,222064000,51.459476,-3.282282,129,8.79514,24,01 +DAB,D1 National 3312,D1 National,222064000,52.743618,0.384937,4,0.03,33,12 +DAB,D1 National 1D04,D1 National,222064000,51.336803,-2.264225,87,0.0978,1D,04 +DAB,D1 National 2C06,D1 National,222064000,53.812989,-2.411689,172,0.03,2C,06 +DAB,D1 National 2E05,D1 National,222064000,54.473215,-0.595572,60,1,2E,05 +DAB,D1 National 0704,D1 National,222064000,54.496676,-3.557726,133,1.95,07,04 +DAB,D1 National 0A0E,D1 National,222064000,50.824954,-0.113611,120,0.870964,0A,0E +DAB,D1 National 3405,D1 National,222064000,55.035277,-1.453767,40,0.01,34,05 +DAB,D1 National 2B11,D1 National,222064000,53.625547,-2.514794,439,10,2B,11 +DAB,D1 National 1E0D,D1 National,222064000,52.655393,0.160854,4,0.015,1E,0D +DAB,D1 National 0701,D1 National,222064000,54.635112,-3.548915,37,1,07,01 +DAB,D1 National 0107,D1 National,222064000,51.320696,0.287702,219,4.5,01,07 +DAB,D1 National 0109,D1 National,222064000,51.187004,0.955865,98,0.5,01,09 +DAB,D1 National 160E,D1 National,222064000,51.877958,-0.483622,207,3.12716,16,0E +DAB,Derbyshire 200C,Derbyshire,211648000,53.094354,-1.561526,315,0.6,20,0C +DAB,Derbyshire 2016,Derbyshire,211648000,52.63655,-1.759098,145,5,20,16 +DAB,Derbyshire 2004,Derbyshire,211648000,52.973416,-1.507057,125,3,20,04 +DAB,Derbyshire 200D,Derbyshire,211648000,53.170195,-1.633756,305,1.6,20,0D +DAB,Derry/Londonderry small-scale ,Derry/Londonderry small-scale,220352000,54.82055,-7.440534,123,0.1,, +DAB,Derry/Londonderry small-scale ,Derry/Londonderry small-scale,220352000,55.004444,-7.365259,160,0.2,, +DAB,Devon 0E17,Devon,220352000,50.505425,-3.752519,156,0.1,0E,17 +DAB,Devon 0E03,Devon,213360000,51.040763,-4.13826,116,0.6,0E,03 +DAB,Devon 0E07,Devon,220352000,50.447129,-3.610498,196,5,0E,07 +DAB,Devon 0E12,Devon,213360000,51.111834,-4.151684,95,0.6,0E,12 +DAB,Devon 0E0A,Devon,220352000,50.395927,-3.518996,50,0.3,0E,0A +DAB,Devon 0E13,Devon,220352000,50.634311,-3.354151,102,0.6,0E,13 +DAB,Devon 0E09,Devon,220352000,50.719122,-3.562148,102,1,0E,09 +DAB,Devon 0E0C,Devon,220352000,50.566699,-3.506408,205,0.5,0E,0C +DAB,Devon 0E08,Devon,213360000,50.979244,-4.098818,200,3.90895,0E,08 +DAB,Devon 0E14,Devon,213360000,51.197967,-4.138233,203,0.3,0E,14 +DAB,Devon 0E10,Devon,220352000,50.349538,-3.565025,107,0.4,0E,10 +DAB,Devon 0E02,Devon,213360000,50.753618,-4.005483,208,0.3,0E,02 +DAB,Devon 0E01,Devon,220352000,50.684407,-3.223662,112,0.3,0E,01 +DAB,Devon 0E0B,Devon,220352000,50.807088,-3.104951,227,5,0E,0B +DAB,Devon 0E0E,Devon,220352000,50.903183,-3.509706,142,0.3,0E,0E +DAB,Dudley-Sbridge small-scale ,Dudley-Sbridge small-scale,195936000,52.479497,-2.124668,162,0.12,, +DAB,Dudley-Sbridge small-scale ,Dudley-Sbridge small-scale,195936000,52.508028,-2.08762,202,0.05,, +DAB,East Bristol small-scale 2315,East Bristol small-scale,204640000,51.434452,-2.568038,67,0.015,23,15 +DAB,East Bristol small-scale 2313,East Bristol small-scale,204640000,51.456323,-2.608393,57,0.018,23,13 +DAB,East Bristol small-scale 2308,East Bristol small-scale,204640000,51.392699,-2.47831,98,0.057963,23,08 +DAB,Edinburgh 4315,Edinburgh,229072000,55.974965,-2.776943,175,1,43,15 +DAB,Edinburgh 4308,Edinburgh,229072000,55.860005,-3.873572,275,2.4,43,08 +DAB,Edinburgh 4312,Edinburgh,229072000,55.912262,-3.200598,202,0.977237,43,12 +DAB,Edinburgh 430C,Edinburgh,229072000,56.071791,-3.233186,181,6,43,0C +DAB,Edinburgh 430D,Edinburgh,229072000,56.071792,-4.055753,410,0.74,43,0D +DAB,Edinburgh 4309,Edinburgh,229072000,55.948651,-3.200764,121,0.0272,43,09 +DAB,Edinburgh 4307,Edinburgh,229072000,56.126954,-3.523569,355,1.58,43,07 +DAB,Edinburgh 4306,Edinburgh,229072000,55.819142,-3.194377,248,2.5,43,06 +DAB,Edinburgh small-scale ,Edinburgh small-scale,204640000,55.912262,-3.200598,202,0.109441,, +DAB,Edinburgh small-scale ,Edinburgh small-scale,204640000,55.950839,-3.272833,160,0.0816,, +DAB,Essex 0615,Essex,229072000,51.705132,0.401129,90,1,06,15 +DAB,Essex 0614,Essex,229072000,51.550856,0.5811,80,1.2,06,14 +DAB,Essex 060C,Essex,229072000,51.865628,0.576571,62,0.5,06,0C +DAB,Essex 0601,Essex,229072000,51.803409,1.165049,7,0.12,06,01 +DAB,Essex 0605,Essex,229072000,51.917174,0.925798,45,0.5,06,05 +DAB,Essex ,Essex,229072000,51.469253,0.260425,3,1e-05,, +DAB,Essex 0603,Essex,229072000,51.801904,0.710885,81,0.5,06,03 +DAB,Essex 060B,Essex,229072000,51.739903,0.097485,110,0.25,06,0B +DAB,Essex 060F,Essex,229072000,51.92387,1.086097,35,0.25,06,0F +DAB,Essex 0613,Essex,229072000,51.540835,0.698653,33,1,06,13 +DAB,Essex 0610,Essex,229072000,52.004239,0.784592,71,1,06,10 +DAB,Exeter small-scale ,Exeter small-scale,202928000,50.755187,-3.399176,27,0.1,, +DAB,Exeter small-scale ,Exeter small-scale,202928000,50.747157,-3.526652,155,0.1,, +DAB,Exeter small-scale ,Exeter small-scale,202928000,50.728418,-3.539432,37,0.1,, +DAB,Glasgow 3904,Glasgow,220352000,55.860005,-3.873572,275,4.23,39,04 +DAB,Glasgow 390E,Glasgow,220352000,55.825353,-4.290679,67,0.1,39,0E +DAB,Glasgow 3906,Glasgow,220352000,55.579376,-4.289814,286,1,39,06 +DAB,Glasgow 3907,Glasgow,220352000,56.071792,-4.055753,410,2,39,07 +DAB,Glasgow 390B,Glasgow,220352000,55.886844,-4.294621,26,0.1,39,0B +DAB,Glasgow 3902,Glasgow,220352000,55.861436,-4.268991,16,0.3,39,02 +DAB,Glasgow 390F,Glasgow,220352000,55.982322,-4.600708,152,0.4,39,0F +DAB,Glasgow 390C,Glasgow,220352000,55.991937,-4.793795,107,1.8,39,0C +DAB,Glasgow 390D,Glasgow,220352000,55.878164,-4.998928,166,1,39,0D +DAB,Glasgow 3909,Glasgow,220352000,55.80577,-4.466669,230,0.886001,39,09 +DAB,Glasgow small-scale ,Glasgow small-scale,211648000,55.867219,-4.257501,29,0.1,, +DAB,Gloucestershire 1B11,Gloucestershire,213360000,51.868264,-2.175397,147,2,1B,11 +DAB,Gloucestershire 1B0A,Gloucestershire,213360000,51.750794,-1.994303,184,1.5,1B,0A +DAB,Gloucestershire 1B05,Gloucestershire,213360000,51.904177,-1.707798,241,1,1B,05 +DAB,Gloucestershire 1B16,Gloucestershire,213360000,51.775824,-2.234753,250,1.2,1B,16 +DAB,Hereford-Worcs 1C04,Hereford-Worcs,223936000,52.355115,-2.078214,147,0.533301,1C,04 +DAB,Hereford-Worcs 1C05,Hereford-Worcs,223936000,52.024853,-2.694563,164,0.6,1C,05 +DAB,Hereford-Worcs 1C06,Hereford-Worcs,223936000,52.363252,-2.282794,82,1,1C,06 +DAB,Hereford-Worcs 1C15,Hereford-Worcs,223936000,52.115715,-2.330146,161,5,1C,15 +DAB,Hereford-Worcs 1C01,Hereford-Worcs,223936000,51.997433,-2.53989,204,4,1C,01 +DAB,Herts Beds Bucks 1606,Herts Beds Bucks,215072000,51.819509,-0.811742,81,0.6,16,06 +DAB,Herts Beds Bucks 1609,Herts Beds Bucks,215072000,51.998806,-0.669784,169,2.73603,16,09 +DAB,Herts Beds Bucks 1601,Herts Beds Bucks,215072000,51.6119,-0.734849,142,0.6,16,01 +DAB,Herts Beds Bucks 1605,Herts Beds Bucks,215072000,51.744172,-0.128729,122,2,16,05 +DAB,Herts Beds Bucks 1612,Herts Beds Bucks,215072000,51.728571,-0.426217,142,3.90895,16,12 +DAB,Herts Beds Bucks 160D,Herts Beds Bucks,215072000,51.981709,-0.201702,82,0.025,16,0D +DAB,Herts Beds Bucks 1614,Herts Beds Bucks,215072000,51.915442,-0.184286,133,0.06,16,14 +DAB,Herts Beds Bucks 1603,Herts Beds Bucks,215072000,52.130132,-0.241462,54,4.89779,16,03 +DAB,Herts Beds Bucks 160E,Herts Beds Bucks,215072000,51.877958,-0.483622,207,0.488619,16,0E +DAB,Humberside 2F0C,Humberside,215072000,54.124979,-0.218986,105,1.58489,2F,0C +DAB,Humberside 2F0F,Humberside,215072000,54.001193,-0.762246,240,1.2,2F,0F +DAB,Humberside 2F0A,Humberside,215072000,53.567838,-0.079989,4,0.2,2F,0A +DAB,Humberside 2F07,Humberside,215072000,53.803052,-0.565371,164,5,2F,07 +DAB,Humberside 2F06,Humberside,215072000,53.765567,-0.335735,2,0.2,2F,06 +DAB,Humberside 2F01,Humberside,215072000,53.679468,0.03562,26,0.6,2F,01 +DAB,Humberside 2F09,Humberside,215072000,53.57127,-0.670181,42,1,2F,09 +DAB,Inverness 3805,Inverness,218640000,57.532303,-3.135126,353,5,38,05 +DAB,Inverness 3803,Inverness,218640000,57.591626,-4.27683,212,10,38,03 +DAB,Kent 0117,Kent,220352000,51.550856,0.5811,80,1.2,01,17 +DAB,Kent 0108,Kent,220352000,51.323563,0.520373,191,1.95447,01,08 +DAB,Kent 0103,Kent,220352000,51.21959,0.812581,193,2,01,03 +DAB,Kent 010B,Kent,220352000,51.265673,1.013529,67,0.5,01,0B +DAB,Kent 0105,Kent,220352000,51.099738,1.182579,166,0.0209,01,05 +DAB,Kent ,Kent,220352000,51.469253,0.260425,3,1e-05,, +DAB,Kent 010D,Kent,220352000,51.292731,0.979008,122,2,01,0D +DAB,Kent 010E,Kent,220352000,51.107491,1.084665,174,1.2,01,0E +DAB,Kent 0113,Kent,220352000,51.11386,0.259324,144,0.2,01,13 +DAB,Kent 0114,Kent,220352000,51.137832,1.335758,122,0.34,01,14 +DAB,Kent 010A,Kent,220352000,51.36004,1.397292,49,0.116657,01,0A +DAB,Kent 0110,Kent,220352000,51.172557,0.297815,124,1,01,10 +DAB,Kent 0111,Kent,220352000,51.068688,1.072375,1,0.1,01,11 +DAB,Kent 0107,Kent,220352000,51.320696,0.287702,219,2,01,07 +DAB,Kent 0109,Kent,220352000,51.187004,0.955865,98,1,01,09 +DAB,King's Lynn small-scale 0F07,King's Lynn small-scale,206352000,52.755989,0.409029,3,0,0F,07 +DAB,King's Lynn small-scale 0F0B,King's Lynn small-scale,206352000,52.75732,0.613636,90,0,0F,0B +DAB,Lancashire 2C07,Lancashire,223936000,53.809005,-3.05038,6,1.2,2C,07 +DAB,Lancashire 2C02,Lancashire,223936000,53.696571,-2.443266,261,0.6,2C,02 +DAB,Lancashire 2C0D,Lancashire,223936000,53.841893,-2.266074,276,2.95121,2C,0D +DAB,Lancashire 2C01,Lancashire,223936000,53.625547,-2.514794,439,2.93171,2C,01 +DAB,Leeds 3A09,Leeds,229072000,53.811543,-1.641253,149,0.977237,3A,09 +DAB,Leeds 3A01,Leeds,229072000,53.611985,-1.66456,256,5,3A,01 +DAB,Leeds 3A0F,Leeds,229072000,53.959135,-1.67687,283,1.1,3A,0F +DAB,Leeds 3A10,Leeds,229072000,53.736807,-1.572457,120,1,3A,10 +DAB,Leeds small-scale 3A05,Leeds small-scale,202928000,53.791637,-1.573115,43,0.1,3A,05 +DAB,Leeds small-scale 3A02,Leeds small-scale,202928000,53.811777,-1.550434,55,0.05,3A,02 +DAB,Leeds small-scale 3A07,Leeds small-scale,202928000,53.825224,-1.541327,104,0.0391,3A,07 +DAB,Leicestershire 4102,Leicestershire,218640000,52.71359,-1.319033,271,0.6,41,02 +DAB,Leicestershire 4111,Leicestershire,218640000,52.710153,-1.285042,240,1.8,41,11 +DAB,Leicestershire 4115,Leicestershire,218640000,52.63314,-1.002896,153,1.2,41,15 +DAB,Leicestershire 4108,Leicestershire,218640000,52.637434,-1.125451,57,0.3,41,08 +DAB,Leicestershire 4105,Leicestershire,218640000,52.763046,-1.275729,91,0.6005,41,05 +DAB,Leicestershire 4110,Leicestershire,218640000,52.801451,-0.80088,138,1.14599,41,10 +DAB,Lincolnshire 3202,Lincolnshire,223936000,53.335814,-0.171983,125,4.01063,32,02 +DAB,Lincolnshire 3206,Lincolnshire,223936000,52.918371,-0.592549,124,0.6,32,06 +DAB,Lincolnshire 320B,Lincolnshire,223936000,53.803052,-0.565371,164,5,32,0B +DAB,Lincolnshire 3209,Lincolnshire,223936000,53.205578,-0.546174,15,0.6,32,09 +DAB,Liverpool 2A0A,Liverpool,213360000,53.509257,-2.71981,170,1.6,2A,0A +DAB,Liverpool 2A07,Liverpool,213360000,53.105512,-3.053022,315,0.89,2A,07 +DAB,Liverpool 2A05,Liverpool,213360000,53.220944,-3.31452,336,1.2,2A,05 +DAB,Liverpool 2A04,Liverpool,213360000,53.406267,-2.981914,10,0.6,2A,04 +DAB,Liverpool 2A0F,Liverpool,213360000,53.625547,-2.514794,439,3,2A,0F +DAB,London 1 0B02,London 1,227360000,51.594459,-0.129257,92,0.8,0B,02 +DAB,London 1 0B15,London 1,227360000,51.324006,0.520684,192,1,0B,15 +DAB,London 1 0817,London 1,227360000,51.521504,-0.138879,27,0.8,08,17 +DAB,London 1 080D,London 1,227360000,51.263565,-0.086822,226,0.14,08,0D +DAB,London 1 0B06,London 1,227360000,51.40986,-0.085755,114,5,0B,06 +DAB,London 1 ,London 1,227360000,51.469253,0.260425,3,1e-05,, +DAB,London 1 0B03,London 1,227360000,51.228358,-0.605467,142,0.977237,0B,03 +DAB,London 1 0B07,London 1,227360000,51.728571,-0.426217,142,0.390895,0B,07 +DAB,London 1 1610,London 1,227360000,51.640531,-0.763678,156,0.01,16,10 +DAB,London 1 0304,London 1,227360000,51.234232,-0.820719,179,0.08,03,04 +DAB,London 1 0B14,London 1,227360000,51.317089,-0.09335,152,0.008079,0B,14 +DAB,London 1 0812,London 1,227360000,51.319591,-0.372374,60,0.01,08,12 +DAB,London 1 0805,London 1,227360000,51.548667,-0.775255,85,0.079433,08,05 +DAB,London 1 0B0C,London 1,227360000,51.915442,-0.184286,133,0.06,0B,0C +DAB,London 1 0B05,London 1,227360000,51.254494,-0.200986,234,1.23027,0B,05 +DAB,London 1 080F,London 1,227360000,51.320696,0.287702,219,4.5,08,0F +DAB,London 1 0313,London 1,227360000,51.877958,-0.483622,207,0.488619,03,13 +DAB,London 2 0B02,London 2,223936000,51.594459,-0.129257,92,1.04713,0B,02 +DAB,London 2 0B11,London 2,223936000,51.646963,-0.238974,144,0.25,0B,11 +DAB,London 2 0B04,London 2,223936000,51.324006,0.520684,192,2,0B,04 +DAB,London 2 0817,London 2,223936000,51.521504,-0.138879,27,0.709999,08,17 +DAB,London 2 080D,London 2,223936000,51.263565,-0.086822,226,0.14,08,0D +DAB,London 2 0808,London 2,223936000,51.58316,-0.247792,46,0.003,08,08 +DAB,London 2 0B06,London 2,223936000,51.40986,-0.085755,114,2,0B,06 +DAB,London 2 0B01,London 2,223936000,51.424161,-0.074944,110,2.88403,0B,01 +DAB,London 2 ,London 2,223936000,51.469253,0.260425,3,1e-05,, +DAB,London 2 0811,London 2,223936000,51.361981,-0.349183,24,0.003,08,11 +DAB,London 2 0B03,London 2,223936000,51.228358,-0.605467,142,1.6613,0B,03 +DAB,London 2 0B09,London 2,223936000,51.739903,0.097485,110,0.1,0B,09 +DAB,London 2 0803,London 2,223936000,51.622949,-0.356487,125,0.003,08,03 +DAB,London 2 0B07,London 2,223936000,51.728571,-0.426217,142,0.25,0B,07 +DAB,London 2 1610,London 2,223936000,51.640531,-0.763678,156,0.01,16,10 +DAB,London 2 0304,London 2,223936000,51.234232,-0.820719,179,0.08,03,04 +DAB,London 2 0B14,London 2,223936000,51.317089,-0.09335,152,0.0081,0B,14 +DAB,London 2 0812,London 2,223936000,51.319591,-0.372374,60,0.01,08,12 +DAB,London 2 0801,London 2,223936000,51.13246,-0.23632,92,0.117268,08,01 +DAB,London 2 0805,London 2,223936000,51.548667,-0.775255,85,0.079433,08,05 +DAB,London 2 0B0F,London 2,223936000,51.615389,-0.448479,105,0.1,0B,0F +DAB,London 2 0B0C,London 2,223936000,51.915442,-0.184286,133,0.06,0B,0C +DAB,London 2 0B05,London 2,223936000,51.254494,-0.200986,234,1.44204,0B,05 +DAB,London 2 0813,London 2,223936000,51.451704,-0.297446,40,0.003,08,13 +DAB,London 2 080B,London 2,223936000,51.43569,-0.508094,16,0.003,08,0B +DAB,London 2 080F,London 2,223936000,51.320696,0.287702,219,4.5,08,0F +DAB,London 2 0313,London 2,223936000,51.877958,-0.483622,207,0.342033,03,13 +DAB,London 3 0B02,London 3,218640000,51.594459,-0.129257,92,0.7,0B,02 +DAB,London 3 0B12,London 3,218640000,51.323563,0.520373,191,0.900001,0B,12 +DAB,London 3 0817,London 3,218640000,51.521504,-0.138879,27,0.8,08,17 +DAB,London 3 080D,London 3,218640000,51.263565,-0.086822,226,0.14,08,0D +DAB,London 3 0316,London 3,218640000,51.6119,-0.734849,142,0.6,03,16 +DAB,London 3 0B06,London 3,218640000,51.40986,-0.085755,114,2.5,0B,06 +DAB,London 3 ,London 3,218640000,51.469253,0.260425,3,1e-05,, +DAB,London 3 0809,London 3,218640000,51.744172,-0.128729,122,1,08,09 +DAB,London 3 0B03,London 3,218640000,51.228358,-0.605467,142,0.78179,0B,03 +DAB,London 3 0B07,London 3,218640000,51.728571,-0.426217,142,0.244309,0B,07 +DAB,London 3 0812,London 3,218640000,51.319591,-0.372374,60,0.01,08,12 +DAB,London 3 0805,London 3,218640000,51.548667,-0.775255,85,0.025,08,05 +DAB,London 3 0B0C,London 3,218640000,51.915442,-0.184286,133,0.06,0B,0C +DAB,London 3 0B05,London 3,218640000,51.254494,-0.200986,234,0.381997,0B,05 +DAB,London 3 080F,London 3,218640000,51.320696,0.287702,219,4.5,08,0F +DAB,London 3 0313,London 3,218640000,51.877958,-0.483622,207,0.42658,03,13 +DAB,Manchester 2B17,Manchester,227360000,53.646225,-2.076355,229,0.6,2B,17 +DAB,Manchester 2B06,Manchester,227360000,53.480177,-2.23864,43,0.5,2B,06 +DAB,Manchester 2B12,Manchester,227360000,53.541535,-2.020635,347,0.6,2B,12 +DAB,Manchester 2B0C,Manchester,227360000,53.206041,-2.10072,401,1,2B,0C +DAB,Manchester 2B11,Manchester,227360000,53.625547,-2.514794,439,4,2B,11 +DAB,Mid & West Wales 2813,Mid & West Wales,229072000,51.867126,-4.309135,137,0.6,28,13 +DAB,Mid & West Wales 280F,Mid & West Wales,229072000,51.818501,-4.066216,255,5,28,0F +DAB,Mid & West Wales 2803,Mid & West Wales,229072000,52.012591,-4.996935,123,0.977237,28,03 +DAB,Mid & West Wales 2811,Mid & West Wales,229072000,51.674549,-5.002613,71,1,28,11 +DAB,Mid & West Wales 2815,Mid & West Wales,229072000,51.62891,-3.919745,193,1.16,28,15 +DAB,Mid & West Wales 2805,Mid & West Wales,229072000,51.944404,-4.661027,323,5,28,05 +DAB,Morecambe Bay 0707,Morecambe Bay,218640000,54.314466,-2.708587,177,1.155,07,07 +DAB,Morecambe Bay 2C0E,Morecambe Bay,218640000,54.089336,-2.779963,88,1.5,2C,0E +DAB,Morecambe Bay 0705,Morecambe Bay,218640000,54.202505,-3.167346,259,1,07,05 +DAB,Morecambe Bay 070B,Morecambe Bay,218640000,54.37436,-2.951306,216,1,07,0B +DAB,N. Ireland 1908,N. Ireland,229072000,54.342402,-6.629562,109,5,19,08 +DAB,N. Ireland 1914,N. Ireland,229072000,54.661435,-5.675928,21,0.024,19,14 +DAB,N. Ireland 1902,N. Ireland,229072000,54.586989,-6.022076,301,7,19,02 +DAB,N. Ireland 1903,N. Ireland,229072000,54.423191,-7.462812,305,4.35,19,03 +DAB,N. Ireland 190A,N. Ireland,229072000,54.160861,-6.385716,340,3,19,0A +DAB,N. Ireland 1906,N. Ireland,229072000,54.653575,-5.957634,335,1,19,06 +DAB,N. Ireland 1907,N. Ireland,229072000,55.109172,-6.886121,341,6.2,19,07 +DAB,N. Ireland 1904,N. Ireland,229072000,55.00421,-7.368968,175,6.30957,19,04 +DAB,N. Ireland 1910,N. Ireland,229072000,54.203198,-5.913247,251,2,19,10 +DAB,N. Ireland 1913,N. Ireland,229072000,54.590668,-5.677949,20,0.015,19,13 +DAB,N. Ireland 1905,N. Ireland,229072000,54.799414,-7.388644,274,3.3,19,05 +DAB,NE Wales W Chesh 2903,NE Wales W Chesh,215072000,53.220944,-3.31452,336,3.55,29,03 +DAB,NE Wales W Chesh 2908,NE Wales W Chesh,215072000,53.406267,-2.981914,10,1.5,29,08 +DAB,NE Wales W Chesh 2906,NE Wales W Chesh,215072000,53.076278,-3.044994,210,3,29,06 +DAB,Newcastle and Gateshead small-scale ,Newcastle and Gateshead small-scale,195936000,54.996393,-1.671097,105,0.1,, +DAB,Newcastle and Gateshead small-scale ,Newcastle and Gateshead small-scale,195936000,54.938423,-1.580416,160,0.1,, +DAB,Norfolk 330C,Norfolk,211648000,52.659164,1.715858,17,0.5,33,0C +DAB,Norfolk 3310,Norfolk,211648000,52.652502,0.872498,85,1.2,33,10 +DAB,Norfolk 3303,Norfolk,211648000,52.602996,1.722916,1,0.25,33,03 +DAB,Norfolk 330B,Norfolk,211648000,52.745033,1.582514,2,0.3,33,0B +DAB,Norfolk 3317,Norfolk,211648000,52.234496,1.107319,64,2,33,17 +DAB,Norfolk 330A,Norfolk,211648000,52.82694,1.381376,27,0.07,33,0A +DAB,Norfolk 3316,Norfolk,211648000,52.640225,1.305146,38,0.3,33,16 +DAB,Norfolk 3301,Norfolk,211648000,52.486385,1.715554,8,0.25,33,01 +DAB,Norfolk 3302,Norfolk,211648000,52.574817,1.331664,65,1.17268,33,02 +DAB,Norfolk 3306,Norfolk,211648000,52.422601,0.741906,39,0.25,33,06 +DAB,Norfolk 3307,Norfolk,211648000,52.924381,1.251171,99,0.2,33,07 +DAB,North and West Cumbria 070F,North and West Cumbria,218640000,54.682913,-3.463248,125,1.4,07,0F +DAB,North and West Cumbria 0709,North and West Cumbria,218640000,54.773382,-3.091075,289,5,07,09 +DAB,North and West Cumbria 070A,North and West Cumbria,218640000,54.5916,-3.117626,178,1.2,07,0A +DAB,North and West Cumbria 0706,North and West Cumbria,218640000,54.674729,-2.728805,263,1,07,06 +DAB,North and West Cumbria 0704,North and West Cumbria,218640000,54.496676,-3.557726,133,1,07,04 +DAB,North Birmingham small-scale 1313,North Birmingham small-scale,202928000,52.500637,-1.889474,117,0.08,13,13 +DAB,North Birmingham small-scale 1304,North Birmingham small-scale,202928000,52.480135,-1.73741,92,0.08,13,04 +DAB,North Birmingham small-scale 1306,North Birmingham small-scale,202928000,52.560384,-1.805848,131,0.08,13,06 +DAB,North Birmingham small-scale 1315,North Birmingham small-scale,202928000,52.520926,-1.794158,80,0.08,13,15 +DAB,North West Wales 0516,North West Wales,215072000,53.390547,-4.301313,160,0.6,05,16 +DAB,North West Wales 0502,North West Wales,215072000,53.01985,-4.273475,300,4.88619,05,02 +DAB,North West Wales 0513,North West Wales,229072000,53.271606,-3.828796,114,0.5,05,13 +DAB,North West Wales 0505,North West Wales,229072000,53.32441,-3.386164,226,0.6469,05,05 +DAB,North West Wales 0506,North West Wales,215072000,53.307315,-4.683071,135,1,05,06 +DAB,North West Wales 0501,North West Wales,215072000,53.307002,-4.12825,146,3.54913,05,01 +DAB,North West Wales 050C,North West Wales,229072000,53.286941,-3.684982,125,0.6138,05,0C +DAB,North Yorkshire 2E0D,North Yorkshire,213360000,54.046924,-0.786852,224,2,2E,0D +DAB,North Yorkshire 3B04,North Yorkshire,213360000,54.336239,-1.394168,101,0.3,3B,04 +DAB,North Yorkshire 2E08,North Yorkshire,213360000,54.358848,-1.149317,381,2,2E,08 +DAB,North Yorkshire 2E06,North Yorkshire,213360000,53.995727,-1.592234,150,2,2E,06 +DAB,North Yorkshire 2E01,North Yorkshire,213360000,54.267351,-0.404494,151,2,2E,01 +DAB,North Yorkshire 2E0E,North Yorkshire,213360000,54.252192,-1.205693,294,1,2E,0E +DAB,Northamptonshire 1702,Northamptonshire,213360000,52.253028,-1.139914,199,1.2,17,02 +DAB,Northamptonshire 1707,Northamptonshire,213360000,52.267931,-0.780155,103,0.3,17,07 +DAB,Northamptonshire 1705,Northamptonshire,213360000,52.445531,-0.666816,118,5,17,05 +DAB,Northamptonshire 170F,Northamptonshire,213360000,52.275355,-0.885481,127,1.2,17,0F +DAB,Northamptonshire 1704,Northamptonshire,213360000,52.166487,-1.029003,160,0.25,17,04 +DAB,Northamptonshire 1706,Northamptonshire,213360000,52.297367,-0.675082,43,0.3,17,06 +DAB,Nottinghamshire 300A,Nottinghamshire,227360000,53.140513,-1.232922,168,1,30,0A +DAB,Nottinghamshire 3008,Nottinghamshire,227360000,52.976309,-1.132626,122,1,30,08 +DAB,Nottinghamshire 3006,Nottinghamshire,227360000,52.986825,-1.251436,129,0.6,30,06 +DAB,Nottinghamshire 3001,Nottinghamshire,227360000,52.801451,-0.80088,138,4,30,01 +DAB,Oxfordshire 1203,Oxfordshire,211648000,51.723637,-1.302007,162,1.2,12,03 +DAB,Oxfordshire 1201,Oxfordshire,211648000,52.044582,-1.224699,157,1,12,01 +DAB,Oxfordshire 1206,Oxfordshire,211648000,51.951697,-1.551799,209,0.3,12,06 +DAB,Oxfordshire 120E,Oxfordshire,211648000,51.790638,-1.179183,130,4.77496,12,0E +DAB,Oxfordshire 1202,Oxfordshire,211648000,51.526905,-1.068756,183,0.6,12,02 +DAB,Peterborough 1E04,Peterborough,229072000,52.331465,-0.200759,25,0.25,1E,04 +DAB,Peterborough 1E0A,Peterborough,229072000,52.817122,0.029814,3,0.3,1E,0A +DAB,Peterborough 1E05,Peterborough,229072000,52.464961,0.100577,1,1.2,1E,05 +DAB,Peterborough 1E08,Peterborough,229072000,52.832469,-0.431001,73,0.5,1E,08 +DAB,Peterborough 1E01,Peterborough,229072000,52.507615,-0.343282,56,6.30001,1E,01 +DAB,Peterborough 1E06,Peterborough,229072000,52.475956,-0.497308,49,0.6,1E,06 +DAB,Peterborough 1E09,Peterborough,229072000,52.773292,-0.143159,3,1.2,1E,09 +DAB,Peterborough 1E03,Peterborough,229072000,52.662748,-0.501852,58,1.2,1E,03 +DAB,Peterborough 1E0D,Peterborough,229072000,52.655393,0.160854,4,0.3,1E,0D +DAB,Plymouth 2208,Plymouth,229072000,50.368664,-3.926486,142,0.3,22,08 +DAB,Plymouth 220D,Plymouth,229072000,50.274442,-3.794967,93,0.2,22,0D +DAB,Plymouth 220F,Plymouth,229072000,50.550217,-4.008413,508,3.2,22,0F +DAB,Plymouth 2204,Plymouth,229072000,50.381346,-4.067802,113,2.93171,22,04 +DAB,Plymouth 2203,Plymouth,229072000,50.353472,-4.242037,108,0.4,22,03 +DAB,Salisbury small-scale 1D03,Salisbury small-scale,195936000,51.18517,-1.722235,184,0.05,1D,03 +DAB,Salisbury small-scale 1D02,Salisbury small-scale,195936000,51.102938,-1.8427,139,0,1D,02 +DAB,SDL National 0B02,SDL National,216928000,51.594459,-0.129257,92,1.5,0B,02 +DAB,SDL National 3502,SDL National,216928000,53.027231,-2.28071,220,5,35,02 +DAB,SDL National 3C08,SDL National,216928000,56.555053,-2.986125,312,10,3C,08 +DAB,SDL National 1606,SDL National,216928000,51.819509,-0.811742,81,0.03,16,06 +DAB,SDL National 0E07,SDL National,216928000,50.447129,-3.610498,196,5,0E,07 +DAB,SDL National 3202,SDL National,216928000,53.335814,-0.171983,125,4.18888,32,02 +DAB,SDL National 3B02,SDL National,216928000,54.358848,-1.149317,381,2,3B,02 +DAB,SDL National 0D03,SDL National,216928000,50.66283,-2.443645,160,0.234537,0D,03 +DAB,SDL National 3F04,SDL National,216928000,55.860005,-3.873572,275,9.52796,3F,04 +DAB,SDL National 0112,SDL National,216928000,51.324006,0.520684,192,1.95547,01,12 +DAB,SDL National 1A0B,SDL National,216928000,51.609363,-1.794027,148,2.5,1A,0B +DAB,SDL National 1609,SDL National,216928000,51.998806,-0.669784,169,2.73603,16,09 +DAB,SDL National 0817,SDL National,216928000,51.521504,-0.138879,27,0.8,08,17 +DAB,SDL National 3415,SDL National,216928000,54.969789,-1.608675,15,0.025,34,15 +DAB,SDL National 0405,SDL National,216928000,50.511364,-4.43683,369,2.5001,04,05 +DAB,SDL National 390E,SDL National,216928000,55.825353,-4.290679,67,0.01,39,0E +DAB,SDL National 0211,SDL National,216928000,50.649245,-1.328934,166,5,02,11 +DAB,SDL National 1B11,SDL National,216928000,51.868264,-2.175397,147,4,1B,11 +DAB,SDL National 0605,SDL National,216928000,51.917174,0.925798,45,1,06,05 +DAB,SDL National 3F02,SDL National,216928000,56.071791,-3.233186,181,5,3F,02 +DAB,SDL National 0B01,SDL National,216928000,51.424161,-0.074944,110,5.72995,0B,01 +DAB,SDL National 0616,SDL National,216928000,51.719492,0.58056,105,3.5,06,16 +DAB,SDL National ,SDL National,216928000,51.469253,0.260425,3,1e-05,, +DAB,SDL National 400A,SDL National,216928000,55.579376,-4.289814,286,6.68495,40,0A +DAB,SDL National 1702,SDL National,216928000,52.253028,-1.139914,199,4.77496,17,02 +DAB,SDL National 1901,SDL National,216928000,54.607538,-6.009471,368,9.54993,19,01 +DAB,SDL National 2D06,SDL National,216928000,53.531884,-1.091294,7,0.022,2D,06 +DAB,SDL National 010D,SDL National,216928000,51.292731,0.979008,122,0.900001,01,0D +DAB,SDL National 2402,SDL National,216928000,51.611393,-3.302735,381,1.2,24,02 +DAB,SDL National 1507,SDL National,216928000,52.412282,0.279524,22,0.04,15,07 +DAB,SDL National 2E14,SDL National,216928000,53.611985,-1.66456,256,7.4131,2E,14 +DAB,SDL National 3B,SDL National,216928000,54.556455,-1.120934,237,0.8,3B, +DAB,SDL National 0E09,SDL National,216928000,50.719122,-3.562148,102,1,0E,09 +DAB,SDL National 390B,SDL National,216928000,55.886844,-4.294621,26,0.01,39,0B +DAB,SDL National 3902,SDL National,216928000,55.861436,-4.268991,16,0.3,39,02 +DAB,SDL National 0C16,SDL National,216928000,51.228358,-0.605467,142,4.88619,0C,16 +DAB,SDL National 030C,SDL National,216928000,51.307873,-1.244777,220,4.6,03,0C +DAB,SDL National 0A06,SDL National,216928000,50.861622,0.566431,76,0.2,0A,06 +DAB,SDL National 1612,SDL National,216928000,51.728571,-0.426217,142,3.12716,16,12 +DAB,SDL National 2F07,SDL National,216928000,53.803052,-0.565371,164,3.8,2F,07 +DAB,SDL National 2703,SDL National,216928000,51.62891,-3.919745,193,5,27,03 +DAB,SDL National 3008,SDL National,216928000,52.976309,-1.132626,122,1.55,30,08 +DAB,SDL National 3707,SDL National,216928000,52.905093,-2.493571,100,0.018665,37,07 +DAB,SDL National 2302,SDL National,216928000,51.236969,-2.625476,303,4.88619,23,02 +DAB,SDL National 310E,SDL National,216928000,52.234496,1.107319,64,2.2661,31,0E +DAB,SDL National 2903,SDL National,216928000,53.220944,-3.31452,336,10,29,03 +DAB,SDL National 1D09,SDL National,216928000,51.416202,-2.076595,175,1.90999,1D,09 +DAB,SDL National 120E,SDL National,216928000,51.790638,-1.179183,130,9.54993,12,0E +DAB,SDL National 1E01,SDL National,216928000,52.507615,-0.343282,56,8.69741,1E,01 +DAB,SDL National 2204,SDL National,216928000,50.381346,-4.067802,113,2.44309,22,04 +DAB,SDL National 3401,SDL National,216928000,54.868838,-1.771233,302,19.0999,34,01 +DAB,SDL National 0D07,SDL National,216928000,50.729221,-1.948658,64,0.390895,0D,07 +DAB,SDL National 230F,SDL National,216928000,51.48519,-2.562764,91,2,23,0F +DAB,SDL National 310a,SDL National,216928000,52.290839,0.777315,69,0.6,31,0a +DAB,SDL National 3E13,SDL National,216928000,57.113656,-2.096244,87,1.2,3E,13 +DAB,SDL National 0403,SDL National,216928000,50.209786,-5.238489,237,1.81485,04,03 +DAB,SDL National 0B05,SDL National,216928000,51.254494,-0.200986,234,0.954993,0B,05 +DAB,SDL National 1C01,SDL National,216928000,51.997433,-2.53989,204,2,1C,01 +DAB,SDL National 1603,SDL National,216928000,52.130132,-0.241462,54,7.62246,16,03 +DAB,SDL National 2D03,SDL National,216928000,53.379385,-1.513809,247,2.8,2D,03 +DAB,SDL National 0613,SDL National,216928000,51.540835,0.698653,33,0.024,06,13 +DAB,SDL National 3302,SDL National,216928000,52.574817,1.331664,65,0.390895,33,02 +DAB,SDL National 1312,SDL National,216928000,52.600539,-1.833856,169,20,13,12 +DAB,SDL National 3709,SDL National,216928000,52.670935,-2.550228,396,3.90895,37,09 +DAB,SDL National 0204,SDL National,216928000,50.961044,-1.454599,84,1,02,04 +DAB,SDL National 0A04,SDL National,216928000,50.882048,-0.257307,211,2.4,0A,04 +DAB,SDL National 130F,SDL National,216928000,52.496364,-2.048417,267,8.11744,13,0F +DAB,SDL National 4110,SDL National,216928000,52.801451,-0.80088,138,9.54993,41,10 +DAB,SDL National 2401,SDL National,216928000,51.459476,-3.282282,129,8.79514,24,01 +DAB,SDL National 0A0E,SDL National,216928000,50.824954,-0.113611,120,0.6,0A,0E +DAB,SDL National 2B11,SDL National,216928000,53.625547,-2.514794,439,20,2B,11 +DAB,SDL National 0107,SDL National,216928000,51.320696,0.287702,219,25,01,07 +DAB,SDL National 0109,SDL National,216928000,51.187004,0.955865,98,1,01,09 +DAB,SDL National 160E,SDL National,216928000,51.877958,-0.483622,207,3.32261,16,0E +DAB,Sheffield 2D15,Sheffield,220352000,53.550702,-1.412685,94,2,2D,15 +DAB,Sheffield 2D12,Sheffield,220352000,53.283991,-1.427446,179,1,2D,12 +DAB,Sheffield 2D0A,Sheffield,220352000,53.346243,-0.886897,62,1.2,2D,0A +DAB,Sheffield 2D05,Sheffield,220352000,53.457744,-1.220893,138,1,2D,05 +DAB,Sheffield 2D06,Sheffield,220352000,53.531884,-1.091294,7,0.6,2D,06 +DAB,Sheffield 2D03,Sheffield,220352000,53.379385,-1.513809,247,1.1,2D,03 +DAB,Sheffield and Rotherham small-scale 2D08,Sheffield and Rotherham small-scale,206352000,53.416904,-1.351035,115,0.198166,2D,08 +DAB,Sheffield and Rotherham small-scale 2D09,Sheffield and Rotherham small-scale,206352000,53.379385,-1.513809,247,0.06,2D,09 +DAB,Somerset 2116,Somerset,211648000,50.916513,-2.700119,134,2,21,16 +DAB,Somerset 2105,Somerset,211648000,51.325227,-2.918301,73,2,21,05 +DAB,Somerset 210A,Somerset,211648000,51.236969,-2.625476,303,3.12716,21,0A +DAB,Somerset 2110,Somerset,211648000,51.058123,-3.070536,130,1,21,10 +DAB,South Birmingham small-scale 1316,South Birmingham small-scale,206352000,52.473153,-1.919722,152,0.149311,13,16 +DAB,South Birmingham small-scale 1310,South Birmingham small-scale,206352000,52.425856,-1.77363,120,0.199081,13,10 +DAB,South East Wales 2412,South East Wales,227360000,51.702007,-3.398531,282,0.36,24,12 +DAB,South East Wales 2405,South East Wales,227360000,51.807795,-3.097781,433,0.342033,24,05 +DAB,South East Wales 2415,South East Wales,227360000,51.714666,-3.12404,400,0.6,24,15 +DAB,South East Wales 2404,South East Wales,227360000,51.601588,-2.935417,94,2,24,04 +DAB,South East Wales 2413,South East Wales,227360000,51.771714,-3.218938,442,0.36,24,13 +DAB,South East Wales 2402,South East Wales,227360000,51.611393,-3.302735,381,1.2,24,02 +DAB,South East Wales 2411,South East Wales,227360000,51.740421,-3.419414,451,1,24,11 +DAB,South East Wales 2414,South East Wales,227360000,51.236969,-2.625476,303,1.501,24,14 +DAB,South East Wales 2417,South East Wales,227360000,51.604177,-3.122175,360,0.4,24,17 +DAB,South East Wales 2407,South East Wales,227360000,51.632846,-3.151491,369,0.6,24,07 +DAB,South East Wales 2409,South East Wales,227360000,51.685712,-3.036095,250,0.5,24,09 +DAB,South East Wales 2406,South East Wales,227360000,51.633901,-3.460735,316,0.6,24,06 +DAB,South East Wales 2410,South East Wales,227360000,51.730587,-3.264891,419,0.6,24,10 +DAB,South East Wales 2408,South East Wales,227360000,51.457374,-3.402986,126,2,24,08 +DAB,South East Wales 2401,South East Wales,227360000,51.459476,-3.282282,129,3.81997,24,01 +DAB,South Hampshire 0211,South Hampshire,220352000,50.649245,-1.328934,166,5,02,11 +DAB,South Hampshire 0210,South Hampshire,220352000,51.063167,-1.360216,158,1.5,02,10 +DAB,South Hampshire 0208,South Hampshire,220352000,50.853922,-1.067587,102,0.5,02,08 +DAB,South Hampshire 0213,South Hampshire,220352000,50.877178,-1.278479,50,0.6,02,13 +DAB,South Hampshire 020B,South Hampshire,220352000,50.89247,-0.755575,194,0.4,02,0B +DAB,South Hampshire 0204,South Hampshire,220352000,50.961044,-1.454599,84,1,02,04 +DAB,South Hampshire 020E,South Hampshire,220352000,50.601933,-1.199325,227,0.3,02,0E +DAB,Stoke & Stafford 3502,Stoke & Stafford,229072000,53.027231,-2.28071,220,0.64,35,02 +DAB,Stoke & Stafford 3510,Stoke & Stafford,229072000,53.116187,-2.211069,325,2,35,10 +DAB,Stoke & Stafford 3513,Stoke & Stafford,229072000,52.728576,-2.0198,234,0.85,35,13 +DAB,Stoke & Stafford 3506,Stoke & Stafford,229072000,52.87502,-2.142442,113,0.3,35,06 +DAB,Stoke & Stafford 350E,Stoke & Stafford,229072000,53.206041,-2.10072,401,0.5,35,0E +DAB,Stoke & Stafford 350B,Stoke & Stafford,229072000,53.003549,-2.055691,265,1.95447,35,0B +DAB,Suffolk 3102,Suffolk,213360000,51.951883,1.331834,2,0.6,31,02 +DAB,Suffolk 310E,Suffolk,213360000,52.234496,1.107319,64,2.1,31,0E +DAB,Suffolk 310A,Suffolk,213360000,52.290839,0.777315,69,2,31,0A +DAB,Suffolk 3103,Suffolk,213360000,52.037726,1.200836,32,1,31,03 +DAB,Surrey 080D,Surrey,213360000,51.263565,-0.086822,226,1.2,08,0D +DAB,Surrey 0C04,Surrey,213360000,51.424161,-0.074944,110,3,0C,04 +DAB,Surrey 0C15,Surrey,213360000,51.221643,-0.326426,127,0.6,0C,15 +DAB,Surrey 0C16,Surrey,213360000,51.228358,-0.605467,142,0.586342,0C,16 +DAB,Surrey 0C01,Surrey,213360000,51.234232,-0.820719,179,0.6,0C,01 +DAB,Surrey 0C0F,Surrey,213360000,51.319591,-0.372374,60,1,0C,0F +DAB,Surrey 0C02,Surrey,213360000,51.254494,-0.200986,234,0.954993,0C,02 +DAB,Sussex 0A02,Sussex,211648000,50.909654,-0.627813,245,0.830652,0A,02 +DAB,Sussex 0A01,Sussex,211648000,50.764511,0.288682,11,0.25,0A,01 +DAB,Sussex 0A12,Sussex,211648000,50.853924,-0.410233,124,0.28,0A,12 +DAB,Sussex 0A06,Sussex,211648000,50.861622,0.566431,76,0.92,0A,06 +DAB,Sussex 0A07,Sussex,211648000,50.976724,0.230437,158,2,0A,07 +DAB,Sussex 0A09,Sussex,211648000,51.064289,-0.321546,53,0.3,0A,09 +DAB,Sussex 0A08,Sussex,211648000,51.13246,-0.23632,92,1.17268,0A,08 +DAB,Sussex 0A0A,Sussex,211648000,51.017054,-0.70092,185,0.6,0A,0A +DAB,Sussex 0A03,Sussex,211648000,50.787726,0.035848,81,0.488619,0A,03 +DAB,Sussex 0A0D,Sussex,211648000,50.946708,0.709647,44,0.6,0A,0D +DAB,Sussex 0A04,Sussex,211648000,50.882048,-0.257307,211,1.8,0A,04 +DAB,Sussex 0A0E,Sussex,211648000,50.824954,-0.113611,120,1,0A,0E +DAB,Swansea SW Wales 2708,Swansea SW Wales,223936000,51.867126,-4.309135,137,0.6,27,08 +DAB,Swansea SW Wales 2707,Swansea SW Wales,223936000,51.818501,-4.066216,255,1.95447,27,07 +DAB,Swansea SW Wales 2703,Swansea SW Wales,223936000,51.62891,-3.919745,193,2,27,03 +DAB,Swansea SW Wales 280C,Swansea SW Wales,223936000,51.750918,-4.154115,279,1.2,28,0C +DAB,Swansea SW Wales 2716,Swansea SW Wales,223936000,51.457374,-3.402986,126,1,27,16 +DAB,Swindon 1A0B,Swindon,220352000,51.609363,-1.794027,148,2.5,1A,0B +DAB,Swindon 1A03,Swindon,220352000,51.750794,-1.994303,184,0.6,1A,03 +DAB,Swindon 1A05,Swindon,220352000,51.591795,-2.089739,91,1,1A,05 +DAB,Swindon 1A13,Swindon,220352000,51.417912,-1.699977,192,0.501187,1A,13 +DAB,Swindon 1A12,Swindon,220352000,51.484903,-1.558836,211,1,1A,12 +DAB,Tayside 3C08,Tayside,218640000,56.555053,-2.986125,312,3,3C,08 +DAB,Tayside 3C0F,Tayside,218640000,56.705122,-3.646339,480,1.5,3C,0F +DAB,Tayside 3C09,Tayside,218640000,56.372293,-3.453361,178,1.44631,3C,09 +DAB,Tayside 3C10,Tayside,218640000,56.23998,-3.207285,337,1.49,3C,10 +DAB,Teesside 3B04,Teesside,218640000,54.336239,-1.394168,101,0.6,3B,04 +DAB,Teesside 3B02,Teesside,218640000,54.358848,-1.149317,381,3,3B,02 +DAB,Teesside 3B11,Teesside,218640000,54.618813,-1.682509,212,1,3B,11 +DAB,Teesside 3B03,Teesside,218640000,54.697573,-1.735424,173,0.3,3B,03 +DAB,Teesside 3B0A,Teesside,218640000,54.556455,-1.120934,237,4,3B,0A +DAB,Teesside 3B05,Teesside,218640000,54.593159,-2.041753,352,1,3B,05 +DAB,Trial Brighton ,Trial Brighton,202928000,50.822557,-0.149203,19,0.1,, +DAB,Trial Bristol ,Trial Bristol,202928000,51.439897,-2.628676,16,0.07,, +DAB,Trial London 08,Trial London,202928000,51.447582,-0.055538,88,0.2,08, +DAB,Trial London ,Trial London,202928000,51.508681,-0.198773,30,0.1,, +DAB,Trial London 08,Trial London,202928000,51.574443,-0.148552,122,0.2,08, +DAB,Trial Manchester ,Trial Manchester,211648000,53.478111,-2.238327,40,0.1,, +DAB,Trial Norwich 0F03,Trial Norwich,206352000,52.614553,1.306609,22,0.2,0F,03 +DAB,Trial Norwich 0F01,Trial Norwich,206352000,52.65073,1.270152,25,0.1,0F,01 +DAB,Trial Portsmouth 0208,Trial Portsmouth,194064000,50.853922,-1.067587,102,0.2,02,08 +DAB,Trial Portsmouth ,Trial Portsmouth,194064000,50.86903,-1.00234,12,0.005,, +DAB,Trial Woking ,Trial Woking,195936000,51.254436,-0.765605,107,0.1,, +DAB,Trial Woking ,Trial Woking,195936000,51.312761,-0.60248,56,0.1,, +DAB,Tyne & Wear 3408,Tyne & Wear,220352000,54.8219,-1.714848,240,4.38,34,08 +DAB,Tyne & Wear 3415,Tyne & Wear,220352000,54.969789,-1.608675,15,0.3,34,15 +DAB,Tyne & Wear 3416,Tyne & Wear,220352000,54.775175,-1.590656,100,0.3,34,16 +DAB,Tyne & Wear 3403,Tyne & Wear,220352000,54.978039,-1.662966,120,1.5,34,03 +DAB,Tyne & Wear 3409,Tyne & Wear,220352000,54.893895,-1.363068,10,0.8,34,09 +DAB,Tyne & Wear 3411,Tyne & Wear,220352000,55.001052,-1.665743,120,0.1,34,11 +DAB,Tyne & Wear 340E,Tyne & Wear,220352000,55.171858,-1.659136,60,1.1,34,0E +DAB,Tyne & Wear 340F,Tyne & Wear,220352000,54.982447,-1.945593,165,0.6,34,0F +DAB,Tyne & Wear 340A,Tyne & Wear,220352000,55.430165,-1.647593,107,1.2,34,0A +DAB,Tyne & Wear 340D,Tyne & Wear,220352000,54.873774,-1.899456,199,0.3,34,0D +DAB,Tyne & Wear 3404,Tyne & Wear,220352000,54.74117,-1.961914,404,1,34,04 +DAB,Tyne & Wear 3405,Tyne & Wear,220352000,55.035277,-1.453767,40,0.1,34,05 +DAB,Tynemouth and South Shields small-scale 3417,Tynemouth and South Shields small-scale,204640000,54.965374,-1.396894,80,0.2,34,17 +DAB,W & S Wiltshire 1D17,W & S Wiltshire,215072000,51.38779,-2.332925,175,0.488619,1D,17 +DAB,W & S Wiltshire 1D11,W & S Wiltshire,215072000,51.184826,-2.177079,160,0.5,1D,11 +DAB,W & S Wiltshire 1D09,W & S Wiltshire,215072000,51.416202,-2.076595,175,0.763994,1D,09 +DAB,W & S Wiltshire 1D04,W & S Wiltshire,215072000,51.336803,-2.264225,87,1,1D,04 +DAB,Winchester small-scale 0210,Winchester small-scale,206352000,51.064004,-1.358677,152,0.3,02,10 +DAB,Wolv'ton & Shrop 3704,Wolv'ton & Shrop,218640000,52.7257,-2.01965,227,0.6,37,04 +DAB,Wolv'ton & Shrop 3701,Wolv'ton & Shrop,218640000,52.531128,-2.790828,343,0.64,37,01 +DAB,Wolv'ton & Shrop 3707,Wolv'ton & Shrop,218640000,52.905093,-2.493571,100,0.554794,37,07 +DAB,Wolv'ton & Shrop 3702,Wolv'ton & Shrop,218640000,52.878444,-3.091941,305,0.64,37,02 +DAB,Wolv'ton & Shrop 3708,Wolv'ton & Shrop,218640000,52.547739,-2.115424,225,0.6,37,08 +DAB,Wolv'ton & Shrop 3709,Wolv'ton & Shrop,218640000,52.670935,-2.550228,396,1.95447,37,09 +DAB,Wolv'ton & Shrop 3711,Wolv'ton & Shrop,218640000,52.496364,-2.048417,267,4,37,11 diff --git a/plugins/feature/map/icons.qrc b/plugins/feature/map/icons.qrc index e136bbc56..46b171f4c 100644 --- a/plugins/feature/map/icons.qrc +++ b/plugins/feature/map/icons.qrc @@ -5,5 +5,7 @@ icons/ibp.png icons/muf.png icons/fof2.png + icons/controltower.png + icons/vor.png diff --git a/plugins/feature/map/icons/controltower.png b/plugins/feature/map/icons/controltower.png new file mode 100644 index 0000000000000000000000000000000000000000..d33c9d66078d71ec0fb332f73723850fbe3cdcc5 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^d_XM5!3HEhoL#F9q&N#aB8wRq*jzxEvG>W`aG>Bb zPZ!4!i{7Wfj)Khw0(Xo!9GHZZ7&$#0oKzJUIj1(Ts3i7yS8?Ay|LLwXkw(v_#cC;O%9DC1#|3VW8NDxH@{xS zX=Ax7;-}j)8>2^(PDP;yQ|eEOt_YkEaA&u4rmaAE*z|&Rx|WeeKQ3(ix_*k4+L~*& z?i-w)wXR4ii|t#y{_T&SWq+Ct%0o4FuKN9>O!NSEB;VAByEvn70)5Qj>FVdQ&MBb@ E0B&G&+5i9m literal 0 HcmV?d00001 diff --git a/plugins/feature/map/icons/vor.png b/plugins/feature/map/icons/vor.png new file mode 100644 index 0000000000000000000000000000000000000000..ac66aad04c85cc94e7bc578442882b4091e29eb6 GIT binary patch literal 365 zcmV-z0h0cSP)5nZU6uQA4x<(R5*>bRlyB|Fbq6U2Vesjp(8LtMqmU+V1zz803&n+MxcKl zjKBt01vxEHlO~{AI)O-hj&06KNJ6n1Km}mZ78T0?v;b~jOE$m;8Oc$e+Ip0aw)sY~ ziXeBW#Mc|(O0qvd?$8UzZh($tc_Kh59Pe-Gq8$dn2%rmWtY)2X7_G@Rz2d~_9g1a{ zT?P$+heSVXqi{7Y0~hhvZ<&*91$n@4J68naU;$?}CsX%$#1CpTK+E{9OlLnIFVz+$={$C-dI~G;q(1aD2v% zFTDf!Ds#Fy$y(-drjHws%wumf)#sud($>(5ua6jhg=Db4!vVYim$vAmap/antennafm.png map/antennaam.png map/ionosonde.png + map/VOR.png + map/VOR-DME.png + map/VORTAC.png + map/DVOR.png + map/DVOR-DME.png + map/DVORTAC.png + map/NDB.png + map/DME.png + map/airport_large.png + map/airport_medium.png + map/airport_small.png + map/heliport.png map/map3d.html diff --git a/plugins/feature/map/map/DME.png b/plugins/feature/map/map/DME.png new file mode 100644 index 0000000000000000000000000000000000000000..f95bac447836c8882dc3873850f219cedb0b6cd9 GIT binary patch literal 10606 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 literal 0 HcmV?d00001 diff --git a/plugins/feature/map/map/DVOR.png b/plugins/feature/map/map/DVOR.png new file mode 100644 index 0000000000000000000000000000000000000000..0d6949fde5025be971f69c6b0572951528f9c26a GIT binary patch literal 415 zcmV;Q0bu@#P)00009a7bBm000C^ z000C^0ljtSLMVhnI0%Dq5DH-s3ZW1NVGzdP zO_|*3*5>0lX_iHbbh=BNm*;24IgreD00#i<)IS02N^6QPoNOX;1#l&~W(OLYh+G0N zl1p}Ufu%6{!?HU|2e4PR4%u}xfOZP#)C17Q?yAhYKouuDK@~TfnrNcA0ob=Js)Q~g zZ>qPvAlpQr4xq>`j@Hm^Wb3xhzQ~k_yaTxONC5`6;vT8-^^-&&*g8gqo*FO!*h7?O zKMn*IQpEBLl%@d2L^lZ3X&YR(mmxgQPJ@dYWXlPl7*>7urvROMUqM8}++gd+TMz!M zG_)p4npda2b4W)o&(1~OHlO>Z6#6|%kHOX+O$nSad2-fcW}}ZkKal4yT{vrzm)${M zmh9y)C%8CNMMXz(*I%)$lbxXam(eZFqp$7%?+1qh9{VeZ#1|e4Q=R*2MxFow002ov JPDHLkV1ja&s@DJj literal 0 HcmV?d00001 diff --git a/plugins/feature/map/map/DVORTAC.png b/plugins/feature/map/map/DVORTAC.png new file mode 100644 index 0000000000000000000000000000000000000000..f7df0a0b38a174b07fa25f8c808cc57200f27fbb GIT binary patch literal 847 zcmV-V1F-ywP)asXkb9dy4iWN@7~NV z1`(}w0Am0@0361CyA21>2QULLh~^#vb_jq<{t>{zErIF)_y%CX`OIUvtP9oxFbTjF zKJb6v5~u?J!l|sMT2347Y^EG*R?<9faYSje`-JGfw6kO+%RB+=2aAs7E zP_WJyb>iYU=#4q&yokI-y7@rA0K5e7LGgSSz!L!bK8?g@{{nbSM3+n7CWy#g_Z4wT z5fQ2Pl$3m9uy&^sT%w57`9;S2)?#JMS$|RoP9q{>Sr!89Wv;&@E=ACA643-bHEIJF znYr9dE>mGpT%+o7n zkf#|5R2mUY0lZK??s0s-9tcV@e7Xq{;n-dU&j6hBXVEOG5SRIiS_Ut(G+-x#5%kW5ut0T_%RF|~ zAniNh4oE1~7f|V3`0j<1%L)Zm;DQDI0r(>Py#(A@!uo#gKPe-g7#uHfl(2Jc3tE;6 z^)vOvp9GE<8YR$a%zdW{+(a_6@oB~Py?%183UI~INGb+Zrw#uOw}tDy18|v|rwUw& zCR6FK%oOdji*L+IeNJ`DwsMCeF`oVWv@s&0u5wI@nsd&tF(smoDuAXUT#&9*T$J$( z`Bz^Xs&=k0=iG=3q^oRwT+a-DlXXl)eRZJB>K1a}HQu!o2A6jaYLLirins{kb*u`O zMazIfCq&fC3T91pqiPr8BI;e6j$^iSg*oRw19-?Ypw=D$cuhn{7CG%(1Yvs*;2D5> znQ>lOCA4Q1h%a<3?6*}ymf-H3?Z7qFcHo+7J8(_49k{024qQ{sa&W#rhZ)%NKgwtg Zz<&Xuil2FEQ*!_S002ovPDHLkV1gS3cHjU2 literal 0 HcmV?d00001 diff --git a/plugins/feature/map/map/NDB.png b/plugins/feature/map/map/NDB.png new file mode 100644 index 0000000000000000000000000000000000000000..4987f3be0f4c4363eb1a55ae030a0f8601982ebc GIT binary patch literal 674 zcmV;T0$u%yP)F7cgd4#lWQ3p-WCU+e zjo=Mb5O_R1Fmx;jSKN;VP^>SCpO2JMYfZlM_v2f+zav0OX-p|)^k;48XI;B2fx4i# ziAYfr5xHZ$X+!^pwQ}jq(+wgc4qik=HD8Sh#+ig$F}Hwb{0af|;9W$fV1D8;^(WAr zTH_Vt-ONjKs^NnE9a;{g@f@6^Zra}wU^8FSoc>iZ|AhVkfd;s&n)xxmbqjz4*qk#C z$zU)zHxx%dTg(J5dy0ujfW{_cQ)9f4cDwC`;O3sAy{$)p4;NgS4m21(NZT3x2g4B7 zVwY)Pe!LU_3=CGQ)4UMVLRybRI|qBcG9?s%@V=7yY82%d@0e@oFT}L5JBV)e`9Yj? z_XxWX?g1?qVqDQ0C98tHjDltXi;S6H!VnwpywT-{#{NXyvNRl!*#KMbBbKQk~!1uCl^rfvhGW1&%;Fh`BSyU<72f2JWv!7TS}?u z8s-Mj00009a7bBm000C; z000C;0U7^T5C8xIK1oDDR9J=0SM5>bKn#@_{vT9u?toAM>401Zxe7=Lrh{Aup@UEX z&_U9H>3|O2&C9*@?Ko?jEb9!K*?ijCr?>Kx7g%PPX=GROs%COr6gd?C=EAViD*GZ5>THBkSS;Xkc?O&LYcWH zjie61psyMt zL`7$9GC|F|pt2-D4!WR_<16ylgr{$onZGH;f6sBGgs+0n5aG#5u3$boOy#m(hvN&9 zu%~kXNy#6HkiZs-atmOa;iHlyS$Id3Wb<=MLB!HV$5yvYu@!Z9MmPhIY$v8N733E) z`=xZ4$F+|F_S4;q_fR7i>TP@MEhyEY$FWwmq^S_!beqXkmtf~8$_kwOJ*jt3gHo$X z)DL~FYC#L^B-7Po~P*3B?0#; z=1Cix`wsJ&#;uYTB%pVm>;)x>2=iGHiHIa%u)Dpq|HEg>2<8WCn!A^nl*vB3h^0G= m$&npuFaIe$mVeF6c7Fl00;$kZ1o_(l00004=OGI literal 0 HcmV?d00001 diff --git a/plugins/feature/map/map/VOR.png b/plugins/feature/map/map/VOR.png new file mode 100644 index 0000000000000000000000000000000000000000..0d6949fde5025be971f69c6b0572951528f9c26a GIT binary patch literal 415 zcmV;Q0bu@#P)00009a7bBm000C^ z000C^0ljtSLMVhnI0%Dq5DH-s3ZW1NVGzdP zO_|*3*5>0lX_iHbbh=BNm*;24IgreD00#i<)IS02N^6QPoNOX;1#l&~W(OLYh+G0N zl1p}Ufu%6{!?HU|2e4PR4%u}xfOZP#)C17Q?yAhYKouuDK@~TfnrNcA0ob=Js)Q~g zZ>qPvAlpQr4xq>`j@Hm^Wb3xhzQ~k_yaTxONC5`6;vT8-^^-&&*g8gqo*FO!*h7?O zKMn*IQpEBLl%@d2L^lZ3X&YR(mmxgQPJ@dYWXlPl7*>7urvROMUqM8}++gd+TMz!M zG_)p4npda2b4W)o&(1~OHlO>Z6#6|%kHOX+O$nSad2-fcW}}ZkKal4yT{vrzm)${M zmh9y)C%8CNMMXz(*I%)$lbxXam(eZFqp$7%?+1qh9{VeZ#1|e4Q=R*2MxFow002ov JPDHLkV1ja&s@DJj literal 0 HcmV?d00001 diff --git a/plugins/feature/map/map/VORTAC.png b/plugins/feature/map/map/VORTAC.png new file mode 100644 index 0000000000000000000000000000000000000000..f7df0a0b38a174b07fa25f8c808cc57200f27fbb GIT binary patch literal 847 zcmV-V1F-ywP)asXkb9dy4iWN@7~NV z1`(}w0Am0@0361CyA21>2QULLh~^#vb_jq<{t>{zErIF)_y%CX`OIUvtP9oxFbTjF zKJb6v5~u?J!l|sMT2347Y^EG*R?<9faYSje`-JGfw6kO+%RB+=2aAs7E zP_WJyb>iYU=#4q&yokI-y7@rA0K5e7LGgSSz!L!bK8?g@{{nbSM3+n7CWy#g_Z4wT z5fQ2Pl$3m9uy&^sT%w57`9;S2)?#JMS$|RoP9q{>Sr!89Wv;&@E=ACA643-bHEIJF znYr9dE>mGpT%+o7n zkf#|5R2mUY0lZK??s0s-9tcV@e7Xq{;n-dU&j6hBXVEOG5SRIiS_Ut(G+-x#5%kW5ut0T_%RF|~ zAniNh4oE1~7f|V3`0j<1%L)Zm;DQDI0r(>Py#(A@!uo#gKPe-g7#uHfl(2Jc3tE;6 z^)vOvp9GE<8YR$a%zdW{+(a_6@oB~Py?%183UI~INGb+Zrw#uOw}tDy18|v|rwUw& zCR6FK%oOdji*L+IeNJ`DwsMCeF`oVWv@s&0u5wI@nsd&tF(smoDuAXUT#&9*T$J$( z`Bz^Xs&=k0=iG=3q^oRwT+a-DlXXl)eRZJB>K1a}HQu!o2A6jaYLLirins{kb*u`O zMazIfCq&fC3T91pqiPr8BI;e6j$^iSg*oRw19-?Ypw=D$cuhn{7CG%(1Yvs*;2D5> znQ>lOCA4Q1h%a<3?6*}ymf-H3?Z7qFcHo+7J8(_49k{024qQ{sa&W#rhZ)%NKgwtg Zz<&Xuil2FEQ*!_S002ovPDHLkV1gS3cHjU2 literal 0 HcmV?d00001 diff --git a/plugins/feature/map/map/airport_large.png b/plugins/feature/map/map/airport_large.png new file mode 100644 index 0000000000000000000000000000000000000000..72299fcf635bd41f907c1a227e8290994c377eee GIT binary patch literal 1261 zcmVEX>4Tx04R}tkv&MmP!xqvQ>9WW3KkJj$WWauh>AE$6^me@v=v%)FnQ^Z(4-+r zad8w}3l9D)RvlcNb#-tR1i>E=Cr2km7b)?+q|hS92bcG8-aCi;?gNB+nW<*SIG}2l zk&4H}Y;HviydsEUs($oJ%+wRsRcxRP3sKrNQcR@iJm%pabo@zj$>iDq zBgZ@{P$4;f@IUxHTeC1Z;UpV2qvfWBKGxa!WWd5+TuAVafSx&aOj zfzcvmuX((?t9@?&-f7P72V?zmp-nzC`v3p{24YJ`L;(K){{a7>y{D4^000SaNLh0L z01ejw01ejxLMWSf00007bV*G`2jmJJ3L61>WEu?s00QYrL_t(&-tC!9XcIvc$A4>5 zjg`jMfIWz|RzzAAg@WK0C`3;RUIeA22SL45JqjL*D0t{eYC&2>Jo$+rf(H*p!K$DZ z@!|(U4_1q4gj7>eYps_T9M;|G&TiZ^&HiD?WA^3Ee|Fw`GjGSj94CPlz;~dXGQ$I4 z68KtbBC{xCMC2p#l}0}9(AOl*4Yl$c1JWA37r;o^6FM%bFlgHsxs3)fMP3IS0=584 zieP&-uo|caUjOfj94L~z*jsnxHXgGLz)_%Inc!oQABk%fa0JMRycc*QaszOqROE+% zL5I~DRr&!wDDq3-xyX4#9-DyO5+e(M^T5Ta?6{Gi2h=%`uTuH}5{jHuo+VxE?gv_d z7N8Tjrv&$5MemFpz0Uy;fo5P0unJfVi~+~O4%lv`e+<|z{V7>R6T8{41NH=v6S*3= z1-u8cK)s=@J8GV<1LguBfu%(t`cw*+0pOYReFJ_2+Z4C0@o4Xt>=*q&m%NC7kN`df zbd@}?(1pYtNeEtT^#E%nEA7gE{*%;EeohR(@K|HI;@j9GVY@$=v5aH^d2JL!0cB%c_hy`R8_pyUr45`3k3)@nfhhu2`K z0(OP)=C2x%9|zhr&u;?bmZY}PGAp9y17D&qW)b-!rpi2UNplWq7Wp#Hmki5+ts>u5 z3Ud`TQnVN9-}^4(wMkj(h@`_d|5h{MUPaHXXvru#85f;KMWOi zs63y*{mN#MB5wqiIq0mk$xgQFZ8p;yE;BD+_#)2UC=2c00000NkvXXu0mjf#&k0? literal 0 HcmV?d00001 diff --git a/plugins/feature/map/map/airport_medium.png b/plugins/feature/map/map/airport_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..8347f8b3d8ada0876822d9b755b6d445ec2b089e GIT binary patch literal 1015 zcmVEX>4Tx04R}tkv&MmP!xqvQ>9WW3KkJj$WWauh>AE$6^me@v=v%)FnQ^Z(4-+r zad8w}3l9D)RvlcNb#-tR1i>E=Cr2km7b)?+q|hS92bcG8-aCi;?gNB+nW<*SIG}2l zk&4H}Y;HviydsEUs($oJ%+wRsRcxRP3sKrNQcR@iJm%pabo@zj$>iDq zBgZ@{P$4;f@IUxHTeC1Z;UpV2qvfWBKGxa!WWd5+TuAVafSx&aOj zfzcvmuX((?t9@?&-f7P72V?zmp-nzC`v3p{24YJ`L;(K){{a7>y{D4^000SaNLh0L z01ejw01ejxLMWSf00007bV*G`2jmJJ3L+>rQV-hz00Hw!L_t(o!|m8hh)!V~$MMfx z)P&hkCPm0?fk;ZSAlr$uuvGR^7FbwGNr@>7QvTHjyys%Zq4TSM=e(!?^LxL~bDry=QKLqg>PvavkCRxBM|A|>j;Rnse-orP z<@rF$eQf}1qyBIm!q!Ni+z`nb#;0)K#$AlhH0bL{pX(OaGko^oGEQK@p9GvL5HB-) z&PVdbF@lA40_?+;Sbhtau)GRjy8z&`E?%>6BcWUiV^|i;Ux6dI8Y;3g$@ESEz_U3j zJdokp#swV5^OT%Zal<9}kOS^126MiZIk;c2`$S`P+;APfW)ygb#Ra?07EG3aYhh86 z;c!ZU?^v6VKZvCXEw>L3N`Ot^8n&g?cy>y`Hwn4tLhDRoFE(Mc%Uei_FJW-(4*#F2 zB7plV^si1F45L1`iU9WFaRs<1W%dF^0AVA3B;PpqjM;OB_fSQVq`0Gt==n}v2aGqIzNE?KAXv2K8? z!u37Q)bUL676-ygQ~9VcU4!KRKh+(=%7h8Fqxn^*hZ1^)k)H757kX;ecoUfW&%ENp lk?Ei=deMB_Yt$%*egl$RIeOf1UkCsI002ovPDHLkV1jry&~E?$ literal 0 HcmV?d00001 diff --git a/plugins/feature/map/map/airport_small.png b/plugins/feature/map/map/airport_small.png new file mode 100644 index 0000000000000000000000000000000000000000..2509056d676a878c2d0bf57d2eac734a8e6779c3 GIT binary patch literal 1084 zcmV-C1jGA@P)EX>4Tx04R}tkv&MmP!xqvQ>9WW3KkJj$WWauh>AE$6^me@v=v%)FnQ^Z(4-+r zad8w}3l9D)RvlcNb#-tR1i>E=Cr2km7b)?+q|hS92bcG8-aCi;?gNB+nW<*SIG}2l zk&4H}Y;HviydsEUs($oJ%+wRsRcxRP3sKrNQcR@iJm%pabo@zj$>iDq zBgZ@{P$4;f@IUxHTeC1Z;UpV2qvfWBKGxa!WWd5+TuAVafSx&aOj zfzcvmuX((?t9@?&-f7P72V?zmp-nzC`v3p{24YJ`L;(K){{a7>y{D4^000SaNLh0L z01ejw01ejxLMWSf00007bV*G`2jmL^6d4}o_?3A800KBkL_t(o!|m8jh>cMg2k@Vn zh8l*26@$nu7@CbD^0iTtkdld#6&sP k;_jFrYhXe^XylEo}gA~7sbj9E-E6E-qF zX3B7F9(CvT-nnzuc!CE=RD_}f6v!>-b)o#R8hrW#guq1K@%2ZHqK)pOGMY9 z7rBscIE5KmB3U1#e&!KwJxD;cn6G8MSI`Exd{D=xMtx|%0Wf1v_FGc1Ca4;{cQ@QJxMsY63T78k#ABxQPqBXCZsu&#+ z_@#(lz-}xHE7jvL-WJh+ip>-02TS1yF5_&Ji6P97QqdFA8oF%>>!)I0%rzy<-@~y; znn_`2WZN4&!n^U%AgBItZ-4cVpDL>OAMhKz6zz9r{fdPE0000EX>4Tx04R}tkv&MmP!xqvQ>9WW3KkJj$WWauh>AE$6^me@v=v%)FnQ^Z(4-+r zad8w}3l9D)RvlcNb#-tR1i>E=Cr2km7b)?+q|hS92bcG8-aCi;?gNB+nW<*SIG}2l zk&4H}Y;HviydsEUs($oJ%+wRsRcxRP3sKrNQcR@iJm%pabo@zj$>iDq zBgZ@{P$4;f@IUxHTeC1Z;UpV2qvfWBKGxa!WWd5+TuAVafSx&aOj zfzcvmuX((?t9@?&-f7P72V?zmp-nzC`v3p{24YJ`L;(K){{a7>y{D4^000SaNLh0L z01ejw01ejxLMWSf00007bV*G`2jmJJ3j`-*@%vc-00L)8L_t(Y$L-hMi%nq^2Jjzd zG{Q`nXcQTdBtwJbBP3kVkjRDdk>uLPh1^O}{0j=>U*JN9M3j(X5{ep(k6{qaXf7N# z>(tw^&pCT$xRIxJd!N0Y^}Ns7`+e8DHvcg^j2J@BB&@(Z%#Gg-7>yqog?`kDj1Hg!)AE{Ij-Hr1tz|f`P{6eudL6;- zDidEEQ=|v$s)@}Nd@eEVLOM9uo;$v;9GT_4G`Vt;h;dkdWD9pi_tl*L4RV*zdP#e2NkyoE% z4vtIs1F_>|VM)R}nnjq5??LD+Gk8lP@^uh(wKvIIm=UkXgNT2x^cMHUTqxjbl$5N6 zRLJpaQ#?%a_LjsZ;6}uLVt+NULy6eSlC7vYis`y2uzAs%>OYW_e6RTtae?L_}QHVsy&F;?HVMCcvPMrSj95L&abCw87MiC!O0M~5`zc54E5 zM)6z{1+|EeQTgA*UfLHcy*7HpS#dOE%*hM57bNI_gq1h4G2W(=9}4`4EM=@Xvme`~nU%t 11 ? mapZoomLevel : 11 + sourceItem: Grid { + columns: 1 + Grid { + //layer.enabled: true + //layer.smooth: true + horizontalItemAlignment: Grid.AlignHCenter + Text { + id: polygonText + text: label + } + } + } + } + } + + Component { + id: polylineComponent + MapPolyline { + line.width: 1 + line.color: lineColor + path: coordinates + autoFadeIn: false + } + } + + Component { + id: polylineNameComponent + MapQuickItem { + coordinate: position + anchorPoint.x: polylineText.width/2 + anchorPoint.y: polylineText.height/2 + zoomLevel: mapZoomLevel > 11 ? mapZoomLevel : 11 + sourceItem: Grid { + columns: 1 + Grid { + //layer.enabled: true + //layer.smooth: true + horizontalItemAlignment: Grid.AlignHCenter + Text { + id: polylineText + text: label + } + } + } + } + } + Component { id: mapComponent MapQuickItem { @@ -134,8 +247,9 @@ Item { Grid { horizontalItemAlignment: Grid.AlignHCenter columnSpacing: 5 - layer.enabled: true - layer.smooth: true + // This is very slow with lots of items, so we use MSAA for the whole map instead + //layer.enabled: true + //layer.smooth: true Image { id: image rotation: mapImageRotation @@ -149,7 +263,7 @@ Item { if (mouse.button === Qt.LeftButton) { selected = !selected if (selected) { - mapModel.moveToFront(index) + mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) } } else if (mouse.button === Qt.RightButton) { if (frequency > 0) { @@ -159,6 +273,8 @@ Item { freqMenuItem.text = "No frequency available" freqMenuItem.enabled = false } + var c = mapPtr.toCoordinate(Qt.point(mouse.x, mouse.y)) + coordsMenuItem.text = "Coords: " + c.latitude.toFixed(6) + ", " + c.longitude.toFixed(6) contextMenu.popup() } } @@ -186,7 +302,7 @@ Item { if (mouse.button === Qt.LeftButton) { selected = !selected if (selected) { - mapModel.moveToFront(index) + mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) } } else if (mouse.button === Qt.RightButton) { if (frequency > 0) { @@ -196,6 +312,8 @@ Item { freqMenuItem.text = "No frequency available" freqMenuItem.enabled = false } + var c = mapPtr.toCoordinate(Qt.point(mouse.x, mouse.y)) + coordsMenuItem.text = "Coords: " + c.latitude.toFixed(6) + ", " + c.longitude.toFixed(6) contextMenu.popup() } } @@ -212,15 +330,19 @@ Item { } MenuItem { text: "Move to front" - onTriggered: mapModel.moveToFront(index) + onTriggered: mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) } MenuItem { text: "Move to back" - onTriggered: mapModel.moveToBack(index) + onTriggered: mapModel.moveToBack(mapModelFiltered.mapRowToSource(index)) } MenuItem { text: "Track on 3D map" - onTriggered: mapModel.track3D(index) + onTriggered: mapModel.track3D(mapModelFiltered.mapRowToSource(index)) + } + MenuItem { + id: coordsMenuItem + text: "" } } } diff --git a/plugins/feature/map/map/map3d.html b/plugins/feature/map/map/map3d.html index 3d7f252f8..0f0aca7f5 100644 --- a/plugins/feature/map/map/map3d.html +++ b/plugins/feature/map/map/map3d.html @@ -147,6 +147,30 @@ } } + // Polygons (such as for airspaces) should be prioritized behind other entities + function pickEntityPrioritized(e) + { + var picked = viewer.scene.drillPick(e.position); + if (Cesium.defined(picked)) { + var firstPolygon = null; + for (let i = 0; i < picked.length; i++) { + var id = Cesium.defaultValue(picked[i].id, picked[i].primitive.id); + if (id instanceof Cesium.Entity) { + if (!Cesium.defined(id.polygon)) { + return id; + } else if (firstPolygon == null) { + firstPolygon = id; + } + } + } + return firstPolygon; + } + } + + function pickEntity(e) { + viewer.selectedEntity = pickEntityPrioritized(e); + } + Cesium.Ion.defaultAccessToken = '$CESIUM_ION_API_KEY$'; const viewer = new Cesium.Viewer('cesiumContainer', { @@ -161,6 +185,7 @@ terrainProviderViewModels: [] // User should adjust terrain via dialog, so depthTestAgainstTerrain doesn't get set }); viewer.scene.globe.depthTestAgainstTerrain = false; // So labels/points aren't clipped by terrain + viewer.screenSpaceEventHandler.setInputAction(pickEntity, Cesium.ScreenSpaceEventType.LEFT_CLICK); var buildings = undefined; const images = new Map(); @@ -351,7 +376,7 @@ fabric: { type: 'Image', uniforms: { - image: 'data:image/png;base64,' + command.data, + image: command.data, } }, translucent: true diff --git a/plugins/feature/map/mapgui.cpp b/plugins/feature/map/mapgui.cpp index 1d85a431c..70bbec72a 100644 --- a/plugins/feature/map/mapgui.cpp +++ b/plugins/feature/map/mapgui.cpp @@ -37,6 +37,7 @@ #include "device/deviceuiset.h" #include "util/units.h" #include "util/maidenhead.h" +#include "util/morse.h" #include "maplocationdialog.h" #include "mapmaidenheaddialog.h" #include "mapsettingsdialog.h" @@ -181,7 +182,10 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur m_pluginAPI(pluginAPI), m_featureUISet(featureUISet), m_doApplySettings(true), - m_mapModel(this), + m_objectMapModel(this), + m_imageMapModel(this), + m_polygonMapModel(this), + m_polylineMapModel(this), m_beacons(nullptr), m_beaconDialog(this), m_ibpBeaconDialog(this), @@ -197,6 +201,16 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur rollupContents->arrangeRollups(); connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + // Enable MSAA antialiasing on 2D map, otherwise text is not clear + // This is much faster than using layer.smooth in the QML, when there are many items + int multisamples = MainCore::instance()->getSettings().getMapMultisampling(); + if (multisamples > 0) + { + QSurfaceFormat format; + format.setSamples(multisamples); + ui->map->setFormat(format); + } + m_osmPort = 0; m_templateServer = new OSMTemplateServer(thunderforestAPIKey(), maptilerAPIKey(), m_osmPort); @@ -206,13 +220,17 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur ui->map->setAttribute(Qt::WA_AcceptTouchEvents, true); - ui->map->rootContext()->setContextProperty("mapModel", &m_mapModel); - // 5.12 doesn't display map items when fully zoomed out -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map/map_5_12.qml"))); -#else + m_objectMapFilter.setSourceModel(&m_objectMapModel); + m_imageMapFilter.setSourceModel(&m_imageMapModel); + m_polygonMapFilter.setSourceModel(&m_polygonMapModel); + m_polylineMapFilter.setSourceModel(&m_polylineMapModel); + + ui->map->rootContext()->setContextProperty("mapModelFiltered", &m_objectMapFilter); + ui->map->rootContext()->setContextProperty("mapModel", &m_objectMapModel); + ui->map->rootContext()->setContextProperty("imageModelFiltered", &m_imageMapFilter); + ui->map->rootContext()->setContextProperty("polygonModelFiltered", &m_polygonMapFilter); + ui->map->rootContext()->setContextProperty("polylineModelFiltered", &m_polylineMapFilter); ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map/map.qml"))); -#endif m_settings.m_modelURL = QString("http://127.0.0.1:%1/3d/").arg(m_webPort); m_webServer->addPathSubstitution("3d", m_settings.m_modelDir); @@ -236,6 +254,11 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur float stationLongitude = MainCore::instance()->getSettings().getLongitude(); float stationAltitude = MainCore::instance()->getSettings().getAltitude(); m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude); + QGeoCoordinate stationPosition(stationLatitude, stationLongitude, stationAltitude); + m_objectMapFilter.setPosition(stationPosition); + m_imageMapFilter.setPosition(stationPosition); + m_polygonMapFilter.setPosition(stationPosition); + m_polylineMapFilter.setPosition(stationPosition); // Centre map at My Position QQuickItem *item = ui->map->rootObject(); @@ -257,7 +280,9 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur m_antennaMapItem.setImageRotation(0); m_antennaMapItem.setText(new QString(MainCore::instance()->getSettings().getStationName())); m_antennaMapItem.setModel(new QString("antenna.glb")); - m_antennaMapItem.setFixedPosition(true); + m_antennaMapItem.setFixedPosition(false); + m_antennaMapItem.setPositionDateTime(new QString(QDateTime::currentDateTime().toString(Qt::ISODateWithMs))); + m_antennaMapItem.setAvailableUntil(new QString(QDateTime::currentDateTime().addDays(365).toString(Qt::ISODateWithMs))); m_antennaMapItem.setOrientation(0); m_antennaMapItem.setLabel(new QString(MainCore::instance()->getSettings().getStationName())); m_antennaMapItem.setLabelAltitudeOffset(4.5); @@ -277,6 +302,10 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur addRadioTimeTransmitters(); addRadar(); addIonosonde(); + addBroadcast(); + addNavAids(); + addAirspace(); + addAirports(); displaySettings(); applySettings(true); @@ -317,31 +346,18 @@ void MapGUI::setWorkspaceIndex(int index) m_feature->setWorkspaceIndex(index); } -// Update a map item or image +// Update a map item void MapGUI::update(const QObject *source, SWGSDRangel::SWGMapItem *swgMapItem, const QString &group) { - if (swgMapItem->getType() == 0) - { - m_mapModel.update(source, swgMapItem, group); - } - else if (m_cesium) - { - QString name = *swgMapItem->getName(); - QString image = *swgMapItem->getImage(); - if (!image.isEmpty()) - { - m_cesium->updateImage(name, - swgMapItem->getImageTileEast(), - swgMapItem->getImageTileWest(), - swgMapItem->getImageTileNorth(), - swgMapItem->getImageTileSouth(), - swgMapItem->getAltitude(), - image); - } - else - { - m_cesium->removeImage(name); - } + int type = swgMapItem->getType(); + if (type == 0) { + m_objectMapModel.update(source, swgMapItem, group); + } else if (type == 1) { + m_imageMapModel.update(source, swgMapItem, group); + } else if (type == 2) { + m_polygonMapModel.update(source, swgMapItem, group); + } else if (type == 3) { + m_polylineMapModel.update(source, swgMapItem, group); } } @@ -401,11 +417,15 @@ void MapGUI::addIBPBeacons() } const QList MapGUI::m_radioTimeTransmitters = { - {"MSF", 60000, 54.9075f, -3.27333f, 17}, - {"DCF77", 77500, 50.01611111f, 9.00805556f, 50}, - {"TDF", 162000, 47.1694f, 2.2044f, 800}, - {"WWVB", 60000, 40.67805556f, -105.04666667f, 70}, - {"JJY", 60000, 33.465f, 130.175555f, 50} + {"MSF", 60000, 54.9075f, -3.27333f, 17}, // UK + {"DCF77", 77500, 50.01611111f, 9.00805556f, 50}, // Germany + {"TDF", 162000, 47.1694f, 2.2044f, 800}, // France + {"WWVB", 60000, 40.67805556f, -105.04666667f, 70}, // USA + {"JJY-40", 40000, 37.3725f, 140.848889f, 50}, // Japan + {"JJY-60", 60000, 33.465556f, 130.175556f, 50}, // Japan + {"RTZ", 50000, 52.436111f, 103.685833f, 10}, // Russia - On 22:00 to 21:00 UTC + {"RBU", 66666, 56.733333f, 37.663333f, 10}, // Russia + {"BPC", 68500, 34.457f, 115.837f, 90}, // China - On 1:00 to 21:00 UTC }; void MapGUI::addRadioTimeTransmitters() @@ -539,7 +559,111 @@ static QString arrayToString(QJsonArray array) return s; } +void MapGUI::addBroadcast() +{ + QFile file(":/map/data/transmitters.csv"); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream in(&file); + + QString error; + QHash colIndexes = CSV::readHeader(in, {"Type", "Id", "Name", "Frequency (Hz)", "Latitude", "Longitude", "Altitude (m)", "Power", "TII Main", "TII Sub"}, error); + if (error.isEmpty()) + { + int typeCol = colIndexes.value("Type"); + int idCol = colIndexes.value("Id"); + int nameCol = colIndexes.value("Name"); + int frequencyCol = colIndexes.value("Frequency (Hz)"); + int latCol = colIndexes.value("Latitude"); + int longCol = colIndexes.value("Longitude"); + int altCol = colIndexes.value("Altitude (m)"); + int powerCol = colIndexes.value("Power"); + int tiiMainCol = colIndexes.value("TII Main"); + int tiiSubCol = colIndexes.value("TII Sub"); + + QStringList cols; + while (CSV::readRow(in, &cols)) + { + QString type = cols[typeCol]; + QString id = cols[idCol]; + QString name = cols[nameCol]; + QString frequency = cols[frequencyCol]; + double latitude = cols[latCol].toDouble(); + double longitude = cols[longCol].toDouble(); + double altitude = cols[altCol].toDouble(); + QString power = cols[powerCol]; + + SWGSDRangel::SWGMapItem mapItem; + mapItem.setLatitude(latitude); + mapItem.setLongitude(longitude); + mapItem.setAltitude(altitude); + mapItem.setImageRotation(0); + mapItem.setModel(new QString("antenna.glb")); + mapItem.setFixedPosition(true); + mapItem.setOrientation(0); + mapItem.setLabelAltitudeOffset(4.5); + mapItem.setAltitudeReference(1); + + if (type == "AM") + { + // Name should be unique + mapItem.setName(new QString(id)); + mapItem.setImage(new QString("antennaam.png")); + mapItem.setLabel(new QString(name)); + QString text = QString("%1 Transmitter\nStation: %2\nFrequency: %3 kHz\nPower (ERMP): %4 kW") + .arg(type) + .arg(name) + .arg(frequency.toDouble() / 1e3) + .arg(power) + ; + mapItem.setText(new QString(text)); + update(m_map, &mapItem, "AM"); + } + else if (type == "FM") + { + mapItem.setName(new QString(id)); + mapItem.setImage(new QString("antennafm.png")); + mapItem.setLabel(new QString(name)); + QString text = QString("%1 Transmitter\nStation: %2\nFrequency: %3 MHz\nPower (ERP): %4 kW") + .arg(type) + .arg(name) + .arg(frequency.toDouble() / 1e6) + .arg(power) + ; + mapItem.setText(new QString(text)); + update(m_map, &mapItem, "FM"); + } + else if (type == "DAB") + { + mapItem.setName(new QString(id)); + mapItem.setImage(new QString("antennadab.png")); + mapItem.setLabel(new QString(name)); + QString text = QString("%1 Transmitter\nEnsemble: %2\nFrequency: %3 MHz\nPower (ERP): %4 kW\nTII: %5 %6") + .arg(type) + .arg(name) + .arg(frequency.toDouble() / 1e6) + .arg(power) + .arg(cols[tiiMainCol]) + .arg(cols[tiiSubCol]) + ; + mapItem.setText(new QString(text)); + update(m_map, &mapItem, "DAB"); + } + } + } + else + { + qCritical() << "MapGUI::addBroadcast: Failed reading transmitters.csv - " << error; + } + } + else + { + qCritical() << "MapGUI::addBroadcast: Failed to open transmitters.csv"; + } +} + // Coming soon +/* Code for FM list / DAB list, should they allow access void MapGUI::addDAB() { QFile file("stationlist_SI.json"); @@ -663,6 +787,201 @@ void MapGUI::addDAB() qDebug() << "MapGUI::addDAB: Failed to open DAB json"; } } +*/ + +void MapGUI::addNavAids() +{ + m_navAids = OpenAIP::getNavAids(); + + for (const auto navAid : *m_navAids) + { + SWGSDRangel::SWGMapItem navAidMapItem; + navAidMapItem.setName(new QString(navAid->m_name + " " + navAid->m_ident)); // Neither name or ident are unique... + navAidMapItem.setLatitude(navAid->m_latitude); + navAidMapItem.setLongitude(navAid->m_longitude); + navAidMapItem.setAltitude(Units::feetToMetres(navAid->m_elevation)); + QString image = QString("%1.png").arg(navAid->m_type); + navAidMapItem.setImage(new QString(image)); + navAidMapItem.setImageRotation(0); + QString text = QString("NAVAID\nName: %1").arg(navAid->m_name); + if (navAid->m_type == "NDB") { + text.append(QString("\nFrequency: %1 kHz").arg(navAid->m_frequencykHz, 0, 'f', 1)); + } else { + text.append(QString("\nFrequency: %1 MHz").arg(navAid->m_frequencykHz / 1000.0f, 0, 'f', 2)); + } + if (navAid->m_channel != "") { + text.append(QString("\nChannel: %1").arg(navAid->m_channel)); + } + text.append(QString("\nIdent: %1 %2").arg(navAid->m_ident).arg(Morse::toSpacedUnicodeMorse(navAid->m_ident))); + text.append(QString("\nRange: %1 nm").arg(navAid->m_range)); + if (navAid->m_alignedTrueNorth) { + text.append(QString("\nMagnetic declination: Aligned to true North")); + } else if (navAid->m_magneticDeclination != 0.0f) { + text.append(QString("\nMagnetic declination: %1%2").arg(std::round(navAid->m_magneticDeclination)).arg(QChar(0x00b0))); + } + navAidMapItem.setText(new QString(text)); + navAidMapItem.setModel(new QString("antenna.glb")); + navAidMapItem.setFixedPosition(true); + navAidMapItem.setOrientation(0); + navAidMapItem.setLabel(new QString(navAid->m_name)); + navAidMapItem.setLabelAltitudeOffset(4.5); + navAidMapItem.setAltitudeReference(1); + update(m_map, &navAidMapItem, "NavAid"); + } +} + +void MapGUI::addAirspace(const Airspace *airspace, const QString& group, int cnt) +{ + //MapSettings::MapItemSettings *itemSettings = getItemSettings(group); + + QString details; + details.append(airspace->m_name); + details.append(QString("\n%1 - %2") + .arg(airspace->getAlt(&airspace->m_bottom)) + .arg(airspace->getAlt(&airspace->m_top))); + QString name = QString("Airspace %1 (%2)").arg(airspace->m_name).arg(cnt); + + SWGSDRangel::SWGMapItem airspaceMapItem; + airspaceMapItem.setName(new QString(name)); + airspaceMapItem.setLatitude(airspace->m_position.y()); + airspaceMapItem.setLongitude(airspace->m_position.x()); + airspaceMapItem.setAltitude(airspace->bottomHeightInMetres()); + QString image = QString("none"); + airspaceMapItem.setImage(new QString(image)); + airspaceMapItem.setImageRotation(0); + airspaceMapItem.setText(new QString(details)); // Not used - label is used instead for now + airspaceMapItem.setFixedPosition(true); + airspaceMapItem.setLabel(new QString(details)); + airspaceMapItem.setAltitudeReference(0); + QList *coords = new QList(); + for (const auto p : airspace->m_polygon) + { + SWGSDRangel::SWGMapCoordinate* c = new SWGSDRangel::SWGMapCoordinate(); + c->setLatitude(p.y()); + c->setLongitude(p.x()); + c->setAltitude(airspace->bottomHeightInMetres()); + coords->append(c); + } + airspaceMapItem.setCoordinates(coords); + airspaceMapItem.setExtrudedHeight(airspace->topHeightInMetres()); + airspaceMapItem.setType(2); + update(m_map, &airspaceMapItem, group); +} + + +void MapGUI::addAirspace() +{ + m_airspaces = OpenAIP::getAirspaces(); + + int cnt = 0; + for (const auto airspace : *m_airspaces) + { + static const QMap groupMap { + {"A", "Airspace (A)"}, + {"B", "Airspace (B)"}, + {"C", "Airspace (C)"}, + {"D", "Airspace (D)"}, + {"E", "Airspace (E)"}, + {"F", "Airspace (F)"}, + {"G", "Airspace (G)"}, + {"FIR", "Airspace (FIR)"}, + {"CTR", "Airspace (CTR)"}, + {"RMZ", "Airspace (RMZ)"}, + {"TMA", "Airspace (TMA)"}, + {"TMZ", "Airspace (TMZ)"}, + {"OTH", "Airspace (OTH)"}, + {"RESTRICTED", "Airspace (Restricted)"}, + {"GLIDING", "Airspace (Gliding)"}, + {"DANGER", "Airspace (Danger)"}, + {"PROHIBITED", "Airspace (Prohibited)"}, + {"WAVE", "Airspace (Wave)"}, + }; + + if (groupMap.contains(airspace->m_category)) + { + QString group = groupMap[airspace->m_category]; + addAirspace(airspace, group, cnt); + cnt++; + + if ( (airspace->bottomHeightInMetres() == 0) + && ((airspace->m_category == "D") || (airspace->m_category == "G") || (airspace->m_category == "CTR")) + && (!((airspace->m_country == "IT") && (airspace->m_name.startsWith("FIR")))) + && (!((airspace->m_country == "PL") && (airspace->m_name.startsWith("FIS")))) + ) + { + group = "Airspace (Airports)"; + addAirspace(airspace, group, cnt); + cnt++; + } + } + else + { + qDebug() << "MapGUI::addAirspace: No group for airspace category " << airspace->m_category; + } + } +} + +void MapGUI::addAirports() +{ + m_airportInfo = OurAirportsDB::getAirportsById(); + if (m_airportInfo) + { + QHashIterator i(*m_airportInfo); + while (i.hasNext()) + { + i.next(); + AirportInformation *airport = i.value(); + + SWGSDRangel::SWGMapItem airportMapItem; + airportMapItem.setName(new QString(airport->m_ident)); + airportMapItem.setLatitude(airport->m_latitude); + airportMapItem.setLongitude(airport->m_longitude); + airportMapItem.setAltitude(Units::feetToMetres(airport->m_elevation)); + airportMapItem.setImage(new QString(airport->getImageName())); + airportMapItem.setImageRotation(0); + QStringList list; + list.append(QString("%1: %2").arg(airport->m_ident).arg(airport->m_name)); + for (int i = 0; i < airport->m_frequencies.size(); i++) + { + const AirportInformation::FrequencyInformation *frequencyInfo = airport->m_frequencies[i]; + list.append(QString("%1: %2 MHz").arg(frequencyInfo->m_type).arg(frequencyInfo->m_frequency)); + } + airportMapItem.setText(new QString(list.join("\n"))); + airportMapItem.setModel(new QString("airport.glb")); // No such model currently, but we don't really want one + airportMapItem.setFixedPosition(true); + airportMapItem.setOrientation(0); + airportMapItem.setLabel(new QString(airport->m_ident)); + airportMapItem.setLabelAltitudeOffset(4.5); + airportMapItem.setAltitudeReference(1); + QString group; + if (airport->m_type == AirportInformation::Small) { + group = "Airport (Small)"; + } else if (airport->m_type == AirportInformation::Medium) { + group = "Airport (Medium)"; + } else if (airport->m_type == AirportInformation::Large) { + group = "Airport (Large)"; + } else { + group = "Heliport"; + } + update(m_map, &airportMapItem, group); + } + } +} + +void MapGUI::navAidsUpdated() +{ + addNavAids(); +} + +void MapGUI::airspacesUpdated() +{ + addAirspace(); +} + +void MapGUI::airportsUpdated() +{ + addAirports(); +} void MapGUI::blockApplySettings(bool block) { @@ -799,7 +1118,7 @@ void MapGUI::redrawMap() if (object) { double zoom = object->property("zoomLevel").value(); - object->setProperty("zoomLevel", QVariant::fromValue(zoom+1)); + object->setProperty("zoomLevel", QVariant::fromValue(zoom+1.0)); object->setProperty("zoomLevel", QVariant::fromValue(zoom)); } } @@ -834,6 +1153,15 @@ bool MapGUI::eventFilter(QObject *obj, QEvent *event) return FeatureGUI::eventFilter(obj, event); } +MapSettings::MapItemSettings *MapGUI::getItemSettings(const QString &group) +{ + if (m_settings.m_itemSettings.contains(group)) { + return m_settings.m_itemSettings[group]; + } else { + return nullptr; + } +} + void MapGUI::supportedMapsChanged() { QQuickItem *item = ui->map->rootObject(); @@ -893,7 +1221,8 @@ void MapGUI::applyMap3DSettings(bool reloadMap) #ifdef QT_WEBENGINE_FOUND if (m_settings.m_map3DEnabled && ((m_cesium == nullptr) || reloadMap)) { - if (m_cesium == nullptr) { + if (m_cesium == nullptr) + { m_cesium = new CesiumInterface(&m_settings); connect(m_cesium, &CesiumInterface::connected, this, &MapGUI::init3DMap); connect(m_cesium, &CesiumInterface::received, this, &MapGUI::receivedCesiumEvent); @@ -924,6 +1253,10 @@ void MapGUI::applyMap3DSettings(bool reloadMap) m_cesium->getDateTime(); m_cesium->showMUF(m_settings.m_displayMUF); m_cesium->showfoF2(m_settings.m_displayfoF2); + m_objectMapModel.allUpdated(); + m_imageMapModel.allUpdated(); + m_polygonMapModel.allUpdated(); + m_polylineMapModel.allUpdated(); } MapSettings::MapItemSettings *ionosondeItemSettings = getItemSettings("Ionosonde Stations"); if (ionosondeItemSettings) { @@ -934,9 +1267,10 @@ void MapGUI::applyMap3DSettings(bool reloadMap) #else ui->displayMUF->setVisible(false); ui->displayfoF2->setVisible(false); - m_mapModel.allUpdated(); - float stationLatitude = MainCore::instance()->getSettings().getLatitude(); - float stationLongitude = MainCore::instance()->getSettings().getLongitude(); + m_objectMapModel.allUpdated(); + m_imageMapModel.allUpdated(); + m_polygonMapModel.allUpdated(); + m_polylineMapModel.allUpdated(); #endif } @@ -947,6 +1281,11 @@ void MapGUI::init3DMap() m_cesium->initCZML(); + float stationLatitude = MainCore::instance()->getSettings().getLatitude(); + float stationLongitude = MainCore::instance()->getSettings().getLongitude(); + float stationAltitude = MainCore::instance()->getSettings().getLongitude(); + + m_cesium->setPosition(QGeoCoordinate(stationLatitude, stationLongitude, stationAltitude)); m_cesium->setTerrain(m_settings.m_terrain, maptilerAPIKey()); m_cesium->setBuildings(m_settings.m_buildings); m_cesium->setSunLight(m_settings.m_sunLightEnabled); @@ -954,9 +1293,10 @@ void MapGUI::init3DMap() m_cesium->setAntiAliasing(m_settings.m_antiAliasing); m_cesium->getDateTime(); - m_mapModel.allUpdated(); - float stationLatitude = MainCore::instance()->getSettings().getLatitude(); - float stationLongitude = MainCore::instance()->getSettings().getLongitude(); + m_objectMapModel.allUpdated(); + m_imageMapModel.allUpdated(); + m_polygonMapModel.allUpdated(); + m_polylineMapModel.allUpdated(); // Set 3D view after loading initial objects m_cesium->setHomeView(stationLatitude, stationLongitude); @@ -977,10 +1317,13 @@ void MapGUI::displaySettings() ui->displayAllGroundTracks->setChecked(m_settings.m_displayAllGroundTracks); ui->displayMUF->setChecked(m_settings.m_displayMUF); ui->displayfoF2->setChecked(m_settings.m_displayfoF2); - m_mapModel.setDisplayNames(m_settings.m_displayNames); - m_mapModel.setDisplaySelectedGroundTracks(m_settings.m_displaySelectedGroundTracks); - m_mapModel.setDisplayAllGroundTracks(m_settings.m_displayAllGroundTracks); - m_mapModel.updateItemSettings(m_settings.m_itemSettings); + m_objectMapModel.setDisplayNames(m_settings.m_displayNames); + m_objectMapModel.setDisplaySelectedGroundTracks(m_settings.m_displaySelectedGroundTracks); + m_objectMapModel.setDisplayAllGroundTracks(m_settings.m_displayAllGroundTracks); + m_objectMapModel.updateItemSettings(m_settings.m_itemSettings); + m_imageMapModel.updateItemSettings(m_settings.m_itemSettings); + m_polygonMapModel.updateItemSettings(m_settings.m_itemSettings); + m_polylineMapModel.updateItemSettings(m_settings.m_itemSettings); applyMap2DSettings(true); applyMap3DSettings(true); getRollupContents()->restoreState(m_rollupState); @@ -1049,19 +1392,19 @@ void MapGUI::on_maidenhead_clicked() void MapGUI::on_displayNames_clicked(bool checked) { m_settings.m_displayNames = checked; - m_mapModel.setDisplayNames(checked); + m_objectMapModel.setDisplayNames(checked); } void MapGUI::on_displaySelectedGroundTracks_clicked(bool checked) { m_settings.m_displaySelectedGroundTracks = checked; - m_mapModel.setDisplaySelectedGroundTracks(checked); + m_objectMapModel.setDisplaySelectedGroundTracks(checked); } void MapGUI::on_displayAllGroundTracks_clicked(bool checked) { m_settings.m_displayAllGroundTracks = checked; - m_mapModel.setDisplayAllGroundTracks(checked); + m_objectMapModel.setDisplayAllGroundTracks(checked); } void MapGUI::on_displayMUF_clicked(bool checked) @@ -1183,13 +1526,15 @@ void MapGUI::find(const QString& target) } else { - MapItem *mapItem = m_mapModel.findMapItem(target); + // FIXME: Support polygon/polyline + ObjectMapItem *mapItem = m_objectMapModel.findMapItem(target); if (mapItem != nullptr) { map->setProperty("center", QVariant::fromValue(mapItem->getCoordinates())); if (m_cesium) { m_cesium->track(target); } + m_objectMapModel.moveToFront(m_objectMapModel.findMapItemIndex(target).row()); } else { @@ -1224,7 +1569,10 @@ void MapGUI::track3D(const QString& target) void MapGUI::on_deleteAll_clicked() { - m_mapModel.removeAll(); + m_objectMapModel.removeAll(); + m_imageMapModel.removeAll(); + m_polygonMapModel.removeAll(); + m_polylineMapModel.removeAll(); if (m_cesium) { m_cesium->removeAllCZMLEntities(); @@ -1235,6 +1583,9 @@ void MapGUI::on_deleteAll_clicked() void MapGUI::on_displaySettings_clicked() { MapSettingsDialog dialog(&m_settings); + connect(&dialog, &MapSettingsDialog::navAidsUpdated, this, &MapGUI::navAidsUpdated); + connect(&dialog, &MapSettingsDialog::airspacesUpdated, this, &MapGUI::airspacesUpdated); + connect(&dialog, &MapSettingsDialog::airportsUpdated, this, &MapGUI::airportsUpdated); new DialogPositioner(&dialog, true); if (dialog.exec() == QDialog::Accepted) { @@ -1244,7 +1595,10 @@ void MapGUI::on_displaySettings_clicked() applyMap2DSettings(dialog.m_map2DSettingsChanged); applyMap3DSettings(dialog.m_map3DSettingsChanged); applySettings(); - m_mapModel.allUpdated(); + m_objectMapModel.allUpdated(); + m_imageMapModel.allUpdated(); + m_polygonMapModel.allUpdated(); + m_polylineMapModel.allUpdated(); } } @@ -1289,17 +1643,17 @@ void MapGUI::receivedCesiumEvent(const QJsonObject &obj) if (event == "selected") { if (obj.contains("id")) { - m_mapModel.setSelected3D(obj.value("id").toString()); + m_objectMapModel.setSelected3D(obj.value("id").toString()); } else { - m_mapModel.setSelected3D(""); + m_objectMapModel.setSelected3D(""); } } else if (event == "tracking") { if (obj.contains("id")) { - //m_mapModel.setTarget(obj.value("id").toString()); + //m_objectMapModel.setTarget(obj.value("id").toString()); } else { - //m_mapModel.setTarget(""); + //m_objectMapModel.setTarget(""); } } else if (event == "clock") @@ -1346,9 +1700,10 @@ void MapGUI::preferenceChanged(int elementType) float stationLongitude = MainCore::instance()->getSettings().getLongitude(); float stationAltitude = MainCore::instance()->getSettings().getAltitude(); - if ( (stationLatitude != m_azEl.getLocationSpherical().m_latitude) - || (stationLongitude != m_azEl.getLocationSpherical().m_longitude) - || (stationAltitude != m_azEl.getLocationSpherical().m_altitude)) + QGeoCoordinate stationPosition(stationLatitude, stationLongitude, stationAltitude); + QGeoCoordinate previousPosition(m_azEl.getLocationSpherical().m_latitude, m_azEl.getLocationSpherical().m_longitude, m_azEl.getLocationSpherical().m_altitude); + + if (stationPosition != previousPosition) { // Update position of station m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude); @@ -1356,7 +1711,24 @@ void MapGUI::preferenceChanged(int elementType) m_antennaMapItem.setLatitude(stationLatitude); m_antennaMapItem.setLongitude(stationLongitude); m_antennaMapItem.setAltitude(stationAltitude); + delete m_antennaMapItem.getPositionDateTime(); + m_antennaMapItem.setPositionDateTime(new QString(QDateTime::currentDateTime().toString(Qt::ISODateWithMs))); update(m_map, &m_antennaMapItem, "Station"); + + m_objectMapFilter.setPosition(stationPosition); + m_imageMapFilter.setPosition(stationPosition); + m_polygonMapFilter.setPosition(stationPosition); + m_polylineMapFilter.setPosition(stationPosition); + if (m_cesium) + { + m_cesium->setPosition(stationPosition); + if (!m_lastFullUpdatePosition.isValid() || (stationPosition.distanceTo(m_lastFullUpdatePosition) >= 1000)) + { + // Update all objects so distance filter is reapplied + m_objectMapModel.allUpdated(); + m_lastFullUpdatePosition = stationPosition; + } + } } } if (pref == Preferences::StationName) @@ -1384,3 +1756,4 @@ void MapGUI::makeUIConnections() QObject::connect(ui->ibpBeacons, &QToolButton::clicked, this, &MapGUI::on_ibpBeacons_clicked); QObject::connect(ui->radiotime, &QToolButton::clicked, this, &MapGUI::on_radiotime_clicked); } + diff --git a/plugins/feature/map/mapgui.h b/plugins/feature/map/mapgui.h index 2e8a4c3fe..bf41dd065 100644 --- a/plugins/feature/map/mapgui.h +++ b/plugins/feature/map/mapgui.h @@ -33,6 +33,8 @@ #include "util/messagequeue.h" #include "util/giro.h" #include "util/azel.h" +#include "util/openaip.h" +#include "util/ourairportsdb.h" #include "settings/rollupstate.h" #include "SWGMapItem.h" @@ -152,11 +154,16 @@ public: void addRadioTimeTransmitters(); void addRadar(); void addIonosonde(); + void addBroadcast(); void addDAB(); + void addNavAids(); + void addAirspace(const Airspace *airspace, const QString& group, int cnt); + void addAirspace(); + void addAirports(); void find(const QString& target); void track3D(const QString& target); Q_INVOKABLE void supportedMapsChanged(); - MapSettings::MapItemSettings *getItemSettings(const QString &group) { return m_settings.m_itemSettings[group]; } + MapSettings::MapItemSettings *getItemSettings(const QString &group); CesiumInterface *cesium() { return m_cesium; } private: @@ -171,7 +178,14 @@ private: Map* m_map; MessageQueue m_inputMessageQueue; - MapModel m_mapModel; + ObjectMapModel m_objectMapModel; + ObjectMapFilter m_objectMapFilter; + ImageMapModel m_imageMapModel; + ImageFilter m_imageMapFilter; + PolygonMapModel m_polygonMapModel; + PolygonFilter m_polygonMapFilter; + PolylineMapModel m_polylineMapModel; + PolylineFilter m_polylineMapFilter; AzEl m_azEl; // Position of station SWGSDRangel::SWGMapItem m_antennaMapItem; QList *m_beacons; @@ -183,6 +197,10 @@ private: QTimer m_redrawMapTimer; GIRO *m_giro; QHash m_ionosondeStations; + QSharedPointer> m_navAids; + QSharedPointer> m_airspaces; + QSharedPointer> m_airportInfo; + QGeoCoordinate m_lastFullUpdatePosition; CesiumInterface *m_cesium; WebServer *m_webServer; @@ -238,6 +256,9 @@ private slots: void giroDataUpdated(const GIRO::GIROStationData& data); void mufUpdated(const QJsonDocument& document); void foF2Updated(const QJsonDocument& document); + void navAidsUpdated(); + void airspacesUpdated(); + void airportsUpdated(); }; diff --git a/plugins/feature/map/mapitem.cpp b/plugins/feature/map/mapitem.cpp new file mode 100644 index 000000000..9f1466aec --- /dev/null +++ b/plugins/feature/map/mapitem.cpp @@ -0,0 +1,288 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "mapitem.h" + +MapItem::MapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) : + m_altitude(0.0) +{ + m_sourcePipe = sourcePipe; + m_group = group; + m_itemSettings = itemSettings; + m_name = *mapItem->getName(); + m_hashKey = m_sourcePipe->objectName() + m_name; +} + +void MapItem::update(SWGSDRangel::SWGMapItem *mapItem) +{ + if (mapItem->getLabel()) { + m_label = *mapItem->getLabel(); + } else { + m_label = ""; + } + m_latitude = mapItem->getLatitude(); + m_longitude = mapItem->getLongitude(); + m_altitude = mapItem->getAltitude(); +} + +void ObjectMapItem::update(SWGSDRangel::SWGMapItem *mapItem) +{ + MapItem::update(mapItem); + if (mapItem->getPositionDateTime()) { + m_positionDateTime = QDateTime::fromString(*mapItem->getPositionDateTime(), Qt::ISODateWithMs); + } else { + m_positionDateTime = QDateTime(); + } + m_useHeadingPitchRoll = mapItem->getOrientation() == 1; + m_heading = mapItem->getHeading(); + m_pitch = mapItem->getPitch(); + m_roll = mapItem->getRoll(); + if (mapItem->getOrientationDateTime()) { + m_orientationDateTime = QDateTime::fromString(*mapItem->getOrientationDateTime(), Qt::ISODateWithMs); + } else { + m_orientationDateTime = QDateTime(); + } + m_image = *mapItem->getImage(); + m_imageRotation = mapItem->getImageRotation(); + QString *text = mapItem->getText(); + if (text != nullptr) { + m_text = text->replace("\n", "
"); // Convert to HTML + } else { + m_text = ""; + } + if (mapItem->getModel()) { + m_model = *mapItem->getModel(); + } else { + m_model = ""; + } + m_labelAltitudeOffset = mapItem->getLabelAltitudeOffset(); + m_modelAltitudeOffset = mapItem->getModelAltitudeOffset(); + m_altitudeReference = mapItem->getAltitudeReference(); + m_fixedPosition = mapItem->getFixedPosition(); + QList *animations = mapItem->getAnimations(); + if (animations) + { + for (auto animation : *animations) { + m_animations.append(new CesiumInterface::Animation(animation)); + } + } + findFrequency(); + if (!m_fixedPosition) + { + updateTrack(mapItem->getTrack()); + updatePredictedTrack(mapItem->getPredictedTrack()); + } + if (mapItem->getAvailableUntil()) { + m_availableUntil = QDateTime::fromString(*mapItem->getAvailableUntil(), Qt::ISODateWithMs); + } else { + m_availableUntil = QDateTime(); + } +} + +void ImageMapItem::update(SWGSDRangel::SWGMapItem *mapItem) +{ + MapItem::update(mapItem); + + m_image = "data:image/png;base64," + *mapItem->getImage(); + m_imageZoomLevel = mapItem->getImageZoomLevel(); + + float east = mapItem->getImageTileEast(); + float west = mapItem->getImageTileWest(); + float north = mapItem->getImageTileNorth(); + float south = mapItem->getImageTileSouth(); + m_latitude = north - (north - south) / 2.0; + m_longitude = east - (east - west) / 2.0; + m_bounds = QGeoRectangle(QGeoCoordinate(north, west), QGeoCoordinate(south, east)); +} + +void PolygonMapItem::update(SWGSDRangel::SWGMapItem *mapItem) +{ + MapItem::update(mapItem); + m_extrudedHeight = mapItem->getExtrudedHeight(); + + qDeleteAll(m_points); + m_points.clear(); + QList *coords = mapItem->getCoordinates(); + if (coords) + { + for (int i = 0; i < coords->size(); i++) + { + SWGSDRangel::SWGMapCoordinate* p = coords->at(i); + QGeoCoordinate *c = new QGeoCoordinate(p->getLatitude(), p->getLongitude(), p->getAltitude()); + m_points.append(c); + } + } + + // Calculate bounds + m_polygon.clear(); + qreal latMin = 90.0, latMax = -90.0, lonMin = 180.0, lonMax = -180.0; + for (const auto p : m_points) + { + QGeoCoordinate coord = *p; + latMin = std::min(latMin, coord.latitude()); + latMax = std::max(latMax, coord.latitude()); + lonMin = std::min(lonMin, coord.longitude()); + lonMax = std::max(lonMax, coord.longitude()); + m_polygon.push_back(QVariant::fromValue(coord)); + } + m_bounds = QGeoRectangle(QGeoCoordinate(latMax, lonMin), QGeoCoordinate(latMin, lonMax)); +} + +void PolylineMapItem::update(SWGSDRangel::SWGMapItem *mapItem) +{ + MapItem::update(mapItem); + + qDeleteAll(m_points); + m_points.clear(); + QList *coords = mapItem->getCoordinates(); + if (coords) + { + for (int i = 0; i < coords->size(); i++) + { + SWGSDRangel::SWGMapCoordinate* p = coords->at(i); + QGeoCoordinate *c = new QGeoCoordinate(p->getLatitude(), p->getLongitude(), p->getAltitude()); + m_points.append(c); + } + } + + // Calculate bounds + m_polyline.clear(); + qreal latMin = 90.0, latMax = -90.0, lonMin = 180.0, lonMax = -180.0; + for (const auto p : m_points) + { + QGeoCoordinate coord = *p; + latMin = std::min(latMin, coord.latitude()); + latMax = std::max(latMax, coord.latitude()); + lonMin = std::min(lonMin, coord.longitude()); + lonMax = std::max(lonMax, coord.longitude()); + m_polyline.push_back(QVariant::fromValue(coord)); + } + m_bounds = QGeoRectangle(QGeoCoordinate(latMax, lonMin), QGeoCoordinate(latMin, lonMax)); +} + +QGeoCoordinate ObjectMapItem::getCoordinates() +{ + QGeoCoordinate coords; + coords.setLatitude(m_latitude); + coords.setLongitude(m_longitude); + return coords; +} + +void ObjectMapItem::findFrequency() +{ + // Look for a frequency in the text for this object + QRegExp re("(([0-9]+(\\.[0-9]+)?) *([kMG])?Hz)"); + if (re.indexIn(m_text) != -1) + { + QStringList capture = re.capturedTexts(); + m_frequency = capture[2].toDouble(); + if (capture.length() == 5) + { + QChar unit = capture[4][0]; + if (unit == 'k') + m_frequency *= 1000.0; + else if (unit == 'M') + m_frequency *= 1000000.0; + else if (unit == 'G') + m_frequency *= 1000000000.0; + } + m_frequencyString = capture[0]; + } + else + { + m_frequency = 0.0; + } +} + +void ObjectMapItem::updateTrack(QList *track) +{ + if (track != nullptr) + { + qDeleteAll(m_takenTrackCoords); + m_takenTrackCoords.clear(); + qDeleteAll(m_takenTrackDateTimes); + m_takenTrackDateTimes.clear(); + m_takenTrack.clear(); + m_takenTrack1.clear(); + m_takenTrack2.clear(); + for (int i = 0; i < track->size(); i++) + { + SWGSDRangel::SWGMapCoordinate* p = track->at(i); + QGeoCoordinate *c = new QGeoCoordinate(p->getLatitude(), p->getLongitude(), p->getAltitude()); + QDateTime *d = new QDateTime(QDateTime::fromString(*p->getDateTime(), Qt::ISODate)); + m_takenTrackCoords.push_back(c); + m_takenTrackDateTimes.push_back(d); + m_takenTrack.push_back(QVariant::fromValue(*c)); + } + } + else + { + // Automatically create a track + if (m_takenTrackCoords.size() == 0) + { + QGeoCoordinate *c = new QGeoCoordinate(m_latitude, m_longitude, m_altitude); + m_takenTrackCoords.push_back(c); + if (m_positionDateTime.isValid()) { + m_takenTrackDateTimes.push_back(new QDateTime(m_positionDateTime)); + } else { + m_takenTrackDateTimes.push_back(new QDateTime(QDateTime::currentDateTime())); + } + m_takenTrack.push_back(QVariant::fromValue(*c)); + } + else + { + QGeoCoordinate *prev = m_takenTrackCoords.last(); + QDateTime *prevDateTime = m_takenTrackDateTimes.last(); + if ((prev->latitude() != m_latitude) || (prev->longitude() != m_longitude) + || (prev->altitude() != m_altitude) || (*prevDateTime != m_positionDateTime)) + { + QGeoCoordinate *c = new QGeoCoordinate(m_latitude, m_longitude, m_altitude); + m_takenTrackCoords.push_back(c); + if (m_positionDateTime.isValid()) { + m_takenTrackDateTimes.push_back(new QDateTime(m_positionDateTime)); + } else { + m_takenTrackDateTimes.push_back(new QDateTime(QDateTime::currentDateTime())); + } + m_takenTrack.push_back(QVariant::fromValue(*c)); + } + } + } +} + +void ObjectMapItem::updatePredictedTrack(QList *track) +{ + if (track != nullptr) + { + qDeleteAll(m_predictedTrackCoords); + m_predictedTrackCoords.clear(); + qDeleteAll(m_predictedTrackDateTimes); + m_predictedTrackDateTimes.clear(); + m_predictedTrack.clear(); + m_predictedTrack1.clear(); + m_predictedTrack2.clear(); + for (int i = 0; i < track->size(); i++) + { + SWGSDRangel::SWGMapCoordinate* p = track->at(i); + QGeoCoordinate *c = new QGeoCoordinate(p->getLatitude(), p->getLongitude(), p->getAltitude()); + QDateTime *d = new QDateTime(QDateTime::fromString(*p->getDateTime(), Qt::ISODate)); + m_predictedTrackCoords.push_back(c); + m_predictedTrackDateTimes.push_back(d); + m_predictedTrack.push_back(QVariant::fromValue(*c)); + } + } +} + diff --git a/plugins/feature/map/mapitem.h b/plugins/feature/map/mapitem.h new file mode 100644 index 000000000..182511c50 --- /dev/null +++ b/plugins/feature/map/mapitem.h @@ -0,0 +1,184 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_MAPITEM_H_ +#define INCLUDE_FEATURE_MAPITEM_H_ + +#include +#include +#include + +#include "mapsettings.h" +#include "cesiuminterface.h" + +#include "SWGMapItem.h" + +class MapModel; +class ObjectMapModel; +class PolygonMapModel; +class PolylineMapModel; +class ImageMapModel; +class CZML; + +class MapItem { + +public: + + MapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem); + virtual void update(SWGSDRangel::SWGMapItem *mapItem); + +protected: + + friend CZML; + friend MapModel; + friend ObjectMapModel; + friend PolygonMapModel; + friend PolylineMapModel; + + QString m_group; + MapSettings::MapItemSettings *m_itemSettings; + const QObject *m_sourcePipe; // Channel/feature that created the item + QString m_hashKey; + + QString m_name; // Unique id + QString m_label; + float m_latitude; // Position for label + float m_longitude; + float m_altitude; // In metres + QDateTime m_availableUntil; // Date & time this item is visible until (for 3D map). Invalid date/time is forever +}; + + +// Information required about each item displayed on the map +class ObjectMapItem : public MapItem { + +public: + ObjectMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) : + MapItem(sourcePipe, group, itemSettings, mapItem) + { + update(mapItem); + } + void update(SWGSDRangel::SWGMapItem *mapItem) override; + QGeoCoordinate getCoordinates(); + +protected: + void findFrequency(); + void updateTrack(QList *track); + void updatePredictedTrack(QList *track); + + friend ObjectMapModel; + friend CZML; + QDateTime m_positionDateTime; + bool m_useHeadingPitchRoll; + float m_heading; + float m_pitch; + float m_roll; + QDateTime m_orientationDateTime; + QString m_image; + int m_imageRotation; + QString m_text; + double m_frequency; // Frequency to set + QString m_frequencyString; + bool m_fixedPosition; // Don't record/display track + QList m_predictedTrackCoords; + QList m_predictedTrackDateTimes; + QVariantList m_predictedTrack; // Line showing where the object is going + QVariantList m_predictedTrack1; + QVariantList m_predictedTrack2; + QGeoCoordinate m_predictedStart1; + QGeoCoordinate m_predictedStart2; + QGeoCoordinate m_predictedEnd1; + QGeoCoordinate m_predictedEnd2; + QList m_takenTrackCoords; + QList m_takenTrackDateTimes; + QVariantList m_takenTrack; // Line showing where the object has been + QVariantList m_takenTrack1; + QVariantList m_takenTrack2; + QGeoCoordinate m_takenStart1; + QGeoCoordinate m_takenStart2; + QGeoCoordinate m_takenEnd1; + QGeoCoordinate m_takenEnd2; + + // For 3D map + QString m_model; + int m_altitudeReference; + float m_labelAltitudeOffset; + float m_modelAltitudeOffset; + QList m_animations; +}; + +class PolygonMapItem : public MapItem { + +public: + PolygonMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) : + MapItem(sourcePipe, group, itemSettings, mapItem) + { + update(mapItem); + } + void update(SWGSDRangel::SWGMapItem *mapItem) override; + +protected: + friend PolygonMapModel; + friend CZML; + + QList m_points; // FIXME: Remove? + float m_extrudedHeight; // In metres + QVariantList m_polygon; + QGeoRectangle m_bounds; // Bounding boxes for the polygons, for view clipping +}; + +class PolylineMapItem : public MapItem { + +public: + PolylineMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) : + MapItem(sourcePipe, group, itemSettings, mapItem) + { + update(mapItem); + } + void update(SWGSDRangel::SWGMapItem *mapItem) override; + +protected: + friend PolylineMapModel; + friend CZML; + + QList m_points; // FIXME: Remove? + QVariantList m_polyline; + QGeoRectangle m_bounds; // Bounding boxes for the polyline, for view clipping +}; + +class ImageMapItem : public MapItem { + +public: + ImageMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) : + MapItem(sourcePipe, group, itemSettings, mapItem) + { + update(mapItem); + } + void update(SWGSDRangel::SWGMapItem *mapItem) override; + +protected: + friend ImageMapModel; + friend CZML; + + QString m_image; + float m_imageZoomLevel; + QGeoRectangle m_bounds; + +}; + +#endif // INCLUDE_FEATURE_MAPITEM_H_ + diff --git a/plugins/feature/map/mapmodel.cpp b/plugins/feature/map/mapmodel.cpp index 6e958925a..7827460c0 100644 --- a/plugins/feature/map/mapmodel.cpp +++ b/plugins/feature/map/mapmodel.cpp @@ -26,193 +26,54 @@ #include "SWGTargetAzimuthElevation.h" -MapItem::MapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) : - m_altitude(0.0) +QVariant MapModel::data(const QModelIndex &index, int role) const { - m_sourcePipe = sourcePipe; - m_group = group; - m_itemSettings = itemSettings; - m_name = *mapItem->getName(); - update(mapItem); -} - -void MapItem::update(SWGSDRangel::SWGMapItem *mapItem) -{ - if (mapItem->getLabel()) { - m_label = *mapItem->getLabel(); - } else { - m_label = ""; + int row = index.row(); + if ((row < 0) || (row >= m_items.count())) { + return QVariant(); } - m_latitude = mapItem->getLatitude(); - m_longitude = mapItem->getLongitude(); - m_altitude = mapItem->getAltitude(); - if (mapItem->getPositionDateTime()) { - m_positionDateTime = QDateTime::fromString(*mapItem->getPositionDateTime(), Qt::ISODateWithMs); - } else { - m_positionDateTime = QDateTime(); - } - m_useHeadingPitchRoll = mapItem->getOrientation() == 1; - m_heading = mapItem->getHeading(); - m_pitch = mapItem->getPitch(); - m_roll = mapItem->getRoll(); - if (mapItem->getOrientationDateTime()) { - m_orientationDateTime = QDateTime::fromString(*mapItem->getOrientationDateTime(), Qt::ISODateWithMs); - } else { - m_orientationDateTime = QDateTime(); - } - m_image = *mapItem->getImage(); - m_imageRotation = mapItem->getImageRotation(); - QString *text = mapItem->getText(); - if (text != nullptr) { - m_text = text->replace("\n", "
"); // Convert to HTML - } else { - m_text = ""; - } - if (mapItem->getModel()) { - m_model = *mapItem->getModel(); - } else { - m_model = ""; - } - m_labelAltitudeOffset = mapItem->getLabelAltitudeOffset(); - m_modelAltitudeOffset = mapItem->getModelAltitudeOffset(); - m_altitudeReference = mapItem->getAltitudeReference(); - m_fixedPosition = mapItem->getFixedPosition(); - QList *animations = mapItem->getAnimations(); - if (animations) + switch (role) { - for (auto animation : *animations) { - m_animations.append(new CesiumInterface::Animation(animation)); - } - } - findFrequency(); - updateTrack(mapItem->getTrack()); - updatePredictedTrack(mapItem->getPredictedTrack()); -} - -QGeoCoordinate MapItem::getCoordinates() -{ - QGeoCoordinate coords; - coords.setLatitude(m_latitude); - coords.setLongitude(m_longitude); - return coords; -} - -void MapItem::findFrequency() -{ - // Look for a frequency in the text for this object - QRegExp re("(([0-9]+(\\.[0-9]+)?) *([kMG])?Hz)"); - if (re.indexIn(m_text) != -1) + case itemSettingsRole: + return QVariant::fromValue(m_items[row]->m_itemSettings); + case nameRole: + return QVariant::fromValue(m_items[row]->m_name); + case labelRole: + return QVariant::fromValue(m_items[row]->m_label); + case positionRole: { - QStringList capture = re.capturedTexts(); - m_frequency = capture[2].toDouble(); - if (capture.length() == 5) - { - QChar unit = capture[4][0]; - if (unit == 'k') - m_frequency *= 1000.0; - else if (unit == 'M') - m_frequency *= 1000000.0; - else if (unit == 'G') - m_frequency *= 1000000000.0; - } - m_frequencyString = capture[0]; + // Coordinates to display the label at + QGeoCoordinate coords; + coords.setLatitude(m_items[row]->m_latitude); + coords.setLongitude(m_items[row]->m_longitude); + coords.setAltitude(m_items[row]->m_altitude); + return QVariant::fromValue(coords); } - else - { - m_frequency = 0.0; + case mapImageMinZoomRole: + // Minimum zoom level at which this is visible + return QVariant::fromValue(m_items[row]->m_itemSettings->m_2DMinZoom); + default: + return QVariant(); } } -void MapItem::updateTrack(QList *track) +bool MapModel::setData(const QModelIndex &index, const QVariant& value, int role) { - if (track != nullptr) - { - qDeleteAll(m_takenTrackCoords); - m_takenTrackCoords.clear(); - qDeleteAll(m_takenTrackDateTimes); - m_takenTrackDateTimes.clear(); - m_takenTrack.clear(); - m_takenTrack1.clear(); - m_takenTrack2.clear(); - for (int i = 0; i < track->size(); i++) - { - SWGSDRangel::SWGMapCoordinate* p = track->at(i); - QGeoCoordinate *c = new QGeoCoordinate(p->getLatitude(), p->getLongitude(), p->getAltitude()); - QDateTime *d = new QDateTime(QDateTime::fromString(*p->getDateTime(), Qt::ISODate)); - m_takenTrackCoords.push_back(c); - m_takenTrackDateTimes.push_back(d); - m_takenTrack.push_back(QVariant::fromValue(*c)); - } - } - else - { - // Automatically create a track - if (m_takenTrackCoords.size() == 0) - { - QGeoCoordinate *c = new QGeoCoordinate(m_latitude, m_longitude, m_altitude); - m_takenTrackCoords.push_back(c); - if (m_positionDateTime.isValid()) { - m_takenTrackDateTimes.push_back(new QDateTime(m_positionDateTime)); - } else { - m_takenTrackDateTimes.push_back(new QDateTime(QDateTime::currentDateTime())); - } - m_takenTrack.push_back(QVariant::fromValue(*c)); - } - else - { - QGeoCoordinate *prev = m_takenTrackCoords.last(); - QDateTime *prevDateTime = m_takenTrackDateTimes.last(); - if ((prev->latitude() != m_latitude) || (prev->longitude() != m_longitude) - || (prev->altitude() != m_altitude) || (*prevDateTime != m_positionDateTime)) - { - QGeoCoordinate *c = new QGeoCoordinate(m_latitude, m_longitude, m_altitude); - m_takenTrackCoords.push_back(c); - if (m_positionDateTime.isValid()) { - m_takenTrackDateTimes.push_back(new QDateTime(m_positionDateTime)); - } else { - m_takenTrackDateTimes.push_back(new QDateTime(QDateTime::currentDateTime())); - } - m_takenTrack.push_back(QVariant::fromValue(*c)); - } - } + (void) value; + (void) role; + + int row = index.row(); + if ((row < 0) || (row >= m_items.count())) { + return false; } + return true; } -void MapItem::updatePredictedTrack(QList *track) -{ - if (track != nullptr) - { - qDeleteAll(m_predictedTrackCoords); - m_predictedTrackCoords.clear(); - qDeleteAll(m_predictedTrackDateTimes); - m_predictedTrackDateTimes.clear(); - m_predictedTrack.clear(); - m_predictedTrack1.clear(); - m_predictedTrack2.clear(); - for (int i = 0; i < track->size(); i++) - { - SWGSDRangel::SWGMapCoordinate* p = track->at(i); - QGeoCoordinate *c = new QGeoCoordinate(p->getLatitude(), p->getLongitude(), p->getAltitude()); - QDateTime *d = new QDateTime(QDateTime::fromString(*p->getDateTime(), Qt::ISODate)); - m_predictedTrackCoords.push_back(c); - m_predictedTrackDateTimes.push_back(d); - m_predictedTrack.push_back(QVariant::fromValue(*c)); - } - } -} - -MapModel::MapModel(MapGUI *gui) : - m_gui(gui), - m_target(-1) -{ - connect(this, &MapModel::dataChanged, this, &MapModel::update3DMap); -} - -Q_INVOKABLE void MapModel::add(MapItem *item) +void MapModel::add(MapItem *item) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); m_items.append(item); - m_selected.append(false); + m_itemsHash.insert(item->m_hashKey, item); endInsertRows(); } @@ -237,7 +98,6 @@ void MapModel::update(const QObject *sourcePipe, SWGSDRangel::SWGMapItem *swgMap { // Update the item item->update(swgMapItem); - splitTracks(item); update(item); } } @@ -248,35 +108,311 @@ void MapModel::update(const QObject *sourcePipe, SWGSDRangel::SWGMapItem *swgMap if (!image.isEmpty()) { // Add new item - item = new MapItem(sourcePipe, group, m_gui->getItemSettings(group), swgMapItem); + item = newMapItem(sourcePipe, group, m_gui->getItemSettings(group), swgMapItem); add(item); // Add to 3D Map (we don't appear to get a dataChanged signal when adding) - CesiumInterface *cesium = m_gui->cesium(); - if (cesium) { - cesium->update(item, isTarget(item), isSelected3D(item)); - } - playAnimations(item); + update3D(item); } } } +void MapModel::update(MapItem *item) +{ + int row = m_items.indexOf(item); + if (row >= 0) + { + QModelIndex idx = index(row); + emit dataChanged(idx, idx); + } +} + +void MapModel::remove(MapItem *item) +{ + int row = m_items.indexOf(item); + if (row >= 0) + { + QString key = m_items[row]->m_hashKey; + beginRemoveRows(QModelIndex(), row, row); + m_items.removeAt(row); + m_itemsHash.remove(key); + endRemoveRows(); + } +} + +void MapModel::removeAll() +{ + if (m_items.count() > 0) + { + beginRemoveRows(QModelIndex(), 0, m_items.count() - 1); + m_items.clear(); + m_itemsHash.clear(); + endRemoveRows(); + } +} + +// After new settings are deserialised, we need to update +// pointers to item settings for all existing items +void MapModel::updateItemSettings(QHash m_itemSettings) +{ + for (auto item : m_items) + { + if (m_itemSettings.contains(item->m_group)) { + item->m_itemSettings = m_itemSettings[item->m_group]; + } + } +} + +void MapModel::allUpdated() +{ + if (m_items.count() > 0) { + emit dataChanged(index(0), index(m_items.count()-1)); + } +} + +MapItem *MapModel::findMapItem(const QObject *source, const QString& name) +{ + QString key = source->objectName() + name; + if (m_itemsHash.contains(key)) { + return m_itemsHash.value(key); + } + return nullptr; +} + +QHash MapModel::roleNames() const +{ + QHash roles; + roles[itemSettingsRole] = "itemSettings"; + roles[nameRole] = "name"; + roles[labelRole] = "label"; + roles[positionRole] = "position"; + roles[mapImageMinZoomRole] = "mapImageMinZoom"; + return roles; +} + // Slot called on dataChanged signal, to update 3D map void MapModel::update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { (void) roles; + for (int row = topLeft.row(); row <= bottomRight.row(); row++) { + update3D(m_items[row]); + } +} + +MapItem *ImageMapModel::newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) +{ + return new ImageMapItem(sourcePipe, group, itemSettings, mapItem); +} + +QVariant ImageMapModel::data(const QModelIndex &index, int role) const +{ + int row = index.row(); + if ((row < 0) || (row >= m_items.count())) { + return QVariant(); + } + ImageMapItem *mapItem = (ImageMapItem*)m_items[row]; + switch (role) + { + case imageRole: + return QVariant::fromValue(mapItem->m_image); + case imageZoomLevelRole: + return QVariant::fromValue(mapItem->m_imageZoomLevel); + case boundsRole: + return QVariant::fromValue(mapItem->m_bounds); + default: + return MapModel::data(index, role); + } +} + +void ImageMapModel::update3D(MapItem *item) +{ + CesiumInterface *cesium = m_gui->cesium(); + if (cesium) + { + ImageMapItem *imageItem = (ImageMapItem *)item; + if (!imageItem->m_image.isEmpty()) + { + /*qDebug() << "ImageMapModel::update3D - " << imageItem->m_name + << imageItem->m_bounds.right() + << imageItem->m_bounds.left() + << imageItem->m_bounds.top() + << imageItem->m_bounds.bottom() + ; */ + cesium->updateImage(imageItem->m_name, + imageItem->m_bounds.topRight().longitude(), + imageItem->m_bounds.bottomLeft().longitude(), + imageItem->m_bounds.topRight().latitude(), + imageItem->m_bounds.bottomLeft().latitude(), + imageItem->m_altitude, + imageItem->m_image); + } + else + { + qDebug() << "ImageMapModel::update3D - removeImage " << imageItem->m_name; + cesium->removeImage(imageItem->m_name); + } + } +} + +MapItem *PolygonMapModel::newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) +{ + return new PolygonMapItem(sourcePipe, group, itemSettings, mapItem); +} + +QVariant PolygonMapModel::data(const QModelIndex &index, int role) const +{ + int row = index.row(); + if ((row < 0) || (row >= m_items.count())) { + return QVariant(); + } + PolygonMapItem *polygonItem = ((PolygonMapItem *)m_items[row]); + switch (role) + { + case borderColorRole: + return QVariant::fromValue(QColor(0x00, 0x00, 0x00, 0x00)); // Transparent + case fillColorRole: + if (m_items[row]->m_itemSettings->m_display2DTrack) { + return QVariant::fromValue(QColor::fromRgba(m_items[row]->m_itemSettings->m_2DTrackColor)); + } else { + return QVariant::fromValue(QColor(0x00, 0x00, 0x00, 0x00)); // Transparent + } + case polygonRole: + return polygonItem->m_polygon; + case boundsRole: + return QVariant::fromValue(polygonItem->m_bounds); + default: + return MapModel::data(index, role); + } +} + +void PolygonMapModel::update3D(MapItem *item) +{ + CesiumInterface *cesium = m_gui->cesium(); + if (cesium) { + cesium->update((PolygonMapItem *)item); + } +} + +MapItem *PolylineMapModel::newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) +{ + return new PolylineMapItem(sourcePipe, group, itemSettings, mapItem); +} + +QVariant PolylineMapModel::data(const QModelIndex &index, int role) const +{ + int row = index.row(); + if ((row < 0) || (row >= m_items.count())) { + return QVariant(); + } + PolylineMapItem *polylineItem = (PolylineMapItem *)m_items[row]; + switch (role) + { + case lineColorRole: + return QVariant::fromValue(QColor::fromRgba(m_items[row]->m_itemSettings->m_2DTrackColor)); + case coordinatesRole: + return QVariant::fromValue(polylineItem->m_polyline); + case boundsRole: + return QVariant::fromValue(polylineItem->m_bounds); + default: + return MapModel::data(index, role); + } +} + +void PolylineMapModel::update3D(MapItem *item) +{ + CesiumInterface *cesium = m_gui->cesium(); + if (cesium) { + cesium->update((PolylineMapItem *)item); + } +} + +ObjectMapModel::ObjectMapModel(MapGUI *gui) : + MapModel(gui), + m_target(-1) +{ + //connect(this, &ObjectMapModel::dataChanged, this, &ObjectMapModel::update3DMap); +} + +Q_INVOKABLE void ObjectMapModel::add(MapItem *item) +{ + m_selected.append(false); + MapModel::add(item); +} + +/*void ObjectMapModel::update(const QObject *sourcePipe, SWGSDRangel::SWGMapItem *swgMapItem, const QString &group) +{ + QString name = *swgMapItem->getName(); + // Add, update or delete and item + ObjectMapItem *item = (ObjectMapItem *)MapModel::findMapItem(sourcePipe, name); + if (item != nullptr) + { + QString image = *swgMapItem->getImage(); + if (image.isEmpty()) + { + // Delete the item + remove(item); + // Need to call update, for it to be removed in 3D map + // Item is set to not be available from this point in time + // It will still be available if time is set in the past + item->update(swgMapItem); + } + else + { + // Update the item + item->update(swgMapItem); + splitTracks(item); // ******** diff from base FIXME + update(item); + } + } + else + { + // Make sure not a duplicate request to delete + QString image = *swgMapItem->getImage(); + if (!image.isEmpty()) + { + // Add new item + item = (ObjectMapItem *)newMapItem(sourcePipe, group, m_gui->getItemSettings(group), swgMapItem); + add(item); + // Add to 3D Map (we don't appear to get a dataChanged signal when adding) + update3D(item); + } + } +}*/ + +MapItem *ObjectMapModel::newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) +{ + return new ObjectMapItem(sourcePipe, group, itemSettings, mapItem); +} + +void ObjectMapModel::update3D(MapItem *item) +{ + CesiumInterface *cesium = m_gui->cesium(); + if (cesium) + { + ObjectMapItem *objectMapItem = (ObjectMapItem *)item; + cesium->update(objectMapItem, isTarget(objectMapItem), isSelected3D(objectMapItem)); + playAnimations(objectMapItem); + } +} + +// Slot called on dataChanged signal, to update 3D map +/*void ObjectMapModel::update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) +{ + (void) roles; + CesiumInterface *cesium = m_gui->cesium(); if (cesium) { for (int row = topLeft.row(); row <= bottomRight.row(); row++) { - cesium->update(m_items[row], isTarget(m_items[row]), isSelected3D(m_items[row])); - playAnimations(m_items[row]); + ObjectMapItem *item = (ObjectMapItem *)m_items[row]; + cesium->update(item, isTarget(item), isSelected3D(item)); + playAnimations(item); } } -} +} */ -void MapModel::playAnimations(MapItem *item) +void ObjectMapModel::playAnimations(ObjectMapItem *item) { CesiumInterface *cesium = m_gui->cesium(); if (cesium) @@ -289,67 +425,69 @@ void MapModel::playAnimations(MapItem *item) item->m_animations.clear(); } -void MapModel::update(MapItem *item) +void ObjectMapModel::update(MapItem *item) { + splitTracks((ObjectMapItem *)item); + MapModel::update(item); int row = m_items.indexOf(item); if (row >= 0) { - QModelIndex idx = index(row); - emit dataChanged(idx, idx); if (row == m_target) { updateTarget(); } } } -void MapModel::remove(MapItem *item) +void ObjectMapModel::remove(MapItem *item) { int row = m_items.indexOf(item); if (row >= 0) { - beginRemoveRows(QModelIndex(), row, row); - m_items.removeAt(row); m_selected.removeAt(row); if (row == m_target) { m_target = -1; } else if (row < m_target) { m_target--; } - endRemoveRows(); + MapModel::remove(item); } } -void MapModel::allUpdated() +void ObjectMapModel::removeAll() { - for (int i = 0; i < m_items.count(); i++) - { - // Updates both 2D and 3D Map - QModelIndex idx = index(i); - emit dataChanged(idx, idx); - } + MapModel::removeAll(); + m_selected.clear(); } -void MapModel::removeAll() +QHash ObjectMapModel::roleNames() const { - if (m_items.count() > 0) - { - beginRemoveRows(QModelIndex(), 0, m_items.count()); - m_items.clear(); - m_selected.clear(); - endRemoveRows(); - } + QHash roles = MapModel::roleNames(); + //roles[itemSettingsRole] = "itemSettings"; + //roles[nameRole] = "name"; + //roles[positionRole] = "position"; + //roles[mapTextRole] = "mapText"; + roles[MapModel::labelRole] = "mapText"; + roles[mapTextVisibleRole] = "mapTextVisible"; + roles[mapImageVisibleRole] = "mapImageVisible"; + roles[mapImageRole] = "mapImage"; + roles[mapImageRotationRole] = "mapImageRotation"; + //roles[mapImageMinZoomRole] = "mapImageMinZoom"; + roles[bubbleColourRole] = "bubbleColour"; + roles[selectedRole] = "selected"; + roles[targetRole] = "target"; + roles[frequencyRole] = "frequency"; + roles[frequencyStringRole] = "frequencyString"; + roles[predictedGroundTrack1Role] = "predictedGroundTrack1"; + roles[predictedGroundTrack2Role] = "predictedGroundTrack2"; + roles[groundTrack1Role] = "groundTrack1"; + roles[groundTrack2Role] = "groundTrack2"; + roles[groundTrackColorRole] = "groundTrackColor"; + roles[predictedGroundTrackColorRole] = "predictedGroundTrackColor"; + roles[hasTracksRole] = "hasTracks"; + return roles; } -// After new settings are deserialised, we need to update -// pointers to item settings for all existing items -void MapModel::updateItemSettings(QHash m_itemSettings) -{ - for (auto item : m_items) { - item->m_itemSettings = m_itemSettings[item->m_group]; - } -} - -void MapModel::updateTarget() +void ObjectMapModel::updateTarget() { // Calculate range, azimuth and elevation to object from station AzEl *azEl = m_gui->getAzEl(); @@ -371,21 +509,21 @@ void MapModel::updateTarget() } } -void MapModel::setTarget(const QString& name) +void ObjectMapModel::setTarget(const QString& name) { if (name.isEmpty()) { QModelIndex idx = index(-1); - setData(idx, QVariant(-1), MapModel::targetRole); + setData(idx, QVariant(-1), ObjectMapModel::targetRole); } else { QModelIndex idx = findMapItemIndex(name); - setData(idx, QVariant(idx.row()), MapModel::targetRole); + setData(idx, QVariant(idx.row()), ObjectMapModel::targetRole); } } -bool MapModel::isTarget(const MapItem *mapItem) const +bool ObjectMapModel::isTarget(const ObjectMapItem *mapItem) const { if (m_target < 0) { return false; @@ -396,13 +534,13 @@ bool MapModel::isTarget(const MapItem *mapItem) const // FIXME: This should use Z order - rather than adding/removing // but I couldn't quite get it to work -Q_INVOKABLE void MapModel::moveToFront(int oldRow) +Q_INVOKABLE void ObjectMapModel::moveToFront(int oldRow) { // Last item in list is drawn on top, so remove than add to end of list if (oldRow < m_items.size() - 1) { bool wasTarget = m_target == oldRow; - MapItem *item = m_items[oldRow]; + ObjectMapItem *item = (ObjectMapItem *)m_items[oldRow]; bool wasSelected = m_selected[oldRow]; remove(item); add(item); @@ -416,7 +554,7 @@ Q_INVOKABLE void MapModel::moveToFront(int oldRow) } } -Q_INVOKABLE void MapModel::moveToBack(int oldRow) +Q_INVOKABLE void ObjectMapModel::moveToBack(int oldRow) { // First item in list is drawn first, so remove item then add to front of list if ((oldRow < m_items.size()) && (oldRow > 0)) @@ -440,32 +578,22 @@ Q_INVOKABLE void MapModel::moveToBack(int oldRow) } } -MapItem *MapModel::findMapItem(const QObject *source, const QString& name) -{ - // FIXME: Should consider adding a QHash for this - QListIterator i(m_items); - while (i.hasNext()) - { - MapItem *item = i.next(); - if ((item->m_name == name) && (item->m_sourcePipe == source)) - return item; - } - return nullptr; -} - -MapItem *MapModel::findMapItem(const QString& name) +// FIXME: This should potentially return a list, as we have have multiple items with the same name +// from different sources +ObjectMapItem *ObjectMapModel::findMapItem(const QString& name) { QListIterator i(m_items); while (i.hasNext()) { MapItem *item = i.next(); - if (item->m_name == name) - return item; + if (item->m_name == name) { + return (ObjectMapItem *)item; + } } return nullptr; } -QModelIndex MapModel::findMapItemIndex(const QString& name) +QModelIndex ObjectMapModel::findMapItemIndex(const QString& name) { int idx = 0; QListIterator i(m_items); @@ -480,76 +608,50 @@ QModelIndex MapModel::findMapItemIndex(const QString& name) return index(-1); } -int MapModel::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent) - return m_items.count(); -} - -QVariant MapModel::data(const QModelIndex &index, int role) const +QVariant ObjectMapModel::data(const QModelIndex &index, int role) const { int row = index.row(); - if ((row < 0) || (row >= m_items.count())) { return QVariant(); } - if (role == MapModel::positionRole) + ObjectMapItem *mapItem = (ObjectMapItem*)m_items[row]; + switch (role) { - // Coordinates to display the item at - QGeoCoordinate coords; - coords.setLatitude(m_items[row]->m_latitude); - coords.setLongitude(m_items[row]->m_longitude); - return QVariant::fromValue(coords); - } - else if (role == MapModel::mapTextRole) + case labelRole: // mapTextRole) { // Create the text to go in the bubble next to the image - QString name = m_items[row]->m_label.isEmpty() ? m_items[row]->m_name : m_items[row]->m_label; + QString name = mapItem->m_label.isEmpty() ? mapItem->m_name :mapItem->m_label; if (row == m_target) { AzEl *azEl = m_gui->getAzEl(); - QString text = QString("%1
Az: %2%5 El: %3%5 Dist: %4 km") - .arg(m_selected[row] ? m_items[row]->m_text : name) + QString text = QString("%1
Az: %2%5 El: %3%5 Dist: %4 km
Coords: %6, %7") + .arg(m_selected[row] ? mapItem->m_text : name) .arg(std::round(azEl->getAzimuth())) .arg(std::round(azEl->getElevation())) .arg(std::round(azEl->getDistance() / 1000.0)) - .arg(QChar(0xb0)); + .arg(QChar(0xb0)) + .arg(mapItem->m_latitude) + .arg(mapItem->m_longitude); return QVariant::fromValue(text); } else if (m_selected[row]) { - return QVariant::fromValue(m_items[row]->m_text); + return QVariant::fromValue(mapItem->m_text); } else { return QVariant::fromValue(name); } } - else if (role == MapModel::mapTextVisibleRole) - { - return QVariant::fromValue((m_selected[row] || m_displayNames) && m_items[row]->m_itemSettings->m_enabled && m_items[row]->m_itemSettings->m_display2DLabel); - } - else if (role == MapModel::mapImageVisibleRole) - { - return QVariant::fromValue(m_items[row]->m_itemSettings->m_enabled && m_items[row]->m_itemSettings->m_display2DIcon); - } - else if (role == MapModel::mapImageRole) - { - // Set an image to use - return QVariant::fromValue(m_items[row]->m_image); - } - else if (role == MapModel::mapImageRotationRole) - { - // Angle to rotate image by - return QVariant::fromValue(m_items[row]->m_imageRotation); - } - else if (role == MapModel::mapImageMinZoomRole) - { - // Minimum zoom level - //return QVariant::fromValue(m_items[row]->m_imageMinZoom); - return QVariant::fromValue(m_items[row]->m_itemSettings->m_2DMinZoom); - } - else if (role == MapModel::bubbleColourRole) + case mapTextVisibleRole: + return QVariant::fromValue((m_selected[row] || m_displayNames) && mapItem->m_itemSettings->m_display2DLabel); + case mapImageVisibleRole: + return QVariant::fromValue(mapItem->m_itemSettings->m_display2DIcon); + case mapImageRole: + return QVariant::fromValue(mapItem->m_image); // Set an image to use + case mapImageRotationRole: + return QVariant::fromValue(mapItem->m_imageRotation); // Angle to rotate image by + case bubbleColourRole: { // Select a background colour for the text bubble next to the item if (m_selected[row]) { @@ -558,81 +660,81 @@ QVariant MapModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(QColor("lightblue")); } } - else if (role == MapModel::selectedRole) - { + case selectedRole: return QVariant::fromValue(m_selected[row]); - } - else if (role == MapModel::targetRole) - { + case targetRole: return QVariant::fromValue(m_target == row); - } - else if (role == MapModel::frequencyRole) - { - return QVariant::fromValue(m_items[row]->m_frequency); - } - else if (role == MapModel::frequencyStringRole) - { - return QVariant::fromValue(m_items[row]->m_frequencyString); - } - else if (role == MapModel::predictedGroundTrack1Role) + case frequencyRole: + return QVariant::fromValue(mapItem->m_frequency); + case frequencyStringRole: + return QVariant::fromValue(mapItem->m_frequencyString); + case predictedGroundTrack1Role: { if ( (m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) - && m_items[row]->m_itemSettings->m_enabled && m_items[row]->m_itemSettings->m_display2DTrack) { - return m_items[row]->m_predictedTrack1; + && mapItem->m_itemSettings->m_display2DTrack) { + return mapItem->m_predictedTrack1; } else { return QVariantList(); } } - else if (role == MapModel::predictedGroundTrack2Role) + case predictedGroundTrack2Role: { if ( (m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) - && m_items[row]->m_itemSettings->m_enabled && m_items[row]->m_itemSettings->m_display2DTrack) { - return m_items[row]->m_predictedTrack2; + && mapItem->m_itemSettings->m_display2DTrack) { + return mapItem->m_predictedTrack2; } else { return QVariantList(); } } - else if (role == MapModel::groundTrack1Role) + case groundTrack1Role: { if ( (m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) - && m_items[row]->m_itemSettings->m_enabled && m_items[row]->m_itemSettings->m_display2DTrack) { - return m_items[row]->m_takenTrack1; + && mapItem->m_itemSettings->m_display2DTrack) { + return mapItem->m_takenTrack1; } else { return QVariantList(); } } - else if (role == MapModel::groundTrack2Role) + case groundTrack2Role: { if ( (m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) - && m_items[row]->m_itemSettings->m_enabled && m_items[row]->m_itemSettings->m_display2DTrack) { - return m_items[row]->m_takenTrack2; + && mapItem->m_itemSettings->m_display2DTrack) { + return mapItem->m_takenTrack2; } else { return QVariantList(); } } - else if (role == groundTrackColorRole) + case groundTrackColorRole: + return QVariant::fromValue(QColor::fromRgb(mapItem->m_itemSettings->m_2DTrackColor)); + case predictedGroundTrackColorRole: + return QVariant::fromValue(QColor::fromRgb(mapItem->m_itemSettings->m_2DTrackColor).lighter()); + case hasTracksRole: { - return QVariant::fromValue(QColor::fromRgb(m_items[row]->m_itemSettings->m_2DTrackColor)); + bool hasTracks = (m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) + && ( (mapItem->m_predictedTrack1.size() > 1) + || (mapItem->m_predictedTrack2.size() > 1) + || (mapItem->m_takenTrack1.size() > 1) + || (mapItem->m_takenTrack2.size() > 1) + ); + return QVariant::fromValue(hasTracks); } - else if (role == predictedGroundTrackColorRole) - { - return QVariant::fromValue(QColor::fromRgb(m_items[row]->m_itemSettings->m_2DTrackColor).lighter()); + default: + return MapModel::data(index, role); } - return QVariant(); } -bool MapModel::setData(const QModelIndex &idx, const QVariant& value, int role) +bool ObjectMapModel::setData(const QModelIndex &idx, const QVariant& value, int role) { int row = idx.row(); if ((row < 0) || (row >= m_items.count())) return false; - if (role == MapModel::selectedRole) + if (role == selectedRole) { m_selected[row] = value.toBool(); emit dataChanged(idx, idx); return true; } - else if (role == MapModel::targetRole) + else if (role == targetRole) { if (m_target >= 0) { @@ -649,37 +751,31 @@ bool MapModel::setData(const QModelIndex &idx, const QVariant& value, int role) return true; } -Qt::ItemFlags MapModel::flags(const QModelIndex &index) const -{ - (void) index; - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; -} - -void MapModel::setDisplayNames(bool displayNames) +void ObjectMapModel::setDisplayNames(bool displayNames) { m_displayNames = displayNames; allUpdated(); } -void MapModel::setDisplaySelectedGroundTracks(bool displayGroundTracks) +void ObjectMapModel::setDisplaySelectedGroundTracks(bool displayGroundTracks) { m_displaySelectedGroundTracks = displayGroundTracks; allUpdated(); } -void MapModel::setDisplayAllGroundTracks(bool displayGroundTracks) +void ObjectMapModel::setDisplayAllGroundTracks(bool displayGroundTracks) { m_displayAllGroundTracks = displayGroundTracks; allUpdated(); } -void MapModel::setFrequency(double frequency) +void ObjectMapModel::setFrequency(double frequency) { // Set as centre frequency ChannelWebAPIUtils::setCenterFrequency(0, frequency); } -void MapModel::track3D(int index) +void ObjectMapModel::track3D(int index) { if (index < m_items.count()) { @@ -688,17 +784,21 @@ void MapModel::track3D(int index) } } -void MapModel::splitTracks(MapItem *item) +void ObjectMapModel::splitTracks(ObjectMapItem *item) { if (item->m_takenTrackCoords.size() > 1) + { splitTrack(item->m_takenTrackCoords, item->m_takenTrack, item->m_takenTrack1, item->m_takenTrack2, item->m_takenStart1, item->m_takenStart2, item->m_takenEnd1, item->m_takenEnd2); + } if (item->m_predictedTrackCoords.size() > 1) + { splitTrack(item->m_predictedTrackCoords, item->m_predictedTrack, item->m_predictedTrack1, item->m_predictedTrack2, item->m_predictedStart1, item->m_predictedStart2, item->m_predictedEnd1, item->m_predictedEnd2); + } } -void MapModel::interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen) +void ObjectMapModel::interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen) { double x1 = c1->longitude(); double y1 = c1->latitude(); @@ -721,7 +821,7 @@ void MapModel::interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, ci->setAltitude(c1->altitude()); } -void MapModel::interpolateWest(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen) +void ObjectMapModel::interpolateWest(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen) { double x1 = c1->longitude(); double y1 = c1->latitude(); @@ -827,7 +927,7 @@ static bool crossesEdge(double lon, double prevLon, double bottomLeftLongitude, } } -void MapModel::interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottomLeftLongitude, double bottomRightLongitude, QGeoCoordinate* ci, bool offScreen) +void ObjectMapModel::interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottomLeftLongitude, double bottomRightLongitude, QGeoCoordinate* ci, bool offScreen) { double x1 = c1->longitude(); double x2 = c2->longitude(); @@ -849,7 +949,7 @@ void MapModel::interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottom } } -void MapModel::splitTrack(const QList& coords, const QVariantList& track, +void ObjectMapModel::splitTrack(const QList& coords, const QVariantList& track, QVariantList& track1, QVariantList& track2, QGeoCoordinate& start1, QGeoCoordinate& start2, QGeoCoordinate& end1, QGeoCoordinate& end2) @@ -968,29 +1068,297 @@ void MapModel::splitTrack(const QList& coords, const QVariantL */ } -void MapModel::viewChanged(double bottomLeftLongitude, double bottomRightLongitude) +void ObjectMapModel::viewChanged(double bottomLeftLongitude, double bottomRightLongitude) { (void) bottomRightLongitude; + if (!std::isnan(bottomLeftLongitude)) { for (int row = 0; row < m_items.size(); row++) { - MapItem *item = m_items[row]; - if (item->m_takenTrackCoords.size() > 1) + ObjectMapItem *item = (ObjectMapItem *)m_items[row]; + if (m_items[row]->m_itemSettings->m_enabled) { - splitTrack(item->m_takenTrackCoords, item->m_takenTrack, item->m_takenTrack1, item->m_takenTrack2, - item->m_takenStart1, item->m_takenStart2, item->m_takenEnd1, item->m_takenEnd2); - QModelIndex idx = index(row); - emit dataChanged(idx, idx); - } - if (item->m_predictedTrackCoords.size() > 1) - { - splitTrack(item->m_predictedTrackCoords, item->m_predictedTrack, item->m_predictedTrack1, item->m_predictedTrack2, - item->m_predictedStart1, item->m_predictedStart2, item->m_predictedEnd1, item->m_predictedEnd2); - QModelIndex idx = index(row); - emit dataChanged(idx, idx); + if (item->m_takenTrackCoords.size() > 1) + { + splitTrack(item->m_takenTrackCoords, item->m_takenTrack, item->m_takenTrack1, item->m_takenTrack2, + item->m_takenStart1, item->m_takenStart2, item->m_takenEnd1, item->m_takenEnd2); + QModelIndex idx = index(row); + QVector roles = {groundTrack1Role, groundTrack2Role}; + emit dataChanged(idx, idx, roles); + } + if (item->m_predictedTrackCoords.size() > 1) + { + splitTrack(item->m_predictedTrackCoords, item->m_predictedTrack, item->m_predictedTrack1, item->m_predictedTrack2, + item->m_predictedStart1, item->m_predictedStart2, item->m_predictedEnd1, item->m_predictedEnd2); + QModelIndex idx = index(row); + QVector roles = {predictedGroundTrack1Role, predictedGroundTrack2Role}; + emit dataChanged(idx, idx, roles); + } } } } } +bool ObjectMapFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent); + + MapSettings::MapItemSettings *itemSettings = sourceModel()->data(index0, ObjectMapModel::itemSettingsRole).value(); + if (!itemSettings->m_enabled) { + return false; + } + + // Don't show tiny items when we're zoomed out + int minZoom = sourceModel()->data(index0, ObjectMapModel::mapImageMinZoomRole).toInt(); + if (minZoom - 3 >= m_zoomLevel) { + return false; + } + + // Don't show off-screen items, unless they have tracks, as these may be on screen + // In the future, we could calculate a bounding box for tracks, if helpful for performance + QGeoCoordinate coord = sourceModel()->data(index0, ObjectMapModel::positionRole).value(); + float lat = coord.latitude(); + float lon = coord.longitude(); + bool onScreen = (lat >= m_bottomRightLatitude) && (lat <= m_topLeftLatitude) && (lon >= m_topLeftLongitude) && (lon <= m_bottomRightLongitude); + if (!onScreen) + { + bool hasTracks = sourceModel()->data(index0, ObjectMapModel::hasTracksRole).toBool(); + if (!hasTracks) { + return false; + } + } + + // Apply user filter + if (!itemSettings->m_filterName.isEmpty()) + { + QString name = sourceModel()->data(index0, ObjectMapModel::nameRole).toString(); + QRegularExpressionMatch match = itemSettings->m_filterNameRE.match(name); + if (!match.hasMatch()) { + return false; + } + } + if (itemSettings->m_filterDistance > 0) + { + QGeoCoordinate position = sourceModel()->data(index0, ObjectMapModel::positionRole).value(); + if (m_position.distanceTo(position) > itemSettings->m_filterDistance) { + return false; + } + } + + return true; +} + + +void ObjectMapFilter::viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel) +{ + m_zoomLevel = zoomLevel; + if (!std::isnan(topLeftLongitude)) + { + m_topLeftLongitude = topLeftLongitude; + m_topLeftLatitude = topLeftLatitude; + m_bottomRightLongitude = bottomRightLongitude; + m_bottomRightLatitude = bottomRightLatitude; + } + invalidateFilter(); +} + +Q_INVOKABLE int ObjectMapFilter::mapRowToSource(int row) +{ + QModelIndex sourceIndex = mapToSource(index(row, 0)); + return sourceIndex.row(); +} + + +bool PolygonFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent); + + MapSettings::MapItemSettings *itemSettings = sourceModel()->data(index0, PolygonMapModel::itemSettingsRole).value(); + if (!itemSettings->m_enabled) { + return false; + } + + // Don't show tiny items when we're zoomed out + int minZoom = sourceModel()->data(index0, PolygonMapModel::mapImageMinZoomRole).toInt(); + if (minZoom - 3 >= m_zoomLevel) { + return false; + } + + // Filter off-screen items + QGeoRectangle bounds = sourceModel()->data(index0, PolygonMapModel::boundsRole).value(); + if (!m_view.intersects(bounds)) { + return false; + } + + // Apply user filter + if (!itemSettings->m_filterName.isEmpty()) + { + QString name = sourceModel()->data(index0, PolygonMapModel::nameRole).toString(); + QRegularExpressionMatch match = itemSettings->m_filterNameRE.match(name); + if (!match.hasMatch()) { + return false; + } + } + if (itemSettings->m_filterDistance > 0) + { + QGeoCoordinate position = sourceModel()->data(index0, PolygonMapModel::positionRole).value(); + if (m_position.distanceTo(position) > itemSettings->m_filterDistance) { + return false; + } + } + + return true; +} + +void PolygonFilter::viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel) +{ + m_zoomLevel = zoomLevel; + if (!std::isnan(topLeftLongitude)) { + m_view = QGeoRectangle(QGeoCoordinate(topLeftLatitude, topLeftLongitude), QGeoCoordinate(bottomRightLatitude, bottomRightLongitude)); + } + invalidateFilter(); +} + +Q_INVOKABLE int PolygonFilter::mapRowToSource(int row) +{ + QModelIndex sourceIndex = mapToSource(index(row, 0)); + return sourceIndex.row(); +} + +bool PolylineFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent); + + MapSettings::MapItemSettings *itemSettings = sourceModel()->data(index0, PolylineMapModel::itemSettingsRole).value(); + if (!itemSettings->m_enabled) { + return false; + } + + // Don't show tiny items when we're zoomed out + int minZoom = sourceModel()->data(index0, PolylineMapModel::mapImageMinZoomRole).toInt(); + if (minZoom - 3 >= m_zoomLevel) { + return false; + } + + // Filter off-screen items + QGeoRectangle bounds = sourceModel()->data(index0, PolylineMapModel::boundsRole).value(); + if (!m_view.intersects(bounds)) { + return false; + } + + // Apply user filter + if (!itemSettings->m_filterName.isEmpty()) + { + QString name = sourceModel()->data(index0, PolylineMapModel::nameRole).toString(); + QRegularExpressionMatch match = itemSettings->m_filterNameRE.match(name); + if (!match.hasMatch()) { + return false; + } + } + if (itemSettings->m_filterDistance > 0) + { + QGeoCoordinate position = sourceModel()->data(index0, PolylineMapModel::positionRole).value(); + if (m_position.distanceTo(position) > itemSettings->m_filterDistance) { + return false; + } + } + + return true; +} + +void PolylineFilter::viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel) +{ + m_zoomLevel = zoomLevel; + if (!std::isnan(topLeftLongitude)) { + m_view = QGeoRectangle(QGeoCoordinate(topLeftLatitude, topLeftLongitude), QGeoCoordinate(bottomRightLatitude, bottomRightLongitude)); + } + invalidateFilter(); +} + +Q_INVOKABLE int PolylineFilter::mapRowToSource(int row) +{ + QModelIndex sourceIndex = mapToSource(index(row, 0)); + return sourceIndex.row(); +} + +bool ImageFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent); + + MapSettings::MapItemSettings *itemSettings = sourceModel()->data(index0, ImageMapModel::itemSettingsRole).value(); + if (!itemSettings->m_enabled || !itemSettings->m_display2DIcon) { + return false; + } + + // Don't show tiny items when we're zoomed out + int minZoom = sourceModel()->data(index0, ImageMapModel::mapImageMinZoomRole).toInt(); + if (minZoom - 3 >= m_zoomLevel) { + return false; + } + + // Filter off-screen items + QGeoRectangle bounds = sourceModel()->data(index0, ImageMapModel::boundsRole).value(); + if (!m_view.intersects(bounds)) { + return false; + } + + // Apply user filter + if (!itemSettings->m_filterName.isEmpty()) + { + QString name = sourceModel()->data(index0, ImageMapModel::nameRole).toString(); + QRegularExpressionMatch match = itemSettings->m_filterNameRE.match(name); + if (!match.hasMatch()) { + return false; + } + } + if (itemSettings->m_filterDistance > 0) + { + QGeoCoordinate position = sourceModel()->data(index0, ImageMapModel::positionRole).value(); + if (m_position.distanceTo(position) > itemSettings->m_filterDistance) { + return false; + } + } + + return true; +} + +void ImageFilter::viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel) +{ + m_zoomLevel = zoomLevel; + if (!std::isnan(topLeftLongitude)) { + m_view = QGeoRectangle(QGeoCoordinate(topLeftLatitude, topLeftLongitude), QGeoCoordinate(bottomRightLatitude, bottomRightLongitude)); + } + invalidateFilter(); +} + +Q_INVOKABLE int ImageFilter::mapRowToSource(int row) +{ + QModelIndex sourceIndex = mapToSource(index(row, 0)); + return sourceIndex.row(); +} + +void PolygonFilter::setPosition(const QGeoCoordinate& position) +{ + m_position = position; + invalidateFilter(); +} + +void PolylineFilter::setPosition(const QGeoCoordinate& position) +{ + m_position = position; + invalidateFilter(); +} + +void ObjectMapFilter::setPosition(const QGeoCoordinate& position) +{ + m_position = position; + invalidateFilter(); +} + +void ImageFilter::setPosition(const QGeoCoordinate& position) +{ + m_position = position; + invalidateFilter(); +} + diff --git a/plugins/feature/map/mapmodel.h b/plugins/feature/map/mapmodel.h index 69bb36480..3db617eb4 100644 --- a/plugins/feature/map/mapmodel.h +++ b/plugins/feature/map/mapmodel.h @@ -19,135 +19,227 @@ #define INCLUDE_FEATURE_MAPMODEL_H_ #include +#include #include +#include #include #include "util/azel.h" +#include "util/openaip.h" #include "mapsettings.h" +#include "mapitem.h" #include "cesiuminterface.h" #include "SWGMapItem.h" -class MapModel; class MapGUI; class CZML; -// Information required about each item displayed on the map -class MapItem { - -public: - MapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem); - void update(SWGSDRangel::SWGMapItem *mapItem); - QGeoCoordinate getCoordinates(); - -private: - void findFrequency(); - void updateTrack(QList *track); - void updatePredictedTrack(QList *track); - - friend MapModel; - friend CZML; - QString m_group; - MapSettings::MapItemSettings *m_itemSettings; - const QObject *m_sourcePipe; // Channel/feature that created the item - QString m_name; - QString m_label; - float m_latitude; - float m_longitude; - float m_altitude; // In metres - QDateTime m_positionDateTime; - bool m_useHeadingPitchRoll; - float m_heading; - float m_pitch; - float m_roll; - QDateTime m_orientationDateTime; - QString m_image; - int m_imageRotation; - QString m_text; - double m_frequency; // Frequency to set - QString m_frequencyString; - QList m_predictedTrackCoords; - QList m_predictedTrackDateTimes; - QVariantList m_predictedTrack; // Line showing where the object is going - QVariantList m_predictedTrack1; - QVariantList m_predictedTrack2; - QGeoCoordinate m_predictedStart1; - QGeoCoordinate m_predictedStart2; - QGeoCoordinate m_predictedEnd1; - QGeoCoordinate m_predictedEnd2; - QList m_takenTrackCoords; - QList m_takenTrackDateTimes; - QVariantList m_takenTrack; // Line showing where the object has been - QVariantList m_takenTrack1; - QVariantList m_takenTrack2; - QGeoCoordinate m_takenStart1; - QGeoCoordinate m_takenStart2; - QGeoCoordinate m_takenEnd1; - QGeoCoordinate m_takenEnd2; - - // For 3D map - QString m_model; - int m_altitudeReference; - float m_labelAltitudeOffset; - float m_modelAltitudeOffset; - bool m_fixedPosition; - QList m_animations; -}; - -// Model used for each item on the map class MapModel : public QAbstractListModel { Q_OBJECT public: - using QAbstractListModel::QAbstractListModel; enum MarkerRoles { - positionRole = Qt::UserRole + 1, - mapTextRole = Qt::UserRole + 2, - mapTextVisibleRole = Qt::UserRole + 3, - mapImageVisibleRole = Qt::UserRole + 4, - mapImageRole = Qt::UserRole + 5, - mapImageRotationRole = Qt::UserRole + 6, - mapImageMinZoomRole = Qt::UserRole + 7, - bubbleColourRole = Qt::UserRole + 8, - selectedRole = Qt::UserRole + 9, - targetRole = Qt::UserRole + 10, - frequencyRole = Qt::UserRole + 11, - frequencyStringRole = Qt::UserRole + 12, - predictedGroundTrack1Role = Qt::UserRole + 13, - predictedGroundTrack2Role = Qt::UserRole + 14, - groundTrack1Role = Qt::UserRole + 15, - groundTrack2Role = Qt::UserRole + 16, - groundTrackColorRole = Qt::UserRole + 17, - predictedGroundTrackColorRole = Qt::UserRole + 18 + itemSettingsRole = Qt::UserRole + 1, + nameRole = Qt::UserRole + 2, + labelRole = Qt::UserRole + 3, + positionRole = Qt::UserRole + 4, + mapImageMinZoomRole = Qt::UserRole + 5, + lastRole = Qt::UserRole + 6 }; - MapModel(MapGUI *gui); + MapModel(MapGUI *gui) : + m_gui(gui) + { + connect(this, &MapModel::dataChanged, this, &MapModel::update3DMap); + } - void playAnimations(MapItem *item); - - Q_INVOKABLE void add(MapItem *item); + virtual void add(MapItem *item); + virtual void remove(MapItem *item); + virtual void removeAll(); void update(const QObject *source, SWGSDRangel::SWGMapItem *swgMapItem, const QString &group=""); - void update(MapItem *item); - void remove(MapItem *item); - void allUpdated(); - void removeAll(); void updateItemSettings(QHash m_itemSettings); + void allUpdated(); + + MapItem *findMapItem(const QObject *source, const QString& name); + + QHash roleNames() const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant& value, int role = Qt::EditRole) override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override + { + (void) parent; + return m_items.count(); + } + + Qt::ItemFlags flags(const QModelIndex &index) const override + { + (void) index; + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; + } + +public slots: + void update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); + +protected: + + MapGUI *m_gui; + QList m_items; + QHash m_itemsHash; + + virtual void update(MapItem *item); + virtual void update3D(MapItem *item) = 0; + virtual MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) = 0; + +}; + +class ImageMapModel : public MapModel { + Q_OBJECT + +public: + enum MarkerRoles { + imageRole = MapModel::lastRole + 0, + imageZoomLevelRole = MapModel::lastRole + 1, + boundsRole = MapModel::lastRole + 2 + }; + + ImageMapModel(MapGUI *gui) : + MapModel(gui) + {} + + QHash roleNames() const override + { + QHash roles = MapModel::roleNames(); + roles[imageRole] = "imageData"; + roles[imageZoomLevelRole] = "imageZoomLevel"; + roles[boundsRole] = "bounds"; + return roles; + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +protected: + MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) override; + void update3D(MapItem *item) override; + +}; + +class PolygonMapModel : public MapModel { + Q_OBJECT + +public: + enum MarkerRoles { + borderColorRole = MapModel::lastRole + 0, + fillColorRole = MapModel::lastRole + 1, + polygonRole = MapModel::lastRole + 2, + boundsRole = MapModel::lastRole + 3 + }; + + PolygonMapModel(MapGUI *gui) : + MapModel(gui) + {} + + QHash roleNames() const override + { + QHash roles = MapModel::roleNames(); + roles[borderColorRole] = "borderColor"; + roles[fillColorRole] = "fillColor"; + roles[polygonRole] = "polygon"; + roles[boundsRole] = "bounds"; + return roles; + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +protected: + void update3D(MapItem *item) override; + MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) override; + +}; + +class PolylineMapModel : public MapModel { + Q_OBJECT + +public: + + enum MarkerRoles { + lineColorRole = MapModel::lastRole + 0, + coordinatesRole = MapModel::lastRole + 1, + boundsRole = MapModel::lastRole + 2, + }; + + PolylineMapModel(MapGUI *gui) : + MapModel(gui) + {} + + QHash roleNames() const override + { + QHash roles = MapModel::roleNames(); + roles[lineColorRole] = "lineColor"; + roles[coordinatesRole] = "coordinates"; + roles[boundsRole] = "bounds"; + return roles; + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +protected: + void update3D(MapItem *item) override; + MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) override; +}; + +// Model used for each item on the map +class ObjectMapModel : public MapModel { + Q_OBJECT + +public: + + enum MarkerRoles { + //itemSettingsRole = Qt::UserRole + 1, + //nameRole = Qt::UserRole + 2, + //positionRole = Qt::UserRole + 3, + // label? mapTextRole = Qt::UserRole + 4, + mapTextVisibleRole =MapModel::lastRole + 0, + mapImageVisibleRole = MapModel::lastRole + 1, + mapImageRole = MapModel::lastRole + 2, + mapImageRotationRole = MapModel::lastRole + 3, + //mapImageMinZoomRole = MapModel::lastRole + 9, + bubbleColourRole = MapModel::lastRole + 4, + selectedRole = MapModel::lastRole + 5, + targetRole = MapModel::lastRole + 6, + frequencyRole = MapModel::lastRole + 7, + frequencyStringRole = MapModel::lastRole + 8, + predictedGroundTrack1Role = MapModel::lastRole + 9, + predictedGroundTrack2Role = MapModel::lastRole + 10, + groundTrack1Role = MapModel::lastRole + 11, + groundTrack2Role = MapModel::lastRole + 12, + groundTrackColorRole = MapModel::lastRole + 13, + predictedGroundTrackColorRole = MapModel::lastRole + 14, + hasTracksRole = MapModel::lastRole + 15 + }; + + ObjectMapModel(MapGUI *gui); + + Q_INVOKABLE void add(MapItem *item) override; + //void update(const QObject *source, SWGSDRangel::SWGMapItem *swgMapItem, const QString &group=""); + using MapModel::update; + void remove(MapItem *item) override; + void removeAll() override; + QHash roleNames() const override; void updateTarget(); void setTarget(const QString& name); - bool isTarget(const MapItem *mapItem) const; + bool isTarget(const ObjectMapItem *mapItem) const; Q_INVOKABLE void moveToFront(int oldRow); Q_INVOKABLE void moveToBack(int oldRow); - MapItem *findMapItem(const QObject *source, const QString& name); - MapItem *findMapItem(const QString& name); + ObjectMapItem *findMapItem(const QString& name); QModelIndex findMapItemIndex(const QString& name); - int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant& value, int role = Qt::EditRole) override; - Qt::ItemFlags flags(const QModelIndex &index) const override; void setDisplayNames(bool displayNames); void setDisplaySelectedGroundTracks(bool displayGroundTracks); @@ -155,48 +247,9 @@ public: Q_INVOKABLE void setFrequency(double frequency); Q_INVOKABLE void track3D(int index); - void interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen); - void interpolateWest(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen); - void interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottomLeftLongitude, double bottomRightLongitude, QGeoCoordinate* ci, bool offScreen); - - void splitTracks(MapItem *item); - void splitTrack(const QList& coords, const QVariantList& track, - QVariantList& track1, QVariantList& track2, - QGeoCoordinate& start1, QGeoCoordinate& start2, - QGeoCoordinate& end1, QGeoCoordinate& end2); Q_INVOKABLE void viewChanged(double bottomLeftLongitude, double bottomRightLongitude); - QHash roleNames() const - { - QHash roles; - roles[positionRole] = "position"; - roles[mapTextRole] = "mapText"; - roles[mapTextVisibleRole] = "mapTextVisible"; - roles[mapImageVisibleRole] = "mapImageVisible"; - roles[mapImageRole] = "mapImage"; - roles[mapImageRotationRole] = "mapImageRotation"; - roles[mapImageMinZoomRole] = "mapImageMinZoom"; - roles[bubbleColourRole] = "bubbleColour"; - roles[selectedRole] = "selected"; - roles[targetRole] = "target"; - roles[frequencyRole] = "frequency"; - roles[frequencyStringRole] = "frequencyString"; - roles[predictedGroundTrack1Role] = "predictedGroundTrack1"; - roles[predictedGroundTrack2Role] = "predictedGroundTrack2"; - roles[groundTrack1Role] = "groundTrack1"; - roles[groundTrack2Role] = "groundTrack2"; - roles[groundTrackColorRole] = "groundTrackColor"; - roles[predictedGroundTrackColorRole] = "predictedGroundTrackColor"; - return roles; - } - - // Linear interpolation - double interpolate(double x0, double y0, double x1, double y1, double x) - { - return (y0*(x1-x) + y1*(x-x0)) / (x1-x0); - } - - bool isSelected3D(const MapItem *item) const + bool isSelected3D(const ObjectMapItem *item) const { return m_selected3D == item->m_name; } @@ -206,13 +259,24 @@ public: m_selected3D = selected; } -public slots: - void update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); +//public slots: +// void update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()) override; + +protected: + void playAnimations(ObjectMapItem *item); + MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) override; + void update(MapItem *item) override; + void update3D(MapItem *item) override; + + // Linear interpolation + double interpolate(double x0, double y0, double x1, double y1, double x) const + { + return (y0*(x1-x) + y1*(x-x0)) / (x1-x0); + } private: - MapGUI *m_gui; - QList m_items; - QList m_selected; + QList m_selected; // Whether each item on 2D map is selected + QString m_selected3D; // Name of item selected on 3D map - only supports 1 item, unlike 2D map int m_target; // Row number of current target, or -1 for none bool m_displayNames; bool m_displaySelectedGroundTracks; @@ -221,8 +285,112 @@ private: double m_bottomLeftLongitude; double m_bottomRightLongitude; - QString m_selected3D; // Name of item selected on 3D map - only supports 1 item, unlike 2D map + void interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen); + void interpolateWest(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen); + void interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottomLeftLongitude, double bottomRightLongitude, QGeoCoordinate* ci, bool offScreen); + + void splitTracks(ObjectMapItem *item); + void splitTrack(const QList& coords, const QVariantList& track, + QVariantList& track1, QVariantList& track2, + QGeoCoordinate& start1, QGeoCoordinate& start2, + QGeoCoordinate& end1, QGeoCoordinate& end2); }; +class PolygonFilter : public QSortFilterProxyModel { + Q_OBJECT +public: + PolygonFilter() : + m_zoomLevel(10), + m_settings(nullptr) + { + } + + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + Q_INVOKABLE void viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel); + Q_INVOKABLE int mapRowToSource(int row); + void setPosition(const QGeoCoordinate& position); + +private: + QGeoRectangle m_view; + double m_zoomLevel; + MapSettings *m_settings; + QGeoCoordinate m_position;; + +}; + +class PolylineFilter : public QSortFilterProxyModel { + Q_OBJECT +public: + PolylineFilter() : + m_zoomLevel(10), + m_settings(nullptr) + { + } + + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + Q_INVOKABLE void viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel); + Q_INVOKABLE int mapRowToSource(int row); + void setPosition(const QGeoCoordinate& position); + +private: + QGeoRectangle m_view; + double m_zoomLevel; + MapSettings *m_settings; + QGeoCoordinate m_position;; + +}; + +class ObjectMapFilter : public QSortFilterProxyModel { + Q_OBJECT +public: + ObjectMapFilter() : + m_topLeftLongitude(0), + m_topLeftLatitude(0), + m_bottomRightLongitude(0), + m_bottomRightLatitude(0), + m_zoomLevel(10), + m_settings(nullptr) + { + } + + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + Q_INVOKABLE void viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel); + void applySettings(MapSettings *settings); + Q_INVOKABLE int mapRowToSource(int row); + void setPosition(const QGeoCoordinate& position); + +private: + double m_topLeftLongitude; + double m_topLeftLatitude; + double m_bottomRightLongitude; + double m_bottomRightLatitude; + double m_zoomLevel; + MapSettings *m_settings; + QGeoCoordinate m_position; + +}; + +class ImageFilter : public QSortFilterProxyModel { + Q_OBJECT +public: + ImageFilter() : + m_zoomLevel(10), + m_settings(nullptr) + { + } + + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + Q_INVOKABLE void viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel); + Q_INVOKABLE int mapRowToSource(int row); + void setPosition(const QGeoCoordinate& position); + +private: + QGeoRectangle m_view; + double m_zoomLevel; + MapSettings *m_settings; + QGeoCoordinate m_position;; + +}; #endif // INCLUDE_FEATURE_MAPMODEL_H_ + diff --git a/plugins/feature/map/mapsettings.cpp b/plugins/feature/map/mapsettings.cpp index ac3c883ab..0a3930c0e 100644 --- a/plugins/feature/map/mapsettings.cpp +++ b/plugins/feature/map/mapsettings.cpp @@ -26,25 +26,31 @@ #include "mapsettings.h" const QStringList MapSettings::m_pipeTypes = { + QStringLiteral("ACARSDemod"), QStringLiteral("ADSBDemod"), QStringLiteral("AIS"), QStringLiteral("APRS"), QStringLiteral("APTDemod"), QStringLiteral("FT8Demod"), + QStringLiteral("HeatMap"), QStringLiteral("Radiosonde"), QStringLiteral("StarTracker"), - QStringLiteral("SatelliteTracker") + QStringLiteral("SatelliteTracker"), + QStringLiteral("VORLocalizer") }; const QStringList MapSettings::m_pipeURIs = { + QStringLiteral("sdrangel.channel.acarsdemod"), QStringLiteral("sdrangel.channel.adsbdemod"), QStringLiteral("sdrangel.feature.ais"), QStringLiteral("sdrangel.feature.aprs"), QStringLiteral("sdrangel.channel.aptdemod"), QStringLiteral("sdrangel.channel.ft8demod"), + QStringLiteral("sdrangel.channel.heatmap"), QStringLiteral("sdrangel.feature.radiosonde"), QStringLiteral("sdrangel.feature.startracker"), - QStringLiteral("sdrangel.feature.satellitetracker") + QStringLiteral("sdrangel.feature.satellitetracker"), + QStringLiteral("sdrangel.feature.vorlocalizer") }; // GUI combo box should match ordering in this list @@ -62,24 +68,70 @@ MapSettings::MapSettings() : // Source names should match m_pipeTypes // Colors currently match color of rollup widget for that plugin int modelMinPixelSize = 50; - m_itemSettings.insert("ADSBDemod", new MapItemSettings("ADSBDemod", QColor(244, 151, 57), false, 11, modelMinPixelSize)); - m_itemSettings.insert("AIS", new MapItemSettings("AIS", QColor(102, 0, 0), false, 11, modelMinPixelSize)); - m_itemSettings.insert("APRS", new MapItemSettings("APRS", QColor(255, 255, 0), false, 11)); - m_itemSettings.insert("StarTracker", new MapItemSettings("StarTracker", QColor(230, 230, 230), true, 3)); - m_itemSettings.insert("SatelliteTracker", new MapItemSettings("SatelliteTracker", QColor(0, 0, 255), false, 0, modelMinPixelSize)); - m_itemSettings.insert("Beacons", new MapItemSettings("Beacons", QColor(255, 0, 0), true, 8)); - m_itemSettings.insert("Radiosonde", new MapItemSettings("Radiosonde", QColor(102, 0, 102), false, 11, modelMinPixelSize)); - m_itemSettings.insert("Radio Time Transmitters", new MapItemSettings("Radio Time Transmitters", QColor(255, 0, 0), true, 8)); - m_itemSettings.insert("Radar", new MapItemSettings("Radar", QColor(255, 0, 0), true, 8)); - m_itemSettings.insert("FT8Demod", new MapItemSettings("FT8Demod", QColor(0, 192, 255), true, 8)); + MapItemSettings *aptSettings = new MapItemSettings("APTDemod", true, QColor(216, 112, 169), true, false, 11); + aptSettings->m_display2DIcon = false; // Disabled as 2D projection is wrong + m_itemSettings.insert("APTDemod", aptSettings); + m_itemSettings.insert("ACARSDemod", new MapItemSettings("ACARSDemod", true, QColor(244, 151, 57), true, false, 11, modelMinPixelSize)); + m_itemSettings.insert("ADSBDemod", new MapItemSettings("ADSBDemod", true, QColor(244, 151, 57), true, false, 11, modelMinPixelSize)); + m_itemSettings.insert("AIS", new MapItemSettings("AIS", true, QColor(102, 0, 0), true, false, 11, modelMinPixelSize)); + MapItemSettings *aprsSettings = new MapItemSettings("APRS", true, QColor(255, 255, 0), true, false, 11); + aprsSettings->m_extrapolate = 0; + m_itemSettings.insert("APRS", aprsSettings); + m_itemSettings.insert("StarTracker", new MapItemSettings("StarTracker", true, QColor(230, 230, 230), true, true, 3)); + m_itemSettings.insert("SatelliteTracker", new MapItemSettings("SatelliteTracker", true, QColor(0, 0, 255), true, false, 0, modelMinPixelSize)); + m_itemSettings.insert("Beacons", new MapItemSettings("Beacons", true, QColor(255, 0, 0), false, true, 8)); + m_itemSettings.insert("Radiosonde", new MapItemSettings("Radiosonde", true, QColor(102, 0, 102), true, false, 11, modelMinPixelSize)); + m_itemSettings.insert("Radio Time Transmitters", new MapItemSettings("Radio Time Transmitters", true, QColor(255, 0, 0), false, true, 8)); + m_itemSettings.insert("Radar", new MapItemSettings("Radar", true, QColor(255, 0, 0), false, true, 8)); + m_itemSettings.insert("FT8Demod", new MapItemSettings("FT8Demod", true, QColor(0, 192, 255), true, true, 8)); + m_itemSettings.insert("HeatMap", new MapItemSettings("HeatMap", true, QColor(102, 40, 220), true, false, 11)); - MapItemSettings *ionosondeItemSettings = new MapItemSettings("Ionosonde Stations", QColor(255, 255, 0), true, 4); + m_itemSettings.insert("AM", new MapItemSettings("AM", false, QColor(255, 0, 0), false, true, 10)); + MapItemSettings *fmSettings = new MapItemSettings("FM", false, QColor(255, 0, 0), false, true, 12); + fmSettings->m_filterDistance = 150000; + m_itemSettings.insert("FM", fmSettings); + MapItemSettings *dabSettings = new MapItemSettings("DAB", false, QColor(255, 0, 0), false, true, 12); + dabSettings->m_filterDistance = 75000; + m_itemSettings.insert("DAB", dabSettings); + + MapItemSettings *navAidSettings = new MapItemSettings("NavAid", false, QColor(255, 0, 255), false, true, 11); + navAidSettings->m_filterDistance = 500000; + m_itemSettings.insert("NavAid", navAidSettings); + + m_itemSettings.insert("Airport (Large)", new MapItemSettings("Airport (Large)", false, QColor(255, 0, 255), false, true, 11)); + m_itemSettings.insert("Airport (Medium)", new MapItemSettings("Airport (Medium)", false, QColor(255, 0, 255), false, true, 11)); + m_itemSettings.insert("Airport (Small)", new MapItemSettings("Airport (Small)", false, QColor(255, 0, 255), false, true, 13)); + m_itemSettings.insert("Heliport", new MapItemSettings("Heliport", false, QColor(255, 0, 255), false, true, 12)); + MapItemSettings *stationSettings = new MapItemSettings("Station", true, QColor(255, 0, 0), false, true, 11); + stationSettings->m_extrapolate = 0; + stationSettings->m_display3DTrack = false; + m_itemSettings.insert("Station", stationSettings); + m_itemSettings.insert("VORLocalizer", new MapItemSettings("VORLocalizer", true, QColor(255, 255, 0), false, true, 11)); + + MapItemSettings *ionosondeItemSettings = new MapItemSettings("Ionosonde Stations", true, QColor(255, 255, 0), false, true, 4); ionosondeItemSettings->m_display2DIcon = false; m_itemSettings.insert("Ionosonde Stations", ionosondeItemSettings); - MapItemSettings *stationItemSettings = new MapItemSettings("Station", QColor(255, 0, 0), true, 11); - stationItemSettings->m_display2DTrack = false; - m_itemSettings.insert("Station", stationItemSettings); + m_itemSettings.insert("Airspace (A)", new MapItemSettings("Airspace (A)", false, QColor(255, 0, 0, 0x20), false, false, 7)); + m_itemSettings.insert("Airspace (B)", new MapItemSettings("Airspace (B)", false, QColor(255, 0, 0, 0x20), false, false, 7)); + m_itemSettings.insert("Airspace (C)", new MapItemSettings("Airspace (C)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (D)", new MapItemSettings("Airspace (D)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (E)", new MapItemSettings("Airspace (E)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (F)", new MapItemSettings("Airspace (F)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (G)", new MapItemSettings("Airspace (G)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (FIR)", new MapItemSettings("Airspace (FIR)", false, QColor(255, 0, 0, 0x20), false, false, 7)); + m_itemSettings.insert("Airspace (CTR)", new MapItemSettings("Airspace (CTR)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (RMZ)", new MapItemSettings("Airspace (RMZ)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (TMA)", new MapItemSettings("Airspace (TMA)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (TMZ)", new MapItemSettings("Airspace (TMZ)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (OTH)", new MapItemSettings("Airspace (OTH)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (Restricted)", new MapItemSettings("Airspace (Restricted)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (Gliding)", new MapItemSettings("Airspace (Gliding)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (Danger)", new MapItemSettings("Airspace (Danger)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (Prohibited)", new MapItemSettings("Airspace (Prohibited)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (Wave)", new MapItemSettings("Airspace (Wave)", false, QColor(255, 0, 0, 0x20), false, false, 11)); + m_itemSettings.insert("Airspace (Airports)", new MapItemSettings("Airspace (Airports)", false, QColor(0, 0, 255, 0x20), false, false, 11)); + resetToDefaults(); } @@ -104,7 +156,7 @@ void MapSettings::resetToDefaults() m_displaySelectedGroundTracks = true; m_displayAllGroundTracks = true; m_title = "Map"; - m_displayAllGroundTracks = QColor(225, 25, 99).rgb(); + m_displayAllGroundTracks = QColor(225, 25, 99).rgba(); m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -121,6 +173,7 @@ void MapSettings::resetToDefaults() m_displayMUF = false; m_displayfoF2 = false; m_workspaceIndex = 0; + m_checkWXAPIKey = ""; } QByteArray MapSettings::serialize() const @@ -165,6 +218,8 @@ QByteArray MapSettings::serialize() const s.writeBool(35, m_displayMUF); s.writeBool(36, m_displayfoF2); + s.writeString(46, m_checkWXAPIKey); + return s.final(); } @@ -184,6 +239,7 @@ bool MapSettings::deserialize(const QByteArray& data) uint32_t utmp; QString strtmp; QByteArray blob; + QString string; d.readBool(1, &m_displayNames, true); d.readString(2, &m_mapProvider, "osm"); @@ -195,7 +251,7 @@ bool MapSettings::deserialize(const QByteArray& data) d.readString(3, &m_mapBoxAPIKey, ""); d.readString(4, &m_mapBoxStyles, ""); d.readString(8, &m_title, "Map"); - d.readU32(9, &m_rgbColor, QColor(225, 25, 99).rgb()); + d.readU32(9, &m_rgbColor, QColor(225, 25, 99).rgba()); d.readBool(10, &m_useReverseAPI, false); d.readString(11, &m_reverseAPIAddress, "127.0.0.1"); d.readU32(12, &utmp, 0); @@ -241,6 +297,8 @@ bool MapSettings::deserialize(const QByteArray& data) d.readBool(35, &m_displayMUF, false); d.readBool(36, &m_displayfoF2, false); + d.readString(46, &m_checkWXAPIKey, ""); + return true; } else @@ -251,16 +309,20 @@ bool MapSettings::deserialize(const QByteArray& data) } MapSettings::MapItemSettings::MapItemSettings(const QString& group, + bool enabled, const QColor color, + bool display2DTrack, bool display3DPoint, int minZoom, int modelMinPixelSize) { m_group = group; resetToDefaults(); - m_3DPointColor = color.rgb(); - m_2DTrackColor = color.darker().rgb(); - m_3DTrackColor = color.darker().rgb(); + m_enabled = enabled, + m_3DPointColor = color.rgba(); + m_2DTrackColor = color.darker().rgba(); + m_3DTrackColor = color.darker().rgba(); + m_display2DTrack = display2DTrack; m_display3DPoint = display3DPoint; m_2DMinZoom = minZoom; m_3DModelMinPixelSize = modelMinPixelSize; @@ -277,16 +339,19 @@ void MapSettings::MapItemSettings::resetToDefaults() m_display2DIcon = true; m_display2DLabel = true; m_display2DTrack = true; - m_2DTrackColor = QColor(150, 0, 20).rgb(); + m_2DTrackColor = QColor(150, 0, 20).rgba(); m_2DMinZoom = 1; m_display3DModel = true; m_display3DPoint = false; - m_3DPointColor = QColor(225, 0, 0).rgb(); + m_3DPointColor = QColor(225, 0, 0).rgba(); m_display3DLabel = true; m_display3DTrack = true; - m_3DTrackColor = QColor(150, 0, 20).rgb(); + m_3DTrackColor = QColor(150, 0, 20).rgba(); m_3DModelMinPixelSize = 0; m_3DLabelScale = 0.5f; + m_filterName = ""; + m_filterDistance = 0; + m_extrapolate = 60; } QByteArray MapSettings::MapItemSettings::serialize() const @@ -308,6 +373,9 @@ QByteArray MapSettings::MapItemSettings::serialize() const s.writeU32(13, m_3DTrackColor); s.writeS32(14, m_3DModelMinPixelSize); s.writeFloat(15, m_3DLabelScale); + s.writeString(16, m_filterName); + s.writeS32(17, m_filterDistance); + s.writeS32(18, m_extrapolate); return s.final(); } @@ -329,16 +397,21 @@ bool MapSettings::MapItemSettings::deserialize(const QByteArray& data) d.readBool(3, &m_display2DIcon, true); d.readBool(4, &m_display2DLabel, true); d.readBool(5, &m_display2DTrack, true); - d.readU32(6, &m_2DTrackColor, QColor(150, 0, 0).rgb()); + d.readU32(6, &m_2DTrackColor, QColor(150, 0, 0).rgba()); d.readS32(7, &m_2DMinZoom, 1); d.readBool(8, &m_display3DModel, true); d.readBool(9, &m_display3DLabel, true); d.readBool(10, &m_display3DPoint, true); - d.readU32(11, &m_3DPointColor, QColor(255, 0, 0).rgb()); + d.readU32(11, &m_3DPointColor, QColor(255, 0, 0).rgba()); d.readBool(12, &m_display3DTrack, true); - d.readU32(13, &m_3DTrackColor, QColor(150, 0, 20).rgb()); + d.readU32(13, &m_3DTrackColor, QColor(150, 0, 20).rgba()); d.readS32(14, &m_3DModelMinPixelSize, 0); d.readFloat(15, &m_3DLabelScale, 0.5f); + d.readString(16, &m_filterName, ""); + d.readS32(17, &m_filterDistance, 0); + d.readS32(18, &m_extrapolate, 60); + m_filterNameRE.setPattern(m_filterName); + m_filterNameRE.optimize(); return true; } else @@ -567,3 +640,4 @@ QString MapSettings::getDebugString(const QStringList& settingsKeys, bool force) return QString(ostr.str().c_str()); } + diff --git a/plugins/feature/map/mapsettings.h b/plugins/feature/map/mapsettings.h index 71804e26d..06754f552 100644 --- a/plugins/feature/map/mapsettings.h +++ b/plugins/feature/map/mapsettings.h @@ -22,6 +22,7 @@ #include #include #include +#include class Serializable; @@ -32,7 +33,7 @@ struct MapSettings bool m_enabled; // Whether enabled at all on 2D or 3D map bool m_display2DIcon; // Display image 2D map bool m_display2DLabel; // Display label on 2D map - bool m_display2DTrack; // Display tracks on 2D map + bool m_display2DTrack; // Display tracks (or polygon) on 2D map quint32 m_2DTrackColor; int m_2DMinZoom; bool m_display3DModel; // Draw 3D model for item @@ -43,14 +44,26 @@ struct MapSettings quint32 m_3DTrackColor; int m_3DModelMinPixelSize; float m_3DLabelScale; + QString m_filterName; + QRegularExpression m_filterNameRE; + int m_filterDistance; // Filter items > this distance in metres away from My Position. <= 0 don't filter + int m_extrapolate; // Extrapolate duration in seconds on 3D map - MapItemSettings(const QString& group, const QColor color, bool display3DPoint=true, int minZoom=11, int modelMinPixelSize=0); + MapItemSettings(const QString& group, bool enabled, const QColor color, bool display2DTrack=true, bool display3DPoint=true, int minZoom=11, int modelMinPixelSize=0); MapItemSettings(const QByteArray& data); void resetToDefaults(); QByteArray serialize() const; bool deserialize(const QByteArray& data); }; + struct MapPolygonSettings { + QString m_group; + bool m_enabled; + quint32 m_2DColor; + int m_2DMinZoom; + quint32 m_3DColor; + }; + struct AvailableChannelOrFeature { QString m_kind; //!< "R" for channel, "F" for feature @@ -107,6 +120,8 @@ struct MapSettings bool m_displayMUF; // Plot MUF contours bool m_displayfoF2; // Plot foF2 contours + QString m_checkWXAPIKey; //!< checkwxapi.com API key + // Per source settings QHash m_itemSettings; @@ -127,4 +142,7 @@ struct MapSettings static const QStringList m_mapProviders; }; +Q_DECLARE_METATYPE(MapSettings::MapItemSettings *); + #endif // INCLUDE_FEATURE_MAPSETTINGS_H_ + diff --git a/plugins/feature/map/mapsettingsdialog.cpp b/plugins/feature/map/mapsettingsdialog.cpp index 859cc176a..9ce212513 100644 --- a/plugins/feature/map/mapsettingsdialog.cpp +++ b/plugins/feature/map/mapsettingsdialog.cpp @@ -109,6 +109,7 @@ MapSettingsDialog::MapSettingsDialog(MapSettings *settings, QWidget* parent) : QDialog(parent), m_settings(settings), m_downloadDialog(this), + m_progressDialog(nullptr), ui(new Ui::MapSettingsDialog) { ui->setupUi(this); @@ -117,6 +118,7 @@ MapSettingsDialog::MapSettingsDialog(MapSettings *settings, QWidget* parent) : ui->maptilerAPIKey->setText(settings->m_maptilerAPIKey); ui->mapBoxAPIKey->setText(settings->m_mapBoxAPIKey); ui->cesiumIonAPIKey->setText(settings->m_cesiumIonAPIKey); + ui->checkWXAPIKey->setText(settings->m_checkWXAPIKey); ui->osmURL->setText(settings->m_osmURL); ui->mapBoxStyles->setText(settings->m_mapBoxStyles); ui->map2DEnabled->setChecked(m_settings->m_map2DEnabled); @@ -129,10 +131,10 @@ MapSettingsDialog::MapSettingsDialog(MapSettings *settings, QWidget* parent) : // Sort groups in table alphabetically QList itemSettings = m_settings->m_itemSettings.values(); - std::sort(itemSettings.begin(), itemSettings.end(), - [](const MapSettings::MapItemSettings* a, const MapSettings::MapItemSettings* b) -> bool { - return a->m_group < b->m_group; - }); + std::sort(itemSettings.begin(), itemSettings.end(), + [](const MapSettings::MapItemSettings* a, const MapSettings::MapItemSettings* b) -> bool { + return a->m_group < b->m_group; + }); QListIterator itr(itemSettings); while (itr.hasNext()) { @@ -163,6 +165,14 @@ MapSettingsDialog::MapSettingsDialog(MapSettings *settings, QWidget* parent) : item->setCheckState(itemSettings->m_display3DLabel ? Qt::Checked : Qt::Unchecked); ui->mapItemSettings->setItem(row, COL_3D_LABEL, item); + item = new QTableWidgetItem(itemSettings->m_filterName); + ui->mapItemSettings->setItem(row, COL_FILTER_NAME, item); + item = new QTableWidgetItem(); + if (itemSettings->m_filterDistance > 0) { + item->setText(QString::number(itemSettings->m_filterDistance / 1000)); + } + ui->mapItemSettings->setItem(row, COL_FILTER_DISTANCE, item); + MapItemSettingsGUI *gui = new MapItemSettingsGUI(ui->mapItemSettings, row, itemSettings); m_mapItemSettingsGUIs.append(gui); } @@ -172,6 +182,15 @@ MapSettingsDialog::MapSettingsDialog(MapSettings *settings, QWidget* parent) : on_map3DEnabled_clicked(m_settings->m_map3DEnabled); connect(&m_dlm, &HttpDownloadManagerGUI::downloadComplete, this, &MapSettingsDialog::downloadComplete); + connect(&m_openAIP, &OpenAIP::downloadingURL, this, &MapSettingsDialog::downloadingURL); + connect(&m_openAIP, &OpenAIP::downloadError, this, &MapSettingsDialog::downloadError); + connect(&m_openAIP, &OpenAIP::downloadAirspaceFinished, this, &MapSettingsDialog::downloadAirspaceFinished); + connect(&m_openAIP, &OpenAIP::downloadNavAidsFinished, this, &MapSettingsDialog::downloadNavAidsFinished); + connect(&m_ourAirportsDB, &OurAirportsDB::downloadingURL, this, &MapSettingsDialog::downloadingURL); + connect(&m_ourAirportsDB, &OurAirportsDB::downloadProgress, this, &MapSettingsDialog::downloadProgress); + connect(&m_ourAirportsDB, &OurAirportsDB::downloadError, this, &MapSettingsDialog::downloadError); + connect(&m_ourAirportsDB, &OurAirportsDB::downloadAirportInformationFinished, this, &MapSettingsDialog::downloadAirportInformationFinished); + #ifndef QT_WEBENGINE_FOUND ui->map3DSettings->setVisible(false); ui->downloadModels->setVisible(false); @@ -257,6 +276,16 @@ void MapSettingsDialog::accept() itemSettings->m_3DTrackColor = gui->m_track3D.m_color; itemSettings->m_3DModelMinPixelSize = gui->m_minPixels->value(); itemSettings->m_3DLabelScale = gui->m_labelScale->value(); + itemSettings->m_filterName = ui->mapItemSettings->item(row, COL_FILTER_NAME)->text(); + itemSettings->m_filterNameRE.setPattern(itemSettings->m_filterName); + itemSettings->m_filterNameRE.optimize(); + bool ok; + int filterDistance = ui->mapItemSettings->item(row, COL_FILTER_DISTANCE)->text().toInt(&ok); + if (ok && filterDistance > 0) { + itemSettings->m_filterDistance = filterDistance * 1000; + } else { + itemSettings->m_filterDistance = 0; + } } QDialog::accept(); @@ -307,6 +336,7 @@ void MapSettingsDialog::on_map3DEnabled_clicked(bool checked) ui->buildings->setEnabled(checked); ui->sunLightEnabled->setEnabled(checked); ui->eciCamera->setEnabled(checked); + ui->antiAliasing->setEnabled(checked); } // Models have individual licensing. See LICENSE on github @@ -423,3 +453,95 @@ void MapSettingsDialog::downloadComplete(const QString &filename, bool success, QMessageBox::warning(this, "Download failed", QString("Failed to download %1 to %2\n%3").arg(url).arg(filename).arg(errorMessage)); } } + +void MapSettingsDialog::on_getAirportDB_clicked() +{ + // Don't try to download while already in progress + if (m_progressDialog == nullptr) + { + m_progressDialog = new QProgressDialog(this); + m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setWindowFlag(Qt::WindowCloseButtonHint, false); + m_ourAirportsDB.downloadAirportInformation(); + } +} + +void MapSettingsDialog::on_getAirspacesDB_clicked() +{ + // Don't try to download while already in progress + if (m_progressDialog == nullptr) + { + m_progressDialog = new QProgressDialog(this); + m_progressDialog->setMaximum(OpenAIP::m_countryCodes.size()); + m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setWindowFlag(Qt::WindowCloseButtonHint, false); + m_openAIP.downloadAirspaces(); + } +} + +void MapSettingsDialog::downloadingURL(const QString& url) +{ + if (m_progressDialog) + { + m_progressDialog->setLabelText(QString("Downloading %1.").arg(url)); + m_progressDialog->setValue(m_progressDialog->value() + 1); + } +} + +void MapSettingsDialog::downloadProgress(qint64 bytesRead, qint64 totalBytes) +{ + if (m_progressDialog) + { + m_progressDialog->setMaximum(totalBytes); + m_progressDialog->setValue(bytesRead); + } +} + +void MapSettingsDialog::downloadError(const QString& error) +{ + QMessageBox::critical(this, "Map", error); + if (m_progressDialog) + { + m_progressDialog->close(); + delete m_progressDialog; + m_progressDialog = nullptr; + } +} + +void MapSettingsDialog::downloadAirspaceFinished() +{ + if (m_progressDialog) { + m_progressDialog->setLabelText("Reading airspaces."); + } + emit airspacesUpdated(); + m_openAIP.downloadNavAids(); +} + +void MapSettingsDialog::downloadNavAidsFinished() +{ + if (m_progressDialog) { + m_progressDialog->setLabelText("Reading NAVAIDs."); + } + emit navAidsUpdated(); + if (m_progressDialog) + { + m_progressDialog->close(); + delete m_progressDialog; + m_progressDialog = nullptr; + } +} + +void MapSettingsDialog::downloadAirportInformationFinished() +{ + if (m_progressDialog) { + m_progressDialog->setLabelText("Reading airports."); + } + emit airportsUpdated(); + if (m_progressDialog) + { + m_progressDialog->close(); + delete m_progressDialog; + m_progressDialog = nullptr; + } +} + diff --git a/plugins/feature/map/mapsettingsdialog.h b/plugins/feature/map/mapsettingsdialog.h index c8d60b9e7..6eade0e69 100644 --- a/plugins/feature/map/mapsettingsdialog.h +++ b/plugins/feature/map/mapsettingsdialog.h @@ -21,8 +21,11 @@ #include #include #include +#include #include "gui/httpdownloadmanagergui.h" +#include "util/openaip.h" +#include "util/ourairportsdb.h" #include "ui_mapsettingsdialog.h" #include "mapsettings.h" @@ -78,7 +81,9 @@ public: COL_3D_LABEL, COL_3D_POINT, COL_3D_TRACK, - COL_3D_LABEL_SCALE + COL_3D_LABEL_SCALE, + COL_FILTER_NAME, + COL_FILTER_DISTANCE }; public: @@ -92,6 +97,9 @@ private: HttpDownloadManagerGUI m_dlm; int m_fileIdx; QMessageBox m_downloadDialog; + QProgressDialog *m_progressDialog; + OpenAIP m_openAIP; + OurAirportsDB m_ourAirportsDB; void unzip(const QString &filename); @@ -100,7 +108,20 @@ private slots: void on_map2DEnabled_clicked(bool checked=false); void on_map3DEnabled_clicked(bool checked=false); void on_downloadModels_clicked(); + void on_getAirportDB_clicked(); + void on_getAirspacesDB_clicked(); void downloadComplete(const QString &filename, bool success, const QString &url, const QString &errorMessage); + void downloadingURL(const QString& url); + void downloadProgress(qint64 bytesRead, qint64 totalBytes); + void downloadError(const QString& error); + void downloadAirspaceFinished(); + void downloadNavAidsFinished(); + void downloadAirportInformationFinished(); + +signals: + void navAidsUpdated(); + void airspacesUpdated(); + void airportsUpdated(); private: Ui::MapSettingsDialog* ui; diff --git a/plugins/feature/map/mapsettingsdialog.ui b/plugins/feature/map/mapsettingsdialog.ui index 30cc95f37..6728e47c5 100644 --- a/plugins/feature/map/mapsettingsdialog.ui +++ b/plugins/feature/map/mapsettingsdialog.ui @@ -6,8 +6,8 @@ 0 0 - 1016 - 720 + 1267 + 648
@@ -35,68 +35,6 @@ Maps - - - - QAbstractItemView::NoSelection - - - - Enabled - - - - - 2D Icon - - - - - 2D Label - - - - - 2D Min Zoom - - - - - 2D Track - - - - - 3D Model - - - - - 3D Min Pixels - - - - - 3D Label - - - - - 3D Point - - - - - 3D Track - - - - - 3D Label Scale - - - - @@ -346,6 +284,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -358,6 +309,34 @@ + + + + Download the latest OurAirports airport databases (10MB) + + + + + + + :/map/icons/controltower.png:/map/icons/controltower.png + + + + + + + Download airspaces and NAVAIDs from OpenAIP (40MB) + + + + + + + :/map/icons/vor.png:/map/icons/vor.png + + + @@ -375,6 +354,115 @@ + + + Map Items + + + + + + QAbstractItemView::NoSelection + + + + Enabled + + + Whether items of this type will be displayed on the maps + + + + + 2D Icon + + + Whether to display icon on 2D map + + + + + 2D Label + + + Whether to display label on 2D map + + + + + 2D Min Zoom + + + + + 2D Colour + + + Track colour or 2D map + + + + + 3D Model + + + Whether to display model on 3D map + + + + + 3D Min Pixels + + + + + 3D Label + + + Whether to display label on 3D map + + + + + 3D Point + + + Whether to display a point on 3D map + + + + + 3D Colour + + + + + 3D Label Scale + + + Scale factor for label on 3D map + + + + + Filter Name + + + Regular expression to filter by name (Only items with names matching the pattern will be displayed) + + + + + Filter Distance (km) + + + Filter objects further than this distance in km away from My Position + + + + + + API Keys @@ -466,6 +554,20 @@ + + + + CheckWX API key + + + + + + + checkwxapi.com API key for accessing airport weather (METARs) + + + @@ -489,8 +591,6 @@ - tabWidget - mapItemSettings map2DEnabled mapProvider osmURL @@ -507,7 +607,10 @@ mapBoxAPIKey cesiumIonAPIKey - + + + + buttonBox diff --git a/plugins/feature/map/osmtemplateserver.h b/plugins/feature/map/osmtemplateserver.h index fcada37fe..13b80d881 100644 --- a/plugins/feature/map/osmtemplateserver.h +++ b/plugins/feature/map/osmtemplateserver.h @@ -94,6 +94,25 @@ private slots: \"DataCopyRight\" : \"Maptiler\"\ }").arg(hiresURL).arg(m_maptilerAPIKey); } + else if (tokens[1].contains("transit")) + { + QStringList map({"/night-transit", "/night-transit-hires", "/transit", "/transit-hires"}); + QStringList mapId({"thf-nighttransit", "thf-nighttransit-hires", "thf-transit", "thf-transit-hires"}); + QStringList mapUrl({"dark_nolabels", "dark_nolabels", "light_nolabels", "light_nolabels"}); + + // Use CartoDB maps without labels for aviation maps + int idx = map.indexOf(tokens[1]); + xml = QString("\ + {\ + \"UrlTemplate\" : \"http://1.basemaps.cartocdn.com/%2/%z/%x/%y.png%1\",\ + \"ImageFormat\" : \"png\",\ + \"QImageFormat\" : \"Indexed8\",\ + \"ID\" : \"%3\",\ + \"MaximumZoomLevel\" : 20,\ + \"MapCopyRight\" : \"CartoDB\",\ + \"DataCopyRight\" : \"CartoDB\"\ + }").arg(hiresURL).arg(mapUrl[idx]).arg(mapId[idx]); + } else { int idx = map.indexOf(tokens[1]); diff --git a/plugins/feature/map/readme.md b/plugins/feature/map/readme.md index c138fdb2a..1a65ddf80 100644 --- a/plugins/feature/map/readme.md +++ b/plugins/feature/map/readme.md @@ -11,10 +11,13 @@ On top of this, it can plot data from other plugins, such as: * Satellites from the Satellite Tracker, * Weather imagery from APT Demodulator, * The Sun, Moon and Stars from the Star Tracker, -* Weather ballons from the RadioSonde feature. +* Weather ballons from the RadioSonde feature, +* Radials and estimated position from the VOR localizer feature. -As well as other other data sources: +As well as other data sources: +* AM, FM and DAB transmitters in the UK, +* Airports, NavAids and airspaces, * Beacons based on the IARU Region 1 beacon database and International Beacon Project, * Radio time transmitters, * GRAVES radar, diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index 146a63129..12fd1f08f 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -197,6 +197,7 @@ set(sdrbase_SOURCES util/morse.cpp util/openaip.cpp util/osndb.cpp + util/ourairportsdb.cpp util/peakfinder.cpp util/planespotters.cpp util/png.cpp @@ -424,6 +425,7 @@ set(sdrbase_HEADERS util/movingaverage.h util/openaip.h util/osndb.h + util/outairportsdb.h util/peakfinder.h util/planespotters.h util/png.h @@ -466,6 +468,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${Boost_INCLUDE_DIRS} ${OPUS_INCLUDE_DIRS} + ${Qt${QT_DEFAULT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS} ) add_library(sdrbase SHARED diff --git a/sdrbase/settings/mainsettings.h b/sdrbase/settings/mainsettings.h index 27573666f..b76b3c2f3 100644 --- a/sdrbase/settings/mainsettings.h +++ b/sdrbase/settings/mainsettings.h @@ -196,6 +196,13 @@ public: emit preferenceChanged(Preferences::Multisampling); } + int getMapMultisampling() const { return m_preferences.getMapMultisampling(); } + void setMapMultisampling(int samples) + { + m_preferences.setMapMultisampling(samples); + emit preferenceChanged(Preferences::MapMultisampling); + } + signals: void preferenceChanged(int); diff --git a/sdrbase/settings/preferences.cpp b/sdrbase/settings/preferences.cpp index dbef62e1e..4f92f4ede 100644 --- a/sdrbase/settings/preferences.cpp +++ b/sdrbase/settings/preferences.cpp @@ -23,6 +23,7 @@ void Preferences::resetToDefaults() m_consoleMinLogLevel = QtDebugMsg; m_fileMinLogLevel = QtDebugMsg; m_multisampling = 0; + m_mapMultisampling = 16; } QByteArray Preferences::serialize() const @@ -43,6 +44,7 @@ QByteArray Preferences::serialize() const s.writeS32((int) SourceItemIndex, m_sourceItemIndex); s.writeS32((int) Multisampling, m_multisampling); s.writeBool((int) AutoUpdatePosition, m_autoUpdatePosition); + s.writeS32((int) MapMultisampling, m_mapMultisampling); return s.final(); } @@ -98,6 +100,7 @@ bool Preferences::deserialize(const QByteArray& data) d.readS32((int) Multisampling, &m_multisampling, 0); d.readBool((int) AutoUpdatePosition, &m_autoUpdatePosition, true); + d.readS32((int) MapMultisampling, &m_mapMultisampling, 16); return true; } diff --git a/sdrbase/settings/preferences.h b/sdrbase/settings/preferences.h index 87c1d15a0..9298a5bda 100644 --- a/sdrbase/settings/preferences.h +++ b/sdrbase/settings/preferences.h @@ -23,7 +23,8 @@ public: Altitude, SourceItemIndex, Multisampling, - AutoUpdatePosition + AutoUpdatePosition, + MapMultisampling }; Preferences(); @@ -79,6 +80,9 @@ public: int getMultisampling() const { return m_multisampling; } void setMultisampling(int samples) { m_multisampling = samples; } + int getMapMultisampling() const { return m_mapMultisampling; } + void setMapMultisampling(int samples) { m_mapMultisampling = samples; } + protected: QString m_sourceDevice; //!< Identification of the source used in R0 tab (GUI flavor) at startup int m_sourceIndex; //!< Index of the source used in R0 tab (GUI flavor) at startup @@ -98,7 +102,8 @@ protected: bool m_useLogFile; QString m_logFileName; - int m_multisampling; //!< Number of samples to use for multisampling anti-aliasing (typically 0 or 4) + int m_multisampling; //!< Number of samples to use for multisampling anti-aliasing for spectrums (typically 0 or 4) + int m_mapMultisampling; //!< Number of samples to use for multisampling anti-aliasing for 2D maps (16 gives best text) }; #endif // INCLUDE_PREFERENCES_H diff --git a/sdrbase/util/openaip.cpp b/sdrbase/util/openaip.cpp index 0950ed568..95b94f245 100644 --- a/sdrbase/util/openaip.cpp +++ b/sdrbase/util/openaip.cpp @@ -17,6 +17,251 @@ #include "openaip.h" +QList Airspace::readXML(const QString &filename) +{ + QList airspaces; + QFile file(filename); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QXmlStreamReader xmlReader(&file); + + while(!xmlReader.atEnd() && !xmlReader.hasError()) + { + if (xmlReader.readNextStartElement()) + { + if (xmlReader.name() == QLatin1String("ASP")) + { + Airspace *airspace = new Airspace(); + + airspace->m_category = xmlReader.attributes().value("CATEGORY").toString(); + + while(xmlReader.readNextStartElement()) + { + if (xmlReader.name() == QLatin1String("COUNTRY")) + { + airspace->m_country = xmlReader.readElementText(); + } + else if (xmlReader.name() == QLatin1String("NAME")) + { + airspace->m_name = xmlReader.readElementText(); + } + else if (xmlReader.name() == QLatin1String("ALTLIMIT_TOP")) + { + while(xmlReader.readNextStartElement()) + { + airspace->m_top.m_reference = xmlReader.attributes().value("REFERENCE").toString(); + airspace->m_top.m_altUnit = xmlReader.attributes().value("UNIT").toString(); + if (xmlReader.name() == QLatin1String("ALT")) + { + airspace->m_top.m_alt = xmlReader.readElementText().toInt(); + } + else + { + xmlReader.skipCurrentElement(); + } + } + } + else if (xmlReader.name() == QLatin1String("ALTLIMIT_BOTTOM")) + { + while(xmlReader.readNextStartElement()) + { + airspace->m_bottom.m_reference = xmlReader.attributes().value("REFERENCE").toString(); + airspace->m_bottom.m_altUnit = xmlReader.attributes().value("UNIT").toString(); + if (xmlReader.name() == QLatin1String("ALT")) + { + airspace->m_bottom.m_alt = xmlReader.readElementText().toInt(); + } + else + { + xmlReader.skipCurrentElement(); + } + } + } + else if (xmlReader.name() == QLatin1String("GEOMETRY")) + { + while(xmlReader.readNextStartElement()) + { + if (xmlReader.name() == QLatin1String("POLYGON")) + { + QString pointsString = xmlReader.readElementText(); + QStringList points = pointsString.split(","); + for (const auto& ps : points) + { + QStringList split = ps.trimmed().split(" "); + if (split.size() == 2) + { + QPointF pf(split[0].toDouble(), split[1].toDouble()); + airspace->m_polygon.append(pf); + } + else + { + qDebug() << "Airspace::readXML - Unexpected polygon point format: " << ps; + } + } + } + else + { + xmlReader.skipCurrentElement(); + } + } + } + else + { + xmlReader.skipCurrentElement(); + } + } + + airspace->calculatePosition(); + //qDebug() << "Adding airspace: " << airspace->m_name << " " << airspace->m_category; + airspaces.append(airspace); + } + } + } + + file.close(); + } + else + { + // Don't warn, as many countries don't have files + //qDebug() << "Airspace::readXML: Could not open " << filename << " for reading."; + } + return airspaces; +} + +QList NavAid::readXML(const QString &filename) +{ + int uniqueId = 1; + QList navAidInfo; + QFile file(filename); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QXmlStreamReader xmlReader(&file); + + while(!xmlReader.atEnd() && !xmlReader.hasError()) + { + if (xmlReader.readNextStartElement()) + { + if (xmlReader.name() == QLatin1String("NAVAID")) + { + QStringView typeRef = xmlReader.attributes().value("TYPE"); + if ((typeRef == QLatin1String("NDB")) + || (typeRef == QLatin1String("DME")) + || (typeRef == QLatin1String("VOR")) + || (typeRef == QLatin1String("VOR-DME")) + || (typeRef == QLatin1String("VORTAC")) + || (typeRef == QLatin1String("DVOR")) + || (typeRef == QLatin1String("DVOR-DME")) + || (typeRef == QLatin1String("DVORTAC"))) + { + QString type = typeRef.toString(); + QString name; + QString id; + float lat = 0.0f; + float lon = 0.0f; + float elevation = 0.0f; + float frequency = 0.0f; + QString channel; + int range = 25; + float declination = 0.0f; + bool alignedTrueNorth = false; + while(xmlReader.readNextStartElement()) + { + if (xmlReader.name() == QLatin1String("NAME")) + { + name = xmlReader.readElementText(); + } + else if (xmlReader.name() == QLatin1String("ID")) + { + id = xmlReader.readElementText(); + } + else if (xmlReader.name() == QLatin1String("GEOLOCATION")) + { + while(xmlReader.readNextStartElement()) + { + if (xmlReader.name() == QLatin1String("LAT")) { + lat = xmlReader.readElementText().toFloat(); + } else if (xmlReader.name() == QLatin1String("LON")) { + lon = xmlReader.readElementText().toFloat(); + } else if (xmlReader.name() == QLatin1String("ELEV")) { + elevation = xmlReader.readElementText().toFloat(); + } else { + xmlReader.skipCurrentElement(); + } + } + } + else if (xmlReader.name() == QLatin1String("RADIO")) + { + while(xmlReader.readNextStartElement()) + { + if (xmlReader.name() == QLatin1String("FREQUENCY")) + { + if (type == "NDB") { + frequency = xmlReader.readElementText().toFloat(); + } else { + frequency = xmlReader.readElementText().toFloat() * 1000.0; + } + } else if (xmlReader.name() == QLatin1String("CHANNEL")) { + channel = xmlReader.readElementText(); + } else { + xmlReader.skipCurrentElement(); + } + } + } + else if (xmlReader.name() == QLatin1String("PARAMS")) + { + while(xmlReader.readNextStartElement()) + { + if (xmlReader.name() == QLatin1String("RANGE")) { + range = xmlReader.readElementText().toInt(); + } else if (xmlReader.name() == QLatin1String("DECLINATION")) { + declination = xmlReader.readElementText().toFloat(); + } else if (xmlReader.name() == QLatin1String("ALIGNEDTOTRUENORTH")) { + alignedTrueNorth = xmlReader.readElementText() == "TRUE"; + } else { + xmlReader.skipCurrentElement(); + } + } + } + else + { + xmlReader.skipCurrentElement(); + } + } + NavAid *navAid = new NavAid(); + navAid->m_id = uniqueId++; + navAid->m_ident = id; + // Check idents conform to our filtering rules + if (navAid->m_ident.size() < 2) { + qDebug() << "NavAid::readXML: Ident less than 2 characters: " << navAid->m_ident; + } else if (navAid->m_ident.size() > 3) { + qDebug() << "NavAid::readXML: Ident greater than 3 characters: " << navAid->m_ident; + } + navAid->m_type = type; + navAid->m_name = name; + navAid->m_frequencykHz = frequency; + navAid->m_channel = channel; + navAid->m_latitude = lat; + navAid->m_longitude = lon; + navAid->m_elevation = elevation; + navAid->m_range = range; + navAid->m_magneticDeclination = declination; + navAid->m_alignedTrueNorth = alignedTrueNorth; + navAidInfo.append(navAid); + } + } + } + } + + file.close(); + } + else + { + // Don't warn, as many countries don't have files + //qDebug() << "NavAid::readNavAidsXML: Could not open " << filename << " for reading."; + } + return navAidInfo; +} + const QStringList OpenAIP::m_countryCodes = { "ad", "ae", @@ -268,6 +513,12 @@ const QStringList OpenAIP::m_countryCodes = { "zw" }; +QSharedPointer> OpenAIP::m_airspaces; +QSharedPointer> OpenAIP::m_navAids; + +QDateTime OpenAIP::m_airspacesModifiedDateTime; +QDateTime OpenAIP::m_navAidsModifiedDateTime; + OpenAIP::OpenAIP(QObject *parent) : QObject(parent) { @@ -390,11 +641,11 @@ void OpenAIP::downloadFinished(const QString& filename, bool success) } // Read airspaces for all countries -QList OpenAIP::readAirspaces() +QList *OpenAIP::readAirspaces() { - QList airspaces; + QList *airspaces = new QList(); for (const auto& countryCode : m_countryCodes) { - airspaces.append(readAirspaces(countryCode)); + airspaces->append(readAirspaces(countryCode)); } return airspaces; } @@ -406,11 +657,11 @@ QList OpenAIP::readAirspaces(const QString& countryCode) } // Read NavAids for all countries -QList OpenAIP::readNavAids() +QList *OpenAIP::readNavAids() { - QList navAids; + QList *navAids = new QList(); for (const auto& countryCode : m_countryCodes) { - navAids.append(readNavAids(countryCode)); + navAids->append(readNavAids(countryCode)); } return navAids; } @@ -420,3 +671,60 @@ QList OpenAIP::readNavAids(const QString& countryCode) { return NavAid::readXML(getNavAidsFilename(countryCode)); } + +QSharedPointer> OpenAIP::getAirspaces() +{ + QDateTime filesDateTime = getAirspacesModifiedDateTime(); + + if (!m_airspaces || (filesDateTime > m_airspacesModifiedDateTime)) + { + // Using shared pointer, so old object, if it exists, will be deleted, when no longer user + m_airspaces = QSharedPointer>(readAirspaces()); + m_airspacesModifiedDateTime = filesDateTime; + } + return m_airspaces; +} + +QSharedPointer> OpenAIP::getNavAids() +{ + QDateTime filesDateTime = getNavAidsModifiedDateTime(); + + if (!m_navAids || (filesDateTime > m_navAidsModifiedDateTime)) + { + // Using shared pointer, so old object, if it exists, will be deleted, when no longer user + m_navAids = QSharedPointer>(readNavAids()); + m_navAidsModifiedDateTime = filesDateTime; + } + return m_navAids; +} + +// Gets the date and time the airspaces files were most recently modified +QDateTime OpenAIP::getAirspacesModifiedDateTime() +{ + QDateTime dateTime; + for (const auto& countryCode : m_countryCodes) + { + QFileInfo fileInfo(getAirspaceFilename(countryCode)); + QDateTime fileModifiedDateTime = fileInfo.lastModified(); + if (fileModifiedDateTime > dateTime) { + dateTime = fileModifiedDateTime; + } + } + return dateTime; +} + +// Gets the date and time the navaid files were most recently modified +QDateTime OpenAIP::getNavAidsModifiedDateTime() +{ + QDateTime dateTime; + for (const auto& countryCode : m_countryCodes) + { + QFileInfo fileInfo(getNavAidsFilename(countryCode)); + QDateTime fileModifiedDateTime = fileInfo.lastModified(); + if (fileModifiedDateTime > dateTime) { + dateTime = fileModifiedDateTime; + } + } + return dateTime; +} + diff --git a/sdrbase/util/openaip.h b/sdrbase/util/openaip.h index 1d4d372d1..ca5e2355f 100644 --- a/sdrbase/util/openaip.h +++ b/sdrbase/util/openaip.h @@ -118,116 +118,7 @@ struct SDRBASE_API Airspace { } // Read OpenAIP XML file - static QList readXML(const QString &filename) - { - QList airspaces; - QFile file(filename); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QXmlStreamReader xmlReader(&file); - - while(!xmlReader.atEnd() && !xmlReader.hasError()) - { - if (xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("ASP")) - { - Airspace *airspace = new Airspace(); - - airspace->m_category = xmlReader.attributes().value("CATEGORY").toString(); - - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("COUNTRY")) - { - airspace->m_country = xmlReader.readElementText(); - } - else if (xmlReader.name() == QLatin1String("NAME")) - { - airspace->m_name = xmlReader.readElementText(); - } - else if (xmlReader.name() == QLatin1String("ALTLIMIT_TOP")) - { - while(xmlReader.readNextStartElement()) - { - airspace->m_top.m_reference = xmlReader.attributes().value("REFERENCE").toString(); - airspace->m_top.m_altUnit = xmlReader.attributes().value("UNIT").toString(); - if (xmlReader.name() == QLatin1String("ALT")) - { - airspace->m_top.m_alt = xmlReader.readElementText().toInt(); - } - else - { - xmlReader.skipCurrentElement(); - } - } - } - else if (xmlReader.name() == QLatin1String("ALTLIMIT_BOTTOM")) - { - while(xmlReader.readNextStartElement()) - { - airspace->m_bottom.m_reference = xmlReader.attributes().value("REFERENCE").toString(); - airspace->m_bottom.m_altUnit = xmlReader.attributes().value("UNIT").toString(); - if (xmlReader.name() == QLatin1String("ALT")) - { - airspace->m_bottom.m_alt = xmlReader.readElementText().toInt(); - } - else - { - xmlReader.skipCurrentElement(); - } - } - } - else if (xmlReader.name() == QLatin1String("GEOMETRY")) - { - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("POLYGON")) - { - QString pointsString = xmlReader.readElementText(); - QStringList points = pointsString.split(","); - for (const auto& ps : points) - { - QStringList split = ps.trimmed().split(" "); - if (split.size() == 2) - { - QPointF pf(split[0].toDouble(), split[1].toDouble()); - airspace->m_polygon.append(pf); - } - else - { - qDebug() << "Airspace::readXML - Unexpected polygon point format: " << ps; - } - } - } - else - { - xmlReader.skipCurrentElement(); - } - } - } - else - { - xmlReader.skipCurrentElement(); - } - } - - airspace->calculatePosition(); - //qDebug() << "Adding airspace: " << airspace->m_name << " " << airspace->m_category; - airspaces.append(airspace); - } - } - } - - file.close(); - } - else - { - // Don't warn, as many countries don't have files - //qDebug() << "Airspace::readXML: Could not open " << filename << " for reading."; - } - return airspaces; - } + static QList readXML(const QString &filename); }; @@ -251,140 +142,7 @@ struct SDRBASE_API NavAid { } // OpenAIP XML file - static QList readXML(const QString &filename) - { - int uniqueId = 1; - QList navAidInfo; - QFile file(filename); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QXmlStreamReader xmlReader(&file); - - while(!xmlReader.atEnd() && !xmlReader.hasError()) - { - if (xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("NAVAID")) - { - QStringView typeRef = xmlReader.attributes().value("TYPE"); - if ((typeRef == QLatin1String("NDB")) - || (typeRef == QLatin1String("DME")) - || (typeRef == QLatin1String("VOR")) - || (typeRef == QLatin1String("VOR-DME")) - || (typeRef == QLatin1String("VORTAC")) - || (typeRef == QLatin1String("DVOR")) - || (typeRef == QLatin1String("DVOR-DME")) - || (typeRef == QLatin1String("DVORTAC"))) - { - QString type = typeRef.toString(); - QString name; - QString id; - float lat = 0.0f; - float lon = 0.0f; - float elevation = 0.0f; - float frequency = 0.0f; - QString channel; - int range = 25; - float declination = 0.0f; - bool alignedTrueNorth = false; - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("NAME")) - { - name = xmlReader.readElementText(); - } - else if (xmlReader.name() == QLatin1String("ID")) - { - id = xmlReader.readElementText(); - } - else if (xmlReader.name() == QLatin1String("GEOLOCATION")) - { - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("LAT")) { - lat = xmlReader.readElementText().toFloat(); - } else if (xmlReader.name() == QLatin1String("LON")) { - lon = xmlReader.readElementText().toFloat(); - } else if (xmlReader.name() == QLatin1String("ELEV")) { - elevation = xmlReader.readElementText().toFloat(); - } else { - xmlReader.skipCurrentElement(); - } - } - } - else if (xmlReader.name() == QLatin1String("RADIO")) - { - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("FREQUENCY")) - { - if (type == "NDB") { - frequency = xmlReader.readElementText().toFloat(); - } else { - frequency = xmlReader.readElementText().toFloat() * 1000.0; - } - } else if (xmlReader.name() == QLatin1String("CHANNEL")) { - channel = xmlReader.readElementText(); - } else { - xmlReader.skipCurrentElement(); - } - } - } - else if (xmlReader.name() == QLatin1String("PARAMS")) - { - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("RANGE")) { - range = xmlReader.readElementText().toInt(); - } else if (xmlReader.name() == QLatin1String("DECLINATION")) { - declination = xmlReader.readElementText().toFloat(); - } else if (xmlReader.name() == QLatin1String("ALIGNEDTOTRUENORTH")) { - alignedTrueNorth = xmlReader.readElementText() == "TRUE"; - } else { - xmlReader.skipCurrentElement(); - } - } - } - else - { - xmlReader.skipCurrentElement(); - } - } - NavAid *navAid = new NavAid(); - navAid->m_id = uniqueId++; - navAid->m_ident = id; - // Check idents conform to our filtering rules - if (navAid->m_ident.size() < 2) { - qDebug() << "NavAid::readXML: Ident less than 2 characters: " << navAid->m_ident; - } else if (navAid->m_ident.size() > 3) { - qDebug() << "NavAid::readXML: Ident greater than 3 characters: " << navAid->m_ident; - } - navAid->m_type = type; - navAid->m_name = name; - navAid->m_frequencykHz = frequency; - navAid->m_channel = channel; - navAid->m_latitude = lat; - navAid->m_longitude = lon; - navAid->m_elevation = elevation; - navAid->m_range = range; - navAid->m_magneticDeclination = declination; - navAid->m_alignedTrueNorth = alignedTrueNorth; - navAidInfo.append(navAid); - } - } - } - } - - file.close(); - } - else - { - // Don't warn, as many countries don't have files - //qDebug() << "NavAid::readNavAidsXML: Could not open " << filename << " for reading."; - } - return navAidInfo; - } - + static QList readXML(const QString &filename); }; class SDRBASE_API OpenAIP : public QObject { @@ -396,18 +154,27 @@ public: static const QStringList m_countryCodes; - static QList readAirspaces(); - static QList readAirspaces(const QString& countryCode); - static QList readNavAids(); - static QList readNavAids(const QString& countryCode); - void downloadAirspaces(); void downloadNavAids(); + static QSharedPointer> getAirspaces(); + static QSharedPointer> getNavAids(); + private: HttpDownloadManager m_dlm; int m_countryIndex; + static QSharedPointer> m_airspaces; + static QSharedPointer> m_navAids; + + static QDateTime m_airspacesModifiedDateTime; + static QDateTime m_navAidsModifiedDateTime; + + static QList *readAirspaces(); + static QList readAirspaces(const QString& countryCode); + static QList *readNavAids(); + static QList readNavAids(const QString& countryCode); + static QString getDataDir(); static QString getAirspaceFilename(int i); static QString getAirspaceFilename(const QString& countryCode); @@ -415,6 +182,8 @@ private: static QString getNavAidsFilename(int i); static QString getNavAidsFilename(const QString& countryCode); static QString getNavAidsURL(int i); + static QDateTime getAirspacesModifiedDateTime(); + static QDateTime getNavAidsModifiedDateTime(); void downloadAirspace(); void downloadNavAid(); @@ -431,3 +200,4 @@ signals: }; #endif // INCLUDE_OPENAIP_H + diff --git a/sdrbase/util/osndb.cpp b/sdrbase/util/osndb.cpp index a8ac992cd..5c6998a7f 100644 --- a/sdrbase/util/osndb.cpp +++ b/sdrbase/util/osndb.cpp @@ -15,6 +15,11 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include +#include + +#include + #include "util/osndb.h" QHash AircraftInformation::m_airlineIcons; @@ -23,3 +28,544 @@ QHash AircraftInformation::m_flagIcons; QHash *AircraftInformation::m_prefixMap; QHash *AircraftInformation::m_militaryMap; QMutex AircraftInformation::m_mutex; + +QSharedPointer> OsnDB::m_aircraftInformation; +QSharedPointer> OsnDB::m_aircraftInformationByReg; +QDateTime OsnDB::m_modifiedDateTime; + + +OsnDB::OsnDB(QObject *parent) : + QObject(parent) +{ + connect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &OsnDB::downloadFinished); +} + +OsnDB::~OsnDB() +{ + disconnect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &OsnDB::downloadFinished); +} + +void OsnDB::downloadAircraftInformation() +{ + QString filename = OsnDB::getOSNDBZipFilename(); + QString urlString = OSNDB_URL; + QUrl dbURL(urlString); + qDebug() << "OsnDB::downloadAircraftInformation: Downloading " << urlString; + emit downloadingURL(urlString); + QNetworkReply *reply = m_dlm.download(dbURL, filename); + connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 bytesRead, qint64 totalBytes) { + emit downloadProgress(bytesRead, totalBytes); + }); +} + +void OsnDB::downloadFinished(const QString& filename, bool success) +{ + if (!success) + { + qWarning() << "OsnDB::downloadFinished: Failed to download: " << filename; + emit downloadError(QString("Failed to download: %1").arg(filename)); + } + else if (filename == OsnDB::getOSNDBZipFilename()) + { + // Extract .csv file from .zip file + QZipReader reader(filename); + QByteArray database = reader.fileData("media/data/samples/metadata/aircraftDatabase.csv"); + if (database.size() > 0) + { + QFile file(OsnDB::getOSNDBFilename()); + if (file.open(QIODevice::WriteOnly)) + { + file.write(database); + file.close(); + emit downloadAircraftInformationFinished(); + } + else + { + qWarning() << "OsnDB::downloadFinished - Failed to open " << file.fileName() << " for writing"; + emit downloadError(QString("Failed to open %1 for writing").arg(file.fileName())); + } + } + else + { + qWarning() << "OsnDB::downloadFinished - aircraftDatabase.csv not in expected dir. Extracting all."; + if (reader.extractAll(getDataDir())) + { + emit downloadAircraftInformationFinished(); + } + else + { + qWarning() << "OsnDB::downloadFinished - Failed to extract files from " << filename; + emit downloadError(QString("Failed to extract files from ").arg(filename)); + } + } + } + else + { + qDebug() << "OsnDB::downloadFinished: Unexpected filename: " << filename; + emit downloadError(QString("Unexpected filename: %1").arg(filename)); + } +} + +QSharedPointer> OsnDB::getAircraftInformation() +{ + QFileInfo fastFileInfo(getFastDBFilename()); + QFileInfo fullFileInfo(getOSNDBFilename()); + QDateTime fastModifiedDateTime = fastFileInfo.lastModified(); + QDateTime fullModifiedDateTime = fullFileInfo.lastModified(); + + // Update fast database, if full database is newer + if (fullModifiedDateTime > fastModifiedDateTime) + { + qDebug() << "AircraftInformation::getAircraftInformation: Creating fast database"; + m_aircraftInformation = QSharedPointer>(OsnDB::readOSNDB(getOSNDBFilename())); + if (m_aircraftInformation) + { + OsnDB::writeFastDB(OsnDB::getFastDBFilename(), m_aircraftInformation.get()); + fastModifiedDateTime = fastFileInfo.lastModified(); + m_modifiedDateTime = fastModifiedDateTime; + m_aircraftInformationByReg = QSharedPointer> (OsnDB::registrationHash(m_aircraftInformation.get())); + } + } + + if (!m_aircraftInformation || (fastModifiedDateTime > m_modifiedDateTime)) + { + m_aircraftInformation = QSharedPointer>(OsnDB::readFastDB(getFastDBFilename())); + if (m_aircraftInformation) + { + m_modifiedDateTime = fastModifiedDateTime; + m_aircraftInformationByReg = QSharedPointer> (OsnDB::registrationHash(m_aircraftInformation.get())); + } + } + + return m_aircraftInformation; +} + +QSharedPointer> OsnDB::getAircraftInformationByReg() +{ + getAircraftInformation(); + return m_aircraftInformationByReg; +} + +QHash *OsnDB::readOSNDB(const QString &filename) +{ + int cnt = 0; + QHash *aircraftInfo = nullptr; + + // Column numbers used for the data as of 2020/10/28 + int icaoCol = 0; + int registrationCol = 1; + int manufacturerNameCol = 3; + int modelCol = 4; + int ownerCol = 13; + int operatorCol = 9; + int operatorICAOCol = 11; + int registeredCol = 15; + + qDebug() << "AircraftInformation::readOSNDB: " << filename; + + FILE *file; + QByteArray utfFilename = filename.toUtf8(); + if ((file = fopen(utfFilename.constData(), "r")) != NULL) + { + char row[2048]; + + if (fgets(row, sizeof(row), file)) + { + aircraftInfo = new QHash(); + aircraftInfo->reserve(500000); + // Read header + int idx = 0; + char *p = strtok(row, ","); + while (p != NULL) + { + if (!strcmp(p, "icao24")) + icaoCol = idx; + else if (!strcmp(p, "registration")) + registrationCol = idx; + else if (!strcmp(p, "manufacturername")) + manufacturerNameCol = idx; + else if (!strcmp(p, "model")) + modelCol = idx; + else if (!strcmp(p, "owner")) + ownerCol = idx; + else if (!strcmp(p, "operator")) + operatorCol = idx; + else if (!strcmp(p, "operatoricao")) + operatorICAOCol = idx; + else if (!strcmp(p, "registered")) + registeredCol = idx; + p = strtok(NULL, ","); + idx++; + } + // Read data + while (fgets(row, sizeof(row), file)) + { + int icao = 0; + char *icaoString = NULL; + char *registration = NULL; + size_t registrationLen = 0; + char *manufacturerName = NULL; + size_t manufacturerNameLen = 0; + char *model = NULL; + size_t modelLen = 0; + char *owner = NULL; + size_t ownerLen = 0; + char *operatorName = NULL; + size_t operatorNameLen = 0; + char *operatorICAO = NULL; + size_t operatorICAOLen = 0; + char *registered = NULL; + size_t registeredLen = 0; + + p = strtok(row, ","); + idx = 0; + while (p != NULL) + { + // Read strings, stripping quotes + if (idx == icaoCol) + { + icaoString = p+1; + icaoString[strlen(icaoString)-1] = '\0'; + icao = strtol(icaoString, NULL, 16); + // Ignore entries with uppercase - might be better to try and merge? + // See: https://opensky-network.org/forum/bug-reports/652-are-the-aircraft-database-dumps-working + for (int i = 0; icaoString[i] != '\0'; i++) + { + char c = icaoString[i]; + if ((c >= 'A') && (c <= 'F')) + { + icao = 0; + break; + } + } + } + else if (idx == registrationCol) + { + registration = p+1; + registrationLen = strlen(registration)-1; + registration[registrationLen] = '\0'; + } + else if (idx == manufacturerNameCol) + { + manufacturerName = p+1; + manufacturerNameLen = strlen(manufacturerName)-1; + manufacturerName[manufacturerNameLen] = '\0'; + } + else if (idx == modelCol) + { + model = p+1; + modelLen = strlen(model)-1; + model[modelLen] = '\0'; + } + else if (idx == ownerCol) + { + owner = p+1; + ownerLen = strlen(owner)-1; + owner[ownerLen] = '\0'; + } + else if (idx == operatorCol) + { + operatorName = p+1; + operatorNameLen = strlen(operatorName)-1; + operatorName[operatorNameLen] = '\0'; + } + else if (idx == operatorICAOCol) + { + operatorICAO = p+1; + operatorICAOLen = strlen(operatorICAO)-1; + operatorICAO[operatorICAOLen] = '\0'; + } + else if (idx == registeredCol) + { + registered = p+1; + registeredLen = strlen(registered)-1; + registered[registeredLen] = '\0'; + } + p = strtok(NULL, ","); + idx++; + } + + // Only create the entry if we have some interesting data + if ((icao != 0) && (registrationLen > 0 || modelLen > 0 || ownerLen > 0 || operatorNameLen > 0 || operatorICAOLen > 0)) + { + QString modelQ = QString(model); + // Tidy up the model names + if (modelQ.endsWith(" (Boeing)")) + modelQ = modelQ.left(modelQ.size() - 9); + else if (modelQ.startsWith("BOEING ")) + modelQ = modelQ.right(modelQ.size() - 7); + else if (modelQ.startsWith("Boeing ")) + modelQ = modelQ.right(modelQ.size() - 7); + else if (modelQ.startsWith("AIRBUS ")) + modelQ = modelQ.right(modelQ.size() - 7); + else if (modelQ.startsWith("Airbus ")) + modelQ = modelQ.right(modelQ.size() - 7); + else if (modelQ.endsWith(" (Cessna)")) + modelQ = modelQ.left(modelQ.size() - 9); + + AircraftInformation *aircraft = new AircraftInformation(); + aircraft->m_icao = icao; + aircraft->m_registration = QString(registration); + aircraft->m_manufacturerName = QString(manufacturerName); + aircraft->m_model = modelQ; + aircraft->m_owner = QString(owner); + aircraft->m_operator = QString(operatorName); + aircraft->m_operatorICAO = QString(operatorICAO); + aircraft->m_registered = QString(registered); + aircraftInfo->insert(icao, aircraft); + cnt++; + } + + } + } + fclose(file); + } + else + qDebug() << "AircraftInformation::readOSNDB: Failed to open " << filename; + + qDebug() << "AircraftInformation::readOSNDB: Read " << cnt << " aircraft"; + + return aircraftInfo; +} + +QHash *OsnDB::registrationHash(const QHash *in) +{ + QHash *out = new QHash(); + QHashIterator i(*in); + while (i.hasNext()) + { + i.next(); + AircraftInformation *info = i.value(); + out->insert(info->m_registration, info); + } + return out; +} + +bool OsnDB::writeFastDB(const QString &filename, const QHash *aircraftInfo) +{ + QFile file(filename); + if (file.open(QIODevice::WriteOnly)) + { + file.write("icao24,registration,manufacturername,model,owner,operator,operatoricao,registered\n"); + QHash::const_iterator i = aircraftInfo->begin(); + while (i != aircraftInfo->end()) + { + AircraftInformation *info = i.value(); + file.write(QString("%1").arg(info->m_icao, 1, 16).toUtf8()); + file.write(","); + file.write(info->m_registration.toUtf8()); + file.write(","); + file.write(info->m_manufacturerName.toUtf8()); + file.write(","); + file.write(info->m_model.toUtf8()); + file.write(","); + file.write(info->m_owner.toUtf8()); + file.write(","); + file.write(info->m_operator.toUtf8()); + file.write(","); + file.write(info->m_operatorICAO.toUtf8()); + file.write(","); + file.write(info->m_registered.toUtf8()); + file.write("\n"); + ++i; + } + file.close(); + return true; + } + else + { + qCritical() << "AircraftInformation::writeFastDB failed to open " << filename << " for writing: " << file.errorString(); + return false; + } +} + +QHash *OsnDB::readFastDB(const QString &filename) +{ + int cnt = 0; + QHash *aircraftInfo = nullptr; + + qDebug() << "AircraftInformation::readFastDB: " << filename; + + FILE *file; + QByteArray utfFilename = filename.toUtf8(); + if ((file = fopen(utfFilename.constData(), "r")) != NULL) + { + char row[2048]; + + if (fgets(row, sizeof(row), file)) + { + // Check header + if (!strcmp(row, "icao24,registration,manufacturername,model,owner,operator,operatoricao,registered\n")) + { + aircraftInfo = new QHash(); + aircraftInfo->reserve(500000); + // Read data + while (fgets(row, sizeof(row), file)) + { + char *p = row; + AircraftInformation *aircraft = new AircraftInformation(); + char *icaoString = csvNext(&p); + int icao = strtol(icaoString, NULL, 16); + aircraft->m_icao = icao; + aircraft->m_registration = QString(csvNext(&p)); + aircraft->m_manufacturerName = QString(csvNext(&p)); + aircraft->m_model = QString(csvNext(&p)); + aircraft->m_owner = QString(csvNext(&p)); + aircraft->m_operator = QString(csvNext(&p)); + aircraft->m_operatorICAO = QString(csvNext(&p)); + aircraft->m_registered = QString(csvNext(&p)); + aircraftInfo->insert(icao, aircraft); + cnt++; + } + } + else + qDebug() << "AircraftInformation::readFastDB: Unexpected header"; + } + else + qDebug() << "AircraftInformation::readFastDB: Empty file"; + fclose(file); + } + else + qDebug() << "AircraftInformation::readFastDB: Failed to open " << filename; + + qDebug() << "AircraftInformation::readFastDB - read " << cnt << " aircraft"; + + return aircraftInfo; +} + +QString AircraftInformation::getFlag() const +{ + QString flag; + if (m_prefixMap) + { + int idx = m_registration.indexOf('-'); + if (idx >= 0) + { + QString prefix; + + // Some countries use AA-A - try these first as first letters are common + prefix = m_registration.left(idx + 2); + if (m_prefixMap->contains(prefix)) + { + flag = m_prefixMap->value(prefix); + } + else + { + // Try letters before '-' + prefix = m_registration.left(idx); + if (m_prefixMap->contains(prefix)) { + flag = m_prefixMap->value(prefix); + } + } + } + else + { + // No '-' Could be one of a few countries or military. + // See: https://en.wikipedia.org/wiki/List_of_aircraft_registration_prefixes + if (m_registration.startsWith("N")) { + flag = m_prefixMap->value("N"); // US + } else if (m_registration.startsWith("JA")) { + flag = m_prefixMap->value("JA"); // Japan + } else if (m_registration.startsWith("HL")) { + flag = m_prefixMap->value("HL"); // Korea + } else if (m_registration.startsWith("YV")) { + flag = m_prefixMap->value("YV"); // Venezuela + } else if ((m_militaryMap != nullptr) && (m_militaryMap->contains(m_operator))) { + flag = m_militaryMap->value(m_operator); + } + } + } + return flag; +} + +QString AircraftInformation::getAirlineIconPath(const QString &operatorICAO) +{ + QString endPath = QString("/airlinelogos/%1.bmp").arg(operatorICAO); + // Try in user directory first, so they can customise + QString userIconPath = OsnDB::getDataDir() + endPath; + QFile file(userIconPath); + if (file.exists()) + { + return userIconPath; + } + else + { + // Try in resources + QString resourceIconPath = ":" + endPath; + QResource resource(resourceIconPath); + if (resource.isValid()) + { + return resourceIconPath; + } + } + return QString(); +} + +QIcon *AircraftInformation::getAirlineIcon(const QString &operatorICAO) +{ + if (m_airlineIcons.contains(operatorICAO)) + { + return m_airlineIcons.value(operatorICAO); + } + else + { + QIcon *icon = nullptr; + QString path = getAirlineIconPath(operatorICAO); + if (!path.isEmpty()) + { + icon = new QIcon(path); + m_airlineIcons.insert(operatorICAO, icon); + } + else + { + if (!m_airlineMissingIcons.contains(operatorICAO)) + { + qDebug() << "ADSBDemodGUI: No airline logo for " << operatorICAO; + m_airlineMissingIcons.insert(operatorICAO, true); + } + } + return icon; + } +} +QString AircraftInformation::getFlagIconPath(const QString &country) +{ + QString endPath = QString("/flags/%1.bmp").arg(country); + // Try in user directory first, so they can customise + QString userIconPath = OsnDB::getDataDir() + endPath; + QFile file(userIconPath); + if (file.exists()) + { + return userIconPath; + } + else + { + // Try in resources + QString resourceIconPath = ":" + endPath; + QResource resource(resourceIconPath); + if (resource.isValid()) + { + return resourceIconPath; + } + } + return QString(); +} + +QIcon *AircraftInformation::getFlagIcon(const QString &country) +{ + if (m_flagIcons.contains(country)) + { + return m_flagIcons.value(country); + } + else + { + QIcon *icon = nullptr; + QString path = getFlagIconPath(country); + if (!path.isEmpty()) + { + icon = new QIcon(path); + m_flagIcons.insert(country, icon); + } + return icon; + } +} + diff --git a/sdrbase/util/osndb.h b/sdrbase/util/osndb.h index 67486b60c..9a6ede114 100644 --- a/sdrbase/util/osndb.h +++ b/sdrbase/util/osndb.h @@ -19,20 +19,19 @@ #define INCLUDE_OSNDB_H #include -#include -#include #include #include #include #include #include #include -#include +#include #include #include #include "util/csv.h" +#include "util/httpdownloadmanager.h" #include "export.h" #define OSNDB_URL "https://opensky-network.org/datasets/metadata/aircraftDatabase.zip" @@ -48,6 +47,34 @@ struct SDRBASE_API AircraftInformation { QString m_operatorICAO; QString m_registered; + static void init() + { + QMutexLocker locker(&m_mutex); + if (!m_prefixMap) + { + // Read registration prefix to country map + m_prefixMap = CSV::hash(":/flags/regprefixmap.csv"); + // Read operator air force to military map + m_militaryMap = CSV::hash(":/flags/militarymap.csv"); + } + } + + + // Get flag based on registration + QString getFlag() const; + + static QString getAirlineIconPath(const QString &operatorICAO); + + // Try to find an airline logo based on ICAO + static QIcon *getAirlineIcon(const QString &operatorICAO); + + static QString getFlagIconPath(const QString &country); + + // Try to find an flag logo based on a country + static QIcon *getFlagIcon(const QString &country); + +private: + static QHash m_airlineIcons; // Hashed on airline ICAO static QHash m_airlineMissingIcons; // Hash containing which ICAOs we don't have icons for static QHash m_flagIcons; // Hashed on country @@ -55,345 +82,20 @@ struct SDRBASE_API AircraftInformation { static QHash *m_militaryMap; // Operator airforce to military (flag name) static QMutex m_mutex; - static void init() - { - QMutexLocker locker(&m_mutex); +}; - // Read registration prefix to country map - m_prefixMap = CSV::hash(":/flags/regprefixmap.csv"); - // Read operator air force to military map - m_militaryMap = CSV::hash(":/flags/militarymap.csv"); - } +class SDRBASE_API OsnDB : public QObject { + Q_OBJECT - // Read OpenSky Network CSV file - // This is large and contains lots of data we don't want, so we convert to - // a smaller version to speed up loading time - // Note that we use C file functions rather than QT, as these are ~30% faster - // and the QT version seemed to occasionally crash - static QHash *readOSNDB(const QString &filename) - { - int cnt = 0; - QHash *aircraftInfo = nullptr; +public: - // Column numbers used for the data as of 2020/10/28 - int icaoCol = 0; - int registrationCol = 1; - int manufacturerNameCol = 3; - int modelCol = 4; - int ownerCol = 13; - int operatorCol = 9; - int operatorICAOCol = 11; - int registeredCol = 15; + OsnDB(QObject* parent=nullptr); + ~OsnDB(); - qDebug() << "AircraftInformation::readOSNDB: " << filename; + void downloadAircraftInformation(); - FILE *file; - QByteArray utfFilename = filename.toUtf8(); - if ((file = fopen(utfFilename.constData(), "r")) != NULL) - { - char row[2048]; - - if (fgets(row, sizeof(row), file)) - { - aircraftInfo = new QHash(); - aircraftInfo->reserve(500000); - // Read header - int idx = 0; - char *p = strtok(row, ","); - while (p != NULL) - { - if (!strcmp(p, "icao24")) - icaoCol = idx; - else if (!strcmp(p, "registration")) - registrationCol = idx; - else if (!strcmp(p, "manufacturername")) - manufacturerNameCol = idx; - else if (!strcmp(p, "model")) - modelCol = idx; - else if (!strcmp(p, "owner")) - ownerCol = idx; - else if (!strcmp(p, "operator")) - operatorCol = idx; - else if (!strcmp(p, "operatoricao")) - operatorICAOCol = idx; - else if (!strcmp(p, "registered")) - registeredCol = idx; - p = strtok(NULL, ","); - idx++; - } - // Read data - while (fgets(row, sizeof(row), file)) - { - int icao = 0; - char *icaoString = NULL; - char *registration = NULL; - size_t registrationLen = 0; - char *manufacturerName = NULL; - size_t manufacturerNameLen = 0; - char *model = NULL; - size_t modelLen = 0; - char *owner = NULL; - size_t ownerLen = 0; - char *operatorName = NULL; - size_t operatorNameLen = 0; - char *operatorICAO = NULL; - size_t operatorICAOLen = 0; - char *registered = NULL; - size_t registeredLen = 0; - - p = strtok(row, ","); - idx = 0; - while (p != NULL) - { - // Read strings, stripping quotes - if (idx == icaoCol) - { - icaoString = p+1; - icaoString[strlen(icaoString)-1] = '\0'; - icao = strtol(icaoString, NULL, 16); - } - else if (idx == registrationCol) - { - registration = p+1; - registrationLen = strlen(registration)-1; - registration[registrationLen] = '\0'; - } - else if (idx == manufacturerNameCol) - { - manufacturerName = p+1; - manufacturerNameLen = strlen(manufacturerName)-1; - manufacturerName[manufacturerNameLen] = '\0'; - } - else if (idx == modelCol) - { - model = p+1; - modelLen = strlen(model)-1; - model[modelLen] = '\0'; - } - else if (idx == ownerCol) - { - owner = p+1; - ownerLen = strlen(owner)-1; - owner[ownerLen] = '\0'; - } - else if (idx == operatorCol) - { - operatorName = p+1; - operatorNameLen = strlen(operatorName)-1; - operatorName[operatorNameLen] = '\0'; - } - else if (idx == operatorICAOCol) - { - operatorICAO = p+1; - operatorICAOLen = strlen(operatorICAO)-1; - operatorICAO[operatorICAOLen] = '\0'; - } - else if (idx == registeredCol) - { - registered = p+1; - registeredLen = strlen(registered)-1; - registered[registeredLen] = '\0'; - } - p = strtok(NULL, ","); - idx++; - } - - // Only create the entry if we have some interesting data - if ((icao != 0) && (registrationLen > 0 || modelLen > 0 || ownerLen > 0 || operatorNameLen > 0 || operatorICAOLen > 0)) - { - QString modelQ = QString(model); - // Tidy up the model names - if (modelQ.endsWith(" (Boeing)")) - modelQ = modelQ.left(modelQ.size() - 9); - else if (modelQ.startsWith("BOEING ")) - modelQ = modelQ.right(modelQ.size() - 7); - else if (modelQ.startsWith("Boeing ")) - modelQ = modelQ.right(modelQ.size() - 7); - else if (modelQ.startsWith("AIRBUS ")) - modelQ = modelQ.right(modelQ.size() - 7); - else if (modelQ.startsWith("Airbus ")) - modelQ = modelQ.right(modelQ.size() - 7); - else if (modelQ.endsWith(" (Cessna)")) - modelQ = modelQ.left(modelQ.size() - 9); - - AircraftInformation *aircraft = new AircraftInformation(); - aircraft->m_icao = icao; - aircraft->m_registration = QString(registration); - aircraft->m_manufacturerName = QString(manufacturerName); - aircraft->m_model = modelQ; - aircraft->m_owner = QString(owner); - aircraft->m_operator = QString(operatorName); - aircraft->m_operatorICAO = QString(operatorICAO); - aircraft->m_registered = QString(registered); - aircraftInfo->insert(icao, aircraft); - cnt++; - } - - } - } - fclose(file); - } - else - qDebug() << "AircraftInformation::readOSNDB: Failed to open " << filename; - - qDebug() << "AircraftInformation::readOSNDB: Read " << cnt << " aircraft"; - - return aircraftInfo; - } - - // Create hash table using registration as key - static QHash *registrationHash(const QHash *in) - { - QHash *out = new QHash(); - QHashIterator i(*in); - while (i.hasNext()) - { - i.next(); - AircraftInformation *info = i.value(); - out->insert(info->m_registration, info); - } - return out; - } - - // Write a reduced size and validated version of the DB, so it loads quicker - static bool writeFastDB(const QString &filename, QHash *aircraftInfo) - { - QFile file(filename); - if (file.open(QIODevice::WriteOnly)) - { - file.write("icao24,registration,manufacturername,model,owner,operator,operatoricao,registered\n"); - QHash::iterator i = aircraftInfo->begin(); - while (i != aircraftInfo->end()) - { - AircraftInformation *info = i.value(); - file.write(QString("%1").arg(info->m_icao, 1, 16).toUtf8()); - file.write(","); - file.write(info->m_registration.toUtf8()); - file.write(","); - file.write(info->m_manufacturerName.toUtf8()); - file.write(","); - file.write(info->m_model.toUtf8()); - file.write(","); - file.write(info->m_owner.toUtf8()); - file.write(","); - file.write(info->m_operator.toUtf8()); - file.write(","); - file.write(info->m_operatorICAO.toUtf8()); - file.write(","); - file.write(info->m_registered.toUtf8()); - file.write("\n"); - ++i; - } - file.close(); - return true; - } - else - { - qCritical() << "AircraftInformation::writeFastDB failed to open " << filename << " for writing: " << file.errorString(); - return false; - } - } - - // Read smaller CSV file with no validation. Takes about 0.5s instead of 2s. - static QHash *readFastDB(const QString &filename) - { - int cnt = 0; - QHash *aircraftInfo = nullptr; - - qDebug() << "AircraftInformation::readFastDB: " << filename; - - FILE *file; - QByteArray utfFilename = filename.toUtf8(); - if ((file = fopen(utfFilename.constData(), "r")) != NULL) - { - char row[2048]; - - if (fgets(row, sizeof(row), file)) - { - // Check header - if (!strcmp(row, "icao24,registration,manufacturername,model,owner,operator,operatoricao,registered\n")) - { - aircraftInfo = new QHash(); - aircraftInfo->reserve(500000); - // Read data - while (fgets(row, sizeof(row), file)) - { - char *p = row; - AircraftInformation *aircraft = new AircraftInformation(); - char *icaoString = csvNext(&p); - int icao = strtol(icaoString, NULL, 16); - aircraft->m_icao = icao; - aircraft->m_registration = QString(csvNext(&p)); - aircraft->m_manufacturerName = QString(csvNext(&p)); - aircraft->m_model = QString(csvNext(&p)); - aircraft->m_owner = QString(csvNext(&p)); - aircraft->m_operator = QString(csvNext(&p)); - aircraft->m_operatorICAO = QString(csvNext(&p)); - aircraft->m_registered = QString(csvNext(&p)); - aircraftInfo->insert(icao, aircraft); - cnt++; - } - } - else - qDebug() << "AircraftInformation::readFastDB: Unexpected header"; - } - else - qDebug() << "AircraftInformation::readFastDB: Empty file"; - fclose(file); - } - else - qDebug() << "AircraftInformation::readFastDB: Failed to open " << filename; - - qDebug() << "AircraftInformation::readFastDB - read " << cnt << " aircraft"; - - return aircraftInfo; - } - - // Get flag based on registration - QString getFlag() const - { - QString flag; - if (m_prefixMap) - { - int idx = m_registration.indexOf('-'); - if (idx >= 0) - { - QString prefix; - - // Some countries use AA-A - try these first as first letters are common - prefix = m_registration.left(idx + 2); - if (m_prefixMap->contains(prefix)) - { - flag = m_prefixMap->value(prefix); - } - else - { - // Try letters before '-' - prefix = m_registration.left(idx); - if (m_prefixMap->contains(prefix)) { - flag = m_prefixMap->value(prefix); - } - } - } - else - { - // No '-' Could be one of a few countries or military. - // See: https://en.wikipedia.org/wiki/List_of_aircraft_registration_prefixes - if (m_registration.startsWith("N")) { - flag = m_prefixMap->value("N"); // US - } else if (m_registration.startsWith("JA")) { - flag = m_prefixMap->value("JA"); // Japan - } else if (m_registration.startsWith("HL")) { - flag = m_prefixMap->value("HL"); // Korea - } else if (m_registration.startsWith("YV")) { - flag = m_prefixMap->value("YV"); // Venezuela - } else if ((m_militaryMap != nullptr) && (m_militaryMap->contains(m_operator))) { - flag = m_militaryMap->value(m_operator); - } - } - } - return flag; - } + static QSharedPointer> getAircraftInformation(); + static QSharedPointer> getAircraftInformationByReg(); static QString getOSNDBZipFilename() { @@ -405,11 +107,6 @@ struct SDRBASE_API AircraftInformation { return getDataDir() + "/aircraftDatabase.csv"; } - static QString getFastDBFilename() - { - return getDataDir() + "/aircraftDatabaseFast.csv"; - } - static QString getDataDir() { // Get directory to store app data in (aircraft & airport databases and user-definable icons) @@ -418,100 +115,44 @@ struct SDRBASE_API AircraftInformation { return locations[0]; } - static QString getAirlineIconPath(const QString &operatorICAO) +private: + HttpDownloadManager m_dlm; + + static QSharedPointer> m_aircraftInformation; + static QSharedPointer> m_aircraftInformationByReg; + static QDateTime m_modifiedDateTime; + + // Write a reduced size and validated version of the DB, so it loads quicker + static bool writeFastDB(const QString &filename, const QHash *aircraftInfo); + + // Read smaller CSV file with no validation. Takes about 0.5s instead of 2s. + static QHash *readFastDB(const QString &filename); + + // Read OpenSky Network CSV file + // This is large and contains lots of data we don't want, so we convert to + // a smaller version to speed up loading time + // Note that we use C file functions rather than QT, as these are ~30% faster + // and the QT version seemed to occasionally crash + static QHash *readOSNDB(const QString &filename); + + static QString getFastDBFilename() { - QString endPath = QString("/airlinelogos/%1.bmp").arg(operatorICAO); - // Try in user directory first, so they can customise - QString userIconPath = getDataDir() + endPath; - QFile file(userIconPath); - if (file.exists()) - { - return userIconPath; - } - else - { - // Try in resources - QString resourceIconPath = ":" + endPath; - QResource resource(resourceIconPath); - if (resource.isValid()) - { - return resourceIconPath; - } - } - return QString(); + return getDataDir() + "/aircraftDatabaseFast.csv"; } - // Try to find an airline logo based on ICAO - static QIcon *getAirlineIcon(const QString &operatorICAO) - { - if (m_airlineIcons.contains(operatorICAO)) - { - return m_airlineIcons.value(operatorICAO); - } - else - { - QIcon *icon = nullptr; - QString path = getAirlineIconPath(operatorICAO); - if (!path.isEmpty()) - { - icon = new QIcon(path); - m_airlineIcons.insert(operatorICAO, icon); - } - else - { - if (!m_airlineMissingIcons.contains(operatorICAO)) - { - qDebug() << "ADSBDemodGUI: No airline logo for " << operatorICAO; - m_airlineMissingIcons.insert(operatorICAO, true); - } - } - return icon; - } - } + // Create hash table using registration as key + static QHash *registrationHash(const QHash *in); - static QString getFlagIconPath(const QString &country) - { - QString endPath = QString("/flags/%1.bmp").arg(country); - // Try in user directory first, so they can customise - QString userIconPath = getDataDir() + endPath; - QFile file(userIconPath); - if (file.exists()) - { - return userIconPath; - } - else - { - // Try in resources - QString resourceIconPath = ":" + endPath; - QResource resource(resourceIconPath); - if (resource.isValid()) - { - return resourceIconPath; - } - } - return QString(); - } +private slots: + void downloadFinished(const QString& filename, bool success); - // Try to find an flag logo based on a country - static QIcon *getFlagIcon(const QString &country) - { - if (m_flagIcons.contains(country)) - { - return m_flagIcons.value(country); - } - else - { - QIcon *icon = nullptr; - QString path = getFlagIconPath(country); - if (!path.isEmpty()) - { - icon = new QIcon(path); - m_flagIcons.insert(country, icon); - } - return icon; - } - } +signals: + void downloadingURL(const QString& url); + void downloadError(const QString& error); + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void downloadAircraftInformationFinished(); }; #endif + diff --git a/sdrbase/util/ourairportsdb.cpp b/sdrbase/util/ourairportsdb.cpp new file mode 100644 index 000000000..cd993e83f --- /dev/null +++ b/sdrbase/util/ourairportsdb.cpp @@ -0,0 +1,419 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include "util/ourairportsdb.h" + +QMutex OurAirportsDB::m_mutex; +QSharedPointer> OurAirportsDB::m_airportsById; +QSharedPointer> OurAirportsDB::m_airportsByIdent; +QDateTime OurAirportsDB::m_modifiedDateTime; + +AirportInformation::~AirportInformation() +{ + qDeleteAll(m_frequencies); +} + +QString AirportInformation::getImageName() const +{ + switch (m_type) + { + case AirportType::Large: + return "airport_large.png"; + case AirportType::Medium: + return "airport_medium.png"; + case AirportType::Heliport: + return "heliport.png"; + default: + return "airport_small.png"; + } +} + +OurAirportsDB::OurAirportsDB(QObject *parent) : + QObject(parent) +{ + connect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &OurAirportsDB::downloadFinished); +} + +OurAirportsDB::~OurAirportsDB() +{ + disconnect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &OurAirportsDB::downloadFinished); +} + +void OurAirportsDB::downloadAirportInformation() +{ + // Download airport database + QString urlString = AIRPORTS_URL; + QUrl dbURL(urlString); + qDebug() << "OurAirportsDB::downloadAirportInformation: Downloading " << urlString; + emit downloadingURL(urlString); + QNetworkReply *reply = m_dlm.download(dbURL, OurAirportsDB::getAirportDBFilename()); + connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 bytesRead, qint64 totalBytes) { + emit downloadProgress(bytesRead, totalBytes); + }); +} + +void OurAirportsDB::downloadFinished(const QString& filename, bool success) +{ + if (!success) + { + qWarning() << "OurAirportsDB::downloadFinished: Failed to download: " << filename; + emit downloadError(QString("Failed to download: %1").arg(filename)); + } + else if (filename == OurAirportsDB::getAirportDBFilename()) + { + // Now download airport frequencies + QString urlString = AIRPORT_FREQUENCIES_URL; + QUrl dbURL(urlString); + qDebug() << "OurAirportsDB::downloadFinished: Downloading " << urlString; + emit downloadingURL(urlString); + QNetworkReply *reply = m_dlm.download(dbURL, OurAirportsDB::getAirportFrequenciesDBFilename()); + connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 bytesRead, qint64 totalBytes) { + emit downloadProgress(bytesRead, totalBytes); + }); + } + else if (filename == OurAirportsDB::getAirportFrequenciesDBFilename()) + { + emit downloadAirportInformationFinished(); + } + else + { + qDebug() << "OurAirportsDB::downloadFinished: Unexpected filename: " << filename; + emit downloadError(QString("Unexpected filename: %1").arg(filename)); + } +} + +QSharedPointer> OurAirportsDB::getAirportsById() +{ + QMutexLocker locker(&m_mutex); + + readDB(); + return m_airportsById; +} + +QSharedPointer> OurAirportsDB::getAirportsByIdent() +{ + QMutexLocker locker(&m_mutex); + + readDB(); + return m_airportsByIdent; +} + +void OurAirportsDB::readDB() +{ + QFileInfo airportDBFileInfo(getAirportDBFilename()); + QDateTime airportDBModifiedDateTime = airportDBFileInfo.lastModified(); + + if (!m_airportsById || (airportDBModifiedDateTime > m_modifiedDateTime)) + { + // Using shared pointer, so old object, if it exists, will be deleted, when no longer user + m_airportsById = QSharedPointer>(OurAirportsDB::readAirportsDB(getAirportDBFilename())); + if (m_airportsById != nullptr) + { + OurAirportsDB::readFrequenciesDB(getAirportFrequenciesDBFilename(), m_airportsById.get()); + m_airportsByIdent = QSharedPointer>(identHash(m_airportsById.get())); + } + + m_modifiedDateTime = airportDBModifiedDateTime; + } +} + +QString OurAirportsDB::getDataDir() +{ + // Get directory to store app data in + QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); + // First dir is writable + return locations[0]; +} + +QString OurAirportsDB::getAirportDBFilename() +{ + return getDataDir() + "/airportDatabase.csv"; +} + +QString OurAirportsDB::getAirportFrequenciesDBFilename() +{ + return getDataDir() + "/airportFrequenciesDatabase.csv"; +} + +QString OurAirportsDB::trimQuotes(const QString s) +{ + if (s.startsWith('\"') && s.endsWith('\"')) { + return s.mid(1, s.size() - 2); + } else { + return s; + } +} + +// Read OurAirport's airport CSV file +// See comments for readOSNDB +QHash *OurAirportsDB::readAirportsDB(const QString &filename) +{ + int cnt = 0; + QHash *airportInfo = nullptr; + + // Column numbers used for the data as of 2020/10/28 + int idCol = 0; + int identCol = 1; + int typeCol = 2; + int nameCol = 3; + int latitudeCol = 4; + int longitudeCol = 5; + int elevationCol = 6; + + qDebug() << "OurAirportsDB::readAirportsDB: " << filename; + + FILE *file; + QByteArray utfFilename = filename.toUtf8(); + QLocale cLocale(QLocale::C); + if ((file = fopen(utfFilename.constData(), "r")) != NULL) + { + char row[2048]; + + if (fgets(row, sizeof(row), file)) + { + airportInfo = new QHash(); + airportInfo->reserve(70000); + + // Read header + int idx = 0; + char *p = strtok(row, ","); + while (p != NULL) + { + if (!strcmp(p, "id")) + idCol = idx; + else if (!strcmp(p, "ident")) + identCol = idx; + else if (!strcmp(p, "type")) + typeCol = idx; + else if (!strcmp(p, "name")) + nameCol = idx; + else if (!strcmp(p, "latitude_deg")) + latitudeCol = idx; + else if (!strcmp(p, "longitude_deg")) + longitudeCol = idx; + else if (!strcmp(p, "elevation_ft")) + elevationCol = idx; + p = strtok(NULL, ","); + idx++; + } + // Read data + while (fgets(row, sizeof(row), file)) + { + int id = 0; + char *idString = NULL; + char *ident = NULL; + size_t identLen = 0; + char *type = NULL; + size_t typeLen = 0; + char *name = NULL; + size_t nameLen = 0; + float latitude = 0.0f; + char *latitudeString = NULL; + size_t latitudeLen = 0; + float longitude = 0.0f; + char *longitudeString = NULL; + size_t longitudeLen = 0; + float elevation = 0.0f; + char *elevationString = NULL; + size_t elevationLen = 0; + + p = strtok(row, ","); + idx = 0; + while (p != NULL) + { + // Read strings, stripping quotes + if (idx == idCol) + { + idString = p; + idString[strlen(idString)] = '\0'; + id = strtol(idString, NULL, 10); + } + else if (idx == identCol) + { + ident = p+1; + identLen = strlen(ident)-1; + ident[identLen] = '\0'; + } + else if (idx == typeCol) + { + type = p+1; + typeLen = strlen(type)-1; + type[typeLen] = '\0'; + } + else if (idx == nameCol) + { + name = p+1; + nameLen = strlen(name)-1; + name[nameLen] = '\0'; + } + else if (idx == latitudeCol) + { + latitudeString = p; + latitudeLen = strlen(latitudeString)-1; + latitudeString[latitudeLen] = '\0'; + latitude = cLocale.toFloat(latitudeString); + } + else if (idx == longitudeCol) + { + longitudeString = p; + longitudeLen = strlen(longitudeString)-1; + longitudeString[longitudeLen] = '\0'; + longitude = cLocale.toFloat(longitudeString); + } + else if (idx == elevationCol) + { + elevationString = p; + elevationLen = strlen(elevationString)-1; + elevationString[elevationLen] = '\0'; + elevation = cLocale.toFloat(elevationString); + } + p = strtok(NULL, ","); + idx++; + } + + // Only create the entry if we have some interesting data + if (((latitude != 0.0f) || (longitude != 0.0f)) && (type && strcmp(type, "closed"))) + { + AirportInformation *airport = new AirportInformation(); + airport->m_id = id; + airport->m_ident = QString(ident); + if (!strcmp(type, "small_airport")) { + airport->m_type = AirportInformation::AirportType::Small; + } else if (!strcmp(type, "medium_airport")) { + airport->m_type = AirportInformation::AirportType::Medium; + } else if (!strcmp(type, "large_airport")) { + airport->m_type = AirportInformation::AirportType::Large; + } else if (!strcmp(type, "heliport")) { + airport->m_type = AirportInformation::AirportType::Heliport; + } + airport->m_name = QString(name); + airport->m_latitude = latitude; + airport->m_longitude = longitude; + airport->m_elevation = elevation; + airportInfo->insert(id, airport); + cnt++; + } + } + } + fclose(file); + } + else + qDebug() << "OurAirportsDB::readAirportsDB: Failed to open " << filename; + + qDebug() << "OurAirportsDB::readAirportsDB: Read " << cnt << " airports"; + + return airportInfo; +} + +// Create hash table using ICAO identifier as key +QHash *OurAirportsDB::identHash(QHash *in) +{ + QHash *out = new QHash(); + QHashIterator i(*in); + while (i.hasNext()) + { + i.next(); + AirportInformation *info = i.value(); + out->insert(info->m_ident, info); + } + return out; +} + +// Read OurAirport's airport frequencies CSV file +bool OurAirportsDB::readFrequenciesDB(const QString &filename, QHash *airportInfo) +{ + int cnt = 0; + + // Column numbers used for the data as of 2020/10/28 + int airportRefCol = 1; + int typeCol = 3; + int descriptionCol = 4; + int frequencyCol = 5; + + qDebug() << "OurAirportsDB::readFrequenciesDB: " << filename; + + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) + { + QList colNames; + int idx; + + // Read header + if (!file.atEnd()) + { + QByteArray row = file.readLine().trimmed(); + colNames = row.split(','); + // Work out which columns the data is in, based on the headers + idx = colNames.indexOf("airport_ref"); + if (idx >= 0) + airportRefCol = idx; + idx = colNames.indexOf("type"); + if (idx >= 0) + typeCol = idx; + idx = colNames.indexOf("descrption"); + if (idx >= 0) + descriptionCol = idx; + idx = colNames.indexOf("frequency_mhz"); + if (idx >= 0) + frequencyCol = idx; + } + // Read data + while (!file.atEnd()) + { + QByteArray row = file.readLine(); + QList cols = row.split(','); + + bool ok = false; + int airportRef = cols[airportRefCol].toInt(&ok, 10); + if (ok) + { + if (airportInfo->contains(airportRef)) + { + QString type = trimQuotes(cols[typeCol]); + QString description = trimQuotes(cols[descriptionCol]); + float frequency = cols[frequencyCol].toFloat(); + + AirportInformation::FrequencyInformation *frequencyInfo = new AirportInformation::FrequencyInformation(); + frequencyInfo->m_type = type; + frequencyInfo->m_description = description; + frequencyInfo->m_frequency = frequency; + airportInfo->value(airportRef)->m_frequencies.append(frequencyInfo); + cnt++; + } + } + } + file.close(); + } + else + { + qDebug() << "Failed to open " << filename << " " << file.errorString(); + return false; + } + + qDebug() << "OurAirportsDB::readFrequenciesDB: - read " << cnt << " airports"; + + return true; +} + diff --git a/sdrbase/util/ourairportsdb.h b/sdrbase/util/ourairportsdb.h new file mode 100644 index 000000000..14d2600d9 --- /dev/null +++ b/sdrbase/util/ourairportsdb.h @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_UTIL_OURAIRPORTSDB_H +#define INCLUDE_UTIL_OURAIRPORTSDB_H + +#include +#include +#include +#include + +#include +#include + +#include "util/csv.h" +#include "util/httpdownloadmanager.h" +#include "export.h" + +#define AIRPORTS_URL "https://davidmegginson.github.io/ourairports-data/airports.csv" +#define AIRPORT_FREQUENCIES_URL "https://davidmegginson.github.io/ourairports-data/airport-frequencies.csv" + +class SDRBASE_API AirportInformation { + +public: + enum AirportType { + Small, + Medium, + Large, + Heliport + }; + + struct FrequencyInformation { + QString m_type; + QString m_description; + float m_frequency; // In MHz + }; + + int m_id; + QString m_ident; + AirportType m_type; + QString m_name; + float m_latitude; + float m_longitude; + float m_elevation; + QVector m_frequencies; + + ~AirportInformation(); + QString getImageName() const; + +}; + +class SDRBASE_API OurAirportsDB : public QObject { + Q_OBJECT + +public: + + OurAirportsDB(QObject *parent=nullptr); + ~OurAirportsDB(); + + void downloadAirportInformation(); + + static QSharedPointer> getAirportsById(); + static QSharedPointer> getAirportsByIdent(); + +private: + HttpDownloadManager m_dlm; + + static QSharedPointer> m_airportsById; + static QSharedPointer> m_airportsByIdent; + static QDateTime m_modifiedDateTime; + + static QMutex m_mutex; + + static QString getDataDir(); + + static void readDB(); + + // Read OurAirport's airport CSV file + // See comments for readOSNDB + static QHash *readAirportsDB(const QString &filename); + + // Create hash table using ICAO identifier as key + static QHash *identHash(QHash *in); + + // Read OurAirport's airport frequencies CSV file + static bool readFrequenciesDB(const QString &filename, QHash *airportInfo); + + static QString trimQuotes(const QString s); + + static QString getAirportDBFilename(); + static QString getAirportFrequenciesDBFilename(); + +private slots: + void downloadFinished(const QString& filename, bool success); + +signals: + void downloadingURL(const QString& url); + void downloadError(const QString& error); + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void downloadAirportInformationFinished(); + +}; + +#endif + diff --git a/sdrgui/gui/graphicsdialog.cpp b/sdrgui/gui/graphicsdialog.cpp index 7da623336..f4a821397 100644 --- a/sdrgui/gui/graphicsdialog.cpp +++ b/sdrgui/gui/graphicsdialog.cpp @@ -32,6 +32,12 @@ GraphicsDialog::GraphicsDialog(MainSettings& mainSettings, QWidget* parent) : } else { ui->multisampling->setCurrentText(QString::number(samples)); } + samples = m_mainSettings.getMapMultisampling(); + if (samples == 0) { + ui->mapMultisampling->setCurrentText("Off"); + } else { + ui->mapMultisampling->setCurrentText(QString::number(samples)); + } } GraphicsDialog::~GraphicsDialog() @@ -42,5 +48,6 @@ GraphicsDialog::~GraphicsDialog() void GraphicsDialog::accept() { m_mainSettings.setMultisampling(ui->multisampling->currentText().toInt()); + m_mainSettings.setMapMultisampling(ui->mapMultisampling->currentText().toInt()); QDialog::accept(); } diff --git a/sdrgui/gui/graphicsdialog.ui b/sdrgui/gui/graphicsdialog.ui index 9dc2642c2..f37a06b25 100644 --- a/sdrgui/gui/graphicsdialog.ui +++ b/sdrgui/gui/graphicsdialog.ui @@ -6,8 +6,8 @@ 0 0 - 277 - 98 + 282 + 131 @@ -23,49 +23,106 @@ - - - - 150 - 0 - + + + Anti-aliasing - - Multisampling (MSAA) - - - - - - - - 80 - 0 - - - - Number of samples to use for mulitsampling anti-aliasing (MSAA) - Requires windows to be reopened - - - - Off - - - - - 2 - - - - - 4 - - - - - 8 - - + + + + + + 150 + 0 + + + + Spectrum (MSAA) + + + + + + + + 80 + 0 + + + + Number of samples to use for mulitsampling anti-aliasing (MSAA) for spectrums + +Requires windows to be reopened to take effect + + + + Off + + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + + + + + + Number of samples to use for mulitsampling anti-aliasing (MSAA) for 2D maps + +Requires windows to be reopened to take effect + + + 2D Map (MSAA) + + + + + + + + Off + + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + + + diff --git a/swagger/sdrangel/api/swagger/include/Map.yaml b/swagger/sdrangel/api/swagger/include/Map.yaml index 5909000b5..e8c9b306c 100644 --- a/swagger/sdrangel/api/swagger/include/Map.yaml +++ b/swagger/sdrangel/api/swagger/include/Map.yaml @@ -118,7 +118,7 @@ MapItem: type: number format: float altitudeReference: - description: "0 - NONE (Absolule), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND" + description: "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND" type: integer animations: description: "Animations to play" @@ -126,7 +126,7 @@ MapItem: items: $ref: "http://swgserver:8081/api/swagger/include/Map.yaml#/MapAnimation" type: - description: "(0 - Map Item, 1 - Image Tile)" + description: "(0 - Map Item, 1 - Image Tile, 2 - Polygon, 3 - Polyline)" type: integer imageTileWest: type: number @@ -140,6 +140,22 @@ MapItem: imageTileNorth: type: number format: float + imageZoomLevel: + description: "For 2D map" + type: number + format: float + coordinates: + description: "Polygon/polyline coordinates" + type: array + items: + $ref: "http://swgserver:8081/api/swagger/include/Map.yaml#/MapCoordinate" + extrudedHeight: + description: "Extruded height (from surface) for polygons" + type: number + format: float + availableUntil: + description: "Date and time until after which this item should no longer appear on 3D map" + type: string MapAnimation: description: "Animation to play in the model on the 3D map" diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem.cpp b/swagger/sdrangel/code/qt5/client/SWGMapItem.cpp index 9608112a6..0b00c0769 100644 --- a/swagger/sdrangel/code/qt5/client/SWGMapItem.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem.cpp @@ -82,6 +82,14 @@ SWGMapItem::SWGMapItem() { m_image_tile_east_isSet = false; image_tile_north = 0.0f; m_image_tile_north_isSet = false; + image_zoom_level = 0.0f; + m_image_zoom_level_isSet = false; + coordinates = nullptr; + m_coordinates_isSet = false; + extruded_height = 0.0f; + m_extruded_height_isSet = false; + available_until = nullptr; + m_available_until_isSet = false; } SWGMapItem::~SWGMapItem() { @@ -144,6 +152,14 @@ SWGMapItem::init() { m_image_tile_east_isSet = false; image_tile_north = 0.0f; m_image_tile_north_isSet = false; + image_zoom_level = 0.0f; + m_image_zoom_level_isSet = false; + coordinates = new QList(); + m_coordinates_isSet = false; + extruded_height = 0.0f; + m_extruded_height_isSet = false; + available_until = new QString(""); + m_available_until_isSet = false; } void @@ -207,6 +223,18 @@ SWGMapItem::cleanup() { + + if(coordinates != nullptr) { + auto arr = coordinates; + for(auto o: *arr) { + delete o; + } + delete coordinates; + } + + if(available_until != nullptr) { + delete available_until; + } } SWGMapItem* @@ -274,6 +302,14 @@ SWGMapItem::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&image_tile_north, pJson["imageTileNorth"], "float", ""); + ::SWGSDRangel::setValue(&image_zoom_level, pJson["imageZoomLevel"], "float", ""); + + + ::SWGSDRangel::setValue(&coordinates, pJson["coordinates"], "QList", "SWGMapCoordinate"); + ::SWGSDRangel::setValue(&extruded_height, pJson["extrudedHeight"], "float", ""); + + ::SWGSDRangel::setValue(&available_until, pJson["availableUntil"], "QString", "QString"); + } QString @@ -371,6 +407,18 @@ SWGMapItem::asJsonObject() { if(m_image_tile_north_isSet){ obj->insert("imageTileNorth", QJsonValue(image_tile_north)); } + if(m_image_zoom_level_isSet){ + obj->insert("imageZoomLevel", QJsonValue(image_zoom_level)); + } + if(coordinates && coordinates->size() > 0){ + toJsonArray((QList*)coordinates, obj, "coordinates", "SWGMapCoordinate"); + } + if(m_extruded_height_isSet){ + obj->insert("extrudedHeight", QJsonValue(extruded_height)); + } + if(available_until != nullptr && *available_until != QString("")){ + toJsonValue(QString("availableUntil"), available_until, obj, QString("QString")); + } return obj; } @@ -645,6 +693,46 @@ SWGMapItem::setImageTileNorth(float image_tile_north) { this->m_image_tile_north_isSet = true; } +float +SWGMapItem::getImageZoomLevel() { + return image_zoom_level; +} +void +SWGMapItem::setImageZoomLevel(float image_zoom_level) { + this->image_zoom_level = image_zoom_level; + this->m_image_zoom_level_isSet = true; +} + +QList* +SWGMapItem::getCoordinates() { + return coordinates; +} +void +SWGMapItem::setCoordinates(QList* coordinates) { + this->coordinates = coordinates; + this->m_coordinates_isSet = true; +} + +float +SWGMapItem::getExtrudedHeight() { + return extruded_height; +} +void +SWGMapItem::setExtrudedHeight(float extruded_height) { + this->extruded_height = extruded_height; + this->m_extruded_height_isSet = true; +} + +QString* +SWGMapItem::getAvailableUntil() { + return available_until; +} +void +SWGMapItem::setAvailableUntil(QString* available_until) { + this->available_until = available_until; + this->m_available_until_isSet = true; +} + bool SWGMapItem::isSet(){ @@ -731,6 +819,18 @@ SWGMapItem::isSet(){ if(m_image_tile_north_isSet){ isObjectUpdated = true; break; } + if(m_image_zoom_level_isSet){ + isObjectUpdated = true; break; + } + if(coordinates && (coordinates->size() > 0)){ + isObjectUpdated = true; break; + } + if(m_extruded_height_isSet){ + isObjectUpdated = true; break; + } + if(available_until && *available_until != QString("")){ + isObjectUpdated = true; break; + } }while(false); return isObjectUpdated; } diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem.h b/swagger/sdrangel/code/qt5/client/SWGMapItem.h index 871f682bc..b807fcaa5 100644 --- a/swagger/sdrangel/code/qt5/client/SWGMapItem.h +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem.h @@ -126,6 +126,18 @@ public: float getImageTileNorth(); void setImageTileNorth(float image_tile_north); + float getImageZoomLevel(); + void setImageZoomLevel(float image_zoom_level); + + QList* getCoordinates(); + void setCoordinates(QList* coordinates); + + float getExtrudedHeight(); + void setExtrudedHeight(float extruded_height); + + QString* getAvailableUntil(); + void setAvailableUntil(QString* available_until); + virtual bool isSet() override; @@ -211,6 +223,18 @@ private: float image_tile_north; bool m_image_tile_north_isSet; + float image_zoom_level; + bool m_image_zoom_level_isSet; + + QList* coordinates; + bool m_coordinates_isSet; + + float extruded_height; + bool m_extruded_height_isSet; + + QString* available_until; + bool m_available_until_isSet; + }; } diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem_2.cpp b/swagger/sdrangel/code/qt5/client/SWGMapItem_2.cpp index 3a26b3c18..5d357c82b 100644 --- a/swagger/sdrangel/code/qt5/client/SWGMapItem_2.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem_2.cpp @@ -82,6 +82,14 @@ SWGMapItem_2::SWGMapItem_2() { m_image_tile_east_isSet = false; image_tile_north = 0.0f; m_image_tile_north_isSet = false; + image_zoom_level = 0.0f; + m_image_zoom_level_isSet = false; + coordinates = nullptr; + m_coordinates_isSet = false; + extruded_height = 0.0f; + m_extruded_height_isSet = false; + available_until = nullptr; + m_available_until_isSet = false; } SWGMapItem_2::~SWGMapItem_2() { @@ -144,6 +152,14 @@ SWGMapItem_2::init() { m_image_tile_east_isSet = false; image_tile_north = 0.0f; m_image_tile_north_isSet = false; + image_zoom_level = 0.0f; + m_image_zoom_level_isSet = false; + coordinates = new QList(); + m_coordinates_isSet = false; + extruded_height = 0.0f; + m_extruded_height_isSet = false; + available_until = new QString(""); + m_available_until_isSet = false; } void @@ -207,6 +223,18 @@ SWGMapItem_2::cleanup() { + + if(coordinates != nullptr) { + auto arr = coordinates; + for(auto o: *arr) { + delete o; + } + delete coordinates; + } + + if(available_until != nullptr) { + delete available_until; + } } SWGMapItem_2* @@ -274,6 +302,14 @@ SWGMapItem_2::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&image_tile_north, pJson["imageTileNorth"], "float", ""); + ::SWGSDRangel::setValue(&image_zoom_level, pJson["imageZoomLevel"], "float", ""); + + + ::SWGSDRangel::setValue(&coordinates, pJson["coordinates"], "QList", "SWGMapCoordinate"); + ::SWGSDRangel::setValue(&extruded_height, pJson["extrudedHeight"], "float", ""); + + ::SWGSDRangel::setValue(&available_until, pJson["availableUntil"], "QString", "QString"); + } QString @@ -371,6 +407,18 @@ SWGMapItem_2::asJsonObject() { if(m_image_tile_north_isSet){ obj->insert("imageTileNorth", QJsonValue(image_tile_north)); } + if(m_image_zoom_level_isSet){ + obj->insert("imageZoomLevel", QJsonValue(image_zoom_level)); + } + if(coordinates && coordinates->size() > 0){ + toJsonArray((QList*)coordinates, obj, "coordinates", "SWGMapCoordinate"); + } + if(m_extruded_height_isSet){ + obj->insert("extrudedHeight", QJsonValue(extruded_height)); + } + if(available_until != nullptr && *available_until != QString("")){ + toJsonValue(QString("availableUntil"), available_until, obj, QString("QString")); + } return obj; } @@ -645,6 +693,46 @@ SWGMapItem_2::setImageTileNorth(float image_tile_north) { this->m_image_tile_north_isSet = true; } +float +SWGMapItem_2::getImageZoomLevel() { + return image_zoom_level; +} +void +SWGMapItem_2::setImageZoomLevel(float image_zoom_level) { + this->image_zoom_level = image_zoom_level; + this->m_image_zoom_level_isSet = true; +} + +QList* +SWGMapItem_2::getCoordinates() { + return coordinates; +} +void +SWGMapItem_2::setCoordinates(QList* coordinates) { + this->coordinates = coordinates; + this->m_coordinates_isSet = true; +} + +float +SWGMapItem_2::getExtrudedHeight() { + return extruded_height; +} +void +SWGMapItem_2::setExtrudedHeight(float extruded_height) { + this->extruded_height = extruded_height; + this->m_extruded_height_isSet = true; +} + +QString* +SWGMapItem_2::getAvailableUntil() { + return available_until; +} +void +SWGMapItem_2::setAvailableUntil(QString* available_until) { + this->available_until = available_until; + this->m_available_until_isSet = true; +} + bool SWGMapItem_2::isSet(){ @@ -731,6 +819,18 @@ SWGMapItem_2::isSet(){ if(m_image_tile_north_isSet){ isObjectUpdated = true; break; } + if(m_image_zoom_level_isSet){ + isObjectUpdated = true; break; + } + if(coordinates && (coordinates->size() > 0)){ + isObjectUpdated = true; break; + } + if(m_extruded_height_isSet){ + isObjectUpdated = true; break; + } + if(available_until && *available_until != QString("")){ + isObjectUpdated = true; break; + } }while(false); return isObjectUpdated; } diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem_2.h b/swagger/sdrangel/code/qt5/client/SWGMapItem_2.h index 809f1d932..fdf07802f 100644 --- a/swagger/sdrangel/code/qt5/client/SWGMapItem_2.h +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem_2.h @@ -126,6 +126,18 @@ public: float getImageTileNorth(); void setImageTileNorth(float image_tile_north); + float getImageZoomLevel(); + void setImageZoomLevel(float image_zoom_level); + + QList* getCoordinates(); + void setCoordinates(QList* coordinates); + + float getExtrudedHeight(); + void setExtrudedHeight(float extruded_height); + + QString* getAvailableUntil(); + void setAvailableUntil(QString* available_until); + virtual bool isSet() override; @@ -211,6 +223,18 @@ private: float image_tile_north; bool m_image_tile_north_isSet; + float image_zoom_level; + bool m_image_zoom_level_isSet; + + QList* coordinates; + bool m_coordinates_isSet; + + float extruded_height; + bool m_extruded_height_isSet; + + QString* available_until; + bool m_available_until_isSet; + }; } From 60a3dfcee7df73a3fb5bd5077b496d302424587d Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 14 Feb 2023 15:03:30 +0000 Subject: [PATCH 02/20] VOR Localizer: Send radials and estimated position to Map feature --- .../feature/vorlocalizer/vorlocalizergui.cpp | 198 ++++++++++++++++-- .../feature/vorlocalizer/vorlocalizergui.h | 9 +- 2 files changed, 184 insertions(+), 23 deletions(-) diff --git a/plugins/feature/vorlocalizer/vorlocalizergui.cpp b/plugins/feature/vorlocalizer/vorlocalizergui.cpp index 604e7e7e3..af8b6e098 100644 --- a/plugins/feature/vorlocalizer/vorlocalizergui.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizergui.cpp @@ -50,6 +50,8 @@ #include "vorlocalizersettings.h" #include "vorlocalizergui.h" +#include "SWGMapItem.h" + // Lats and longs in decimal degrees. Distance in metres. Bearing in degrees. // https://www.movable-type.co.uk/scripts/latlong.html static void calcRadialEndPoint(float startLatitude, float startLongitude, float distance, float bearing, float &endLatitude, float &endLongitude) @@ -351,6 +353,18 @@ bool VORModel::findIntersection(float &lat, float &lon) return false; } +QString VORModel::getRadials() const +{ + QStringList text; + for (int i = 0; i < m_vors.size(); i++) + { + if (m_radials[i] >= 0) { + text.append(QString("%1: %2%3").arg(m_vors[i]->m_name).arg(std::round(m_radials[i])).arg(QChar(0xb0))); + } + } + return text.join("\n"); +} + void VORLocalizerGUI::resizeTable() { // Fill table with a row of dummy data that will size the columns nicely @@ -462,6 +476,8 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected) } else { + QString radialName = QString("VOR Radial %1").arg(vorGUI->m_navAid->m_name); + VORLocalizer::MsgRemoveVORChannel *msg = VORLocalizer::MsgRemoveVORChannel::create(navId); m_vorLocalizer->getInputMessageQueue()->push(msg); @@ -470,6 +486,10 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected) // Remove from settings to remove corresponding demodulator m_settings.m_subChannelSettings.remove(navId); + // Remove radial from Map feature + m_mapFeatureRadialNames.removeOne(radialName); + clearFromMapFeature(radialName, 3); + applySettings(); } } @@ -479,7 +499,7 @@ void VORLocalizerGUI::updateVORs() m_vorModel.removeAllVORs(); AzEl azEl = m_azEl; - for (auto vor : m_vors) + for (const auto vor : *m_vors) { if (vor->m_type.contains("VOR")) // Exclude DMEs { @@ -534,6 +554,130 @@ bool VORLocalizerGUI::deserialize(const QByteArray& data) } } +void VORLocalizerGUI::clearFromMapFeature(const QString& name, int type) +{ + QList mapPipes; + MainCore::instance()->getMessagePipes().getMessagePipes(m_vorLocalizer, "mapitems", mapPipes); + for (const auto& pipe : mapPipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + swgMapItem->setName(new QString(name)); + swgMapItem->setImage(new QString("")); + swgMapItem->setType(type); + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_vorLocalizer, swgMapItem); + messageQueue->push(msg); + } +} + +void VORLocalizerGUI::sendPositionToMapFeature(float lat, float lon) +{ + // Send to Map feature + QList mapPipes; + MainCore::instance()->getMessagePipes().getMessagePipes(m_vorLocalizer, "mapitems", mapPipes); + + if (mapPipes.size() > 0) + { + QString name = MainCore::instance()->getSettings().getStationName(); + if (name != m_mapFeaturePositionName) + { + clearFromMapFeature(m_mapFeaturePositionName, 0); + m_mapFeaturePositionName = name; + } + + QString details = QString("%1\nEstimated position based on VORs\n").arg(name); + details.append(m_vorModel.getRadials()); + + for (const auto& pipe : mapPipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + + swgMapItem->setName(new QString(name)); + swgMapItem->setLatitude(lat); + swgMapItem->setLongitude(lon); + swgMapItem->setAltitude(0); + swgMapItem->setImage(new QString("antenna.png")); + swgMapItem->setImageRotation(0); + swgMapItem->setText(new QString(details)); + swgMapItem->setModel(new QString("antenna.glb")); + swgMapItem->setFixedPosition(false); + swgMapItem->setLabel(new QString(name)); + swgMapItem->setLabelAltitudeOffset(4.5); + swgMapItem->setAltitudeReference(1); + swgMapItem->setType(0); + + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_vorLocalizer, swgMapItem); + messageQueue->push(msg); + } + } +} + +void VORLocalizerGUI::sendRadialToMapFeature(VORGUI *vorGUI, Real radial) +{ + // Send to Map feature + QList mapPipes; + MainCore::instance()->getMessagePipes().getMessagePipes(m_vorLocalizer, "mapitems", mapPipes); + + if (mapPipes.size() > 0) + { + float endLat, endLong; + float bearing; + + if (m_settings.m_magDecAdjust && !vorGUI->m_navAid->m_alignedTrueNorth) { + bearing = radial - vorGUI->m_navAid->m_magneticDeclination; + } else { + bearing = radial; + } + + calcRadialEndPoint(vorGUI->m_navAid->m_latitude, vorGUI->m_navAid->m_longitude, vorGUI->m_navAid->getRangeMetres(), bearing, endLat, endLong); + + QString name = QString("VOR Radial %1").arg(vorGUI->m_navAid->m_name); + QString details = QString("%1%2").arg(std::round(bearing)).arg(QChar(0x00b0)); + + if (!m_mapFeatureRadialNames.contains(name)) { + m_mapFeatureRadialNames.append(name); + } + + for (const auto& pipe : mapPipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + + swgMapItem->setName(new QString(name)); + swgMapItem->setLatitude(vorGUI->m_navAid->m_latitude); + swgMapItem->setLongitude(vorGUI->m_navAid->m_longitude); + swgMapItem->setAltitude(Units::feetToMetres(vorGUI->m_navAid->m_elevation)); + QString image = QString("none"); + swgMapItem->setImage(new QString(image)); + swgMapItem->setImageRotation(0); + swgMapItem->setText(new QString(details)); // Not used - label is used instead for now + //swgMapItem->setFixedPosition(true); + swgMapItem->setLabel(new QString(details)); + swgMapItem->setAltitudeReference(0); + QList *coords = new QList(); + + SWGSDRangel::SWGMapCoordinate* c = new SWGSDRangel::SWGMapCoordinate(); + c->setLatitude(vorGUI->m_navAid->m_latitude); + c->setLongitude(vorGUI->m_navAid->m_longitude); // Centre of VOR + c->setAltitude(Units::feetToMetres(vorGUI->m_navAid->m_elevation)); + coords->append(c); + + c = new SWGSDRangel::SWGMapCoordinate(); + c->setLatitude(endLat); + c->setLongitude(endLong); + c->setAltitude(Units::feetToMetres(vorGUI->m_navAid->m_elevation)); + coords->append(c); + + swgMapItem->setCoordinates(coords); + swgMapItem->setType(3); + + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_vorLocalizer, swgMapItem); + messageQueue->push(msg); + } + } +} + bool VORLocalizerGUI::handleMessage(const Message& message) { if (VORLocalizer::MsgConfigureVORLocalizer::match(message)) @@ -598,6 +742,31 @@ bool VORLocalizerGUI::handleMessage(const Message& message) // Update radial on map m_vorModel.setRadial(subChannelId, validRadial, report.getRadial()); + + // Send to map feature as well + sendRadialToMapFeature(vorGUI, report.getRadial()); + + // Try to determine position, based on intersection of two radials + float lat, lon; + + if (m_vorModel.findIntersection(lat, lon)) + { + // Move antenna icon to estimated position + QQuickItem *item = ui->map->rootObject(); + QObject *stationObject = item->findChild("station"); + + if (stationObject != NULL) + { + QGeoCoordinate coords = stationObject->property("coordinate").value(); + coords.setLatitude(lat); + coords.setLongitude(lon); + stationObject->setProperty("coordinate", QVariant::fromValue(coords)); + stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName())); + } + + // Send estimated position to Map Feature as well + sendPositionToMapFeature(lat, lon); + } } else { @@ -738,7 +907,7 @@ void VORLocalizerGUI::on_getOpenAIPVORDB_clicked() void VORLocalizerGUI::readNavAids() { - m_vors = OpenAIP::readNavAids(); + m_vors = OpenAIP::getNavAids(); updateVORs(); } @@ -1052,10 +1221,13 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe VORLocalizerGUI::~VORLocalizerGUI() { + clearFromMapFeature(m_mapFeaturePositionName, 0); + for (auto const &radialName : m_mapFeatureRadialNames) { + clearFromMapFeature(radialName, 3); + } disconnect(&m_redrawMapTimer, &QTimer::timeout, this, &VORLocalizerGUI::redrawMap); m_redrawMapTimer.stop(); delete ui; - qDeleteAll(m_vors); } void VORLocalizerGUI::setWorkspaceIndex(int index) @@ -1145,27 +1317,8 @@ void VORLocalizerGUI::updateStatus() void VORLocalizerGUI::tick() { - // Try to determine position, based on intersection of two radials - every second if (++m_tickCount == 20) { - float lat, lon; - - if (m_vorModel.findIntersection(lat, lon)) - { - // Move antenna icon to estimated position - QQuickItem *item = ui->map->rootObject(); - QObject *stationObject = item->findChild("station"); - - if (stationObject != NULL) - { - QGeoCoordinate coords = stationObject->property("coordinate").value(); - coords.setLatitude(lat); - coords.setLongitude(lon); - stationObject->setProperty("coordinate", QVariant::fromValue(coords)); - stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName())); - } - } - m_rrSecondsCount++; ui->rrTurnTimeProgress->setMaximum(m_settings.m_rrTime); ui->rrTurnTimeProgress->setValue(m_rrSecondsCount <= m_settings.m_rrTime ? m_rrSecondsCount : m_settings.m_rrTime); @@ -1286,3 +1439,4 @@ void VORLocalizerGUI::makeUIConnections() QObject::connect(ui->rrTime, &QDial::valueChanged, this, &VORLocalizerGUI::on_rrTime_valueChanged); QObject::connect(ui->centerShift, &QDial::valueChanged, this, &VORLocalizerGUI::on_centerShift_valueChanged); } + diff --git a/plugins/feature/vorlocalizer/vorlocalizergui.h b/plugins/feature/vorlocalizer/vorlocalizergui.h index 26fadecc5..3c7695fbf 100644 --- a/plugins/feature/vorlocalizer/vorlocalizergui.h +++ b/plugins/feature/vorlocalizer/vorlocalizergui.h @@ -191,6 +191,7 @@ public: } bool findIntersection(float &lat, float &lon); + QString getRadials() const; private: VORLocalizerGUI *m_gui; @@ -242,7 +243,7 @@ private: OpenAIP m_openAIP; int m_countryIndex; VORModel m_vorModel; - QList m_vors; + QSharedPointer> m_vors; QHash m_selectedVORs; AzEl m_azEl; // Position of station QIcon m_muteIcon; @@ -250,6 +251,8 @@ private: int m_lastFeatureState; int m_rrSecondsCount; QTimer m_redrawMapTimer; + QString m_mapFeaturePositionName; + QStringList m_mapFeatureRadialNames; explicit VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); virtual ~VORLocalizerGUI(); @@ -270,6 +273,9 @@ private: void readNavAids(); void updateChannelList(); void applyMapSettings(); + void clearFromMapFeature(const QString& name, int type); + void sendPositionToMapFeature(float lat, float lon); + void sendRadialToMapFeature(VORGUI *vorGUI, Real radial); private slots: void on_startStop_toggled(bool checked); @@ -296,3 +302,4 @@ private slots: }; #endif // INCLUDE_VORLOCALIZERGUI_H + From df7b763eab5f42c570eacd22468e8e427d6f0c12 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 11:00:30 +0000 Subject: [PATCH 03/20] Optionally reenamable smoothing on 2D maps, as 16 MSAA isn't always available --- plugins/channelrx/demodadsb/adsbdemodgui.cpp | 13 ++++++++--- plugins/channelrx/demodadsb/map/map.qml | 17 +++++++------- plugins/feature/map/map/map.qml | 14 ++++++------ plugins/feature/map/mapgui.cpp | 13 ++++++++--- sdrbase/settings/mainsettings.h | 7 ++++++ sdrbase/settings/preferences.cpp | 5 +++- sdrbase/settings/preferences.h | 9 ++++++-- sdrgui/gui/graphicsdialog.cpp | 2 ++ sdrgui/gui/graphicsdialog.ui | 24 +++++++++++++++++++- 9 files changed, 79 insertions(+), 25 deletions(-) diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index 446ce3f46..3fe544f6f 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -4492,6 +4492,7 @@ void ADSBDemodGUI::applyMapSettings() } // Create the map using the specified provider + QQmlProperty::write(item, "smoothing", MainCore::instance()->getSettings().getMapSmoothing()); QQmlProperty::write(item, "mapProvider", m_settings.m_mapProvider); QVariantMap parameters; QString mapType; @@ -4619,7 +4620,8 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); // Enable MSAA antialiasing on 2D map - // This is much faster than using layer.smooth in the QML, when there are many items + // This can be much faster than using layer.smooth in the QML, when there are many items + // However, only seems to work when set to 16, and doesn't seem to be supported on all graphics cards int multisamples = MainCore::instance()->getSettings().getMapMultisampling(); if (multisamples > 0) { @@ -4628,7 +4630,7 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb ui->map->setFormat(format); } - m_osmPort = 0; // Pick a free port + m_osmPort = 0; // Pick a free port m_templateServer = new ADSBOSMTemplateServer("q2RVNAe3eFKCH4XsrE3r", m_osmPort); ui->map->setAttribute(Qt::WA_AcceptTouchEvents, true); @@ -5726,7 +5728,7 @@ void ADSBDemodGUI::preferenceChanged(int elementType) } } } - if (pref == Preferences::StationName) + else if (pref == Preferences::StationName) { // Update icon label on Map QQuickItem *item = ui->map->rootObject(); @@ -5739,6 +5741,11 @@ void ADSBDemodGUI::preferenceChanged(int elementType) } } } + else if (pref == Preferences::MapSmoothing) + { + QQuickItem *item = ui->map->rootObject(); + QQmlProperty::write(item, "smoothing", MainCore::instance()->getSettings().getMapSmoothing()); + } } void ADSBDemodGUI::initAviationWeather() diff --git a/plugins/channelrx/demodadsb/map/map.qml b/plugins/channelrx/demodadsb/map/map.qml index 78cdbe368..54d491261 100644 --- a/plugins/channelrx/demodadsb/map/map.qml +++ b/plugins/channelrx/demodadsb/map/map.qml @@ -14,6 +14,7 @@ Item { property string requestedMapType property bool lightIcons property variant guiPtr + property bool smoothing function createMap(pluginParameters, requestedMap, gui) { requestedMapType = requestedMap @@ -140,8 +141,8 @@ Item { Grid { horizontalItemAlignment: Grid.AlignHCenter columnSpacing: 5 - //layer.enabled: true - //layer.smooth: true + layer.enabled: smoothing + layer.smooth: smoothing Image { id: image source: navAidImage @@ -206,8 +207,8 @@ Item { sourceItem: Grid { columns: 1 Grid { - //layer.enabled: true - //layer.smooth: true + layer.enabled: smoothing + layer.smooth: smoothing horizontalItemAlignment: Grid.AlignHCenter Text { id: airspaceText @@ -239,8 +240,8 @@ Item { sourceItem: Grid { columns: 1 Grid { - //layer.enabled: true - //layer.smooth: true + layer.enabled: smoothing + layer.smooth: smoothing horizontalItemAlignment: Grid.AlignHCenter Image { id: image @@ -334,8 +335,8 @@ Item { columns: 1 Grid { horizontalItemAlignment: Grid.AlignHCenter - //layer.enabled: true - //layer.smooth: true + layer.enabled: smoothing + layer.smooth: smoothing Image { id: image source: airportImage diff --git a/plugins/feature/map/map/map.qml b/plugins/feature/map/map/map.qml index ab8c81775..c120bc871 100644 --- a/plugins/feature/map/map/map.qml +++ b/plugins/feature/map/map/map.qml @@ -10,6 +10,7 @@ Item { property string mapProvider: "osm" property variant mapPtr property variant guiPtr + property bool smoothing function createMap(pluginParameters, gui) { guiPtr = gui @@ -187,8 +188,8 @@ Item { sourceItem: Grid { columns: 1 Grid { - //layer.enabled: true - //layer.smooth: true + layer.enabled: smoothing + layer.smooth: smoothing horizontalItemAlignment: Grid.AlignHCenter Text { id: polygonText @@ -219,8 +220,8 @@ Item { sourceItem: Grid { columns: 1 Grid { - //layer.enabled: true - //layer.smooth: true + layer.enabled: smoothing + layer.smooth: smoothing horizontalItemAlignment: Grid.AlignHCenter Text { id: polylineText @@ -247,9 +248,8 @@ Item { Grid { horizontalItemAlignment: Grid.AlignHCenter columnSpacing: 5 - // This is very slow with lots of items, so we use MSAA for the whole map instead - //layer.enabled: true - //layer.smooth: true + layer.enabled: smoothing + layer.smooth: smoothing Image { id: image rotation: mapImageRotation diff --git a/plugins/feature/map/mapgui.cpp b/plugins/feature/map/mapgui.cpp index 70bbec72a..590a1a619 100644 --- a/plugins/feature/map/mapgui.cpp +++ b/plugins/feature/map/mapgui.cpp @@ -201,8 +201,9 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur rollupContents->arrangeRollups(); connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - // Enable MSAA antialiasing on 2D map, otherwise text is not clear - // This is much faster than using layer.smooth in the QML, when there are many items + // Enable MSAA antialiasing on 2D map + // This can be much faster than using layer.smooth in the QML, when there are many items + // However, only seems to work when set to 16, and doesn't seem to be supported on all graphics cards int multisamples = MainCore::instance()->getSettings().getMapMultisampling(); if (multisamples > 0) { @@ -1041,6 +1042,7 @@ void MapGUI::applyMap2DSettings(bool reloadMap) } // Create the map using the specified provider + QQmlProperty::write(item, "smoothing", MainCore::instance()->getSettings().getMapSmoothing()); QQmlProperty::write(item, "mapProvider", m_settings.m_mapProvider); QVariantMap parameters; if (!m_settings.m_mapBoxAPIKey.isEmpty() && m_settings.m_mapProvider == "mapbox") @@ -1731,13 +1733,18 @@ void MapGUI::preferenceChanged(int elementType) } } } - if (pref == Preferences::StationName) + else if (pref == Preferences::StationName) { // Update station name m_antennaMapItem.setLabel(new QString(MainCore::instance()->getSettings().getStationName())); m_antennaMapItem.setText(new QString(MainCore::instance()->getSettings().getStationName())); update(m_map, &m_antennaMapItem, "Station"); } + else if (pref == Preferences::MapSmoothing) + { + QQuickItem *item = ui->map->rootObject(); + QQmlProperty::write(item, "smoothing", MainCore::instance()->getSettings().getMapSmoothing()); + } } void MapGUI::makeUIConnections() diff --git a/sdrbase/settings/mainsettings.h b/sdrbase/settings/mainsettings.h index b76b3c2f3..4807555d9 100644 --- a/sdrbase/settings/mainsettings.h +++ b/sdrbase/settings/mainsettings.h @@ -203,6 +203,13 @@ public: emit preferenceChanged(Preferences::MapMultisampling); } + bool getMapSmoothing() const { return m_preferences.getMapSmoothing(); } + void setMapSmoothing(bool smoothing) + { + m_preferences.setMapSmoothing(smoothing); + emit preferenceChanged(Preferences::MapSmoothing); + } + signals: void preferenceChanged(int); diff --git a/sdrbase/settings/preferences.cpp b/sdrbase/settings/preferences.cpp index 4f92f4ede..7670ca60f 100644 --- a/sdrbase/settings/preferences.cpp +++ b/sdrbase/settings/preferences.cpp @@ -23,7 +23,8 @@ void Preferences::resetToDefaults() m_consoleMinLogLevel = QtDebugMsg; m_fileMinLogLevel = QtDebugMsg; m_multisampling = 0; - m_mapMultisampling = 16; + m_mapMultisampling = 0; + m_mapSmoothing = true; } QByteArray Preferences::serialize() const @@ -45,6 +46,7 @@ QByteArray Preferences::serialize() const s.writeS32((int) Multisampling, m_multisampling); s.writeBool((int) AutoUpdatePosition, m_autoUpdatePosition); s.writeS32((int) MapMultisampling, m_mapMultisampling); + s.writeBool((int) MapSmoothing, m_mapSmoothing); return s.final(); } @@ -101,6 +103,7 @@ bool Preferences::deserialize(const QByteArray& data) d.readS32((int) Multisampling, &m_multisampling, 0); d.readBool((int) AutoUpdatePosition, &m_autoUpdatePosition, true); d.readS32((int) MapMultisampling, &m_mapMultisampling, 16); + d.readBool((int) MapSmoothing, &m_mapSmoothing, true); return true; } diff --git a/sdrbase/settings/preferences.h b/sdrbase/settings/preferences.h index 9298a5bda..2c521be8d 100644 --- a/sdrbase/settings/preferences.h +++ b/sdrbase/settings/preferences.h @@ -24,7 +24,8 @@ public: SourceItemIndex, Multisampling, AutoUpdatePosition, - MapMultisampling + MapMultisampling, + MapSmoothing }; Preferences(); @@ -83,6 +84,9 @@ public: int getMapMultisampling() const { return m_mapMultisampling; } void setMapMultisampling(int samples) { m_mapMultisampling = samples; } + bool getMapSmoothing() const { return m_mapSmoothing; } + void setMapSmoothing(bool smoothing) { m_mapSmoothing = smoothing; } + protected: QString m_sourceDevice; //!< Identification of the source used in R0 tab (GUI flavor) at startup int m_sourceIndex; //!< Index of the source used in R0 tab (GUI flavor) at startup @@ -103,7 +107,8 @@ protected: QString m_logFileName; int m_multisampling; //!< Number of samples to use for multisampling anti-aliasing for spectrums (typically 0 or 4) - int m_mapMultisampling; //!< Number of samples to use for multisampling anti-aliasing for 2D maps (16 gives best text) + int m_mapMultisampling; //!< Number of samples to use for multisampling anti-aliasing for 2D maps (16 gives best text, if not using mapSmoothing) + bool m_mapSmoothing; //!< Whether to use smoothing for text boxes on 2D maps }; #endif // INCLUDE_PREFERENCES_H diff --git a/sdrgui/gui/graphicsdialog.cpp b/sdrgui/gui/graphicsdialog.cpp index f4a821397..cc81c5962 100644 --- a/sdrgui/gui/graphicsdialog.cpp +++ b/sdrgui/gui/graphicsdialog.cpp @@ -38,6 +38,7 @@ GraphicsDialog::GraphicsDialog(MainSettings& mainSettings, QWidget* parent) : } else { ui->mapMultisampling->setCurrentText(QString::number(samples)); } + ui->mapSmoothing->setChecked(m_mainSettings.getMapSmoothing()); } GraphicsDialog::~GraphicsDialog() @@ -49,5 +50,6 @@ void GraphicsDialog::accept() { m_mainSettings.setMultisampling(ui->multisampling->currentText().toInt()); m_mainSettings.setMapMultisampling(ui->mapMultisampling->currentText().toInt()); + m_mainSettings.setMapSmoothing(ui->mapSmoothing->isChecked()); QDialog::accept(); } diff --git a/sdrgui/gui/graphicsdialog.ui b/sdrgui/gui/graphicsdialog.ui index f37a06b25..761658d73 100644 --- a/sdrgui/gui/graphicsdialog.ui +++ b/sdrgui/gui/graphicsdialog.ui @@ -7,7 +7,7 @@ 0 0 282 - 131 + 155 @@ -95,6 +95,11 @@ Requires windows to be reopened to take effect + + Number of samples to use for mulitsampling anti-aliasing (MSAA) for 2D Map + +Requires windows to be reopened to take effect + Off @@ -122,6 +127,23 @@ Requires windows to be reopened to take effect + + + + Whether smoothing should be enabled for text on 2D maps + + + + + + + + + + 2D Map Text Smoothing + + + From 63cba7e7d84dc3675e89858efd32a4e22c62e09a Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 12:18:58 +0000 Subject: [PATCH 04/20] Remove unused function --- plugins/feature/map/mapgui.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/plugins/feature/map/mapgui.cpp b/plugins/feature/map/mapgui.cpp index 590a1a619..bb936c93d 100644 --- a/plugins/feature/map/mapgui.cpp +++ b/plugins/feature/map/mapgui.cpp @@ -549,17 +549,6 @@ void MapGUI::foF2Updated(const QJsonDocument& document) } } -static QString arrayToString(QJsonArray array) -{ - QString s; - for (int i = 0; i < array.size(); i++) - { - s = s.append(array[i].toString()); - s = s.append(" "); - } - return s; -} - void MapGUI::addBroadcast() { QFile file(":/map/data/transmitters.csv"); @@ -663,8 +652,20 @@ void MapGUI::addBroadcast() } } -// Coming soon -/* Code for FM list / DAB list, should they allow access +/* + +static QString arrayToString(QJsonArray array) +{ + QString s; + for (int i = 0; i < array.size(); i++) + { + s = s.append(array[i].toString()); + s = s.append(" "); + } + return s; +} + +// Code for FM list / DAB list, should they allow access void MapGUI::addDAB() { QFile file("stationlist_SI.json"); From f807b45df3acd585be85c2e8a9b147d6b26f5e32 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 12:20:31 +0000 Subject: [PATCH 05/20] ADS-B: Add aircraft min zoom setting. Default to only displaying CTR airspace. --- .../demodadsb/adsbdemoddisplaydialog.cpp | 2 ++ .../demodadsb/adsbdemoddisplaydialog.ui | 17 +++++++++++++++++ plugins/channelrx/demodadsb/adsbdemodgui.cpp | 11 ++++++++--- .../channelrx/demodadsb/adsbdemodsettings.cpp | 7 +++++-- plugins/channelrx/demodadsb/adsbdemodsettings.h | 1 + plugins/channelrx/demodadsb/map/map.qml | 8 ++++++-- 6 files changed, 39 insertions(+), 7 deletions(-) diff --git a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.cpp b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.cpp index b2e645fd2..028dd712c 100644 --- a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.cpp +++ b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.cpp @@ -29,6 +29,7 @@ ADSBDemodDisplayDialog::ADSBDemodDisplayDialog(ADSBDemodSettings *settings, QWid { ui->setupUi(this); ui->timeout->setValue(settings->m_removeTimeout); + ui->aircraftMinZoom->setValue(settings->m_aircraftMinZoom); ui->airportRange->setValue(settings->m_airportRange); ui->airportSize->setCurrentIndex((int)settings->m_airportMinimumSize); ui->heliports->setChecked(settings->m_displayHeliports); @@ -61,6 +62,7 @@ ADSBDemodDisplayDialog::~ADSBDemodDisplayDialog() void ADSBDemodDisplayDialog::accept() { m_settings->m_removeTimeout = ui->timeout->value(); + m_settings->m_aircraftMinZoom = ui->aircraftMinZoom->value(); m_settings->m_airportRange = ui->airportRange->value(); m_settings->m_airportMinimumSize = (ADSBDemodSettings::AirportType)ui->airportSize->currentIndex(); m_settings->m_displayHeliports = ui->heliports->isChecked(); diff --git a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui index 417ba074e..2fb04c314 100644 --- a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui +++ b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui @@ -524,6 +524,23 @@ + + + + Scale aircraft minimum zoom level + + + + + + + When map zoom (0 min zoom - 15 max zoom) is higher than this value, aircraft icon size will be scaled + + + 15 + + + diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index 3fe544f6f..35a455966 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -609,7 +609,9 @@ QVariant AirspaceModel::data(const QModelIndex &index, int role) const } else if (role == AirspaceModel::airspaceBorderColorRole) { - if (m_airspaces[row]->m_category == "D") { + if ((m_airspaces[row]->m_category == "D") + || (m_airspaces[row]->m_category == "G") + || (m_airspaces[row]->m_category == "CTR")) { return QVariant::fromValue(QColor(0x00, 0x00, 0xff, 0x00)); } else { return QVariant::fromValue(QColor(0xff, 0x00, 0x00, 0x00)); @@ -617,7 +619,9 @@ QVariant AirspaceModel::data(const QModelIndex &index, int role) const } else if (role == AirspaceModel::airspaceFillColorRole) { - if (m_airspaces[row]->m_category == "D") { + if ((m_airspaces[row]->m_category == "D") + || (m_airspaces[row]->m_category == "G") + || (m_airspaces[row]->m_category == "CTR")) { return QVariant::fromValue(QColor(0x00, 0x00, 0xff, 0x10)); } else { return QVariant::fromValue(QColor(0xff, 0x00, 0x00, 0x10)); @@ -4215,7 +4219,7 @@ void ADSBDemodGUI::updateAirports() if (airportInfo->m_type >= m_settings.m_airportMinimumSize) { // Only display heliports if enabled - if (m_settings.m_displayHeliports || (airportInfo->m_type != ADSBDemodSettings::AirportType::Heliport)) + if (m_settings.m_displayHeliports || (airportInfo->m_type != AirportInformation::AirportType::Heliport)) { m_airportModel.addAirport(airportInfo, azEl.getAzimuth(), azEl.getElevation(), azEl.getDistance()); } @@ -4493,6 +4497,7 @@ void ADSBDemodGUI::applyMapSettings() // Create the map using the specified provider QQmlProperty::write(item, "smoothing", MainCore::instance()->getSettings().getMapSmoothing()); + QQmlProperty::write(item, "aircraftMinZoomLevel", m_settings.m_aircraftMinZoom); QQmlProperty::write(item, "mapProvider", m_settings.m_mapProvider); QVariantMap parameters; QString mapType; diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp index 250a7801b..6312c319b 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp @@ -90,7 +90,7 @@ void ADSBDemodSettings::resetToDefaults() } m_logFilename = "adsb_log.csv"; m_logEnabled = false; - m_airspaces = QStringList({"A", "D", "TMZ"}); + m_airspaces = QStringList({"CTR"}); m_airspaceRange = 500.0f; #ifdef LINUX m_mapProvider = "mapboxgl"; // osm maps do not work in some versions of Linux https://github.com/f4exb/sdrangel/issues/1169 & 1369 @@ -102,6 +102,7 @@ void ADSBDemodSettings::resetToDefaults() m_displayPhotos = true; m_verboseModelMatching = false; m_airfieldElevation = 0; + m_aircraftMinZoom = 11; m_workspaceIndex = 0; m_hidden = false; } @@ -185,6 +186,7 @@ QByteArray ADSBDemodSettings::serialize() const s.writeBool(61, m_hidden); s.writeString(62, m_checkWXAPIKey); s.writeString(63, m_mapProvider); + s.writeS32(64, m_aircraftMinZoom); for (int i = 0; i < ADSBDEMOD_COLUMNS; i++) { s.writeS32(100 + i, m_columnIndexes[i]); @@ -277,7 +279,7 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data) d.readString(36, &m_logFilename, "adsb_log.csv"); d.readBool(37, &m_logEnabled, false); - d.readString(38, &string, "A D TMZ"); + d.readString(38, &string, "CTR"); m_airspaces = string.split(" "); d.readFloat(39, &m_airspaceRange, 500.0f); d.readS32(40, (int *)&m_mapType, (int)AVIATION_LIGHT); @@ -316,6 +318,7 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data) d.readBool(61, &m_hidden, false); d.readString(62, &m_checkWXAPIKey, ""); d.readString(63, &m_mapProvider, "osm"); + d.readS32(64, &m_aircraftMinZoom, 11); #ifdef LINUX if (m_mapProvider == "osm") { m_mapProvider = "mapboxgl"; diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.h b/plugins/channelrx/demodadsb/adsbdemodsettings.h index c8f0b7650..54af2b81e 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.h +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.h @@ -186,6 +186,7 @@ struct ADSBDemodSettings Serializable *m_rollupState; bool m_verboseModelMatching; int m_airfieldElevation; //!< QFE in ft so aircraft takeoff/land from correct position + int m_aircraftMinZoom; ADSBDemodSettings(); void resetToDefaults(); diff --git a/plugins/channelrx/demodadsb/map/map.qml b/plugins/channelrx/demodadsb/map/map.qml index 54d491261..7bb791629 100644 --- a/plugins/channelrx/demodadsb/map/map.qml +++ b/plugins/channelrx/demodadsb/map/map.qml @@ -8,6 +8,7 @@ import QtGraphicalEffects 1.12 Item { id: qmlMap property int aircraftZoomLevel: 11 + property int aircraftMinZoomLevel: 11 property int airportZoomLevel: 11 property string mapProvider: "osm" property variant mapPtr @@ -104,13 +105,16 @@ Item { } onZoomLevelChanged: { + if (zoomLevel > aircraftMinZoomLevel) { + aircraftZoomLevel = zoomLevel + } else { + aircraftZoomLevel = aircraftMinZoomLevel + } if (zoomLevel > 11) { station.zoomLevel = zoomLevel - aircraftZoomLevel = zoomLevel airportZoomLevel = zoomLevel } else { station.zoomLevel = 11 - aircraftZoomLevel = 11 airportZoomLevel = 11 } } From ab97ce7349c186d3bb8dadaee23c4bd6b7fe8abd Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 12:40:05 +0000 Subject: [PATCH 06/20] ADS-B: Only enable text to speech engine if speech used, as this can take 10 seconds on Linux --- plugins/channelrx/demodadsb/adsbdemodgui.cpp | 36 ++++++++++++++++---- plugins/channelrx/demodadsb/adsbdemodgui.h | 1 + 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index 35a455966..4a75e0e78 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -3104,9 +3104,32 @@ void ADSBDemodGUI::checkDynamicNotification(Aircraft *aircraft) } } +// Initialise text to speech engine +// This takes 10 seconds on some versions of Linux, so only do it, if user actually +// has speech notifications configured +void ADSBDemodGUI::enableSpeechIfNeeded() +{ + if (m_speech) { + return; + } + for (const auto& notification : m_settings.m_notificationSettings) + { + if (!notification->m_speech.isEmpty()) + { + qDebug() << "ADSBDemodGUI: Enabling text to speech"; + m_speech = new QTextToSpeech(this); + return; + } + } +} + void ADSBDemodGUI::speechNotification(Aircraft *aircraft, const QString &speech) { - m_speech->say(subAircraftString(aircraft, speech)); + if (m_speech) { + m_speech->say(subAircraftString(aircraft, speech)); + } else { + qDebug() << "ADSBDemodGUI::speechNotification: Unable to say " << speech; + } } void ADSBDemodGUI::commandNotification(Aircraft *aircraft, const QString &command) @@ -3308,7 +3331,9 @@ void ADSBDemodGUI::on_feed_clicked(bool checked) void ADSBDemodGUI::on_notifications_clicked() { ADSBDemodNotificationDialog dialog(&m_settings); - if (dialog.exec() == QDialog::Accepted) { + if (dialog.exec() == QDialog::Accepted) + { + enableSpeechIfNeeded(); applySettings(); } } @@ -4216,7 +4241,7 @@ void ADSBDemodGUI::updateAirports() if (azEl.getDistance() <= m_settings.m_airportRange*1000.0f) { // Only display the airport if it's large enough - if (airportInfo->m_type >= m_settings.m_airportMinimumSize) + if (airportInfo->m_type >= (AirportInformation::AirportType)m_settings.m_airportMinimumSize) { // Only display heliports if enabled if (m_settings.m_displayHeliports || (airportInfo->m_type != AirportInformation::AirportType::Heliport)) @@ -4613,6 +4638,7 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_airspaceModel(this), m_trackAircraft(nullptr), m_highlightAircraft(nullptr), + m_speech(nullptr), m_progressDialog(nullptr), m_loadingData(false) { @@ -4761,9 +4787,6 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb updateNavAids(); update3DModels(); - // Initialise text to speech engine - m_speech = new QTextToSpeech(this); - m_flightInformation = nullptr; m_aviationWeather = nullptr; @@ -4952,6 +4975,7 @@ void ADSBDemodGUI::displaySettings() getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); + enableSpeechIfNeeded(); } void ADSBDemodGUI::leaveEvent(QEvent* event) diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.h b/plugins/channelrx/demodadsb/adsbdemodgui.h index c54f66ecd..f411d0484 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.h +++ b/plugins/channelrx/demodadsb/adsbdemodgui.h @@ -994,6 +994,7 @@ private: SWGSDRangel::SWGMapAnimation *engineAnimation(QDateTime startDateTime, int engine, bool stop); void checkStaticNotification(Aircraft *aircraft); void checkDynamicNotification(Aircraft *aircraft); + void enableSpeechIfNeeded(); void speechNotification(Aircraft *aircraft, const QString &speech); void commandNotification(Aircraft *aircraft, const QString &command); QString subAircraftString(Aircraft *aircraft, const QString &string); From 83fca6a97bbdea43707bba2675382a791a9b0711 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 12:45:09 +0000 Subject: [PATCH 07/20] Update documentation --- plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui | 2 +- plugins/channelrx/demodadsb/readme.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui index 2fb04c314..c18ea946b 100644 --- a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui +++ b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui @@ -527,7 +527,7 @@ - Scale aircraft minimum zoom level + Zoom level for aircraft scaling diff --git a/plugins/channelrx/demodadsb/readme.md b/plugins/channelrx/demodadsb/readme.md index 196fb7313..137b2f446 100644 --- a/plugins/channelrx/demodadsb/readme.md +++ b/plugins/channelrx/demodadsb/readme.md @@ -73,6 +73,7 @@ Clicking the Display Settings button will open the Display Settings dialog, whic * The units for altitude, speed and vertical climb rate. These can be either ft (feet), kn (knots) and ft/min (feet per minute), or m (metres), kph (kilometers per hour) and m/s (metres per second). * The map provider. This can be osm for OpenStreetMaps or mapboxgl for Mapbox. mapboxgl is not supported on Windows. mapboxgl should be used on Linux with Qt 5.15.3, as osm maps will cause SDRangel to hang, due to a bug in Qt. * The type of map that will be displayed. This can either be a light or dark aviation map (with no place names to reduce clutter), a street map or satellite imagery. +* The minimum zoom level (0 min zoom - 15 max zoom) at which aircraft icons will be scaled. * The minimum size airport that will be displayed on the map: small, medium or large. Use small to display GA airfields, medium for regional airports and large for international airports. * Whether or not to display heliports. * The distance (in kilometres), from the location set under Preferences > My Position, at which airports will be displayed on the map. Displaying too many airports will slow down drawing of the map. From 8163dcb0ab6a70119a244b145a17fe9249ce8b01 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:29:17 +0000 Subject: [PATCH 08/20] Prevent warnings about assigning undefined values --- plugins/feature/map/map/map.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/feature/map/map/map.qml b/plugins/feature/map/map/map.qml index c120bc871..193b2d95a 100644 --- a/plugins/feature/map/map/map.qml +++ b/plugins/feature/map/map/map.qml @@ -239,7 +239,8 @@ Item { anchorPoint.x: image.width/2 anchorPoint.y: image.height/2 coordinate: position - zoomLevel: mapZoomLevel > mapImageMinZoom ? mapZoomLevel : mapImageMinZoom + // when zooming, mapImageMinZoom can be temporarily undefined. Not sure why + zoomLevel: (typeof mapImageMinZoom !== 'undefined') ? (mapZoomLevel > mapImageMinZoom ? mapZoomLevel : mapImageMinZoom) : zoomLevel autoFadeIn: false // not in 5.12 sourceItem: Grid { From 40f560daecc3b53c41def783f62c3cec663ea0fa Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:30:14 +0000 Subject: [PATCH 09/20] Remove star tracker items from map on close --- plugins/feature/startracker/startrackerworker.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/feature/startracker/startrackerworker.cpp b/plugins/feature/startracker/startrackerworker.cpp index 3237337e8..9055c2931 100644 --- a/plugins/feature/startracker/startrackerworker.cpp +++ b/plugins/feature/startracker/startrackerworker.cpp @@ -76,9 +76,17 @@ void StarTrackerWorker::startWork() void StarTrackerWorker::stopWork() { QMutexLocker mutexLocker(&m_mutex); - disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - restartServer(false, 0); m_pollTimer.stop(); + disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + if (m_settings.m_drawSunOnMap) + removeFromMap("Sun"); + if (m_settings.m_drawMoonOnMap) + removeFromMap("Moon"); + if (m_settings.m_drawStarOnMap && (m_settings.m_target != "Sun") && (m_settings.m_target != "Moon")) + removeFromMap("Star"); + + restartServer(false, 0); } void StarTrackerWorker::handleInputMessages() From a5226536762b39a1b99fdda40633fd57a792414f Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:30:55 +0000 Subject: [PATCH 10/20] Remove ships from map on close. --- plugins/feature/ais/aisgui.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/plugins/feature/ais/aisgui.cpp b/plugins/feature/ais/aisgui.cpp index e9c0dab47..641a27150 100644 --- a/plugins/feature/ais/aisgui.cpp +++ b/plugins/feature/ais/aisgui.cpp @@ -239,6 +239,16 @@ AISGUI::AISGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur AISGUI::~AISGUI() { + // Remove all ships from map + for (int row = ui->vessels->rowCount() - 1; row >= 0; row--) + { + QString mmsi = ui->vessels->item(row, VESSEL_COL_MMSI)->text(); + sendToMap(mmsi, "", + "", "", + "", 0.0f, 0.0f, + 0.0f, 0.0f, QDateTime(), + 0.0f); + } qDeleteAll(m_vessels); delete ui; } @@ -343,8 +353,8 @@ void AISGUI::removeOldVessels() 0.0f); // Remove from table ui->vessels->removeRow(row); - // Remove from hash - m_vessels.remove(mmsi); + // Remove from hash and free memory + delete m_vessels.take(mmsi); } } } @@ -458,8 +468,11 @@ void AISGUI::sendToMap(const QString &name, const QString &label, swgMapItem->setAltitude(0); swgMapItem->setAltitudeReference(1); // CLAMP_TO_GROUND - if (positionDateTime.isValid()) { + if (positionDateTime.isValid()) + { swgMapItem->setPositionDateTime(new QString(positionDateTime.toString(Qt::ISODateWithMs))); + swgMapItem->setOrientationDateTime(new QString(positionDateTime.toString(Qt::ISODateWithMs))); + swgMapItem->setAvailableUntil(new QString(positionDateTime.addSecs(10*60).toString(Qt::ISODateWithMs))); } swgMapItem->setImageRotation(heading); From e47689edda54a618bb6d39cc22f07adacdc22b85 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:31:43 +0000 Subject: [PATCH 11/20] Remove APRS items from map on close. --- plugins/feature/aprs/aprsgui.cpp | 43 +++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/plugins/feature/aprs/aprsgui.cpp b/plugins/feature/aprs/aprsgui.cpp index 2073404be..d3aa9b037 100644 --- a/plugins/feature/aprs/aprsgui.cpp +++ b/plugins/feature/aprs/aprsgui.cpp @@ -355,21 +355,31 @@ bool APRSGUI::handleMessage(const Message& message) MessageQueue *messageQueue = qobject_cast(pipe->m_element); SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + QString name; if (!aprs->m_objectName.isEmpty()) { - swgMapItem->setName(new QString(aprs->m_objectName)); + name = aprs->m_objectName; } else { - swgMapItem->setName(new QString(aprs->m_from)); + name = aprs->m_from; } + swgMapItem->setName(new QString(name)); swgMapItem->setLatitude(aprs->m_latitude); swgMapItem->setLongitude(aprs->m_longitude); swgMapItem->setAltitude(aprs->m_hasAltitude ? Units::feetToMetres(aprs->m_altitudeFt) : 0); swgMapItem->setAltitudeReference(1); // CLAMP_TO_GROUND - + swgMapItem->setFixedPosition(false); + if (aprs->m_hasTimestamp) { + swgMapItem->setPositionDateTime(new QString(aprs->m_timestamp.toString(Qt::ISODateWithMs))); + } else { + swgMapItem->setPositionDateTime(new QString(QDateTime::currentDateTime().toString(Qt::ISODateWithMs))); + } + // Need to set availableUntil for 3D track to be displayed + swgMapItem->setAvailableUntil(new QString(QDateTime::currentDateTime().addDays(1).toString(Qt::ISODateWithMs))); if (aprs->m_objectKilled) { swgMapItem->setImage(new QString("")); swgMapItem->setText(new QString("")); + m_mapItems.remove(name); } else { @@ -385,6 +395,9 @@ bool APRSGUI::handleMessage(const Message& message) m_settings.m_rainfallUnits == APRSSettings::MILLIMETRE ) )); + if (!m_mapItems.contains(name)) { + m_mapItems.insert(name, true); + } } MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_aprs, swgMapItem); @@ -577,9 +590,33 @@ APRSGUI::APRSGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feat APRSGUI::~APRSGUI() { + QHashIterator itr(m_mapItems); + while (itr.hasNext()) + { + itr.next(); + removeFromMap(itr.key()); + } delete ui; } +void APRSGUI::removeFromMap(const QString& name) +{ + QList mapPipes; + MainCore::instance()->getMessagePipes().getMessagePipes(m_aprs, "mapitems", mapPipes); + + for (const auto& pipe : mapPipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + + swgMapItem->setName(new QString(name)); + swgMapItem->setImage(new QString("")); + + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_aprs, swgMapItem); + messageQueue->push(msg); + } +} + void APRSGUI::setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; From fe300d6d44d063be756418cd351b9c756dc29bf5 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:32:16 +0000 Subject: [PATCH 12/20] Remove APRS items from map on close. --- plugins/feature/aprs/aprsgui.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/feature/aprs/aprsgui.h b/plugins/feature/aprs/aprsgui.h index 9468b8a51..b3acda7cf 100644 --- a/plugins/feature/aprs/aprsgui.h +++ b/plugins/feature/aprs/aprsgui.h @@ -151,9 +151,12 @@ private: QDateTimeAxis m_motionChartXAxis; QValueAxis m_motionChartYAxis; + QHash m_mapItems; + explicit APRSGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); virtual ~APRSGUI(); + void removeFromMap(const QString& name); void blockApplySettings(bool block); void applySettings(bool force = false); void displayTableSettings(QTableWidget *table, QMenu *menu, int *columnIndexes, int *columnSizes, int columns); From 116748bb8d1cde98d82e1d30061a3afd644d58ca Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:32:50 +0000 Subject: [PATCH 13/20] Remove radiosondes from map on close and fix memory leak --- plugins/feature/radiosonde/radiosondegui.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/feature/radiosonde/radiosondegui.cpp b/plugins/feature/radiosonde/radiosondegui.cpp index e13ff4e9c..e95e86fbd 100644 --- a/plugins/feature/radiosonde/radiosondegui.cpp +++ b/plugins/feature/radiosonde/radiosondegui.cpp @@ -200,7 +200,8 @@ RadiosondeGUI::RadiosondeGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, F RadiosondeGUI::~RadiosondeGUI() { - qDeleteAll(m_radiosondes); + // Remove from map and free memory + on_deleteAll_clicked(); delete ui; } @@ -392,8 +393,11 @@ void RadiosondeGUI::sendToMap(const QString &name, const QString &label, swgMapItem->setAltitude(altitude); swgMapItem->setAltitudeReference(0); // ABSOLUTE - if (positionDateTime.isValid()) { + if (positionDateTime.isValid()) + { swgMapItem->setPositionDateTime(new QString(positionDateTime.toString(Qt::ISODateWithMs))); + swgMapItem->setOrientationDateTime(new QString(positionDateTime.toString(Qt::ISODateWithMs))); + swgMapItem->setAvailableUntil(new QString(positionDateTime.addSecs(1*60*60).toString(Qt::ISODateWithMs))); } swgMapItem->setImageRotation(heading); @@ -877,8 +881,8 @@ void RadiosondeGUI::on_deleteAll_clicked() 0.0f); // Remove from table ui->radiosondes->removeRow(row); - // Remove from hash - m_radiosondes.remove(serial); + // Remove from hash and free memory + delete m_radiosondes.take(serial); } } From 9fb1171336aa1eddbef2b1c6f2ddc6a854dd7558 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:33:26 +0000 Subject: [PATCH 14/20] Fix restoring custom time --- plugins/feature/satellitetracker/satellitetrackergui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/feature/satellitetracker/satellitetrackergui.cpp b/plugins/feature/satellitetracker/satellitetrackergui.cpp index ab2446d04..feac7a4d4 100644 --- a/plugins/feature/satellitetracker/satellitetrackergui.cpp +++ b/plugins/feature/satellitetracker/satellitetrackergui.cpp @@ -373,9 +373,9 @@ void SatelliteTrackerGUI::displaySettings() ui->target->blockSignals(false); ui->target->setCurrentIndex(ui->target->findText(m_settings.m_target)); + ui->dateTime->setDateTime(QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs)); ui->dateTimeSelect->setCurrentIndex((int)m_settings.m_dateTimeSelect); ui->dateTime->setVisible(m_settings.m_dateTimeSelect == SatelliteTrackerSettings::CUSTOM); - ui->dateTime->setDateTime(QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs)); ui->autoTarget->setChecked(m_settings.m_autoTarget); ui->darkTheme->setChecked(m_settings.m_chartsDarkTheme); ui->satTable->horizontalHeader()->setSortIndicator(m_settings.m_columnSort, m_settings.m_columnSortOrder); From 4fa132731b41672beec2985869d061d79ae5ef56 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:33:39 +0000 Subject: [PATCH 15/20] Remove satellites from map on close --- .../satellitetracker/satellitetrackerworker.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugins/feature/satellitetracker/satellitetrackerworker.cpp b/plugins/feature/satellitetracker/satellitetrackerworker.cpp index aca2b00f7..81b7bd4d1 100644 --- a/plugins/feature/satellitetracker/satellitetrackerworker.cpp +++ b/plugins/feature/satellitetracker/satellitetrackerworker.cpp @@ -68,6 +68,16 @@ SatelliteTrackerWorker::~SatelliteTrackerWorker() qDebug() << "SatelliteTrackerWorker::~SatelliteTrackerWorker"; stopWork(); m_inputMessageQueue.clear(); + // Remove satellites from Map + QHashIterator itr(m_workerState); + while (itr.hasNext()) + { + itr.next(); + if (m_settings.m_drawOnMap) { + removeFromMap(itr.key()); + } + } + qDeleteAll(m_workerState); } void SatelliteTrackerWorker::startWork() @@ -187,7 +197,13 @@ void SatelliteTrackerWorker::applySettings(const SatelliteTrackerSettings& setti { itr.next(); if (settings.m_satellites.indexOf(itr.key()) == -1) + { + if (m_settings.m_drawOnMap) { + removeFromMap(itr.key()); + } + delete itr.value(); itr.remove(); + } } // Add new satellites From 10ae237b73fd64e7cf936bbcf1a1516b3bf288e4 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:42:29 +0000 Subject: [PATCH 16/20] Add image zoom level for 2D image, although it isn't quite correct. --- plugins/channelrx/demodapt/aptdemodimageworker.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/channelrx/demodapt/aptdemodimageworker.cpp b/plugins/channelrx/demodapt/aptdemodimageworker.cpp index d33c11127..1b22c662d 100644 --- a/plugins/channelrx/demodapt/aptdemodimageworker.cpp +++ b/plugins/channelrx/demodapt/aptdemodimageworker.cpp @@ -706,6 +706,13 @@ void APTDemodImageWorker::sendImageToMap(QImage image) swgMapItem->setImageTileNorth(m_tileNorth); swgMapItem->setImageTileSouth(m_tileSouth); + // FIXME: This isn't correct. Possibly need to use different projection + double earthCircumference = 40075016.686; + double latitude = m_tileSouth + (m_tileNorth - m_tileSouth) / 2.0; + double scale = std::cos(Units::degreesToRadians(latitude)); + double zoom = std::log2(earthCircumference * scale * selectedChannel.width() / 2926600) - 8; + swgMapItem->setImageZoomLevel(zoom); + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_aptDemod, swgMapItem); messageQueue->push(msg); } From c10d24614e784b421072e035e5ad5908c434977d Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:46:14 +0000 Subject: [PATCH 17/20] Display transmitter info (TII) and add button to find transmitter on Map in DAB Demod GUI. Fix display of ensemble and add to table. --- plugins/channelrx/demoddab/dabdemod.cpp | 12 ++ plugins/channelrx/demoddab/dabdemod.h | 20 ++++ .../channelrx/demoddab/dabdemodbaseband.cpp | 6 + plugins/channelrx/demoddab/dabdemodgui.cpp | 94 +++++++++++++-- plugins/channelrx/demoddab/dabdemodgui.h | 3 + plugins/channelrx/demoddab/dabdemodgui.ui | 107 +++++++++++++++++- plugins/channelrx/demoddab/dabdemodsink.cpp | 76 ++++++++++--- plugins/channelrx/demoddab/dabdemodsink.h | 4 + 8 files changed, 294 insertions(+), 28 deletions(-) diff --git a/plugins/channelrx/demoddab/dabdemod.cpp b/plugins/channelrx/demoddab/dabdemod.cpp index 035eb3f35..ad0d16900 100644 --- a/plugins/channelrx/demoddab/dabdemod.cpp +++ b/plugins/channelrx/demoddab/dabdemod.cpp @@ -51,6 +51,7 @@ MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABFIBQuality, Message) MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABSampleRate, Message) MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABData, Message) MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABMOTData, Message) +MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABTII, Message) MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABReset, Message) MESSAGE_CLASS_DEFINITION(DABDemod::MsgDABResetService, Message) @@ -238,6 +239,7 @@ bool DABDemod::handleMessage(const Message& cmd) { getMessageQueueToGUI()->push(new MsgDABProgramName(report)); } + m_basebandSink->getInputMessageQueue()->push(new MsgDABProgramName(report)); return true; } @@ -271,6 +273,16 @@ bool DABDemod::handleMessage(const Message& cmd) return true; } + else if (MsgDABTII::match(cmd)) + { + MsgDABTII& report = (MsgDABTII&)cmd; + if (getMessageQueueToGUI()) + { + getMessageQueueToGUI()->push(new MsgDABTII(report)); + } + + return true; + } else if (MsgDABReset::match(cmd)) { MsgDABReset& report = (MsgDABReset&)cmd; diff --git a/plugins/channelrx/demoddab/dabdemod.h b/plugins/channelrx/demoddab/dabdemod.h index bae6c38ee..a3c28180d 100644 --- a/plugins/channelrx/demoddab/dabdemod.h +++ b/plugins/channelrx/demoddab/dabdemod.h @@ -275,6 +275,26 @@ public: { } }; + class MsgDABTII : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getTII() const { return m_tii; } + + static MsgDABTII* create(int tii) + { + return new MsgDABTII(tii); + } + + private: + int m_tii; + + MsgDABTII(int tii) : + Message(), + m_tii(tii) + { } + }; + class MsgDABReset : public Message { MESSAGE_CLASS_DECLARATION diff --git a/plugins/channelrx/demoddab/dabdemodbaseband.cpp b/plugins/channelrx/demoddab/dabdemodbaseband.cpp index 7d408f476..4bcde8fbd 100644 --- a/plugins/channelrx/demoddab/dabdemodbaseband.cpp +++ b/plugins/channelrx/demoddab/dabdemodbaseband.cpp @@ -162,6 +162,12 @@ bool DABDemodBaseband::handleMessage(const Message& cmd) m_sink.resetService(); return true; } + else if (DABDemod::MsgDABProgramName::match(cmd)) + { + DABDemod::MsgDABProgramName& report = (DABDemod::MsgDABProgramName&) cmd; + m_sink.programAvailable(report.getName()); + return true; + } else { return false; diff --git a/plugins/channelrx/demoddab/dabdemodgui.cpp b/plugins/channelrx/demoddab/dabdemodgui.cpp index f7e9bbbc4..efdc47ea4 100644 --- a/plugins/channelrx/demoddab/dabdemodgui.cpp +++ b/plugins/channelrx/demoddab/dabdemodgui.cpp @@ -38,6 +38,7 @@ #include "gui/crightclickenabler.h" #include "gui/dialogpositioner.h" #include "channel/channelwebapiutils.h" +#include "feature/featurewebapiutils.h" #include "maincore.h" #include "dabdemod.h" @@ -47,6 +48,7 @@ #define PROGRAMS_COL_NAME 0 #define PROGRAMS_COL_ID 1 #define PROGRAMS_COL_FREQUENCY 2 +#define PROGRAMS_COL_ENSEMBLE 3 void DABDemodGUI::resizeTable() { @@ -57,6 +59,7 @@ void DABDemodGUI::resizeTable() ui->programs->setItem(row, PROGRAMS_COL_NAME, new QTableWidgetItem("Some Random Radio Station")); ui->programs->setItem(row, PROGRAMS_COL_ID, new QTableWidgetItem("123456")); ui->programs->setItem(row, PROGRAMS_COL_FREQUENCY, new QTableWidgetItem("200.000")); + ui->programs->setItem(row, PROGRAMS_COL_ENSEMBLE, new QTableWidgetItem("Some random ensemble")); ui->programs->resizeColumnsToContents(); ui->programs->removeRow(row); } @@ -142,9 +145,26 @@ bool DABDemodGUI::deserialize(const QByteArray& data) } } +int DABDemodGUI::findProgramRowById(int id) +{ + QString idText = QString::number(id); + for (int i = 0; i < ui->programs->rowCount(); i++) + { + if (ui->programs->item(i, PROGRAMS_COL_ID)->text() == idText) { + return i; + } + } + return -1; +} + // Add row to table void DABDemodGUI::addProgramName(const DABDemod::MsgDABProgramName& program) { + // Don't add duplicate + if (findProgramRowById(program.getId()) != -1) { + return; + } + ui->programs->setSortingEnabled(false); int row = ui->programs->rowCount(); ui->programs->setRowCount(row + 1); @@ -152,9 +172,11 @@ void DABDemodGUI::addProgramName(const DABDemod::MsgDABProgramName& program) QTableWidgetItem *nameItem = new QTableWidgetItem(); QTableWidgetItem *idItem = new QTableWidgetItem(); QTableWidgetItem *frequencyItem = new QTableWidgetItem(); + QTableWidgetItem *ensembleItem = new QTableWidgetItem(); ui->programs->setItem(row, PROGRAMS_COL_NAME, nameItem); ui->programs->setItem(row, PROGRAMS_COL_ID, idItem); ui->programs->setItem(row, PROGRAMS_COL_FREQUENCY, frequencyItem); + ui->programs->setItem(row, PROGRAMS_COL_ENSEMBLE, ensembleItem); nameItem->setText(program.getName()); idItem->setText(QString::number(program.getId())); double frequencyInHz; @@ -165,7 +187,10 @@ void DABDemodGUI::addProgramName(const DABDemod::MsgDABProgramName& program) frequencyItem->setData(Qt::UserRole, frequencyInHz+m_settings.m_inputFrequencyOffset); } else + { frequencyItem->setData(Qt::UserRole, 0.0); + } + ensembleItem->setText(ui->ensemble->text()); ui->programs->setSortingEnabled(true); filterRow(row); } @@ -178,13 +203,29 @@ void DABDemodGUI::on_programs_cellDoubleClicked(int row, int column) m_settings.m_program = ui->programs->item(row, PROGRAMS_COL_NAME)->text(); double frequencyInHz = ui->programs->item(row, PROGRAMS_COL_FREQUENCY)->data(Qt::UserRole).toDouble(); - ChannelWebAPIUtils::setCenterFrequency(m_dabDemod->getDeviceSetIndex(), frequencyInHz-m_settings.m_inputFrequencyOffset); - + double centreFreq = frequencyInHz-m_settings.m_inputFrequencyOffset; + ChannelWebAPIUtils::setCenterFrequency(m_dabDemod->getDeviceSetIndex(), centreFreq); clearProgram(); - applySettings(); } +// Ensemble name can sometimes be decoded after program name, so we +// need to update entries in the table where ensemble name is "-" +void DABDemodGUI::updateEnsembleName(const QString& ensemble) +{ + double frequencyInHz = m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset; + for (int i = 0; i < ui->programs->rowCount(); i++) + { + if (ui->programs->item(i, PROGRAMS_COL_ENSEMBLE)->text() == "-") + { + if (ui->programs->item(i, PROGRAMS_COL_FREQUENCY)->data(Qt::UserRole).toDouble() == frequencyInHz) + { + ui->programs->item(i, PROGRAMS_COL_ENSEMBLE)->setText(ensemble); + } + } + } +} + bool DABDemodGUI::handleMessage(const Message& message) { if (DABDemod::MsgConfigureDABDemod::match(message)) @@ -201,6 +242,11 @@ bool DABDemodGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + if (m_deviceCenterFrequency != notif.getCenterFrequency()) + { + // Reset on frequency change, to get new ensemble name + resetService(); + } m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); @@ -223,6 +269,7 @@ bool DABDemodGUI::handleMessage(const Message& message) { DABDemod::MsgDABEnsembleName& report = (DABDemod::MsgDABEnsembleName&) message; ui->ensemble->setText(report.getName()); + updateEnsembleName(report.getName()); return true; } else if (DABDemod::MsgDABProgramName::match(message)) @@ -293,7 +340,14 @@ bool DABDemodGUI::handleMessage(const Message& message) } return true; } - + else if (DABDemod::MsgDABTII::match(message)) + { + DABDemod::MsgDABTII& report = (DABDemod::MsgDABTII&) message; + int tii = report.getTII(); + ui->tiiMainId->setText(QStringLiteral("%1").arg((tii >> 8) & 0xff, 2, 16, QLatin1Char('0')).toUpper()); + ui->tiiSubId->setText(QStringLiteral("%1").arg(tii & 0xff, 2, 16, QLatin1Char('0')).toUpper()); + return true; + } return false; } @@ -607,7 +661,6 @@ void DABDemodGUI::clearProgram() { // Clear current program ui->program->setText("-"); - ui->ensemble->setText("-"); ui->programType->setText("-"); ui->language->setText("-"); ui->audio->setText("-"); @@ -621,10 +674,13 @@ void DABDemodGUI::clearProgram() void DABDemodGUI::resetService() { - // Reset DAB audio service, to avoid unpleasent noise when changing frequency - DABDemod::MsgDABResetService* message = DABDemod::MsgDABResetService::create(); - m_dabDemod->getInputMessageQueue()->push(message); + ui->ensemble->setText("-"); + ui->tiiMainId->setText("-"); + ui->tiiSubId->setText("-"); clearProgram(); + // Reset DAB audio service, so we get new ensemble name + DABDemod::MsgDABReset* message = DABDemod::MsgDABReset::create(); + m_dabDemod->getInputMessageQueue()->push(message); } void DABDemodGUI::on_channel_currentIndexChanged(int index) @@ -634,7 +690,6 @@ void DABDemodGUI::on_channel_currentIndexChanged(int index) QString text = ui->channel->currentText(); if (!text.isEmpty()) { - resetService(); // Tune to requested channel QString freq = text.split(" ")[2]; m_channelFreq = freq.toDouble() * 1e6; @@ -715,9 +770,30 @@ void DABDemodGUI::makeUIConnections() QObject::connect(ui->clearTable, &QPushButton::clicked, this, &DABDemodGUI::on_clearTable_clicked); QObject::connect(ui->programs, &QTableWidget::cellDoubleClicked, this, &DABDemodGUI::on_programs_cellDoubleClicked); QObject::connect(ui->channel, QOverload::of(&QComboBox::currentIndexChanged), this, &DABDemodGUI::on_channel_currentIndexChanged); + QObject::connect(ui->findOnMap, &QToolButton::clicked, this, &DABDemodGUI::on_findOnMap_clicked); } void DABDemodGUI::updateAbsoluteCenterFrequency() { setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); } + +void DABDemodGUI::on_findOnMap_clicked() +{ + QString mainID = ui->tiiMainId->text(); + if (mainID.isEmpty() || (mainID == "-")) { + return; + } + QString subID = ui->tiiSubId->text(); + if (subID.isEmpty() || (subID == "-")) { + return; + } + QString ensemble = ui->ensemble->text().trimmed(); + if (ensemble.isEmpty() || (ensemble == "-")) { + return; + } + QString id = ensemble + " " + mainID + subID; + qDebug() << "Finding " << id; + FeatureWebAPIUtils::mapFind(id); +} + diff --git a/plugins/channelrx/demoddab/dabdemodgui.h b/plugins/channelrx/demoddab/dabdemodgui.h index cad4f4be3..1c63f6885 100644 --- a/plugins/channelrx/demoddab/dabdemodgui.h +++ b/plugins/channelrx/demoddab/dabdemodgui.h @@ -93,6 +93,8 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); + void updateEnsembleName(const QString& ensemble); + int findProgramRowById(int id); void addProgramName(const DABDemod::MsgDABProgramName& program); bool handleMessage(const Message& message); void makeUIConnections(); @@ -115,6 +117,7 @@ private slots: void on_clearTable_clicked(); void on_programs_cellDoubleClicked(int row, int column); void on_channel_currentIndexChanged(int index); + void on_findOnMap_clicked(); void filterRow(int row); void filter(); void programs_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex); diff --git a/plugins/channelrx/demoddab/dabdemodgui.ui b/plugins/channelrx/demoddab/dabdemodgui.ui index 5367f6909..90d5ae781 100644 --- a/plugins/channelrx/demoddab/dabdemodgui.ui +++ b/plugins/channelrx/demoddab/dabdemodgui.ui @@ -7,7 +7,7 @@ 0 0 398 - 612 + 657 @@ -673,6 +673,11 @@ Frequency
+ + + Ensemble + + @@ -1006,6 +1011,106 @@ + + + + 10 + 610 + 361 + 40 + + + + Transmitter + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + + TII Sub ID: + + + + + + + Transmitter Identifier Information + + + - + + + + + + + TII Main ID: + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Transmitter Identification Information + + + - + + + + + + + Find transmitter on map + + + + + + + :/gridpolar.png:/gridpolar.png + + + + + + + + + + diff --git a/plugins/channelrx/demoddab/dabdemodsink.cpp b/plugins/channelrx/demoddab/dabdemodsink.cpp index 5709ed5e4..c5cb95e0c 100644 --- a/plugins/channelrx/demoddab/dabdemodsink.cpp +++ b/plugins/channelrx/demoddab/dabdemodsink.cpp @@ -279,6 +279,14 @@ void motDataHandler(uint8_t *data, int len, const char *filename, int contentsub sink->motData(data, len, QString::fromUtf8(filename), contentsubType); } +// Missing ctx for tiiDataHandler - https://github.com/JvanKatwijk/dab-cmdline/issues/89 +DABDemodSink *tiiSink; + +void tiiDataHandler(int tii) +{ + tiiSink->tii(tii); +} + void DABDemodSink::systemData(bool sync, int16_t snr, int32_t freqOffset) { if (getMessageQueueToChannel()) @@ -287,6 +295,7 @@ void DABDemodSink::systemData(bool sync, int16_t snr, int32_t freqOffset) getMessageQueueToChannel()->push(msg); } } + void DABDemodSink::ensembleName(const QString& name, int id) { if (getMessageQueueToChannel()) @@ -351,6 +360,15 @@ void DABDemodSink::motData(const uint8_t *data, int len, const QString& filename } } +void DABDemodSink::tii(int tii) +{ + if (getMessageQueueToChannel()) + { + DABDemod::MsgDABTII *msg = DABDemod::MsgDABTII::create(tii); + getMessageQueueToChannel()->push(msg); + } +} + static int16_t scale(int16_t sample, float factor) { int32_t prod = (int32_t)(((int32_t)sample) * factor); @@ -473,6 +491,7 @@ DABDemodSink::DABDemodSink(DABDemod *packetDemod) : m_dabAudioSampleRate(10000), // Unused value to begin with m_channelSampleRate(DABDEMOD_CHANNEL_SAMPLE_RATE), m_channelFrequencyOffset(0), + m_programSet(false), m_magsqSum(0.0f), m_magsqPeak(0.0f), m_magsqCount(0), @@ -502,8 +521,9 @@ DABDemodSink::DABDemodSink(DABDemod *packetDemod) : m_api.programdata_Handler = programDataHandler; m_api.program_quality_Handler = programQualityHandler; m_api.motdata_Handler = motDataHandler; - m_api.tii_data_Handler = nullptr; + m_api.tii_data_Handler = tiiDataHandler; m_api.timeHandler = nullptr; + tiiSink = this; m_dab = dabInit(&m_device, &m_api, nullptr, @@ -607,29 +627,49 @@ void DABDemodSink::applySettings(const DABDemodSettings& settings, bool force) if ((settings.m_program != m_settings.m_program) || force) { - if (!settings.m_program.isEmpty()) - { - QByteArray ba = settings.m_program.toUtf8(); - const char *program = ba.data(); - if (!is_audioService (m_dab, program)) - qWarning() << settings.m_program << " is not an audio service"; - else - { - dataforAudioService(m_dab, program, &m_ad, 0); - if (!m_ad.defined) - qWarning() << settings.m_program << " audio data is not defined"; - else - { - dabReset_msc(m_dab); - set_audioChannel(m_dab, &m_ad); - } - } + if (!settings.m_program.isEmpty()) { + setProgram(settings.m_program); + } else { + m_programSet = true; } } m_settings = settings; } +// Can't call setProgram directly from callback, so we get here via a message +void DABDemodSink::programAvailable(const QString& programName) +{ + if (!m_programSet && (programName == m_settings.m_program)) { + setProgram(m_settings.m_program); + } +} + +void DABDemodSink::setProgram(const QString& name) +{ + m_programSet = false; + QByteArray ba = name.toUtf8(); + const char *program = ba.data(); + if (!is_audioService (m_dab, program)) + { + qWarning() << name << " is not an audio service"; + } + else + { + dataforAudioService(m_dab, program, &m_ad, 0); + if (!m_ad.defined) + { + qWarning() << name << " audio data is not defined"; + } + else + { + dabReset_msc(m_dab); + set_audioChannel(m_dab, &m_ad); + m_programSet = true; + } + } +} + // Called when audio device sample rate changes void DABDemodSink::applyAudioSampleRate(int sampleRate) { diff --git a/plugins/channelrx/demoddab/dabdemodsink.h b/plugins/channelrx/demoddab/dabdemodsink.h index 3021875c9..153f96969 100644 --- a/plugins/channelrx/demoddab/dabdemodsink.h +++ b/plugins/channelrx/demoddab/dabdemodsink.h @@ -80,6 +80,7 @@ public: void reset(); void resetService(); + void programAvailable(const QString& programName); // Callbacks void systemData(bool sync, int16_t snr, int32_t freqOffset); @@ -91,6 +92,7 @@ public: void fibQuality(int16_t percent); void data(const QString& data); void motData(const uint8_t *data, int len, const QString& filename, int contentSubType); + void tii(int tii); private: struct MagSqLevelsStore @@ -116,6 +118,7 @@ private: DABDemodDevice m_device; audiodata m_ad; API_struct m_api; + bool m_programSet; NCO m_nco; Interpolator m_interpolator; @@ -145,6 +148,7 @@ private: void processOneSample(Complex &ci); void processOneAudioSample(Complex &ci); MessageQueue *getMessageQueueToChannel() { return m_messageQueueToChannel; } + void setProgram(const QString& name); }; #endif // INCLUDE_DABDEMODSINK_H From 6b2547cac4d2e8f2a1294fcf243be9da0613ff22 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 14:47:40 +0000 Subject: [PATCH 18/20] Don't set altitude to NaN, if position provider doesn't supply it. --- sdrbase/maincore.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdrbase/maincore.cpp b/sdrbase/maincore.cpp index a5247e298..bbe70eb9c 100644 --- a/sdrbase/maincore.cpp +++ b/sdrbase/maincore.cpp @@ -378,7 +378,9 @@ void MainCore::positionUpdated(const QGeoPositionInfo &info) { m_settings.setLatitude(m_position.coordinate().latitude()); m_settings.setLongitude(m_position.coordinate().longitude()); - m_settings.setAltitude(m_position.coordinate().altitude()); + if (!std::isnan(m_position.coordinate().altitude())) { + m_settings.setAltitude(m_position.coordinate().altitude()); + } } } } From 1732d07cab3ee6ae1c4e5fe1c16b15d84ff3d1f8 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 16 Feb 2023 15:53:54 +0000 Subject: [PATCH 19/20] Add Heap Map plugin --- doc/img/HeatMap_plugin_map.png | Bin 0 -> 518079 bytes doc/img/HeatMap_plugin_power.png | Bin 0 -> 10240 bytes doc/img/HeatMap_plugin_settings.png | Bin 0 -> 47095 bytes plugins/channelrx/CMakeLists.txt | 2 + plugins/channelrx/heatmap/CMakeLists.txt | 68 + plugins/channelrx/heatmap/heatmap.cpp | 578 ++++++ plugins/channelrx/heatmap/heatmap.h | 178 ++ plugins/channelrx/heatmap/heatmapbaseband.cpp | 178 ++ plugins/channelrx/heatmap/heatmapbaseband.h | 108 ++ plugins/channelrx/heatmap/heatmapgui.cpp | 1469 +++++++++++++++ plugins/channelrx/heatmap/heatmapgui.h | 222 +++ plugins/channelrx/heatmap/heatmapgui.ui | 1620 +++++++++++++++++ plugins/channelrx/heatmap/heatmapplugin.cpp | 92 + plugins/channelrx/heatmap/heatmapplugin.h | 49 + plugins/channelrx/heatmap/heatmapsettings.cpp | 197 ++ plugins/channelrx/heatmap/heatmapsettings.h | 84 + plugins/channelrx/heatmap/heatmapsink.cpp | 229 +++ plugins/channelrx/heatmap/heatmapsink.h | 159 ++ .../heatmap/heatmapwebapiadapter.cpp | 53 + .../channelrx/heatmap/heatmapwebapiadapter.h | 51 + plugins/channelrx/heatmap/readme.md | 159 ++ plugins/feature/map/mapsettings.cpp | 2 +- sdrbase/webapi/webapirequestmapper.cpp | 7 + sdrbase/webapi/webapiutils.cpp | 2 + .../api/swagger/include/ChannelReport.yaml | 2 + .../api/swagger/include/ChannelSettings.yaml | 2 + .../sdrangel/api/swagger/include/HeatMap.yaml | 63 + .../code/qt5/client/SWGChannelReport.cpp | 25 + .../code/qt5/client/SWGChannelReport.h | 7 + .../code/qt5/client/SWGChannelSettings.cpp | 25 + .../code/qt5/client/SWGChannelSettings.h | 7 + .../code/qt5/client/SWGHeatMapReport.cpp | 131 ++ .../code/qt5/client/SWGHeatMapReport.h | 64 + .../code/qt5/client/SWGHeatMapSettings.cpp | 557 ++++++ .../code/qt5/client/SWGHeatMapSettings.h | 176 ++ .../code/qt5/client/SWGModelFactory.h | 12 + 36 files changed, 6577 insertions(+), 1 deletion(-) create mode 100644 doc/img/HeatMap_plugin_map.png create mode 100644 doc/img/HeatMap_plugin_power.png create mode 100644 doc/img/HeatMap_plugin_settings.png create mode 100644 plugins/channelrx/heatmap/CMakeLists.txt create mode 100644 plugins/channelrx/heatmap/heatmap.cpp create mode 100644 plugins/channelrx/heatmap/heatmap.h create mode 100644 plugins/channelrx/heatmap/heatmapbaseband.cpp create mode 100644 plugins/channelrx/heatmap/heatmapbaseband.h create mode 100644 plugins/channelrx/heatmap/heatmapgui.cpp create mode 100644 plugins/channelrx/heatmap/heatmapgui.h create mode 100644 plugins/channelrx/heatmap/heatmapgui.ui create mode 100644 plugins/channelrx/heatmap/heatmapplugin.cpp create mode 100644 plugins/channelrx/heatmap/heatmapplugin.h create mode 100644 plugins/channelrx/heatmap/heatmapsettings.cpp create mode 100644 plugins/channelrx/heatmap/heatmapsettings.h create mode 100644 plugins/channelrx/heatmap/heatmapsink.cpp create mode 100644 plugins/channelrx/heatmap/heatmapsink.h create mode 100644 plugins/channelrx/heatmap/heatmapwebapiadapter.cpp create mode 100644 plugins/channelrx/heatmap/heatmapwebapiadapter.h create mode 100644 plugins/channelrx/heatmap/readme.md create mode 100644 swagger/sdrangel/api/swagger/include/HeatMap.yaml create mode 100644 swagger/sdrangel/code/qt5/client/SWGHeatMapReport.cpp create mode 100644 swagger/sdrangel/code/qt5/client/SWGHeatMapReport.h create mode 100644 swagger/sdrangel/code/qt5/client/SWGHeatMapSettings.cpp create mode 100644 swagger/sdrangel/code/qt5/client/SWGHeatMapSettings.h diff --git a/doc/img/HeatMap_plugin_map.png b/doc/img/HeatMap_plugin_map.png new file mode 100644 index 0000000000000000000000000000000000000000..42b1f348857627a68ad995ca9cfea7839e8a330d GIT binary patch literal 518079 zcmZ6y1y~$Q6E=!vad&rjcPA_k0RkH!ut6>h!P}r9zj!N&G;oz{k|Ng=EJCs?#!MzkKE6D1) z86UPHdy+4t=Xv_}W_w#6Ik~b&iU!a?Mn!kCoJZl{<7iNKXx=a+JL^@<3>C11>tbb7 z^dsw-AbyLS&Q2w{AQm2Fm_zcc0hU#nmHw69z55lFI;?gsp5(e@#6O z)k~*y|Mb2)-!^&dHR-6Zt}`g=I+zP+QUX|FVq!jBnY;+<`qbKS5Rp?;13kV3&8gGW zzWdoZKTiVdK6+X93>mqib`S*{uJL~5<`osa+XuugaCjhE2UwG#{cS^4*e1sU`Keyl zhYPtcceyV|fH;3;$Ka6#a+>U&)ZfnnEeqFG&wr}&OrD=_+D*!J!Fu^xBEHWO+L(O3 zX1IKTfq~Muo!EJczAq;)Pb2kfTrZDfFD(-_!nd#sh&&8MoEG476Y0&|=l$G2SNEBA z@ix+uN-)v9yyE~i`S)+$9lN%p`|^OD`EC7@IylPwroCDb{u88B%fiQBM&FZ@lYJli zeIIv(+nan}e8$n?_;^r*dC=Kt1miU>KL2Ld|89%cn=0b6hXX>GL|Y%JmzS6Ky)X4e zdpehX?3T_Fbp}Z6oNe|i2@X8QzMM&q=18K~<{_BLIn;aCTD`QcKD2^)!UPojlv$Rt zS|?807rxXcXs1KB!Ly%8W&Y`%hx>@0d0_P;>tc1q>q_0n&DYdfg~odd0u$}?wh7Iv3HV?^b6ynE{&nV|6KI<`E#yfrmnFxMPTGe!zDrGwFw)U78$ z@NpS{TtjuUZD8pet-sAD*lqb^0J5K*--wJ91y&&4EIJv;oB@Pl_= z+DJM|wVE$r#v0!CH@>VjK}j#2Xg2cys9n1*O?F8q*zNvupE=jdtaf4A=4xnY=%)R} zduwu;`f&~UU*(e#EQ@l@b{1p!_wS_IYzr@)&-e(^>R?;X z!3gq99-qL+ZyhCdUQE1sg3+u!5IpwW>|Y4Wcb8MqY+5f@sFjM(byWFzf7>ITpGyW9 z;CpT5TmSPX(o>;vm5GrN1u3b&gv+V0!^-2RYnyq)Z&SR#Bl%~xEI^Ka3qDyY_#gns z-w(H@to2;=a$n_p8|sVF%E%0MSWYn2oghCy{{Wt)m6dR$(BDrE^GTIXh((Yl zBS7yRwEYpf0f@Uxl)l5SrncZ}fnOV`R}$^YvWNsyY5P5Q2I3RM%`#T9 z`FNOu_}j_W*48;c*9Xne}BhNC68 z@VUta|IQNvn`g21zQfD4Lnooo!@yWr|EBLH(AQT=4ydFp%-{eO+yL^g2enTYD zibZ5Nk-a$WvN9aVY6II4@BE{&p4d<5UtU$EjqSo51_*0ULx3!}3+Blm8|%L`KcS}} zCjK4pKVmgW+x9vW!9LxL-cyewtX{CKdW{^U_{eB%h@~4il*xXYJ}H1?g(_Nb@or+5 z`5W9N2x-cHfUtlcMdV*>Z_Z4ocbXvYcCrh ztn+%~$kA%g7%Llgj`lk6e#s$=fRX-bOC0rEJvvm;d#lDfXc)HFn575<5R z-iwtf+Bg#-!B%^IT78iW!vZayygZ-CZ*#YBfom6x*|C&BeCb|OZZz0`aRFxS((T(` zuh++HM87n@|Jk{>x3`n|bg83&hYKSTPXsU&%vUyl1ylIlP`YI2E27UAe|e@_IzBc^P5{ito6BZ^}R89 zxiZOzxohHg2nZ}#NubJE;n&FT-u(|heeu`4{k%|xZ(**b_DjZtH{KnkAU5=+?UAq zTl8v*Q}QChu1q^qJ*iyaF(Oa_c?(b;0vbIiMW8FqU9lDC<3p&$>97QgD#-_#)r3g^ zk>Q~JLk{)J-xvsvSKD9yY9?L$eAWtFJaSr{=u-#-j2BWk@^%7US&p#9_d@*eL` zw>9uR2K!^FU-n@vY}Fn%ut&K$m>f;)AEr(%4Y!bq+FqVch|yl9C68EkevY$Q6Xrop zpJPIrys-S;+1V-VTZyj#EY_yA6C@k?tE x0h3Y3D#F#Hi!DxU!N{%{z7rTp#~5b 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 z z(3~)XyYMx~GNru>&)dgYUDn#&BtO>^vV!)QF#JE!LZ9j!4srL+|q075+_&+b6O$EH31^guR5s5o7SJ!U+WIOce0?t7@OASLgi(?A-b)$17 zH{gN=n1Qa=6?zrVq{Q|Du?7fZDID&+Y*7=8?kop<7uN~$#g0`TDX1nJ1V!v7CWQ(Q zzgxMk9dQr@FuVunz>b{*5nfQ3w)m*wxFdDE$Pyr6fJFQ zZlPo`SGnsVh|5sAA$6iIdkf)u7tu-q#(t&H-0>>pke_G)|2%a3az^ z$x2GtM6^KCmzG|GW^RSbO6r_YDv*97KOl=o0Br(A13AP6`nltm&M+qi{<`~+1gZ$> z!WP_LxTU-w3M#RN8)GD(-xe2uHLT^hELctKQkkXU#8HaI5KZ>8396G*Bhl?TPk%R# zz;7q|VwNa=&;sBp;TnIU*R(GB6-|iTE+we&)=ppEDttaU{4YytC32&%}svW?Y%`E*m_5oGCq0dWZKy+2ijvwvGLdAx;Xm0!~O9t{F+#hzRO z_A=gX?gOA=Z%qM*OaER9o);+pUHEJS|HiJL+PoMBc{b-78s>_6I=*hsyjCB_4E#1> zWu)|dm<&N78q9|ZbXHc*1^M`M!%Y+4gR*RKrYLoKliCc7 zG~Who8UY2Hk5zSWyK8?}eEnQpK9dFEO?+b@8YhB=nepc>$HB%9JD46K7%NviP&^Tl z1uE7bH`k4#V~LYZDvk*@v^%QUoqLVqH)<^#-vbuCD>n-m!XA0?WS-m~AZTM`tc61N zX4D15mMDZBDMU}!`_BJlC~;5t zDhW0|n$y<1GmC*u5%B$(KVfMteZO8lTdcj>%i_;syzd$JT#Fw4DwidQc_XN{B>jbO z`_jhk7j3A&vSwQjy2DSytvQL{%CM$tnaep`4*I$vL9@axA+mj}|d?D*$=G zo{5jv={f3P?T0sigsV)6(()WC3cGWgPw<=nat#M|VQ*C&EreLs*lW2nCmW?tG=frt zsqbYwEEWXad+Zk6A`b5O1DFQ9UV}~^XRT-TC_JXvk%@>(N-R7Cnus)xZ+?gUx&Sw> z-V+*?0FmtKM`S;#w}g&JfxB|Hmd+@8oin?1sAxiSGgt}oNdd(?X0>n@$hSbChx{{b ztJq#}SSj+rl`*+$;ye9mlH$cgwyIqxwhX&2r6$EH6}2!+OaVUKE~zuNoq;4lK|7U6 z{kbMyYv)CZf@WmJg}lfCJR`pm3df#?dD3YAf@?oyZVCiG(ox1qDC70H?|I(6Xgh_9 z(k39d>MQFAI#5G{yQ{=iQ{QyVnkPy1bQs&C1m!tu@Rg3KIfMUi%z4CY#1@DCYRN5+r*6ZsCFFbI&q zt)cI+3^$eS2}lT*(oP*5qx-nYgjE00WB`MwxEbd4+`!-@2vI17bAV6i5{@nUC2BS0 zjSISUBpeGVZdKE|T5>^wZX}W|)QbQooYwFQw@@jJIA<)5_oTb(CF-F=S>94K5~)fJ z=(Me&twlDLDfk}=s#6t~T?OCAo$PZtHESCxp-}eR@A}iM?PsPQj`%ubW2% zj)>dh5A`pz32)mb4-0*7Iss6Qmt~W;6X<=uXfLvON2hRCJAck3L-vfsG`f1kukhB) zgnZ%7PC>C?e75qC=Y6@+rXbr^l3P4|Fpo^<(gM-k+cNm&?RNQbdFBvoCVX~_a^}jL z&tc^lRkxv~)d8{BOaF*!SgJ0{|F_TUdPH%|3pR^b+5azq>h*FHbi6w3%$^q~w>{u3 z(%{-1n))f4s_3VBH3UY}Arh2F=quEP8~n^e_mx@3r9+LYfpBG2U`-W>cW5|0WLyUf zbfAmkW=8Bf2H2*YPSDJ0#Su zcJx+0#S;XUnp0;Ydi4`aP?8Jkq83ke!6*Xh5lwrZ6q~r|@G`_ncU|o!xNf3**@`;>@xrDn zbT4I~SQA0^T*I!wy7NQD?$##CbVGUWr?MbteGx;qkkWaXE>>Oo0oG{Quk$g*+Bkwp z4H}wpHsjKoJ&W^6@nOf>Qf8*4u65pUNIptQozBVktb(MqrCfsy|N`j zrIZ=Wv0ID!`e@}Eg&*6Gr-Ofb9PMch#D+r2R_n&zV;NT5f1pakGVBgHHu`l{S=jfL z(*w)4-F3X|5i7{Klq-uZg*cU?kz9!r6>M`MIQBgf^o_0U8&=1e(#`wEzQmreoynoI zP!GmnAwr!w#w$lw%f~C4>K?4zECj12A6_+E z@pG|k)=c9Ns4S2 zH(6DYS}?JI{K;a|L9mW44A|EGIomzRXR)Tl;HpysUCk15jr& zi5v-@S~T>+SxW7@aj8HS$kCdRL;I&Bp?LY%syT51!r0mwXWC5Zc9}UYZQ2-mRs-p| zFmJq2z(yo0eTfo25qI+UZ*Fy=KZgZ%>KY_MG~=pumc1!pDl_1$5Z<_`iic!Cfb2n* zhoGn0Yw+xH`Q^ZsL0+jc6}+Dk=38Yrrd@=iHRfJBIVYzxmxP^v4Smc}Jrnct^z!GT zyzTN|0_4@{m;HB10a*JVss>P^BIE26`Cr&YqRjvTk$df231ont;f{ZJ>5zi%IaD{9 z#B&||o(9@rxVHP==ZX7`fajYV-LIw6T<)-YV^5sHqh#kY!MRBu{1CTAUF}8wLVAa6 zPp$=N{lj-g{^^4J42LltU^&9K$Ee&17Uu2s~eR1EyuR9D@4GfYT zaT&)j8w0=TA%4-RUe>2KU>kL*l;+i|*&AOlti!3NCXTQDPTqN59g@#=plFofolvE$!A1}HQA+>KU2oINsTH-o; z)UHk&svjqFq}PE2e%SBWq0Pc`*uajdkxFmO*gx3_C4Dlx6if9uoQ_l(`6OE8UF zt-+lm9LEm9ZBFW*)!Pts8jZE0jsFr!puh@y>~`}7#)d~9JEwm^IM97>xBTw+p>y4o zkI2k%OqrssJA(KqIVz;c8r!o;?pPG5rsOdYivV~u(3#^Xax6%JqSblpp1?U;BU-%j zDmynyCGBpLY?M}mE|2W@iI01O{kJ|6j@+TkTsU?C^)FO zJN%PbUKVO2L-!}(;&H+XEf&sb!T4k*9}0*wZAPAqeYFYS&#Q_fUZ_dN)~mQ6U#L7| z{k8q^_AI8^^?lj~mMgO7(_i?9cS(^I& zxUAW-V_kaXSFP0HYJ&HZ^lc?YuhMkMag2)J3n|sOi7-p=+J2Gd6bWtJ*w?*h3?rdk z2y&M1Wv*y1H0_S9A{Xq>F5=D1d=oeD+4K(72Ux!ZHP}bMkHMY6cp>g^y?~a$MTkeB z4;A7|O(2i9QQF7%TlDaf^Sl`Lf&A6IV6t}gkQ7onN;MVYiL@C|?bo4967)i;G)FAz z2f?w_aZg^OcuVF6^duzd>Ny$xVZ=O3eMHF6vPy`JSs*_lvq@2m7Q+WIEt>HxZ+5M5 z;EbX4Kwc`*HBhblXRSRAM~oz@I%w{MaI>+_N=^n!bn4B%dv# ziP|*I*7he_CQQp9#Wq9@y6{-{y{Ybd!RULVd?h)UdU=T0cw8K%?7iQES=VYwzmpL4 z(ME!3OZ5eGelyHQU2MH+vv%wJp>Ih?j6nG8_cE~BcTsWv`+< zn}juEUObXtmJimCKwA2s5!4^LU`E3H69E#KLO*>Asy$y_%7AeLOb~Wi-$UzcTU*MQ zFy6^QF>3%~DK=S9-TZw=vhjVFt&6SyZ>-4r6K*sG?2s+W48oRRYNU*(l*LQpBrs07 zgvdXP>>;bEL|JRfb0sV`$+H=;5vl!{6~~bOXfmO7^r%jsHW{k0`$3B67E6Gb*D7Vv zcacOj_z`xo_}-aXhT$X(jlg&3Gz*uq6yCG^d}&>op9k3fphI*QVtf8FpB)SQ!bAsc z+iu8dI8a{he%un5*5;pH;ZKyuqKZ9YZr){CI#GzVxrlZ zJ2JPos#F07u1^FzEeuqXfuFp&`y&oDjvKzl!Z zJ;GdNO)5*fLi$p6#f`y%)x>l#SR<-_JlSR-`zhAYy0nuV+^(+QbTb7^+y{6>DLZCA@fc!^k z5qSxms`_W@96F^4%Gj3WUjl+>s?Usy=O=&rL@9GA+=BG{R1a@+j?;*DcqPyY z)oZvzo%1Gnhn(lW39>K2$2WXjppj5c{L;#*;9@oXe9l&0)>q-<^vQ+ z8Q{21Y*lzAjp8Iubk>yK{dFK?T9*!AoG9=3*G4^JxijBes5Ete8t6JkfN zuP0pUT)~aLY|1tmPyG*p#-jqSk-T&=$|Z>3K!qv}@1yAtc{330*D;Fz0$BHHiXJ~u zdRVhF7pytkp)Z(@aX#vSg|`~@0ymi|fK(zKs-dP;VjzgX)y0)K0h}?)zmteD5AZ*^ zmkYO4IKE?;`wC~fmcK};cYH*K3g`Y!+q|B{mGAlk{1211m9PW-l5n}wXIeGe!@^qg)VOXL!YIE8y#$zA2?KqV1vSc8pqC{ zhySJA28<93Q$V%^I$5XX=?lKdO8Vpo<+RZjk^iN;B$1&4h-_MYtSP-v&I-xgBz~BT zIPbgN9H9TQUFmA(;lTKgKRf>P%G*wCd zuQc-FOT$(+=37iQv3k$3R^4<4T1$N}ySW&doSgdi&?ganb1LneQmmMbMOPHZAPXx= z$TbQ9pI!W&nU$yJ4=ayU^&qtfYdD~8*-%^0AM24zQPP-k`wA$PFZQfGZkc~0e^5)U zbo*S4SnjwtJE~D}g$8p8f>+;_Zb_3C#R{4)Jq9{+E)NDd_hX8WIsgvD-7&msXAmYm zRRoT+UOPph_X35vrt^Or{aoka*fLHRXjb81r>}khlcEA)6LJ73;ZJqtt~8-B%r zo;ui!FgAnC8W_)8xYgj{4P5nEcSdo9P7!)Adoa@c&S5Sww`(oVg<@QvtaSL#2i)xK zJY61aZ(W>Xvx`2RT$Wfd?%(fcV5?H}xc%!%*zmu)GZ)X@0&QYKT4#VVov{S7kJ7~8 zrJw4UET+ILSZNkLR$2`{=#yueI=>PljBUh9$~swK7^G5+lVCYmw6ksu@)7GL2A>pb zezoRV#0YGA*9u#b71LVo{fd=1VG6=xWbo`XRx_A8apd@6&`9+=J(GMXLZ?gesjN8o7^+NORgmQIA*?q7FPeBU0c#@Io^h;J5SJoSaCwE|g( zrR0z~NvguEC8<8iE0DB7iigd3mKc6Byna)XaCZzlDzXx2wIV7-7Mfu|fsz#3Pxn>tA7sdE@(F0bge=fTNPU+#jN0VL2>C$bt=VhXd1V_nl+DJ#t4wRiC`x3!{mZAXF8 zpj5DiceFU- zxxSx>;^aQn7}wLXj-$dye6!}wSzh;FHoN`r-1t8O_A}XiIBfv`-E#=LZ`!*iwvQKK z)uH%FJ@VFkWYIwNWfEU#B-a<mwwPg&^hsU8 z-b|*^m_2ZVw|`Nd(c!p;TO$E7J_*w(CAT+%Ge1z4)?Ro=4uC?jdfo`lclFvfEEv2W zceYEXZqf;;>}`2$iNl;;qMeCTpr4uPn3>O}bQ^V%rG%B80kuIoihS4ue`>jzJ)#9_|jk4Yy;bucTd3wFJpS7R@vE zi6l|H$C3K{~jy? zkR+5ovRXHg#1lY3RJYdr&ev2o-gNF=+6mDL3+@8dE8`tj` zx})arGS2?Sl|{9%nNrOjx~%J7$(prIk=k?46@unv5ODuwTT>^8{dO0z246YWE^(ry z3LvtUaJT!DYE1}UU{+L?h-=Db5G#cYciQR9D`TO`e&&Y|gwsM#%w9I%Uce>LQS6M2 zedy%}XN!fOhTIn&lJMTt&P5TSd2S#N_h%-ufC_YvLMV& zbLx=6b)`=i_=^hhx4S;xXuo$c>3U{_bLA~=bM}PKV9~^QK*nb^WnCIOHaG7?Xpt7W7a{Cv*&)**Z#ekQ|o7(#X%D$#{Z$ba- z*QR?huZN3e@ZqhimuOZ&ycJ`L{nVaxHV`%14u>F`*JfFgD=D5zHwiyPAAjyEK;cha zqdqSj+TxC?3?KHr$FFCU1~u5oj>A|G`2!}Pu6E7TzQT$mzQ>#$S_8Aqft)nIzTCEW zBBg0ceovm@g)HihCmHowbXD1ZsXodwMbCA+eOLHJ5sGO5w+IIac1&eTw>?y+*Q&D| zTL9JOqZCqCk_>)hO>hw&aQ-l8#vKzJLF6Q_Z1-6?&i1&wg7*V1p}~*&G6AIWVN+8g z7&~4UnfiJl(xa~Nj2$zTw)uyMe5yl4t*(^Ls!YW{|JkYttvz4Tp`-(}27E$To z!gA_l;$_B}Unq-R#VUMmOIkr)poOhfu#sxUtvS|=Fq}GDdFJ}h;g10KPR|=y=qm(c z&iWGp!-eKlo7fvu=EnKc(M_!tw%FU|>ACM47`yMj)*;}Uc9Zlk;*g#a3R@UTBe>K& zkpF`^d~n0f9`L}#h)k?Iz~7l0NfMqYa>t;+?_ts)VM;Z_NG?Mfc@{8GftGiSo8ZR1LE6(4)8<7$sxERBu!AFR4BrMV@j`UCug8D z1%&dorSER!xvwPJP=KVjr{y*-r|oUeKbZ!S}ce-C#a_Dn*xsEef6&I-ASn2V) zzp!t2)ct`@U#1I;)@q1t!JQQk?j$2h@ijc<5r;bl9JG4^1dVB}1@(gB7s??LoM7eY zF86+vkgQR>3b9SUf?MI0dtyM|@;mFPT&3*zakDreojVIb2d?6}Ow^CH8dBc56I1@Y zNdk|%U-cui9_R~x#vctRZ0nzBbL=_uOs&HBkI%p%l`EuQ>yki+XQ~wen3hK)ta;c!y*@_mXrir$OZC|X>nF-VXM4^q(pJ7K|EKM z8wW@Ed9UB=gzCoAUE8|f%K@%|?a#r91*clhjTX7-ExhQ!Z&2DYY`<2wA?{2K8zNhu|Rw%-O4A?gAnr>gxJ(CDh zKTB?$OJwz&Pvteup{PV$&lw z^meuXlpS4}Neg%d_VOPOxE&d3*)*k!&;L}QA&jHPN;$Mg9Mlgx?Ks|)b97tie(?48k7Q&vQlxAkDkb)dPqa89rp9bGsqzh#0Cn*J6hwrr8 z&1tV@10K{zqfzw%Ltm`Svp_X!O4PUTGZpHtdEdT90^qS3H;a{+**Z&II@tvLo6OPF zbJV$!4fSjA4O<3uK9y&IL_f_G<5Jh}AVNt8jhWTL5#)AW1Ql*(sktZ%3&Ff2Yh!PhTqTM1t! zB$UDEg%2=SR8C4&%X6a%VBdQS3vOJzPWAokaqv4AD)2j=!xsNb?&pyy_5)|^Pbn8SC4$*c43Nk>TDats5%u2Fe;MMu`M<;DJgWA;06WTC<9M2HNKLi! zH{rv$kzNQ7$vZU_y5v~t&r$IDwX>dZ_4L(YgNDwZI|I!3&$NMz$uZI{5mCMs(dERw zf1*mYyB4prhLx~z_S?OLiAK$le~+9(Rj`lmI4}D5&Wm&5#K`r83f)mhCJ4g>JLGggFLgkgTqXNW+*P|vkhe&`-E1%n3Gsa_2)()U zmzIf<8YdapmfNn`;#;5sK$c}}V1)rKb&k@*H76qnk%fv*5!`Dyf@&c-TGj} zMw7@mR8lzzxwuoYX32^P;l<{)2lc|{IEU`u+p*e^C68p%%Q5O-M0%J+@6?;+XY5fK zM!rXy0@}V66V|k20T}fn3w7GvqwEMDRb+Uzn=}nFNl?#SzYJRC;_j>PdyEO-Pm*xS zQvQv1Vw^bq-p0qH)Q9#!&;4DS;cFvFJS7MgRBm&#HGjUlTkolb2>BFYhL1A1+;2fs z?nONTo!$9vt`r04Nt&L|j`x!=7S?H8T+f7(K+KFTX1%4tVb8^)F_0xGMq2$j=edmr z43Xr)ozKAOFyqN*3%}l#FCt^nP9dbzka8i=$uNkW2M#ez)Ti4fYE>=o33ejdw0bFL z2yu6(}SdmM} z1IuAOW^E-F5=7P}UWya}R8Hls%GDq;fn9hMjegrFx%qvuh1kQIoX{ExtD$?wS?ju3 zt0Q1pyiWDUTFZ(Q%g=724s1ku18R#CFnO7|ORI_^S!vSs@1+vyq+r=N&tJp3?tl+{ zS%2)ck8nG}9zsmxR3S7%$VGZ_byL_QN1#eoq800v;GXz#dsL{#n>;Qm& zH(#VBG>Kg2jc!L;`uj-S?J<{c*TNy6u*KiUE;xg=OeiNW{+@}GDXk7>VWpPnbysZ1 z26AVjFERy@Xtpfzt@}N1alAhG1nhGBdxUYyx+nu)7MC9lKkt}*B#b+i#qX*KR3_?y zUW38Af38-#B_;PJ6r_nKhG!#4yFBdIeV{D{^)N1OLBQ?^3yg*vart|3;0^-ml3>$6 zxYItNxUgt^U+W~(8RsN8K#FL!Sz~OqqE%+}O%UdQUwJEY;>?J*yJu-%|H!2;Wi5H% zVX0@W6XvdbLKPj<0xHJuChDFu0Apvj=|jS2pleR!N7dwV>aJK+N;XZ+;?npcaA5qBangVB*L=ro$D}ZULu6Xq60w*Z70uuxb0LD*Dyl0 zjxTQS){mIuH=KP=>o(wrW`c7p9<@Whax#Co))bL< zK;fEbhWFKnW_7BQB3uScR;2)8}Lp)5e(2rAX8(z303k??wzh!Y_Q~FJW8u*4UJ9#|tX=>HVA&_kJ8~&E@!d=F$=W{Rkk47(|cP zK+3lcfc33m6*zn*K`n``9 zTwBNe^LCGUOcg{9XMZ>RD!Ku8=d)dJhFor(he0uV&DbbxF7*Y;M{-^?+2NXG#0Z5Zkl`Lh?7lmBJBwHH_3>y?@MDu$?&7xqm%L-w(Oew$Af zEwxZ_)`zwg?>Ep^pO$fc@xHK<)`#s#@hW>vEgJ)FxQU6%RLP@|!=# z2M9{UO@`*Eggq)f$^9#M*frUiRGpB+_Ex2YrGiLIjJ#ty_BwnuYOj5>iZL41mt0pa z>B<=oDXJf1*RA5#oRn_q)s(4fCT;r{{ zD$~XJ!ePY5sY1cgqnUx(Z9imP#>^lO*0?hCz)8@0E{FcOg-?U^gyjTS_tMw+bJ2-$ z9X^^YQ_GEPz*=s>Uuc;9Gd!bCl`d=E>SV^BM7Z5n7 zC|F6+>k>;1a_-KbCI$CYZgXT)dDPWBRbIeWDIvL_jK6jW3fm;auMApLcagL$kbj}_ zp?WZP>*mx>EphW(I8n%^=jI6~3=yRXR=PvJgN_mv1iWn(Jbo5?S-%&3z8GwSInn75 zo5YsFnb0b?cW6xeJ7(^;n?sbk&M8PUWa(q0y!Yq5&ezBNd?o>}wt@T(YaI<8T|J~L z8)%)aC-!o!_jp1@fBb96CJUpO4Xi8NT0<}{eBb5Hsg)U(7!Wq<{m7P8RlA1efN~)qNwT;|xhAY7;TCKK?VZSYn8c-L?EK=|Ue|)G> z1s~fhx@2cbZlCQ<#GS5g9Z;xq@W>;cjdSioQw9d*#ur5K3YAl3>6((SM=Sy7%k|`N%e3aFqiI4|lE=m@28FeZWvQGU7u7dh9 z#amxOj>Sl>3WZe8PT3el$1U$)q>xlrxt1>FQM+5@5#MD5Wh+rmi;${?8A(F$RvcF$ zqY8X@x&)oZE`3dDQ)_v9h`YlNpOE;|N^(UtZhdPWT|&lP!3LXX{S-`35=l&paV^-B z7(b_3H-1n_qghrU`&kpbU&U_->3xqV&7C>ulYNfc1nt`kp7weeatb{N66X zhq+MjvhTy0k3+r**)59E_!)N&&ERGrK_!qbB|ZoRRW@C>&6aiVzj;v~pnBf(d~&s| zyQJ9|wC4hr_jGXZpnWd_ptIo_zN``%pUz2huG3~y<7S9d>YCd@!eX38jsl}&|Ge6Y zIDZ-A`1h-=?{NmSM(VlOzVE3m6qu8KaKPNIoRrSrIF}rsp5g%ms1H*5?q5%dc|GS@ zUGFxRv~}epq(YzTEQqVB3Yp*wHf{yAFFLS$Tf`p4Q7A1QaOz!xTWYUr`n5N9`+LbK zPloq}BCnBl#V>4BO$SE(Z%<8*73D&;vxYE`S_NM){FeW%<)io~-5q5vc!ii3tTH>2 z+xfL>ZR)ca44Y71rIh%aNyKt^ZYzR_hOq6gF#g4~vjjMP88E7sT-w*qWAmiKY2W)0 zd9f{k__)uEVRRUCu}>|bZgQf(`cwrFS@OJIqq>l(BLmKgfy)Xsu*f=k_gav2Zs;-C z9~AF~)BdrCSeuBxm!xVkDesQ|*|_jpCu|~(LGgA}?4MC9PtAW7V_m&5LX?UR3-9!C zfc!K~rx4!6G0xsFLT;!g7F5qWYU|&h!LKuRYh85npJ#yb)DkCS1`ABA9vvB=XgU!0E0k%p&OJgVE`)`Xhah3f+AXrE}lk4 zPU|7QuW3GQ#;e`eV?8--cf68W)=cE<(IC5%jrG5Nv5KCFDsVMFMG!k$)k-r zZNIgKtWZ>SwX_=9=*c9m*XkQXPN5uv2fp5Z`wlN0!apZ3zh0k68(@D7xGDU%>3_am z(`9%7O%nVdPTfe%%D5cy5_p~o94!hSe*eV!`$8gj8J|1C)`mcWC?-vptEoW#tgNZX zkXpZrF6A%;5+bzq;NJP+BeF{&JxvFsXQ&6V(@gsQg_Gt=_=SZ-C&64LoV$7OzsmyO9*^_BUO!snq3S*y49dGB@G$C%=Jv zuQtX^tP-2{L+2hRmquhSOu%WxKeee7f zM^6)mhZkt_J;~2W$63S=N2)N6r;p?O-Cot+++HAQo;4KTt{t%*jazh)f$_<7=Bk{T z3QM@6Rf?GXd~oocH~;rUxhJU!XRVgOP0iAHqL1(GT9K9(M$H2{J|ID;CNol^&RvC~ ze<^Tb68~J{W4KZ>nHrF;rn8r)d(RN)ipbQq;W=g8W3Uz(}a2!D>N^;B(;wCEore*BL6OnD;oa$!nBVhhxs{b%_;RH= zYK1zBPk!}r-tF3GqF&weZui4VT`xGu?-BoH_kyT3{^D0~X7!qH53%ok0p&vqEBu=e z#g*`s@p<3@i#IBsSCQKe)$o447M|@Ca~Rbn(fbqhyE=2f$6u1-HaJ&Z*m^SPto*ot zug&}ZHmn#z{xE;s%;DLtIraK~0QNu$zq+d`uJvYc$WJcyd2Y5!?8WUoj|1Uwt2A8qUpVzj^rGJ;La_it4;qWh8aHU^m&v$=e z>yXv0|Du4)m-|TY>Zu9q5mO#k*cD`&c(tI9gO+sIA&x&2vxAF(tD$Z9J zr2OR@h0B8%x2~H65A1@od?|(J>8uH9eU+>GdTy{8Tvl-Xfvu7Z?03DWKghm_1MwlL z^>bVQ*49Y#6_isf=kmo&zK|}Jvp7+M!d9~_<0QHt+27pTy0^FW>Ybba;j7=cv9+-s zJ=}>M?j<6jRCFi0cWdkBt&P|3ZM~jI?ct5QX|mHvr{{^D!;X5wxG(g5#`PMei*}r< zY86$h0FUuKcvqL+ z)m8ug{o(1UJDqB#&B(2K+iDnoKsi>QTdfl=c1McSm(8vqw+I?O^o=}%W=fSrz8KBs z!^zA6sD@?vVAY;#mB?hP(PTN4M#3dBMaX5QUFUR^YFBVIPXW^e69d*jtWlvmC8|{b z0qY1xHCT0F1v)`1iA(5iu&TM`1p~{UgU(c$1~ocrFmcXM?DvFTPjG!+w<)=e0@LUY zV|hIAjqM8{@S9yuGbzJn+@91MDu6Fa3#rz_RpbyO;+ol*&O0Y(4uH=2rGIf12)GBL zc_SHaU$t;bDORaC%B7kP(H%>x#l2hZSORx?YOFw~4U}W{c->>2fjnB68}H zTt!gf>t0OeBC&L+QqMOigyR|<+kgxM@|AX5YBq&ti&s>(-4VK8XSiCRV0kh;znagX zSU$FOTcLS0o(|pGcr@#P6`z!IpU$GaS(yXoIQk_$}ZbRzwN5!U%OyA*2?mXmrQqfoZIs>hzo4e$(<5 z%@tLh7Md6>)d)UVF%%bSxQJi^Qs=5DUn3-xRB)z6LP(h`BumjqWP>m{Bed%k^fe)Qz=^|PlB9zVJ|J(&aRhyq$;rH&5hq*m-FHi9DKaL2>d+;-{)2C|J;HU)>+;2Tz_@o`oHIi zLHP4s&y#qbdA!)Q+Pew@7j~`>eC`i|zwrMq3wD5k??s;UMOctB00I0D!GVH(>%BiY zBYTW9v`!&fPM`QBdyKeylxzqqL{hk!xI`b1z~ zJn%14TR+1u40b_;RpjUK16zf_K|%CYS2+4B@vwnmz- zpd5@q7>-n-wA3|R-!W~2WT<2|wXwT(XJ_-?{_d-HZ~q@&`NqA2{Y0^lDCXn&OgJ6i ziydqpZ0>|ML(%O*IZm@x)8xj(cHfhGt~ed4i%DxXR)#~~@d?ALcf6{$T2s^MW8RSH zjVRqg-uv(S&CAAcM2$wwWXz3*%%D##X7bsoc6ni4T{!2b*4e3ban`-Q>OFom2I5)F zHNzx1vDh>)&84(1Wq7m`G{Go?dD|bUwkPN|+cxNCn-nFqj%Bm?!+3H#nb|8<p>(U-P>YzHBilt*uLLt7n>AK1)14w94&5%UDMxnD z^}yz!M#pRDZcv>Al;iZ6^=bx#kvIa*n8-jm(}^;jsH2f$IkeKQvto&r%1Q@o8IAuR zWB(N_JCY{ofxBzF9MN5=uD%_39Tgp5zs&c5LzL$7DubAwaA-VXH}N2YBj9x zVH;_)(`&Tma35;;GEJK?qwVb4)S5MoYu$Y4<^!MRiTgV|BJR0aSv~XTpEwTp-+y-p z;^P0{P}ve)sPJk-s<)M9C#k(2P#Nu(#(U-dD3?eEP1ZS!eZlEoNhpD4TL!Ed?-oZp zh2c1lXLQ=VRJKgVM5isVwz_?3QUA8yemx@CQ{`B#Cj7a}^RE5dcxN<9A>m}>` zbZ4iybKD&4*P4T3v7S_NTqx!?+BR183#*$8HrIAI;^p{gB;q$3HjKs%i`5VaIt4MB z&PW(>dV>mRe^eWe>wAZtTle@x6C`@6z=PtD7r}Yl~MF zu3Frdm=L2AR5VU{VlGS2Wb|%s`!+2BgP(D6=_s3mT>x+s;?p569pEzoDIZR%u|ksv z&DUALnq-m8s#KxImKr>ILp1t6Je?{>c)dy{$*z zXtSEl4x8Sx4Ty7j?&^hWmloHTO%99G@AiiM4xh{7vYDNLLEGzw^-c4p-Dmd_op?dIZPIYVd5Qo6`X$tW8S#{@qwN0co3 z{Aa4fXUk$%mC|J)S!CrLEoGv7ieTj+E%{>-`XYKn1hNSbfH*?X&v*l@kCeigavd?A&~C#5(;vk@`QG92K7WosMGombpm8_PwrS-IJ)z?KIjg5_|~uBiFA z!~)IWuR{RkWZ={*67aZf;gDAlsC+I7nuv1%H@RFglabTugsSEn4Ha+-G@jrh(I6Qk z++Nql=DNvZ3Q`TV{?UWGXD9okLAzQjWwcvy!fBa@bRm;S zf!nMCO%(E}LLr?@#RZ9FSlS=-8H`&Q=uJYBB!Qx$R;vZSF9$+39B1LMJ2@U}N91qi zV9^2)5-37({+ys$lWAx~M|VxJprbg3807F(JV2RH1=Z5RzdjPT(M|2^4FVv%X^=69W|Ir-C?VI->&xU^s0>6I5|B zG)TcJWTD`xDYBew3Y?FMCYe~zfzJ6VxbwJmyxFlp4p_jzCxLw;=yKIe@LoGV3gk-@ zys8aoBH$C2Py|(Q(X5r(cE%3R3ob={MY{v~qahAtX#)93v_61C@HVT0z2WkiXf7wa zbuxzEAzF8^OmZye1aiTTHc&i^Gm+UCp)Fh)1b1U*uL-2Fz7jB)_3%GO&ikC?p!I3a zKR`KTETmS8$0rBxzK336v3qbp(v;3oIDVs&uGIJ67+~ z%^vIf?>?sf`{&IL(?p0vcRFmZ%eR_LtwQ#?;@)oha6fmrpWhv4LHBnH2m2+^elJz6 z@X1t&7u}-bi>Csh$y}t|5L*3Ie<$DUrOH*ITou(SK%11wv1H8YbZ=U0t9I8$kg&+< zXlGDR>q;s|Co)knMexaxkPgRl5h+XXX^4nkD&=9b5FpWAIG}tEU9JMe0p+qj$U&4- zA@O_a@(rfgnBImA+C*Aw@OACk@=hn->m+&|rPWFlO0*F7x&t~tVNkLJAWp7Kmuq~z zEq4c*!8i}d(&?wid!@a@%E56hU!ooE6|;5DWVyj`4zXzFh=RNoJfa# zq)~6XabxX!^BZq$n6LOq1E=`XWlBf|JcK?F+omKJX8%tNVOlwY$IZSxn9;;5bw7tFV3)m%evrZ1kX1v=R?>2_x z+F(@a57qv#e0?B)r7hOG@djk}6P1=&tg+cjEK?;@HA1cgrLqsPPR7M$5S4NnAD8hnDbOGXJGww+ zt8pnyk-VQ*qB&LGJsRA7czSp;?)K{Ca<*D6jz_&=zul@;;sWP`ZQ%1bfbSi4-L~QS z(i|WT=-kQzx&Y^K0Ohy>9=q2Gl(S_uu5PWZ8P89Br$VKzyyN%ZpK0P79$fgtC115resAt6Y{iC7{Mf*jIe@fo+B zn_CPD-@ zbt|EeM-b^?$m0*X;xeDi#A%M?L@HlOx4ZS-{o&E^?#b!?g9o>Oat8etAcVkEp`gcL z*f4Ex`u)y$oCOSmT?2Y}IDYu>>1fuZJ#sfoCbsDoGJQ3YHuntJO>U2cv4Os3awt zjREDX>(sFUaWiTka!Hi@5Fjah8LX(ZD|v49a+;u;{cRawZ8_Xx*FIgAb&dx5+RjJwd(w7U#eURE9xMf;>6zdn5XgoiSOq6&J5RSR-Z-e^TGwGY=_q18j1Jgvk~w?BZ;iy}P-yn~_JHpUgg^gZJnb&q>M$)poHoVr>mJ1H= zDo{?L!sJz^ROKpl5n!d&Q_yESn{mLG(QfhPoo>CA@C9{N$D-A~AjZ8d^o&(@sKF2v zfu&mIfrMDe;|y-DZ(q5x_>bq--dNeXXmTyO!<#|M_4!rZ!p7#3VSC+RT;1GSbhr!*7b>aB z&R%2hptXP4-r1{<_v%L{otw7@p!Xl`zj*)7-cd_ZNQY-@Y3? z_qyCJbiu~Fy|TG+ZSls%>z6OyxN>88e#5v4WCMr;>hQTt4$G!Vzp9^54loU#$gz2? z7PlD`(qTG8a)3Bwgag(IF>!*Hf>F^&iGD5-q9uQX_fQhxS2&~c#fEk%s=x~A2%jRv zbTpog$psqt1`@0ij!6NM_eOXxBQGZd=IWh}b|)e&e>^=#Du99Qxv> zH|DYh&D(Ch-nvGx{!BShs%I*Vtej$D7gMxflA`5u^7v@*$%jv0KEHSW&f(+xC+|MF z^Z7?FzWU_-51&2y;K{?!UOxZoqxXOOMm=JQYPo*jMv^N;`Fr$7Ak z!*}o9J{k0yxs1%vkwC!haG3o8SA+}@5kEx}#d5aOZ`50Af7HJF;O4_8cVT(+&hgpJ z!~OkHyIoThk)pz~BFHlDbXv@otzggtG_$)m0Gr!)PTqU}*=L`B`1IL>Tepw*_J^%D zaJm4j12!}hu~-dI7no@{g3`rqJ&}Rzv`ud@-w}y8w`p^ILSAX|^{2%|XzxkVTtp;HhLMIxmn1`QTEkjzsG+ zsxtM71k%%?q2?e5JYyi3H8C9@l3A~?%sk*sD8z^}bBG16Y7Qo}giFuYoupCz#Qe9% zg$Jd{B8IsvpaNm&Nb!;~CjMI>q8Jw5% z)j%-PdG-L7lSIxE?8-|N|(-oV0i4k47GF@xMD-EeoX3JGUqa3+hmBe^} zr0g{3;zXYi_bcg0QRTBmIu2*{ad(WfOQ~SCOl4I%Q;I2hB9YUc%_$>}!HPi#_y$xe zhF}%=Cfj6+U7^@Pk8PJ)oZ9BA9RVn(-jV7Mbelr0fo60X4WZo>+byXLeXH@QEa4~g zpy_<1T;qxrL^*1WuQtSbOM)eOYzl!+a^^}4v(uxr}h1#YHyeY zDgp)80YXx;kqBeAdDm7AmzMPx7IklfE^WTOYPh(*eR<1v!{%G{M~xn0%jR37Bu}vs zuXIv{S|UU_%+3vm&*&p;5yo%xY|pP=ThT4*jO)uA^9w82);AZ;7F{4@6C@&El$!1Q za9kbkR0m^qxTEgu*KXY%+}W#yd>>rznrBvwrF@adpZil!@6uErFb zKsjOqux2Q03JE}*c(W(fVS~3g*xIdLqPLUmjOB8N$u=VCT1YPYG|I74ij_^dcr=~k zV>1Ch3zQSh)I|Utxya`0O1)n!HL}Tk+#7Oi8df&-t0t4)A8?1m{y@O%^SXWL%`FbS zX?sntTU=kAUtL;QTUyy%LvL8HZUg0LcjvfZ3I8b8wl-Gut3Wv>r^y*~dI=AxE9eAu zhg<+XKsf{xhV2ld1OBMn6}EUH<`Cnc;{nVrT#{h4=@~H-1)verB$EgdoGZ*aqoS8i z1lVMlRYJ5Jj0oNU?exbSzL+D(xI(Na$a;K~%SqU_eTH@W+NMjl<Rpr4>^Yqqkt&vM-1Vv#Ag~WK&e0cxlvyWfA|Kh>DTZfPD zoxc0{&SxJy`}&jjKYRJ?vv(2V{OF5MfBD1j|M5?M^v{0r(+{3M-Wzs~_D1{TUbUQ) zc*^f}03W!VmSE6L(*(!IK;<@MihG%znxllxzN{?Qkoe(>=JFFt(v7!!N&rS|5J(6+XJ7 ze2sE`^LKv-`9J&Bue75*%KSI~;XeSBOejY~94&HaswKb%9B5vV;EI~TBokVIRxs`W z+-Q*&+fDpv)zLayoj89bxD>mZWPybiy+DwEZ48jc!-fBGDP-fwTAehFC$lcxsLWjrzM}Qal|gN})_mwV&d* zI0yF=1h3BEW>$oKVsE&I-PTliHdoEb%~QqeC9g zr!__UU$4hV^Bt5^tC#8xwb`l9~Hb#3F#xy66HrhD6LpN}%OWR@sZIP@kx6)1*k~^CxJH6!bS!4gGGTbfnhMDdl zGu$bR_ez7^LbVl-r@~>%VsWo*ny)W!UI1O&y0m4zVfC&6--KwhH)1e47U$O9^hHdS zb_z687OWoK!rG-R%d*pNBH4g9?9gqmZdr6zmwA0_<;L=rb^W5#V~i`YYCYBI7Y8GN zo62ZM9q*~5-STL+w6k9x?G^hYI6F_ZdZ~PgVR$zYwfe)`G1em~B*lYU+sfwrx?xFB z=xV3b+ie%>*_asFc5PiMz6p@pV4SC z1o)#ch+`W;Z*XHm}zm3I%Kq+tTXF z-15@g$`btYw=71B%LZ6ubpylM0dbsuw=3WQ;@L26t{K)>w^p~TTV|Kp;dkJxRKZvP zmZ13VV?XH)#C&1KPq4nIh;ECP3rw-0#PKOIBKW9ykX6D|B0!4XFbfdl40CRR z_dpRWgRILFwK+m2yQWUU;)>XSZ)`z}(PLP%uHDezm^aQZS(fLGb8}lafOsq+v&nDV za&4|zR#r_*8|D=s>5{WTwN)7Iw8nd#gTq0mTj_QycWxcN|Kic-AHV$I#iNIJP9EPq zeg5Fq7azX(`8QvD{n7g$J$v%*!+X!}-F|-m&Wi_k-+g@l*71I?S$m^ zJq=zgq=&=K$>}~QK+N93=2EoKJ=sG z?^LwVVw%n6Xt4v`YVlgmG~9qac7lT5xgd;vg3Mw(T0spW!Ibmw{`#+h1JLo_u%*`P zu=;QR`mcd<)LKomnt=$oe+4C4*m)IBaFLcdaSyIA;wM)os@$ukP{s&aK~^TP=_a?8BN-P&8b~((FAYa znScRU<6Wlp;nigt5ZrStunN5f4>%t$q0e|fVq$;5#+F|E1k!a444_vM#P#Tw^rB) zyY17nlShvq^#}cQCLNa(tiXE$0h`-xbGs}qCm_xydbb;#(Jo$Jnp@H>ujp6iSLc@2 z=MAQHy>WSI<;u$1)pgx@Hk|1GAT%gwIP>itjJh-Y-YW+SMz3tqOggyv=EIIp~Yog%*cE z2Wx{xZ_ueR=y|IKj8O!{84i-;ab{;PKiegLdcx&A_Z}%Fb zT!^3pHh@^4)gSTNy%wWY=k%H)l)I?Lhdb)-er@-l27Ck9x_4Lw!0L~3&8`e+SZ#`p zPNLaW)Vc_J0eTW;ovi4KCnKyB3dP)OTk{*n#Y`!_d)&MI@OXUG%c@Bq>0Z#?Skm2C zGb|YF>sIfUGhpzO7CP>gGGX+VKcF0yEH&s_hcDG*IW?Rv1X6i_wiGH>$y$qP_V`v` zX!XQ)PwEa6gI#5?pBf&fdk0EuM=E#dY%QXc19CB#D1_qqkeCeu{y`j^uZR*$bTkAHP*&pymB4LNivADW2zp}ivv9@K|2CVUh z{r*T0U#M~iy=avPLK*-_X99;CSPixAzui*1?aIB|NAJJ;=!173y?lEA`J+3}9^86-=j5x8U;gty{`ohb ze*|Q6x;yIED~(dFoK0pGDZ$es6J=ur6AN>6BreeDq*Sk!@7z9l`SR)e?>~F;^#0kc zqw#LP+9;{D0w^TvEj5*s88JrjQC6g7^aP(ID+0g@z>Of%Ks^3{%kD7o0;N{+{Xq-h z2Eav>XdswMwQzj0cmKhy=YV35?%cd}R4Aq+WWeLKJK&-&pvwh=FyItQ+iGHXtxjAYgK6Nid8fcWatRXMmdgR z*cijo3`e8)B8U9hOiGeOpqywl5{VF)a&SC2cTh$LUsytXnlTLyS0D#B&(3oXUmbM~LhA%G7KX#SyJJ$o~(2_jiB(mw)-2zyJG#vr}jkN`Z3z z)nEM;rW}X>AAI=*)WY7tEz~X7YEb&?|LK3iKJly%a)^9Rf)vD#%9L^-4XQ!U-{6jE zekPMfptx6H^YcIbQ}7A3aQ?si^{>I~yd@qZ^b>M0ia{n+dH;(qaA#n7aCSDGM*8(% z{QB3p;{W@9{a>*GwDq9|I;KPw^{e0f{olc+KsMT>mlhIH6og=n5l7<*P0`a; zSSC{xUDR(;~(96&%t zsEvCKe(*13<`auniUd-#73_bO#@^1$)EmN@$)DE+H#GAP9*{@v+TP3|?f?ij&1r;7H_%5RZSs{k>)!nC!0$aOBrIw&SEK-I0B)KcrO}pwb&4trnFW=B{BjLxvC3qMq@?&L&K8btMW}5~a%2hw z{zOB)Etacvu0*DaM6wtL(8*Myxf+Gui&LZ0_?wa1?KtT=m2EP>H~EgHkZ7UT4Hp_r zp+*;~RIv)3p{sSS)shB1WjxC4?d6Y-%BN@5@ou&^P7YR_Ge~HWsf|SwuXYc(a>;9u`z8k@6=}fkZl(DMs@uoh?z?gIZiN7o`PH zC~EPBwn)YS834 z7RgY|N6jc4bL7 zw`JLI`mHXX%^PsX=!mRH=}a<}RydyV`n|d>U>}`s+hFrJ10HnpPrD%Dr=6at4amkG+BUj%I@`*cd2w;;`qkBo7Z%=n^ZM^!S-!NiwWzo2 zEk4V(+oZP}Hmv$J%f_;KZOOd4U|Qbt8iPW}K{|ELO`sfS#AyitCs_e;#59*vQ;m)~ z+->KJNsrgc(BVoced~1Z{TGj3JiZJ1!HY+qy#MU`pT7U;drxm4?HrD}yWLh!kpL&$ zHj`1ex;%Gvb9K?@w6YYD%gFUgq1&z@!Qpr`?heP@O1(&PBuRy0 z3?U}iR5lT12v5)jl#|RRviW2#pUf9hz&bP&0lqPA>o)bPundL006KsyPz0xBVAE_> zTJ0(vwaRL)(X5=D?!SERX|LY|FrsK8O!%NW84Ut30fMnS6NwTbBA8I5W~+Md{;iKb zdhdhxpS}O?6VMM{KKbaqr$9NCLaJ3O4m&kKoO&h4(~(fXO+~{T8xsVYrlW931ik@p zQHl%`VMR^|Jjc*?n+7whA#Dhv#o8x-ZAH4XgvDKtd2>{^~cs0fht< zL5v5g0JlH`pb#_wBft`tD1vALVQBy41Sse0pZyFX{m*~(D>&dIGSKwj1Lf4~piqRa zXMqQeB)|iv9E>K2UH%5K3x*rbF^>1ICik7QoI?l~Vw_*(TbA zVd4!t+4@t_#x-FJj5v7i1ak(KZ_x(qIY>^*rh>N3>y!h6D?$y72vA*X?$s2CCa?JB zoS+=A)LKKaehMO!c_1wlP3J%kcK*6Rt;z2VbyyqbEHO)Cfi*BgjwVQhWHxy-^RHQ= z-fIqC6DZP}nh5X6N*z13wh*|yg7iwmn)ug+h%zI17R^~%cTb%Sl0PXr==`LbN+Yi+3k0lO1# zb>pqJ&}gvrI#sJioAp??Ne#LzXtxpTHK}2T9d_Aaj~jNmQBT+zCdMPV3+MF3FwdI( z-euGFC9~z4!?g^EBd0>yLaeBAYE7&*;&nirrj#qw*pyvS`1sx7-6yT1JEa~_PMc1ZgNeL9kq^Z4L7*Hd7Y0ofV@jEo zOI%E&oXd-EUs<@Yv@y5s*a}3v@ub-5H4abq`=egDTIMA#5DwVfPK(oSaXRc?G?=5>?D>4U4b$XA%60&Z23>yxe z(YtL8ShhXeR=a_1g9O_ijFa_7L>rkKg<1 z>re0AKkN1y)q1H`FC851931at3rSXpk#rcdjwj$WTDNEce%`rsR*ok)L8Jjw0ztRS zZM8d004p3Hi^f78uN~jQ3?u~11n@K*b-)-(vpG0t=s$h-V7$|VLs>eL020CqU?hkD zB@s?w)7ezLSsji0x9^-jfARSFvqvwUK79P(_PyIDH;?y*y+#=@3n(hiq!m7!mUxzo zk--=lA_4xXNH`pDIvt=szYj|?AqyPGGA#5j91LN~LC5%WhiQBu#)o=LIVki_1?QmI z9gS=tsN<;f(br%9=I{Uh=+-T~3bCi!Y(lVy5DtE3F&@&IfOGwxMmfL=|MJ(r236|_ zUjTPzlrs%J$QU31PlRAIaI1A2@d|jJ-M_4L8}%Fk(BJ+Iq8u$GVam}62GyFmoq2=XFVwv4uM^iwoJg40l1)5eP^M*}Q86@*Kn*32QKAqRC#^94Du5%y0{ zUbT+;hD7TsTEmnx;T$}d^9oZYq@txKprcipywY$cGqdx8Gr@S;&})1Ht5_g?&KCIx zdk`2k5C#aQ4G`G#u!;?4rI0u$Xm@D(nqY^o3uI!QxB~C^;uHw}jm?~&?>z1zuJzju zfj}u(VH;dgtECwFhcZNGdwXVjMc#MttiGVlc^$|WV;dKRF z+jisT_6C5C-mF_Ut}g2qZme9JTfMfpeq(;^>ipVe^}a(v&p@FEh??z0t0T8M2?+l{ zIkjr6sz&NnvQ>}v+H}9ebQ;lagB-M}QIFdj#}9XvqrKGLjxrp?TTQlHA`+4#8a4QR zYd+t)FR;l8o}$W^DnKW^T9c}cL`|cdyvkt2nP?4Ihb>g8oElB%!^vzA_y!UMHCk9tu2!Q}HL6yk zeSSM1hF^!JY-_4Bn^Pt^vs@|1gIGIv3U5w^brruHNom8&GrE*lJ0HYSFExFu~ z3RPZh#4F82zAEIZe6bC4gm zr|r{w>R=xrk4^*S6OU~pN?KD)_pGy2S%9>bb_{KP0qd784ha<6|H|VlBO##9SIUYZ{rAEKChUaf=_U%yE3z*XG)G}Ea5XbGYIb9aO z8aP-rTa`++z_29CMN8!@5YOq^!Om{4(Ny7tO|9escT(xNMo3|bj!JPMo6F=2*-SRo zXjbuK6!lq?(LJKgYmG}Y(TA2CYMPhBu3z(G!^F9XdL!F;di>MKA+p|cH-D$ zv)NrPm)GlcI$cyW%1|^Nqr$-;y8Bo=oTFpzR3NP#^wFfqE2hD6?!KIAs|B$fPwij@ z3IWyug#=y&OB~}r{OVPVM?plB8RbBL2h{lbXFtR7{x5$0igKVjb`I6Chbg{Ho?rs* z0lLyC2SmGWr77UcgmN^q^HV#}h1rF$Stp_LIm-F=)C=wdDA<4{*n^^gc%E`vh;nAQ z_PZzt&-Bb3fwHS3Z%~ zo1XB^)E*Wv5EvI48l<)Q-+t{7PJ@8?Y>e>#+f};Y9ZO%2i|J8kye8 zmH2#_E2>?AYO^r0GWT#01=yaRWUMn{0vEulNa!qXZQk`M8(N(IgxY`f^aR7G; zRk~P16D_$)EL$dlWAbIPScz2{Y@;o-ds4eAwpv1?$yFOnQH^HN=ewg|jHpF>^&h%H z2UNRUb$%iTmXOXu&V+JM69sMR1t_P{6uO!*9W#eAl$_{pNpiOiGwE$Z+SEfXuoD}*zcsv&p z(*6LoZSk$JNnf?6jE<|jr;X+?o2&3Vu$17X1uy&nTHQ>e1DYG{Hg^yE{hd~(Bzwbl zooVUX(p!rgmp09aa$q=PhO=eJ462P7AkN-V?(A;u-s27+ z&a-!SUc9&a?)$qhG=22Ecl%*|=P(U0lvP7=&YQ@=V1uZinIM<+vB?0dgxDlOD}*O% zH+l5yrsetd>sJ;pF6kCrekc640d!c24U(a7i~xM01UAOA0g`a|+(0&KTO0GMi%T0T zkg$0iAT`ZfC%0^V+n#kL^C~lMb$+bIY>1q+0~U(OWiwd+a_Nx;uyTQ3)o* zMqClEj|zs^u#XDZL(X-}#?`fJZ_T~+=8ZQmEMB;>dinas)obfludZELG%T!J*K~HB z!M$w>*lj_lHQ+S5ZR-}}n%S^vH(UHJHyLn7y!MF8MmUUq(~@a<-L~P5d3?0bML2B% ztJ!OEhU|f;hfTyvwd~=^`1o|UKWt>O@nFEgP@!B}8uc2F@11@0^2s+}eDssAKYjW5 zULh5ahG2*;ht;S9%5mG21mCQe4-du%d&AwGKG4Qs*xuV8?jMc-amv-aoDzX@l9@QH z9-ZzL)hsX3VuFQZ4#h@75ueLvcl#ZIu*U&$1?a^3BNlE}Qtv2Au=<$<#2Zv+8 z9e^I7pJ2#?Ue2D90DT}cn^QX7`go@|8h5+B22f7Dp*EU;IcX`*g$cjc=ZZ!ng2*RR z3TPq`SCoXJ#QXjBiFha5w;NJRYy#AM|*9;XsfAV2i~<0Zcha&@p!^_&^L{01~g=YplunoWJ_bZ~hW_* zm{+h{=qn%y)#15Thipb~~5D9~!*Rn+>lW2hTA4K=@$a*)TVK*zAbvpo@^Q~?XB_G+J^ny5i68oo^I zX7$c15@dsZddU7e1qz@6Xl0T{EquoqL9iE$G~YovA;K3=aBzmyYF28MVm_@Dv#Clc zmrKivBGzi9(Wtk#KR!I(1JD`m4io7(pWsAAAeo5M=h!sq7S zVb(3eVcqanAi5$cq?{sCSu$Uw)hdskmu?7+23OZWr(Pi&l?YHyzr*x9)Ue0w??}5N z5uj(#VbRUVgZS<^xxbg)+sy(rRI6OENP(-8DwHcyzQoI^2*tW3C6p=BwU*Ku=Gwzd zv!ATA<7EJyI+w38*$R4QC!>-%ZF)d$Ftrxf=m^cO*z5?67T*BkX>yGgpct?P4VY4_ zqMK}TTCKE7rnCpIG|HLGj>&xv?ra8!{OaNW$`DdEq7*5Bo3zR%%ZyT@;(1cY zhC%skNXUf}B^VBquCW=|J}sf#OEh+}or7ZUsN6d$bq@;t{laLkFx<%v$JyP3(!pt^ zH%ix9Ksh{sqnr!Jvmu}yKJAZ64i}*_y5^~btI$BxIn80F)=QQeVlp3-Go+FwGX*+V zWRjU^roat%>&G|8yGQ*1TS270oSL+IjZ3<#7jOLD!umy{ec2y1af&ZlAOTM+O}+-Z zrY8dE6l-L@63MGXt;P1n%E4*r_WkDl$K6Ly2alf(L7zMyJbyWU@5B9PFNY7Fv=2`5 z?Y>y7Mp6ZTG9Og(p#-9_04;lBaZgn8(sGDPM@cCFptEURyRmld(!zzs%>{SJO^Z|_ zn_wiy9|;1xuyLN3B{nXGVkA(`rpW+&bA4%UZe?L*bIt6uf*F7gK}UQQh$4M>{VTmvu!nfvl!fxOmcgO_*1gk!%!NsB?LrO@aaoR_PtO3WGS$9LXaD8KL zUcazrS=)4M8r%k~wvf#e^Z4n2pAOnXE`!UwZqYC5*RBC|ZRt!Nr-uwjM3xY#ut)}l zFu)BUk>05fa={Q6bcP*{pv_GT{_fF67!ad&TUa=H%~)ay0iBrRV^ z0pCXo6y zK_Cq|5Emiw4^s{-Aq_c@hOmv(5W*qYtMxiW^uPI!|51zaTeGWY85&L1_;0Eb+8A;W5H<%r<2=pzMFDhT>^tGJOdgq05hCEPdQp7MFWCf zAwtmv(s(*XThX$R;Mof#c=VIpso+(R*(&$}OAu{uPXyIae z)M{zI&ei)aoyergsiGYG=bYdsP-nC>a*wDH7fxhqg9IbZcTf(TX{EHU6lKzhv?9t9 zr^NY`EV6VY7;wXxO+J^b*VVoK(Zfe~Z{9g=^%~h?nqs2?!siaSEN+X@Zrn7ZM@tM2 zqrthoy1fpnvu-ULRL%2U-A`r1Q#41rcw+funD=IczV9Ko8ckcC>T(qiix;sEH>nryXB*J?C?SGz4X zn!sTkFiN@3;u#?HYF+J-EA)7|c3)1qNvB&3XsSu4V6{PI>Qq*{gC}37i`rvWmHOmi za`4%0OWhXVY0$kE1KiecvzyxbyI2d1Tw)Ui9~^x@)Y`-K_(n8#^R-z zRE)whQHDfB$cKeOSS+HikR~b-r4mh6V@dS-AGX*PszbT4n`-T4K$|-$^kMTB-|R@k zac2Lhe0sayAE(qhn^$A0LPW|0#Ed_Vz83C}#vNhK5@OAePN}f1(1%n@O|jGvl6f+o z3V|k4;Y2blDPbiO>ki9DXT$xIL8+c`__mifuU%byb47pE>e(Q9XSz(4>U;&N*UxMNu#~Y(V2SdUi0?-)}06KyAL}L9(Nx<8@zaL=Yx+AUw*Lru!Y=WUB3UUB(j5fojS*J5^ZrM#nr`71TnSD-M&;!eDk9EVUU)f$?w*sAPnS5qT zz+(2BtpSUZaJWgAn{<0)UQg7kw{Klvo4+`J<;|-X-nepceq+rM^oLj~D)G?-81&HzKbUZFG979&s+=IJk z-~aNHKmW5o`SQ~b@17miO1a6q@@z(vSsw_xlS!%DZ{EFs^X%3k0Ed#2fM6P(>S(VI zK*LLPrjRUFa+O92v{cCf%6J1#vklIH7U!3)>9$t=Ar~t|<)l!p7miMLZr?q=d++4d zox|hPouiZSoqI<=_~B>2{DU8T_WAoaZygkhNnVJC33rSN3L;f3raPVLc--CJAK{N) zF$@`t5~-w2#YnTsXfc}{c8AaBBS|tIPh>I~MM?5JM-btBK6CHh?R)ocpPn5Khn-5b z0F1>8RI^p-4_a`_m&qz{R3st+gHdNNqGxA7EEbC>N~&5-Cetj-i5yRB_w4vQUNo1Z z3AV%nt2hk6^4nLewzt1^rw+i)?6S*;Uws92F*iUCMEZaASAPX;0pVXG0Q5u>fC99D z5B?C*5#?y;gRj@@ot!}Q!C--&B-gG7VgG;rmw&0X`zt&v^Y8xpuW>7rYg?1>hWf4r zy>pbKo#M}~B0(wG%sL6x|NH+DJ<s1#FoqyP)WW)39YQEvkXPiXd{!CsTW6;Sa6~vh*}r-Fq|<9gq9Je4?SgaGfXfs1z%kwGv6|eL zO`Bn9Yi)6B6;3gi4Qn@aSGg1GmHD^lmM*O8uSa6eOpY#9_B^lBfR4}v!l)3P z7B%c~{SMP>)1yAWzbl^|XAkz0ttQp$iU<37K%ArF>fU~NJT4AL#csb)Z>AH;nBApc z*WXxJxwL6qu)FmH?T}L8T!m9Ri83G#Xh+I7SfxbB#jsKgr`1Tl7FB_Ax&nT)oLZyQ zDpjr0%_iUNCR*sZZa^RO+M9BN1!T$B&?HT^MrCT~2IOQNsZx*0wWy*gtfuO~I%r0x z&|n}o0}TM>04+6|z%F8^1)wAJTI{gH?ev9lj~{l}y^(adpWGcuqk%96+!>0^Ce?!B z@5np*>CtYgKa$a#V0!U-SAw48DzS7qk}i|EDphQ-YD>u1SUFD$nFyCAr2-?Xf>5C8 zG!aXN=nNqgV|;<+as*!>gaX0kLu@X<nD3*hg8j7poLiZ!OulUjoW+F4xzI-vEW0F-ljyLNoD0($Fih#kV|+x&;5wIxUxZ6=4$EBUz@u;f9dUO7cK)Wtt~HY>2y|;+3T_e zJdUu}>UWqt7PHr4@mZ|_tHozFx(u-NQ$9cCbpfwL+}Ru(pw7dBT`jJj=? zJxIq$feW(~DKbn_@H0WP--2()@x;77%I6F@++kNR=63}gdb7^#FuHv;*MD+8<;~X(=hB@=CFquXn1D3C0BJ_xS9ffsmUMV);U{TFcjg zfol2vgTdE7_~-{e{N%%rpFDbec5*hld;jqHyLUeQ{Ke;Ay!_07{mH3J zCe`V*?%ut9>(=RT*ll-e05`A&B4i+&Q(En6r(3T#%2J&32i)5x2xfW+IyRfl>2yj` zyjU!!(-~2WXMuwRk&eXzJ~WpD2ib2O&LIbmzYqyPW(VTmC6hYna6ZYIMx043fpuJt zqYLC~hknfvM=@-T1kJ&~a^^tm1U})O4(1goLiW=tP^5X)e7^FGTujWS#*mBb zwJKUSKwhna6Wl{kTp#lR3W=yXvcXGjTo@Q8n-CY_(pefBgfuP%0k}X+fLP$wdxntb z={1g-z$&ymxesUZ#5n2(RKc!5pyI4!sEWa$Rr!t%LlP3uRn)pBkcJ%G7RdQD$h6kX z18NI~YngpJ;&sXaLEwW}2j4U^@dkCVKx(4rWRj1V0&PaEBFY4Tc9GzfX=gxSTv#A| zz8qJ8+OKG0R-_4T2v%oKW*#)A!8#Gh`VK`t&dDriQt6dw#nVdDa!8=&wC+FxT1TmW zfO1;hS~4v$Oe7NaM#El-i)NEzrIgJiB>-AW($&SbA{e#lsaeXu{ zHe1PBT`80#DM5Mz=EarEm#%&9($(L;zVPd?Lo2&Errch||nHnvZ zh(s|g7edK0k*P#V4Z7Oqsx7Xf-TP8fqm>HXXq=}U1Ul%`R4w$zzfy}UHqnDrDd3x0 zRIZYVN+hl+Bw!UXp(sA~TAR!GV)NryI z$uwfXI{7x6Z?V}rohnDfq+7}OfC5`xu{TnxO*WMeCNe%Dqfx6s=ybcUH)I}XFF!!KkY1L(8|iOw(ql(T!7KRT=2x!=D3xcB(^=*f%m zQ>3H&kJ<-^xn5svwqc(V$&5!*>|ETENPE&nB3GdR3W2?nB}y((a*<7{0wog;!fXqg zZ2_yvvu$)5?0#E_3Q1|HP%E|uol;$;1V&29YO}87GBKX@X|Kj{2fY@TZGLs}>cVwk zomKt1!MbhpIDCZPXy0DkSOi_&S~WShJz;l*C4hARaR8wfHx_QJT)(z-^}_WFZ(n`q z+VcG3=EfQvrJZ(HIN*;FVKy3|!XDD+A-x{b&0X?AtYFeBS|{U@G*i6*zDU@o5Aa|(M&j(mv?qL zckdmap6-lyTBS1li_SiJeDd)pkH7fx#V4OWe)r{_FTQ&I%Rl(?!;c=^y1n!6%eyaM z-a9=Vv|9OW7QLfc6r(^Fe!o2y4N4*dSfd+)vbvodJ?f-amln4c|%W2O)o`F49=OMy10YLF{&~v zJ#UW%EY5Ww$)w_>lL$dzBVg2kH00n&teGGK9GhRcKrJGftWGl^F^Q8#BOriA0|*gd z6-pvj)vm?o^pJYIXp;#o*d`*_tWi;(C$e6L2A5P zJUFV?>IqQ_azY?Vc^q!T>c)+?F8q_4Oti^z7;wk|usf1V#gF;%akjZK^U5n-FRH06n8rq8iH9y*Pj?nFh z{hl!B^Me651nqM$-kqJqU?}zn{9q*YM^e4TRO?i|#WoRDB)g+zdjRp3&lIECQY=@d z)rQdM%I!g_+LENC-%D(*o35>y=QbRx9@fQ`Sg9&1jd;Au^JSXKMW}3;D@K@nD4Oz8 zX)lwVD4X+gc`uLDC**xnF_0*SlnRlmk*OLQMXC}7%1P#f* zr#w>5pDag8ZJ{wrcJ_0v-87^jhfjMWywyW&24coAZ3@M<8PS<7$4XT$ohN~HQaLhH zU~(m?(JQuxs+6Kalp`3k5v-Gm`*Kx&d|cZ*sqY-Bqy6G=uP{C=jt=tOak9}BwOf?< z{y2GbrapW+c>3cD;0?KfPMltw-nj1Z*#(IP%K6~K7bhost!4!%2i;b@KYH)Q<3IVs zpZ)yDKY0G+KCA-zRH}t^PG&{QANE)r+gm1`(Ygf*huh)}IEiQg7$``1V+_GdH00Qw zra-_I3VM8AJ57a3#bmEr+1+W~xxN4F*`2%h4)*q&$rR0U{^3Y{^!VV#yJrs{?VsN4 zK7Mle)%Ra~{K>=j-oN|&#m&2ScLxKtT1|C2#YQ71%S<5PFc?;CHUl^pcsid;C6#z0 zE+&VU;gqBfBMs(fByLwFJHd=?6Xh5{PJ_4oZa1# zqDawLn21b1vsEf*_YX$Ed?vGgL$|WNu?&>s^SddUipS%*TrQKz#N#rs4xD3^@`bo4 z!G6Va}*hg$6*{7N8y7E30jljAlL6x+`U6lz9j0aYe~z+&cBD}PO373XM0sPr|} z1Uw*}tZ6pdGvR;p7x>x}WTBRzpW3&nhqSHYRj^#)uxpPz#$gAinGkiH*X%^y?^uMbiZ85ld<3? z9LKj-jg~F5(`@xvEgqZ6W8Ze$w!L1PWE-?njV3A)Nh6y?l?24$i@_P_q^i+Ojmp=w>6|*NHn@uRsR#6G;}+lU za@{`H9k87q(`?1+&1kg|t+%LFkL?VE&QPkixpIvzRe>tF&M?^V44S*ik~#DE1;`CvTd z5t1%0>5_}VTq9Nis@P3;5A*f0qLc|P>5j$iVb*m~HS0bBekJ_jA&K|vZ{N5)YeD$O6zxeRI zYP%UvCxLRJ91VyA3aq0y8y41uiAp^JsNNPr5s370eMaG^OHXOQvuDQAFk zkfM)O2tGwhSz69>NhRm`KD*6})E)K`Y$PVeXqjP?94MdUg(S}_ z98ius=(IRZX!gZrhJV6F)27p9!Jms#)m%0s=W|H_o$;{!_`&U8{Pde2{osq6C;Nk5 zquZ%fYlUnf8IA^Y#`XD?8`l=DtZptFEqbfN{v(x>9MyH!QK5d_zwyJe0p#*u+Q?BrL z?+xGo;LcZHzj*QP&6~G|m~vXJe7UU9bkOaFlj%)|V;fqL6MV1R>~@;1W_@Qoym@x= zB-4yr_(t*JAMBA>D{}x$K#(}fKb13AaX)2jaR;yK2tz*O>!)7 zw8ckWd=!QRWa2|PObk$quL%@Q2D7;d+XRmn1P>pF zF%WDylUHu1PH-A5(MHoY8?FuwY8`(iGfV6i#-&|=I)^w@w_t!gAQaQW|I}bor1eni z?03oRqSFl6rY(Xy3w!MxO)8^dz!bg9$a%1`G^`%QUmM+Y%TnI+2`4ZpmrN_I45qg9t)f*YJCYy?y!Gg^SnT zxw>#=S+}^be&gc&TNmcvxVZSnrhVDR*h$&PWJ0l|Hl`sYL!8=FKwyalRE{&f2T0oFW1_#C%Cz|{`S?y-@h>TPk;Z~ zKUy-+`vfmnV6rVG(~{E-Nhrj)d_<`+a+OB+<>UfP7C;C1#>W?YLeY=;1|v?q97?D# z1W+PTj(`H_WGiH`8pYFHsayadj^gB#PCn&Isf60&tHXG0D3^L-rcNb_VLt7p5{{T; zr{Yef5UF(H{oVZjNwvS5E7v(zaz+`8l=RD)h?0r1QqUK%nq2?{OTm~;Oc7EhQmBgu zx7xQKjc(rS-MrV;Sf_jYVgK-~I^4^(`f{zsSAl8jbh$gg3eHNDuU$ok`n}KgE+Ly@zdLm4e zWMlqFz!h{k{0^Jfwz{=?W#KZA&GqGLi`shv*NtmNyTRtQY7dj!j1Kdr#kgtN)>};m zyV+ph-n8gejmz^J*B3UfE$gpuT9)hqgNHPSS%;7&Qe`$*6Z4IDt|q0+LL$coY4?U{ zY1Oc>vbDIfh5T-75l z!C)}zbb3H1f*{oEH9(v@cW&LhdD3dtl%y00dK^yl?R4N9{3aeioGrtK&2Ea2!GtU% zlX5ScCrc1Z3HxSWQ6R__wc+x4$cI7sHoLPvnWs( z^0D)o*?AAz+N&Ffr<)W_PE2IhJ`TNFh9x%E3So6p z1f9i5^Bt7q^E=&cEBc18!%PG{xukTwH~8wa55D>G;}2du{@~@~kKTWJd@#%;g={8X zDy8#zrBF=v`t{+cRjOo?8A(X6;aJe>v0A-0tKaDep*twIJ@yT&adB&XVRQNGzmZq- zk)@5f>q{3e&%I&y=tU)5X(R?ag~2%6AEo=_WT!7y>#0z@02=i>l%ck9I$|Ypn@tiMJ4Chpc;&i#rs5Pcsp^N1hP!1qYrzdxZ zNzl$HS??#x9RUKlTp{CSbge3`M&cDRQH=_vFb(LC2ha&iKn7}5sl-5&XC9IQf@}nCRyvyt)bZ6Nr0+NI+5{m2?r(E;wgWwOjTQP;2U6? z!EUiPE;PC+?R9^NW-r|t=F~>q?pd2#eq(;^o$IS_zq9cBtCq!p;AJw=c$rJpP*7Z@?uh_!Z=`WPXOQXzT3$F!GGT(N|MRorquT&Od(exkRV86Or3RVvDw z&5j!;+w}-#W+e}LBR1`H1`H0r!4o!dawuJ5#WbN5Vxyz#%?E?iJDsDO&Ha*f?X#~x|M4$= zGTh%yWKskjbNanTn+bo7+~lwrtlPjku!_?g#?5WJiC`iGL%2h3ok<6LGq-wUabscA ztix~00R_;3Uo4ca8P=C{s|)MP^Q#NEARd!r zTW4Hf)33n!z~cJ+^2VaUylHcp-F`=q@J3@HDb5y486_zaVV}UqN~P54@%WPupZ)P4 z{OFfI`~G;)NGn{qn9OG5v_QH7cD-4*VO(3^S~Zw-R>!u}Z3R}KVni$&4hOw78BQgH zezW@E=JA7@NB2(mpFKEx`S|v|o4YrU2lwvm-nl*6+ppceGyLe|`;VR+?Cw`~_DZ9j zf?DPCMXJ+H@9e6>QE_j-dh7P!!NYxEoyU()?%dhi-EG$Exk@EduNOw6_Q~$_XixPO9Z%qh9ZIy6tAG+wSa)cYD1-BB2C>VTZ#hN#g$g?yXyAj~+cZ zIX&!j8-Oy#Z5>b!Y=n9PJ&{gEgOEwlL@uA|5891py;7-+Mx)cyvj-0zzIgHSv(G+% z|NRe-kB$=YI2?t6a`2^)b3qgd9EIVC3^{uzCx89=7asoo^jl6KC<6SJpku!lZYS%S zpkuiv)5HF&Q1ZIs$cM}(32ZZQgNWo{`cYaobk z&Z|~{eWLz?Xq`qm+IVpaw*`sWsLu%+6c)S=hOZQ7A%Sw#F}$Z>6|$yg(C%+j&cxfK z8U`2bCyVzZYHupAhHcJ^R)Rce{*mAjf<=_O)p9qZOAD|pjWGIS=5Pmt% z)hdO^wjFLT6{K(-(m9F*DVNfKv%anbbfvCUp~-n!vTHn+R{4)>uP|srHf2wnC%SG z-C=65lWO(EVkJ^k2{HQHjQkG@ISXeZTbLQD`=$Hv0S<%?I|c>B`#-n{s| z%Qr5~ugtG)t)ZEJtA4|@wxFB4v2krqcWv1;zwTHz1vlNaDInUTNjH=6Yn0>TGG0FI z5wmD6C!}M?@>1_7)mUr7MCqhw^Yg2OF7}UEa`|)j8)4ZiGl9N!vnEi#vp_Rk4Yn zoQo-WD$2VE)}E{Ktx>jvG}9Sox}$7&ob3#O?b7wOq}Ex`a*Zig&_%RNA(ShI%hgz= zPE{Ke0_7U~IO%qm8;ld9y;Ofk?u-(xL86JSJSHpM1W-<)Ar+glQsQWZ@Y7D99Dmg9 z4B9qKtIL~<%Nt94g1dS5v{)%}5+rVY`sHVjpFcf3J1NzxjKn*9E{n^C$p#Py)L=n; zv#eX4TUl5)Z1^JnU@YhiI89Cy&NHb@9r=#@wm_cIc|vv*{%*j2uX*bfqUZhRMb#sdlA8gH=0HtuL#cc&Q1iV!F(T zsR%6wLX^uLw3uCbvun%jHrRa@N5Jj~IPB<3md)%kZEUZv=$Dr^7B`IR7N^PPwm5xu zA{wAMk`rR0L`!jot$4 zFeu&jhTf!edTk^XVtMeuava6d(S*RN`Seb|egEe1C+|LccK_D#PVaPoaCSJ@=~oAx z(#cWh?4;Z4=SJhw-Fu_M<3_ESsH1nI%axj_R)kJBGZ+@yoebz;SUfrHeemIf&pv1WR#JUAW>>pMH`y}jPS{_yZ%eDmz+6SF%b%d{r-R`3hj3D?Cj+I_g_AK{NU(#4}fNV;i}i?NM{nAZoSp63L*`eWHgk` zCHMA6gF&y=YVGdso}Qi_AD`a6d;g0szWVaZuW#MDmCNNE4##g(4nBUP!>@L04yK%+ z|LLE?Dio>O^G*LodsU2fz<(vUx@LunG(WTSWL5KwJz)gFf{VVTD2!=A02^RA_jM}t z(FXM7w)RA~_Bx!uK{xB*9wJ!L+C{C*bn1NeQHbf|;$J`}$opT+UeALqwI(%z4FX{d zM|I2etKC>&aNmxOS`t?WgUL{k%mSiz-|;kpV*6Q@a|tK}-;*1IP)h&m0W0u;6CgMZ zMPLF;2&2#h?(Kh4UJXav*eEd#-dLa%me@aZ2oeyb&-;fomKoxpw1z>*tL78C0-53m z5-7qAf@dsRjwX5uR<2b!A&Or(0e#>kUrxw#TA(Y`^itKUvvcUD&w3zP)I2u5)s*+Lr4b8Azf# zR2m&VR}SaPA+;7o_gJ7iUU{`Hr1LRR4sk-jAF{0KZd_lyG`D>1#^SXrb64h;=a+RW zdh?daVcxQCZJ5?qj4R8=r6uFyg5kzB-K7=FoYA-LWz4aZm(2$Fe2~xiLB*^;kw^FC zKvo$7F1YteEOsoILxdt7%Xv2&aq?58R% zmWw+q&N+kSs=;zCLR+#Wy3tJy_tf!zb-1f`28DV%t=8p&DrO37Ugbdv+GcgHT0QIA z&Q+at(c;rb#6V0AlTsj2WGjPgp)IGXT)aRExv&D%Rf&oDpp*~DrI4)6;>>UdKu6Xl za>PL`({M%j#)kgPyC zWWp}w{OM{;)o#{Sim-*L{%)q(PZVo3Em(b_4S!e{Bn>gnK?|Ok;N}#BI84ItjTp`D z6{CGINLhqbFqMyHim_xa0?SHM0^sY7bFH3IMPHd<3u-J^ilp-)CF4tG{rM76ssJ2E zRY2rQ1X!opVMe>k!Et`~Ff-gs^>$L-ak{&ktq+nwImK37?W7U~CK?Y0S+^(Za1#!* z+qj}%m|MAaW9b?Z3+)~5~-nsTR zEdTMF|M>Ub`MtNVzB#vgO=n)UdJTTk7U9vBNfu-9+pBb;w_>3|XDVc}9M09E#U@*9 zu!TBXXmF*bSnH)~-E^TAPh_c>;15wwSI}hf81&YSHPhOiD|>R< zfA;L=*I&Q?;fIfJ-P$`o9s%XFTNOBPjfUOvsFzfvaL8}BnXMKRfDRE3u{0wIVoFKY zYxRDASSXYd2}P2mR4Q4kRgRAjfpVTde{%cIX*|Ji8Pf{Q633? zsf_kwn{NxQiz37{4Pioai|^4vIp+)}NQ8ok7UwmC*N6m#g>UJr7zTpA?2V>#w3qv7 zyn^1X3_Zl}zrn3cb>?>Ry5w_|gWjzSdj87{xU0}2>f!Vb)>(Li<@rl6$R7LFjM283 zZh>>Xe&qp{unIQQTWOI@?U4^y)pp24&c6&0F_AV3t-V(=s|8C~1^+nu{wD=ryTV<< zqIDC=~DwJh8jTyZ+MZwusN|JV{6 z_eRbi|ntpY4b9H_d&be2#SCyC{(&(**b(aF9ki<>xX%Ar}<$At@h94x*gOjB>(&IFNwVLs_cEXGX^2zVJ!*DGCAFcX@=QD(RkF04 zrKA)Y&qRR?VuHs{S{#18$+^1iT(buZVb&87`~>ff=c!6RU24m@x)6uWnDQspXcq9R z5>1u~pqxZ0h*YB-r4mWjqDmDyAB~qIVvzuimm;znN!Mc9>j%Z=C;@O&ZnL$4R3F8G za>_kk9f;|Aluo%Laa%|*#}ubj3}u^4xhIyp=y|IUyB!m4 z7nOjVjmSAt&PU_fNFZj`nXfPEE?i%E)8twX#>@fI=n3kqt|dRQl`GTjL3*@b>W(t? zb{r@tS0Xb7B9#ltX&-1NAIufQg>twEsuF6AtTkifz2xaF_29IybC~V#rMo-n?p_Wk zCkxeUe6cB~E25NVnPeo)`)q#m`t}O?_}c3A`IR|Oz*VjksFhlEufrb9r{@=tSxP9>+pLr^}s(a6JX7zS+`}?L&9iB?*qKP zeC_i5rNs?&r_RFK+|tJUhH=^A+6s_PS_~$#v2>Zy-mEB8I#RVO!j{igiA;sa*Wrf* z&>U8Z!9+fgEQO0rZttvi_MpFWQfmw{S(Ot~;Rx$;1hzNKYa15brhRMMZ8m%H3wUfc zzug&fc?oYQ7L2kHpd5$CN{~L5i-f}NV9+UWWVx8!+i5>}aQfw^@BZlfAN}N;PllZ` z;k9zHfFd)cN~TcB#CQ@skPJcdQC2{20}h3KE|=Bmuw)cz+-n`}4$)lB%V$sS-E3B} z8JXef0M7&xB9YIt)mmKpysp&jD799+pfW|3t=6SROX+m8-Chosjb;icCz+xW39?+4 zkB|G`|NaNxeDm@1=XXy|c3Mp}nG~aBP?5!AAtMS5FqYTj^m*Mh73Ellj!~d7GAbt& zKpatwQxqf1igxX3c8!^Qf%mLt$^JoIO1|z@Gvoqd`C%ug|F@rBn2g z>=Sfr&uFx}yNfAjXJ@z5>E66~6TAfif!SORj*cj>oC__G^SdYq5CJTK5AYQqSV9_2 zsQm5UBI7MR7)&Z^>EHbQ--7{E`8U%y>}eB1$RQ;Dt@esPAdJtx`N41g9=#_J#V4%z zZelHVXo*P-!_i|#In(Kx6KDeWP~$M|g*p&9wWxKzX*>jI2ok6{Eo#nI&u;`s&o&OM zq7G<+yD+oC32+1H^MbRr&f=XjVP-vv2H zz(#9i;(yv7)G~I3MQaxpuoX}mBh7cs<&?6WR`u*;|H1uRPoF$^_uZ#2Up{;E=>Ea} zP9~L*1g2O>*Q`*ANqPh!l8~uPRxDRC)kd*Y%clwoC$mv877?Nz z(vR;%c18S7!s86PorGKOv0VRu{&zRz$kOID4`E8=$YPyu^c9GLYJ)A+DYZePSN*oo zy%)UXwmFwKwyrL$URYeays&y@ZsqFA=F+y^Xs{YqHdoiSbb9l)S-Ta~;4tZ|TLw63 zb{f_#Yd1Eoy>acIzBB*5>l+s>flWFYWK%&Q6U6VYQ;I~YOagWk8;puThpTsm_7Ffv zuC$nZh0LmCrV`87;9MEPp@1l-!KUksMmdOM;%ZbZM*wd4Vi;5`Bgz4dmr1D<5ei`; z7ZS5UNoy{nQgGU>b_4*0dXEFjDK$v7Mb*0;wAdLdYLiQ30>P*;KyH()Bd7A?!}`uq zbFf#-RpOKw@PtgRpfSq(n0Sa1gOEdsz6k3MQ4X7TQ*T++nHRQfD~^B>O#`s5c$QQ< zirSV-&A3t^@hgepygyfGGPRfnI$=_kb-3CnUhHz&CY7v4*sLeWn?Om~E);^`C)Z+ODdhtp#<*d=Xs}-ulb%wY zsduGjFW%}UiWNFnilL{*YCIqg75920M!j|J`pWm-zV=`Ilehm*OPiN$zICH*e#3BS zY5gsubuOL?HM$B=&R{3s>?vxUJ4ZSGM9P=S1+s-uz7zt`0WDRCa*gPX;zu`2d&jxq zLAtw}YVV{vyV=@6NmuEV%4BO|sv^imj!#EPAz*ZD&aYkH*j_aO6Iiy~UI)#P6h)FG z5eWDk4jaYL@uU)pMyzh9(Q4A04WI_=Hn5J-X3}lz0k{ElRyKigR_50hZmisxUz=aj zp%1zN&0Jf$y0AV!eY9$G-M9v6o7d_NIqhDv!)Nk@tlIbCgHnb}mFR4R&exc7i?4R! zXTz7x%4rO{=w`s~3N{EA{?QV7R_28%ut3uLl!iVgwgh(fedO6~7-o<6+! z_2=*Z@avDh{`}>rQwccDbi}8`nRchTdoV0j^KvGhNK2yj0Zu?1hr?{MZaZyeI6FGr z9USfqZXWG@^8WLe&+fNsIf)~PfR&266q(Fs>3oSPRrzXDYIG9KzKrg*A7%&R;%KKl z7?!%dLc0T$ldjg}Y?e(XsZuGiyW9NX4?p?iKmPH@AHO(0-pQmBp`gdKy&3Sk1)fgC z`E*K_6H+dd+1(i*9vsx6ay$_V1cQMfL69z&$6~R?_K zt>gniw~`e14@RACy--X`ahBs_91q7g1q|-qyLE7|zqhvslrtKQJDuLn&fd|{@#*Pl zy1JVa)XOMtW2*yz5 z|NFoFZ`cxS5Q{V#|8nx_hU)Aa2+#y(4uBG9P>WugYR$nCg1{^?!2dXjV%zlV=;-Pd zYT{S_{%@z)BB(IwB5c{|766wT+`QJ?sZ3hLbwD)xZ|C4u+!Nd!7FeCMtJMN`Xe8)3+w0+Tr+yBta;03G}ui>yT$5tI)iX7?y~wE z(AKuwv~FI%v2p$Fxi>B>ym@W)g4wHMk|91FlCoh4`6=zD;AAP1sYG+tSfLt4bk$@U zeW5ds1Lfo@WD>nUFpMT(stmvZP)@eVVamZAAZdt$6>w*wuv!RnxgeAAGig7U@r${T zQX+wt)V5e3$c?G?YXiqTe@Py62h?QX6Hm_c1T39pOSlha>Wm$6g^fBHm=VG}k zU#N@ax|CIEr4WIr2?K%i{z8L6pQ_M4%ayLhvJE=l=1M)W*p&)hDcj;RO%62Q7E1ku z+K;PUsn}w(wWv}IOSu3*QnAbDTCgcdCgTnWCTDcR#~In2FIA^1!vuH(a*8D!E@FMd za%tOnLrVL~4Yt}An%#JRm>P^TqrJjlx6tS%l{`tXHnV$q&3JiX%drA*8@g^qW{Z(RIZ{-~qKfY8 zDwKhBf_XLA>~ni3`O#szx2Lpsl-4-e+DRkIsnBvUCYPB+fswKlmn7+U*l5?yuU@mb zjQ+68?X~*?ZkCHlab6TTG7`4itqzyN=632$#+A*DRsA~XvThZYTNb0ivb|~A0_cG> zBmj4=FW-3k>f4v*E?u6#eBt^#Z(Vuw&C73GUAzKtW3X+RoPg#gKpYR@3dX!78=%E7 z@GGx`0Z)^~Shm6d;=rCNx7iB(S~_&0Nv11-lN4paMxAYI!?FpWL$DD!n@}62bRkJHgq#v< z^`anB{(vJcQH^T;Xn*kH$=x4*^~sOE|LLb6J{xyyVUL|6{7Rh7=aYp}2C4wxB$9%d zU}H4l^*Rh&8|H1j*J)D=nFn{z9^b$H{)@*y{QA=`KYRahw_D1`B_S*)B4t%7sX`jg za4M|Y6sjGu-jf==1n_ICmuhu0t#-QEf+eDyN>wS96M#6NtybZ~51)MV&8Lqa-|BX2 zEJJ!dcDoHdNlsIdaw&g!02s1!a&-K~XP_j9`t(6Xs_U_!d zedo@dgM))kr<={@`~BhR>DkfIQKQjdSr#bg{2_jJe1|0n~1{#1EAecY@%fAGIQ5)#1PrxGhju{P@pdExA8u8Si6jW<^N;z8V(|9(04jIzt z;sm}a2g4JTO+l&-RWRiM(11hi2NJjyXc^Ko;=z+QAAa>E4m+6Jrr)~4f+}krMv)kA zB8c=jZcTy}HaRC+&!_2Wusko2g*E|}>GTY8sJVqaXlsHv7;?_-n%O2mX-%|trXIAm zAdT%|brPh%OK?2KwLrA4or4DLausCbCa?i4QIlF*6E9P~!7|C33gqBgxFYz`MyFv6 zz798)+0PFPq|fI-)k(Wr)8G>PqApH|0{MqOS_e=cX6;UDO-BcUGjS7Gpds8Ah}PD` z9*yUBZoF4~Gg+U?tm&D|8pWPx>6u`p`3}l?@#OxCCl4OoyM1)9*Xgt?RW+N-P*lw0 zc10p#L15uL3B6r3DX69Nc+kwH#emmB5^jzQ7mISQR~?O8y+JKolxd!H1ss0T$0oU` z6!TL-i_f-c+cJA?PQv3ReNMt<_Lx?kdh>t#$r`$cz?-Xx-JO!!OypIz-c=x&iOC=> zxGBMHcC1{!{(F~heDCtYTUQq^Twl37zj0%EYiZM>GdWH6pwk|38l9GHm(AjJncQ}h z+iLSW93hv*YuU1It{Rt?x8|1g*R4K1EeC}(A?Ks%GWx_)Mx`O-YDQd*-#V<=U7LZu6te0>ma43%0>E;U8y8#;+s#absj*l(2T zNlFNq92?h{F5Xzaw6?Y23Yg(^A2bkkxI-pw+Q#E0EC4!s^Wuu`%F4zSgL#P+{h1=0 zEK->gQ>+Qa8jrtMnyJLl^X)Yl5uI-^poJD!>I&*0ULDDmp{x#-90bV8twm_CN+p)A zP{2cSF$9Rir~Qc%kwTxjfb9?=We4z$mo<`#Q>n$u1F5y2DRu>^7>Y<%pd7Pz!4+Oh z7Q(eQ3`%PC61_okxRcvCD0PP!wINFBP>?cjI~UfrFRyQ3o?n0St*ignMcq4&fX?Dt zFWJ8e4-H*+A2Nb@aV0q1oXZfCY_csYVp4 zp=yWj@5xiyYAM+w;Y&2b7SCtG9XQY>Di;ssg*9hy%@qkNE{12i9@I3gJK1Vi40 zEEJ2`d@jwgw8LS8_^_ehT;5opUtL~UTf%QWzP5M+KnEj^(PlC^EC4zi#?2ecbAUK_ zF6Zjv)eAQ+T%NzQq+7JO&CYgk&_4q2d`*&H;i`+J!3gx@`a# zz?X7|Dl{XRS}>*hKr_`KfKI+aKqgR5u|+~UUytPLWTnf(PYX!8)|cQ%%cepO!UmMH z=`e1&OlF^L+ilr$7=dzNNlSF4r5>K`@1O3~JJout(&^R{GUswzB#CY}%4f&B@4a~R z({H}~`H#N-bWY+nsEyo36DIm8Mv1z+l;Oi!IjC$8pOw z*r9T@2CCHRsaieVXlC2(e79RtRVAI~Mx*BG=}xCpNu|VKz~yn2xy;TP~LegZ|0M(Srx~o;-PU z>-OpK$=>PN;mPTKx7U#3?6zrhL$?fSFzTExYbL9VclxKNC#TT%&Q7!0%;oasGQdV7 zlgU=ARZ$dya^SFzkMdaHFprPCI1FIQK@&E!liH~OxBytx+igf6-MWP-=iuz@H-G>4 zU;q5)|Msu{8kYa=fBv8G5_keL#Cc$X)&0|xbCjbs4SzI&1gt?ofQDxF2dAfy^DV>y zg&v~PGxQ0n+0DgMCtK&g+zI-@7hmAXo+;&gg`A+ap{-wIT6#SYq5fz=5Oorw6pCc8 z$0}r@$z**hU<{k?TLSsu3J2CnH9T0&CuBm@pD@n3>xr7Xi9`4w)@HRJ2SwzmKn@gP z=TM0E*KZ40YTZFG7$;@|8QQjgZCqMD5=evKwy-@2UY)p}-tGhIP=u?16X+6*MWdRj zOs~t~-eS*4UTtv1zGw%X>m;-aEo%*G>sqH!K6F3>9W1zA`2T!eoC%)s?_F!+watk8 z5AvN5^Pd#(fLob~)-2jzxD}9D8utz(&391F>A}vp*UqJ6o+ z-AhbRxU5BU0c-6Ep5&(Z!NBEuWs6OX1B>6u)7Gi$zz$EDHbOes(^AZ;>;+A&xbJR0OE*+u&hQ? zH9Ftq%N!Uv6`12l^vb&^^v^=v%%f=Bo*{nQr#WN{)92EgQzA zYl|1x4NF$H(I0UVv^UE6Ba9aiCm3@?IB$r8kZG~HbX%sywasf=rUgkM$`G)!q@0Q5 zRR&<9*-w@loKg%YOTcYp7Jrkg8cS=RSkE?@9E6#kR2e1H4OT#(^NdI(lFJ6Uj9p%98DT|~kbOS+|Uq}Z40d#TQ0zSI+id@!1Dgjf?P+Qdwt z+L8J@+0H2486-P>WiZZ+_lu2=oGnqD>|xLiB1%mR9TSoteB=Uq(%etj&@ZZMbw%tI`Awl7i`2=V@EhMtMoZ}K%O3DCOqr22|RR$2J z(iMS&t3CL6(10=kG(a}lS_pIoH=tTRk*S6AtGyJXq9TNFSgm)X=`c>1~ z%J#b6VYG+c)_}w4GOd|5R*mZ+8vZ$Cy5mlNr>izfNzW(^mt-W@;(CHNVgVK1fGTJNm$N5H2hOQQyOsU0WD7lM(CnLbqET4x8mtCYMzzYN6LfFUWcK z#j~IN^vA#W+0OuRe*D890p)z~-uu8W*>r}cXda*}Mti;fSd2=i)8%rh(Wve0jBedJ zy?y)a{)5|3pFO;J>qxESIX)JIgO%6raGHI7S2PwbtNGo%(a!F8I2?An-A1EXESB>5 zVxdqDJiu1?Y8T)LxCH_4&;l$mfO00G2csLJ9Bm_@C5lFqK45`dh+~rq*rV24wA4y* z5iD_dJ1?^ksF_a$Pv?LjhZD;AHsV0pw;X~cRKb~(T{0EOfg-$H!3-Kb7rS2x?##CY z9OB{5JZK%5^$rQFfZ(Pzb0m;H-^z>+AQ#!7aUq_@Ory!v_c_kMmQ%s)Oo}xB8sFf= zM6?+vO|<-10^@^B>=Ojr%$!b#hFXVADAKARdG(>L?~?x{_kbVp1})-lpKp4WGfhmo zhmqzxD5qH|7E&_#|7Y*NV`SIT1V8W}Nf>o^)qB^Z&&crJ2g8#Q43fcMSO&v;?=#Z- zn|bfe>)pHN-FKfi<*V9vS67eeuI{Rt>7E&lFv3F6LJ$^f1POu$i-i_gEmpulyMz5m zM&`S(s(Lh72>X{le91gKJm))yhm7<64$WZ@MZInmMG1;ZuxyfL(_A_j4A^YuC=;&N ziX#~Cwae)wO;adE_=u1PMIEtND3^7t?9sR08vLcgc zEe5LxvAAq{n^B=tNYzq>PNp^~y<3so|MVkoG|0d}D;Cn4RdXv>m!xwm^7&Q8qErn7 zWho@nSv3YkZ}ylSn8QnY{9zwT^I!RaA?dty`MP9jQNFeylR#K!Hv&i@C}Q(itZt*h zp_1#DwN|M!U<*uZm@09)__<*;v4 zPB#X;l5S8u;sDBkUOaR>L!4SDUg0T6R6rcIMx^T`e>tQDND(QvBc%>g?Z;|@R=Ux0 zhky2hfBL7BsB}`LRs3HGWX2sW zVd*AS1ZbP4+gthaAOVEOWPK6NlWT-K>)DOH+U`+n`=9}EGnwXx<4kv$F4gE{#!to^ ze$wc~)OMc&mNu_KV_C9!m2}FR%m&kWf@GYCM~!$?9!!_uuxcyb?4;U#7Ay=Vnej$` zeXB6tF76&wk55}ir;US?>gIlKyv+_alYL%+a?+#S%w)f?eoz6*X-&9FKbdVZ@gfmU zW1+Y=6!S$`yfv)ce|CQ7;n~rRor9z8gM*#NkMBKy@A2`$UaL_H;Q_17qBZI?MxAiw z#-O(uB&xORE7zCht3W(U(v>CYG6X9}0$M9XW0ciqpy|+X&^|fZefsd;m!E$0qwjwC?BU(@K{t$JA=C@Qp?0&{ z>$TeLdbL^v&`G6Yxh$LEl6b)9b0ZXv6*BB}+&ekkd2sji#j|^#eDwVE##X0W7>p|8 z_3B_!?2mK9X`wgC)cG&OMeBoTt{#eJ+@(6x>~M`12Z@Kn+Qvp_cXv3QwyRYx9uGl> z6AokPGy{lp|NhyHlfA=(ottOJ5AL78_w4aUAAaz??|${sn>TlEpFe*1=%Y6uK7IV; z=IL3x*-9l-i9{+EOGF~kbegNz>)mc=IP4!D?mu{N@BV$rak@So7w|AzydpidQ2S-Oo`}+r@(YVv;wcDL?xe~;2=r-S`oJ-Fmcon`!hE120 zGwZ_Nl1s9IFu(zX_ix;Q-dqg-i~sV!gzUf*03X6d6y7QX{wwhl;sSO6Pe54Yj|-0m z0zOZ4dwdpN__#}V%intvX2judPKg4Q6|e3<(Zcs1gjdaH8)ty>gFpHs@eygUXsDt1 zTn+?glw&jkB*7}=6>|v==xu=*@p0GLDhOXSXfeT0i!#eAWEb6===Mb6-LJ69XTFeG zP9ZM{>?0hAuPH}-dtA6y0WvH2LWELy_sm~*5Cp=aeetkDURZ@f`D1n=uy$D!kV~78 z7;tPIGn?44j6 zl8Hnm+@<0Z3%kQ7zg)f4necn~HO4`1z7)~8Q0%NeAmS!I%l}Fu7RncSA$%3yYUGQv zgWn=Xib(StC?^pn;#4T;a|7iBFf^HB8!)CFkEfec=p6ihPdpBzpLDZXs#G#`7-J&A zYBihB1MdVF29HLeFQ8Ivq}Je{L1r@vg2p|lTW{7auPrT0me=G`l}@8E8l)=4l4Nyp zb!kPqvZh#*tK}-4N>)nh(_s(h@rQgewe;K9zIA2c-MQ84D~c6`UaqrhjShneF`8Xw zi`VK5I(?K6)I)gfD5ACLmlTq@wdHx~>eZEn- zp4@8fos>5Z^OOC|V4H1CV$Dgcx5W;2vcsK1bCTvCu4>Zh8WraJ-muN;)7pIcV8l~w zaJ$DFyGNT_dy}2Ljl-keTenW`+&MctJ%%xSDjE0s+!lw`WH(z7tHo&nO3+%gYNJYH z(x?pTRr%`T+LBBySL#%9jY4D8LNYk3Lp1KkeZHVK!Npts#`eL+;o08y!L-uKyD_`f zt#=13A;y`^2e>kxZvd$P)>G|C5|D_8 zW&r43tUgFqy75ATiDd(5*rB${7Zr;uYKg+EHhHXir%`THu4&dJs#TlEM#e}spDNXh zjc&c!t>+3H!B38-!*PGF+dSOgzJGq}qt~y#|K;b8?w*f(op3OKy4|H*b~5Z8>~C*x ztwXY6Arob&WP(Y=BSF8%??xCZ1SB-*H8-cjo$c}Y?ZY=8JUO|sS!<-*y_?@pl`|fwX`0jVU1by}L#o@uh?VGn=y?FWP!NZfI<8Hf? zNpsmuu2?L$+uil`>Gt-{?k?!|ty^c$pFey03=-by586OBY&w?9vxOp8EM+Rye6v;Q zbQ_~_Z)0-|NObGgtvh$_oS)wT3%y>y)oK?CC9lut@p@->tiI`1q4O6zV~}5`9Nvdq z$g593y?nIokY%n_!;F00x|!m|ABwU3KByOhyf=c zW)v|;tdD5n(hh$K$7Fi>$;GUI7q^_=RuHI?nB~9tZ~vSB^Z)&SfU;ix+SA8kP59D< zMgSiK?nzWp#C?Q-U{a`?ctL;{zJ^d&h~*2tNX)mC71CGe2FuA-?-obVXzC4 zkW9=4VX-hV3q*tY*|E7eI*<}JiOC=#gdyhb1R#R7OaAy8Ye3*E5aEX3A7SUj%E5nF z6(U6uUbN=7&n`9bcE4teSu0&s82-;FM_l2n&I_OEQea&uN)$c|pYpOjg)ES2mKp+I zQ;sOJFx2Ah)|koLVWA+g&SJ~_T{45mf4^H-VzSFZ!9HK@x5B?7;!cW4^BX9Ki_zr_ zTgj)}S}rETD3gVr6X=phvD& zszPpG!)JDwSLKp-=H9)scvXC+L1pBp`vcXO)mp1YXV+PMHsBjjC+;?TtQwnMW>86W z$~CQOSt-3PSp>>4I89osR%KKw4Kk^AbxA(AB)=w6&zW7SaKfLdL>dFG-e+sQ1pioZ zCsJ{%wDi!Yec+)1JH;n-n3%MSh(P) zL5nEE&#=sc4!}?fSVwpzo2`Vzx5`tcKrHKx=ez(q*&30nQMp<;TMOr^k!*!Y<-@Tw z5lP|zF-(fW!>9!@X^bj`PHy+uLJ{2Qx0?_h;tpg zv7bm*sdR(Rw3uXtiWl*CF_c16 z%k4yOQXFsA3YDnauSY{>Ch0BJqy0%?vRR(;Q)ZV2lWe0CuQcd#o$L-1y9brs!^-Xv zAWmU=kOj)=Z?lztxY!{Y<5+7w*_^Ps7ENb;0Buy-=OWBHL@v`W$qma0Y9?YB!%|!! z+2{a=wbwUBLvZZ9X1m*})vLvI{y``Jcco6QHLLYjt--3Zxvgl(=kz&@HUj{NU7* zDnwv*hZzr{-A;3FckArN@$;vTzx?!*d$(?lIzTzN+vX@{vKy1}@xk8i_C~+cEEltE zGMbDZi3s#eprTBcY`(KP1u+As`((NwjP+uoYozjy1^%cmcG`0De| zKKkx=KL7srz7+JUAAJA2Km5V>KL6}f{+m?~AH9C{{=@qZ_I7rGa*Fvvz1HaWhg(}a z`}>DSNBk2uCnv{u@1DPS@$C5v0G)@^jZun?)*GeK7;@BF?doK`zqvI5zFD6RhokP+ z_QvVyjq~&KyLaybYUy=PKCdMYJhYPE_84m~58ftu#W3VxfHf zg#vjI?ehf)0zrrqQ(UGI1QPP{btNzM2qI@mc;VB)KgcX3zN|UVBm7bjh!pd_C45G( z$X7-<9FPbS@=Ly6vw&b|wtIZ|t#`e7yWbQ@0>z8gVRe@7e+~H+$^j9oec6hHAK-u853eK;O=dhJ@h4B*memJ7vnnv1b%CKe}2 z3T2`M40O7^#&ly?Drc#1(Bnny4ofzdZnqmLHXb5^FubulY)~%jJXF{2aM%%1?S9Pf z_50LX^|EATNwT~wU0so_>QBn61{F}wvUGVtvM?{1m+Ry@tImX&j1B`(j@qKuShXg% z1qnEvK^GEm0p$SD7+qGA%cgf&Rc1Zlj>@dnBSxKFuY*3_tW+4*WZIQA&Em4+n%X4s zg}{Rb3XN#73CiRf;anYnhR9cOuINt}eA$Yh2c0HSZ1R)%6`J8fE0S+BfH=8!B-7%j z4;CpWQba+cm0+wEqDvT=_mKr3bpbk203hMBS+o0AH6l|Zb5I;VAu<6&_DYw3{DOZ+ zy&W$$WBGb4Ta89i0dLR_5M%Q|cW*K~VQCRQNaV&y6psXbArFGutRAD)V{l?X2Cig2 zoNpvc%~Yw803fKh*}3)2Hz>{ED8IYYmmS<@w_jZ^D;Sa ztcU`N0l*2*R!2&MWN)`zn`Bb8FxP~bXrfF+vREXGGI`h?pd1;|n#16zGTA03Z?;^B}R^|(5$zP|}@1A)SLw*)%eD)gqg z_Bhj?WcwS%-g>b!E|l7-RFSr$<|XCgiiW2g75sv1TBSv$cNkol6HcdSnxPZnP$UGb zQ>qt}Y>XfSZVy6`!A`rmyR&_KbnxiG{m(x7@ZsINTa)!DMcYl*T$3 z2@_?lXEzROyQi)3ZlTx;qom$~NX=Hc*Jmb4FN!+cZi`+o*J`DKfV+@qcXy_b9^U!j z^>aX+*YCsf{V%`x-~H-KK%Dnqy}Wb#_N}v<06O>X+&w-#+E||o z(;si1oSYsVodD&WoSfXed3Nj88Bor9?>!YL=h5-Wey`u$-dR6AJKWly3`d>)gDnUj zLg%GfNa$?)*-;PmtqKxc1n9|nTeYK>*n;48pm{0ilWm?Jtd!4>fy2A0q@3*KSY zcMJVCFTB^i6wwV`csNlYGZ+w!hyvkDnMLvPc9@s1&4Iu=pZFpTAJ03D z%dJ9@V$9e2w!sS#9S-c!FNYAGgVuZqk%J8mVY`2T1yUfW4W(Cbe zj1e|{qZG&phXM|Pz#P1QVTgo{vz%{Tq~VJe3i|aDF0F|oCKeM3J0S*Ux3p#@T@V$d z6l{Kd&_#h&*d*W$Z}ZpX?YyGEnz-pwAjL&8zOHWrhDa%}3t~#4vb>0bJ9Nir0T(vb)s2!(>dAdJ8~z&0L_Cmg1tQ6?IXVnNL2u=z0`8t`lN+EwYw zvUFupvUF|n`rPVb;%-o3maC0wrCzDfD@+dli-U+Cv3u}mQxYXvqxS4O!Iq{1P!V5?I9jofsloKfj zm}-zNW8o4isu(YVPE2?J87L>);AyGUiB@>BiSdu-@b@F)l`bq(?QyO-%vHM?obkwY zE32x-McMphKZnP!tPA{d6i=?PbS1t?7PeyjAax zii7p?`c8f8puKzC+d67b_v?erLTi-f=WYgEYf_*EV6}1}!nvrllj58}IXs8eNno9L zIS8QB-6=JuIj$K=H+TiOAy_ZT`RFX58AETDUMsRVTUTW+~TA#4BXH zOe88~szw3jFiBh7{tJDUy%Ahg8xXx)sye`D&w7IQ_&*~4kFw)}!UA~}~Nitl4i>9I^LxNIKii(oSOrqQqM1O;x-6x6><~7%2ZR@(_T48*Jr(2FAO^$!=+~TNbneOK7y- zw9sA80~(IDs>97{XIv~cQ&BGD3|JNL6R>OaE~7>G;TT;ei^l@z5*Z_6T$D*g2!V2d z!;QtNo(X1sg3buZ)+=$8xgFC0cAksw83bU0YZr^lo2(*qm%`ZSL>y1Lz2|0`Ao7b%u$lby}5%|5_*XxuUBR z2$AV%p}!Vbh4f+;F(AsXtb$xRN!ax3TSXB!i2}A~Wq`n{pdfrQ zG36|9nM<%BY`RR(>o+NfCjwDt!be`@o>>zT&LS^kASw7T2nfln{Vo*IOYQe7s#6j%j;c=1Y*m_QKNG}B9gSV$lyf#QC(6p=p!5%yyymxoDQ zy-Xm+LmpmdH?1zN>--&*b7==G@RgVy7e4VN*$9yH|0CsyB9oK`wQRBOdbwOA-*Q>l13OwcqL4wD$>_jp_`7Xr{zt(NQcYOPU?M8h_R)$MhG znk+`G0fxVNwL!C{luA`n@GEHFkETrEOUzC)@Qpj*b_YC8ztifnnGmziVbp^n20daj zAZ7z%F**TsY(^)KICj6=2P4st-|Ds7ymrWLLJVrN(&*5coPaxP8jI9}TbXpA)Qp!} zaiAQo97^V~bTN=A1yVULP!3!0WGiT~NdV=PJN)y)`6itezP>3cE6jHs1xhHQ;UY={ z)>L@ViPb~V8V-R-c?Lj0LL%j)FJ7~%jZ)2ZuF20plLXKybr|5D`he|i6kFqbsh#!_ zjz!ruaJusn(78qFl0>;C*D5t8oylPa=5wM>C*}+>!FZNQ6_{KtS?%STBN)n8ded@i zknfE0gN^cdr?$S=81K~vJEis{Q|l+8AOY9HxfYdghf|dRl|~5G!GDmU9Dx0bmjV>$ z39+tdAyAue^+_hvj3%q$Xdy&r1K|uNXn@HR(IUkZhzP{zLy0P#@1;t>CF301h(-!{ zqC%w`3|ptu^>DTxX^t|xr@e!-{?1`*G%Zx>(Nr3ZL=i3*s5BytZlXP8!M%-lOFJj+ zquax?`_sv8t=vx3`&@ro+Bxj+9Q3=xLbezQk`8~+jE1Zv?TjVRXu=<6To$`@P5ut3 z!Mqxdde|(P$`IkW-;3J=VGo@mJV7`ObVfv{v#FH^*@|-c+Va(fwRxFtO`={|kj{ZF zO6P!b*3|qrU$th9#sqMqlB#8EDw#s3(pik;X3&CIBJnjh=EO*Eh(<9I@sTE!@K7;4 znhGZ~F*cV>=h;%d0JsoMF#!?-dY~ABjD+IpSglprIox{s^6}G`kM2Ld{aCo7GuiCr zOG&O6&6J|~YP{Hh(-O!A_+~~qqBaI8;MDGVcCeWrZu8e~ru)_Py{dpXypFa3bV`Fw zPzcoEWTV2S#^V6F<-C-qHibazFf^p*!N2(C&Omc^} z2KV3FJH0o7ol4~bC~kK941UxGh!cyE>2x%gO_qw8cB{HR>7U;|ef9F$Cm+B5@{3Qt z`tq|czxeEvk3W3z{MnuJTStcnfHJ*Kw^peRdi}%wgZE#)`oZ_U|C1m6`14OcyLozc z>*nqE-~ZtL{fC>I+lPloXJ=>o`+K{)JNNG0dGX@C7cZYZd3s-9nj=`=ymbt?1A)`C z!`tUKfPSVM!)B{iDizCR=*{YtN+pxYk|gDDAaa#*O(q4(0rv;43A$b0zh1o8E4r&$ z$9&;(W-FrnnyVAD@G`r5!w1DpLhRSV`<8EH=RG0F#a2Fn5X}qxhk~JSLEn~Hq>xO= z!YBUPET8LF^erR2gXG=YMS!kp7#9!(VI=1rk6_ght}!>xx}uzZ7v3$ZY*0qi|eiM;2nl zFys}m;D13N38WOtos|e8*ts+gi;H6?2!!8S;|10r37<~DvR^M3VnnmB6x;anstts} z+{G@;C>-K>c$qzpbE#lf)EV4}A{gQAh&ADBE|er15i9WTkY5KMhSr zj&MlfT;P9b;_-!D5I2cP^BX9q)F?zbrqnDpdbLt5%Vwg%klSk4s?-vhd|4`6)M%v^ zs}>Y-nn)@TPtYL(C8=P(!1emA?Vai7)?_^H7mArM&0o=pMkCNy2KhNh(NHKz(^Q&E zwK~m2DrQG4HiyM*HCgQzhs*BtIvpOw>a;pM4j2l11D>7VrwlfO(QdT5t-N3NyPT*S z@wsdshu&dUS#(mpLaI~9^eUBEr?Z=NHnYxd(L1abz#$3;(6M?QHZKnZCWldFR08YR zye6GZskbY=xGl;C%dKRklPc61u1o^uaHU|j98BkZ$(%baQcjB~cj!`wF0^>W;TqIT zFQz=^DW}9!4uA2c5&*u5HwY1QqLmQw=87FQMg7m-v3t;u0=coCOyMF%DQWGocr=yE$Z+HO~S z*-SNB>2mc!mVZU7nJ9IV{HG}UY^9eh^%8|P!&912|4ft0w)t1bQ?+0?;|gbiX?$Fh zD)r+8>$GAD3#xEa##DtYbP}0HG+rX9G)iXz(E`cjL*Yy?oW)5l7)ql!>xU(PPO8qN zn=!5xkCjP+LlYG`+e)zYNUBP4Rl3?^Hx63cNA1a0rP7F!5r^BSve;HalsTQl3bk;( z8wbi6?G&d6^_?4?qw`T?kS61(Hx&)}f*zyIxFlUw8FVhxZ?s!w8s(ZwE>TKXm1`^V)rGai zW!bVqFXz8osa;!Dt}IFyBr4%kLSax@J$4^~g}UUec!$P%EuK_kwn-RaCTvKbt3+G1`xPBq%q zqtpElK7RGV$1k5ffAIX(qgQX9-MVwMwL2V4>djuE-py7!T(!#zh%=*{S}$4ery2wP zQ|g^braR5{Hh9(&2T@9r%CkNXd9 zy?Xuhl*V)kajc%+}2V1=Kam1+oSEHR;`m{v!O^7B}gxh zdnpoQQ%teQwVKsIzdafE#Y;qB{Pp`U0B#;WxOeO3>G2`Z%J$Co*3Q=U`gqds_Kpva zUcC4G_kQxbfAyC?|Hr@hwJDe#4I3U7eDic zyj*y0@!vN^OfR|+@EtRMC3>t2;T_lPi5z}|XkC<9TQ07p!LH1i3Www(!SE zY@vTY%6VICw%H{gL1vMc1%W;I1G{`FvzF)imH%B`P!8;Z&?X>%_j5V1Ow>#Gh#0}7 z=r|jpqd}+3q}9uSZj=zdNIXDlPRWJEA|KNjm`1S?#9va zUa#L~)A2+y3X~I%M?oWzFo2H3VGH7cLMb0lMlsyy_99lh+39w8{4T&6j6msln9Zf~ zl^hI$%^qX$WzG8E|E12V1FvJS@$<>*twxPWC)Fwz<*Qeg=RmJZ7FU4)%m%f^sIi)0 zsdreAfEU3$28Ts&HyRz_XVg;7n$D)NdQ1j~#^lt(5I>R(6zYj`JC&H{x$(O5Pwr?(08kDC=_@qgQLGeV zD^#hS7;RT4JGJ&Oo8T~;Q?Ay{NfqDnpy~wYPZ#+~7puK^W5j}XH}ccNMz&770=huh zK_}5tJvEqA#~ZC?r-0!OvsG!bs0>DhO1%dBy(*bsSiCm3aCLrpPNG<|I_-$pW3XCe zYW4Ny)g`GyWiYQQ)K?dlt}m@DtgfxdWNRvgL@ASL6&j0HXVYn|8jV$>x9bgv!GP#Z z{M{TYf*}qJQJPgMr#8Ua;$tjW4*4m>h5|GASs&09Dd!3^6K2$w^ua_DvR9c(z|eHD304vo64dzyG(E* zm0P93v|nzP=on=*>kLM%(`kqC37283)pEPp+}YlK_~8C$AAkD6tJmYfh^E3OgAvC9 zty=wffB(sY`|HDAmQ65Jh$ez;B3iE$w>HMNZ{2wBy+`-&-#$FtIlp`M;?9m`TdbQnZj7Njro$Z^aXSZ+Ox^;H*$)hK4UcdR#4}SEs zpZ@HZfBnm!|HaQAKYTJCP5QmzU@)3Yrt9k))9Dl_=kRd<;lul{U%z_s;@Q3Xw*YQ3 z*(6|1An4WUm8+5kschL`RJ+`Ei`AgjsqA(eilQV*(lkvF6ov`&>L5M~050az0ShtUEWhrlAqJL0uRaq#R^TTgF`rV57aYq>_+)(Hya);2 z_Mp7oOM!Jr557ZmBZ7#S@~def%-azH7pwnn$`SnCg@`eN%#1)lNW({qc6iSU4)vlM zZ*3B@&jj*b>^|QDAQ0v+nO(Fn#9USnswzaoRt=;Qns?^NK_Dzx`nn|{^3pep{uN?` zYR|w($oI8eT7WV{BbTNiv1sS-648@GDVMn}L@e+d0+EnJyrd`kb&$(k5D*2zP%hZ~ z6@f@FGOP4kB3R}R2ZZ?D6Y|1NLj3G-{2Jv5_QazkSP<-7%H`1#O8Z}Efwu+PLNqJn z{#6l*n;i>re=piWkc(d!zc0e@0Je%q^BX89nr5OL!=xhNI7u;h0C$@#YL!|7WCNfh zlPzj>GMimbg|SkZ>-OsXK@0kV2t&l;G?z)X+O_SS>7Bc`U|A~XQf!=}LIe!!P%i+h zLLrk%CGf*XF)ta$6D$*=0tk$8eNG?dcKe;apf|=w3)Ot1TTka%m*1(k=*)k3e^INJ zs3a2Q+L}rx(J!YNKs8N~J za-E!iQOm^Nw9?tsdb`T*F<>N;%7=5c7+0cF1so_RTM3n$;X*BxuLcXXK(T>WyWv`& zDR(1blAaLj4`=v0Tyz$T6+&EgGzr?k0;4M zkRLxA0bXUxOUrX}^H=8=uP?1G$y5rh(Wo{UWoqrJT(z(&ySlJCw=7##XqTkQYfG#1 zt7}U#xg18-HnYiTvw9tNKVtLQ%^r&#b@(X13wK%IZ1sRzoI#hHuna#B`1fd{X7|PI z4iwSa_4CpNyU&)bvfcB@&W^iTr#k&wy1SVl@bPCaKm7Q;JNJ$@ zx4XmjYG;^l4YN)D1;BK@&k9#@_zO9(6h7FQYQxDhNekZz;kCDs8EoYzyXE!0>U6&* zT+1o9$Juf_5n=rZs$ErGy|(f@tLg=XaZP1WnA}Ep$fZYg%c>={S>;3>T#0QB8l`%H ziHG$jwMM6KdmQn2q}^%c^BDj%LCd}z5BB@rd-v|V`QY{YuU>UK9h#y%Zg-d>TaEg3 zJlfeShO%@^rh=9TW=1XoSH60at{^Yt`bz2X{Vv^Xks|*~#(# zjgy1JgWcVojibZ8lcU4Ya8NCmE2UDiUf0`+(ue$)kFE|aKK3ow2Q5m+jfD3wa(a=B0_q*Ccfgb4(KPN&P~_W}2S z0~1}2&=>P^@&6klZWSnJ20DVLdfVagz4lvvW#$AR667tP@-?PF7;=FrQFwzwO@#EK z@OcH>LZs-9L<{2fnefTPbV8-XTETJ_hD{gQzpe(zTSoY;7isua5W$9EQeYPNGn*F)dxg$co&`@b{Wv{qP7s`8(I*4)5X;qFeD`4MT`Lv+j-`7e~ohZ z!oMjH3E9CWSiZC`$c&}lwgw_xqWJo5jJOJEL^~itIlPGWF9l*?>&*6B!sq$si|7yu z>G|CdWLA=8HouN2d@ix^XNN>=`5DUa!Z*fDAPno`rkSye1hecHc0{uvVx$;=wBl}x zc|{Rd#dr`gk~e!%G8p_75#zxm>>@NZe`!t-;lN(X?D)bGnnFaH-#|Gb22W(;QI=tn zbR^$L4F=y*wNk24E-R(;(v>UA3)fbcmK0Kz*&tdr8Xj|rr3cBE06N)rB;Vm*)GBnNwNbLSnQe|!!ZXM~ISd|iSiLH}U9Ppt z4GxXPZE~WB7x!UgFc>C+VbbaMm=KG_Wj8ymYO~trwZ?NyccXc9XQwvI6G>kv;R(i_ zc+wSOJw)2eE9W6I9xCGv=X`YD&%fVZ4kT*;Iw28sO2Zf^A8ym-VIoxxg;-~p^U@g< z5Qn#x@BrwfDv?x$p*Y;fxU2z_8c{6k7C~3^OLDtR<5q*Jol1pWs&dGHery4wCu~Qf zu22eKD-g>QsZuzRCxVR2>{2ev-@U%_Th}GOt+&hYsEbSiiUpIEaHbi{wUdP|Tk3Ia zg#m7}dUR6Fk{Qw9q&r)PcY4*{pwaHuVsXlWSY)ylK%6UA-cZU?uhrx>0o)jz`Y>_* z;V+o~?q4rd{`ubd`!d*SL+y5qf0$im)hw%5udG~CTh!rrD3xXMdE0;UzxxlfX$|~X zaMJJbIS{Ai;O6q3-*s&t>oeID06jql_{a036qWK*Ody*}9qi-(_5bl(w{MSj9}PbF z#P{R7<~JWbJHLB4*=Y8L#b%eQ3s-S~Z-8NWMXdC9jFh83+}pTQW%F5-Mw!W} z_u{TtI#Q@+iq$NPJxo@e-lzsg4wbLgigbj~>D9p?n$KtV_jeyXyx;G2QptFPrr1=X z+i8t}7FzXQyWVd%wx*-AlY=|AZ#=kv8z|@aWFH1R>l>r#=D0uVmK()%K1Ii=NP>#8 zG)j0JUNahUMiN0TA1T*Ujdpf0uI%jh>kTdtu={-0V9--2aNAqck3M|;-S2#H=lmv+ z&Ha1lj~_jF^bok~{Pg6;csME-OZ94P*dN?FyZP$H%P&9w;s@XR{*Qn7qu>AC-}~b~ z{F6Wb>EHi{fBzr-<6r!ffBv`s;-fboZ>(<)`lDvEoy!5Bupj_B=jXScK7A~H&Fa~E zj|RgI6D1SLNSceYY3SczP{+SXx__`ep7db|S1jcVg*<>xu~^FGa*0IJ@5i7^M=>-^ zQ-MH0bV9JaAefmC76LQ97>n|hqY*AP@D58*$SC3tbn&7axD?SJfL!_m_%FHv2#bZz zin@?X-vbH6z}q5j6)b^3;6g7qUkYEXnZO!s;xmfMXW`|WKI*Nlm)7{aUuPGEH$MC1 z79WNMWQIKwTjmUJW1?jR(uL6KuQmp74x=cOY*=Te&YFs@YN_tVo;R#!?I1);GL!77{ z039OZA+ug8=cNn&ND+;du|ySECkU*Q>(bc{4XcT25I`r_<}WxEy77EF&g24M5Q_rn z_@X&7k|9yXXAjzRE}g_6xw3ZUUCF!eNZy%O%`fYg=ah3-q_Fy}YqED&^-F5I+~n1n zd|I7L=_0LEIuK3=LUFIjtzOm6&&l4oE`4WFc}?$BVNp*gg_2w#k|(02aH<;R8i`CZ z$z%z;->|A$_X8ZAm9>@Sqkz)ah*N8`$qhQK&1~@?{&0{^God))qkI;xMQhiv zN65XeLn&hsnjyLLSnTU{iqwzArwMs8XpcjyW53_51Bh(a7U;0 z|L5QS2mked`rD&%tA8pe$3Xb6+4G2#9&Trb z+u0%iiS=xMlMjrx3&1*q%|dUQZw`TSVr1NDL?klp^;P8+qeE%)>J^4nwOQsP+}@DO zi0JHIvp?jfVt69Mq;rWB7xM?)KGc;jaP>wx%_UrJ`{L4drAp>@Bh6;*&YfEu8~6O^nM~~LZ1GNj_D*5DxGR~z5=YwrNdTsan3OSX)r6x&9A7k!jU>tJ&&CtR5GP#m#QS=yZUZ zTnO-u0kMJik{f`26jGg126&|B=LwW*0CALRlSXY)1Ldr#Bulb|RppY}CjBlivF3F z&~O>!L8n20@;9woRI&+5Cf@q8Rh(BW&VNxMm~WGX4pr<>)nU9bW{ITJWFqZ+bs4WHnyKAe9zkU6k1=;eNRwg$nkRVcM=c zhlrF9i@GqzjWOOp)b9`b96`k3Hp|TFdByVYEWG>M3-A2);yYI)*RRVLudH2vXXV{@ zR^GWPy}GPfk{Z{PR{5%K>0Qb1s2y@F<^`JZg%K^HSkcZesjsi<7S(nI60%WTh{_Nl zHV{e&@pO>Ngd#aInh)a%)PSg#ff7NxuP>EoE}S%@Rlmsjm;4_o_rx~GV7LB z=B09pMz6NHY<9Q9;;>qsc8Axc(5bJlEJ@TVjn!)R`N9AAND{&PaFXa8W~&zoFrj3L zjppJsN7FTA_l^u9tj>@<7{j8uNWPsd_lvn!E?G{5Im+lUEhrbS%jV|f^Kzry;x_q1 zE-He>lLQkD5+Oskt0<3LT#YK%Qln9KJnr`U?Q%Is5Ezc53`3D*(Cy}ZpVgwzWD!{43!{Qu(klm9XH)&Jc5*}wKzn&x!bmMIe13Mots$kh9B@%oK`IG{0MR={L$ zlO1lSM?0DEE>KRUzsXJZ3e$t~WUn;ZDGs-a?J=CvKsksJSydY6*VI=H4mnVc)~YZ$ zwL~mH#&HC*A*c;dBN+A*On^y{u_PS`dC{OdS4fvDd7MCvX02pxQLT|XUG`Erck|ZC z(a|2@OTXW0Hp=Uh{^rJT&}-Hz`FNDdWs;*o`(S_T?%kWmC;QXQalVv|BzzzC7LSt*gC`OM$1xli?e`it&yIm|fNX$o z?%%s}dgJ)c`K=#(|GR(jkN&|gfALp;{tH_uqT|sM)GW;a4VI(i>DjMB6*-TRW4j?eTPT)a^IR)x0 z442F2^Mz78kt9eeOcQtrOC+Mj0CFRWI!g)Y% z|0_N~6wwWc9^!4UASM=l2}HgvZzmAtn^|Xwa48V~Rz4m+F4I8V#a4kizLpE;30uXK z7s>uE0h?kgi2hO(XeFVDnFvK(lp?J1k>ZL_%C87m&}jJSiui^Unh|ot{z5J>0R&)G zbi*LRb%vQU7Mo5mEy`QfxR8sT1WR8ZOIYRGRLBcPzDYH232d7=`ft<+a*2^b0W*P3 zylLU&;78P)?BP6SQA?q zM6@iV=Y`)aSQc8AZwn{{R-rht^&s(O7Cz~vQ9&S*ud5(pO8!T2QI_~?5s&Y$2y7LR z<~L9dM)=eDR5TUw<6bZ3^r4Ob4g*kMAn2yTSh1Au_UhnZ>Wvb>jmfMPdjY${>_=Vv zy=pcF8pQorzzcAb$);d9*lO2c3BP=;P6d6XMys&c3`7`fbt|A;EAX=M6Vbn`BDv3rZ)u|Om zt=4ALSPg26UJjt6Q_6KJl|iGk=yg^-EH!40%BVEhv<|O@iUra|rdUr_J8Z4TKib(H zr@Nz6dl+vIW9?D2w~-obbDb&MoUru?TOG5dK>|RBYlf4;YvgnZC5wKt;3EVD(1}!o z(Rv6dN4$Z>U)KTX5x@LU#3BVhGgDu@jHc_sY>O!N=*A?~+bKp17=r7NpwUf$ul0u# zL6pYqs8eayuBv47(v^3Y=fAyh_3Fypf_%x~G!hA-)Gg%OTrlqSh3)=`!xypn7^^>S zN0W#@#Vf`-1E6UaubeZ$Apy=2LxvwY?1+Vw@{ z;)-@LP4t71t$_wM4i7T2!pOiHs&YqV%+Ce-QHx3(t-hdW#*>GgxR;vZlKG7gX! zoH=gPjS`sFtiQgzu%=NN5W71R48@{kGKMjvm7hq-4(u3=h3EoJHly_&SE}uy(mpyv zfyRqbuFe*_`CKcLD8(Qql*IKe-PN^gbMm=W-KxcB3DABzjwe`(<>+V(4+NZk)Eo@j zg?FCg#bTz_tgKH4+gt0SVYgl@74jS%4ms>*yUplCEYT=gDslaOtv{$W8o5FtF+R1% z_rt}8;)DOLaQ4^n>YhDa!iz0_vg1lOQtd@rV;*iAL#8o|v?kH+M!dh39PXqid%3}O z8ctNeo%Q|VXeU3|;-5$EOtSTUGMUFbA)OJCNHtfrR*BiAF(PWK$AB|fh{4QGgTbbO zAA%cm@KgQ-oIcEnxXti;j3&bAY{KEP$W;=#V%1<&dAtr7&%g+$*KZC-?Lr|PjS|HI z+iq6|{bs#Z4B>t}=;PA-#oh6wHv(NB#8QmSZ9_vSorn}_#YV4LZdPlZdS}$xJ=(ed zwa$Y=t_6NWJ zyTACWpZ~MJ{hMF@^tFn<|MXw|7ytSH{%`)t z-~90({>g_Qe0X|tCLm7S?R0xR-gqn?jmCg-NHWYYF^DI8*uQ74b<+bBPfDGeazb6<9#*=ZDOS8abObmxk5c7Dw zh~Mu9(22#OK|JVi*r78QDF-@V0dYWP0f89cpAa|mm16I$6+Q{@wTFgYUhL>axm<;< z5a2zAAYwdt2+?W5@>0NmhzTG!BoN(+nCqJ&BoPDxumUj`hQAhwm?h`^ljzSxnMGa- zM9kv&e6vS`e?|BWAj1B?EqsoPDO?#?x7Y4R5t2foLtvtzSe#6A(PD`kjym05qg2j<*6Ky*(JIwE6D6S& zgx@$x1yRfch$FsOzO}vH?KO*~EEUGx9{%+NgHesREp!xb_o~B58$gH6M7^lPY}cy| zN}J2#3wnJ)5BMs*MJIgDQ@EBRS(;x3U4EC!t>ltcj}yUs;w>t*#UwZIH?YL7kt>e@G)-j7u}UZ19A>-g`N4X=znG~vH9i?WJ(+Vf*1XBrwfpXqL9J&$!#EApkTs(seh{I2x zQ{ku8p$mR0Cp;gM^F{LBXwjFfpqXZf1C`JKhWQm$QHUAnfqdTm8=Woh-@#npG0*4|wNm0VetTw4WQy$XkBdH$WnYgbmTUt0qR zTUb&qE-2>bQh|0fa!*h)QCT%xe}_ z4XX-^+~CriJVv=ex(udd3v%t66)_quT8V54TyL6-?;mWveD!Q|d%aM~&s1zy1B(!mOfr&5;Bm_8cj%oaJ)*;+n#?KY?MCRlGm@dw zwG_ZjrjZ7?$+xqGPA*+fMY3Un#e;Fw>^H6IR}@yc-mUkAJ#?B(=cD;zB9{Ya7W8^8 zE|<~gvxh=HCPKvH;Y6Iya7j>r8w~Y$JqY5k0OI((NQ4eWXq=`4EKBF}agK|yEX8p& znG58szs0sE z@$QuEZ}Ly-bf^5gSHdL7T(QZ-GJce@n4L0S0ahk-TPM8iPQsHuiW1_grWe$f?@b9@?B9&rL z)aCKm0s#+61;R{-%_f??22Kap)NAk?ba-%H0V#)C%13j{P@EUzxx#c&G-NC_kaJV zfAS}QIDh+3|K?{u{j)#*!$17lPk;Ik{{El;#XtN9{|Ns5*-wA^r+)%zUcdkT$Vmgf$yiGEhU|E)dK8p&YSTL8*Z*6bw?(Lr4yz%Pw^N&A$^ZezLo&60a zPT{0Ko(e-xb$q(Jv%fwVw-Ri`AArV*Wb3x`sqJzm)q*gDCC*5YNoXIBe zkS`GQlqOw$dg3`&NKBWY$Av zJ>jgE&Uu)EH&*g-4ZJ#v^>(uB$FYpe);OM zbZ%9-u%?*@mB3QHAXP8PR0}fs+#0aX^3|1v>uZZZU_d$ZGGLwgCDr1ZepTa8TKpy- z?WQvna04s@G1No3+@#BaBWAx@jc8x^ob#~zJ`hvVME$9Hd>9d7NcbGc+7DtpSTW>>|@4wj9rvli5NnnIb643zUPR_E;>GPDe7C7)=MAh{a(y z*=;7P#Q^F=tUj+Zg!_ShO5pq&rCzVr@7KEBa=o4{7L(<2vQUgAQh_*&mg|vhC6s@X zAimm6|DyxjA3dXTzFI%rS&!9+;cB03jw8Lz_-L0M@1+5BdK<~sI3|9x6DVh}l^bsH zlShk>A=mq9u1p1K#2d6Y{bs~xa{4VU)CQoV(5(UJ7;GAg)1b2`wI-#>s__S$F!0Fa z6QKS8qBANSPNUan14Udg+EUsPJxTezew)r9MO+4)a0hS~Fc1uiK+%BPkGY**dw}q# za!HgxY&Mflr%94BnXOzVd-L|KJNNF~dvN!~tM@+q`1PZw_knT%XsAfARLyK` z5AQxWJH2%PfqW^AlPH{Tm3o2YlCeZInToUN6qn&rsZ@kvfOWF4gKR93prH@!cAJ@O z60px^H)(ZBwMM4V$_*xs*{ZiWOg_{}PyuKz#BH@YOeU+&Xx19cT9Z|;HK^9)t1FVl z<<*5%>55dorcx_mgsM;|q*9qoCWqzfs$^+td0}C3Wn~p&6bdD%Mx%idFoGa(Qo7w9 zSVG563qq14hG8BL5I5p-Io%$&&2F>WEIz-Nq(UTx2XM^eb-6uGAL=D2JQ|BY4C1sq zoeme&(G9sAE~mreaiV^2AmGPgK!FEHA_&c!h%xaP69e9(DVie4P>=`)C<2GoR5A`4 zWoWkxk*=-Ea|9tQZ3{QX_iAA$o%!W zrG*Zz5j!c#W5<3kwS>mC|N|69Z0cIECH9 zJXJ8P;?Hmp2s@xoHXEEkU<%3;k>)p04#k90T&&V4j@EmdJCoi0jr$L7eemYR$&G!0 z8;{pvvl|o1NPo~eJv+R0`{d|&x6`dBQ%p9O>h>CY`6BtD2%_2E=N1J1lO*;z4XaC#cnnSUnCH z!9&32bz0qs8LSl7GM2R9&9-y3H(iuo0XbR!4;$%H|-bWPu zM2T0t=m{18bbx+r{dKaB*kZlZt^g`g+qGWhjN+U0jvufDT<{hj6ccbAvH zHNW&*R~EiKw|aF^25_?|)y=JH=2lfpGOa{yP#DZ|y+NW;t*B&63dyokvZ9s%TYk14-PgqH~YO_rP0V$Dr~*Z z)oN^##bZf-tsU#HbDi~M3C^e{8MsrA{hL2yI(Tam1-=2$X|G57TM3|?;SLLk)1Jhe zqbPt*Yn%YexqJY*zX70A9&J@yqdZ#((+Lcxy##|YDIy%lgJD1(J%A1@9bU81rZL$x zh{qg>;muBIJnii4kMpIJ53^&q6AL1CM5ofMEU#WssFu8bix0Kh5iJ_9GqFG_9R?qf zD**N-SuPf4LUxx0MiCf=At<6SC}qOzody_S_*_oR>j$?Hr4t-mZPdn-(cb>f#>RTP z)wq50^d~>~{vZD2$A9#@Kl#q5pM3D*y{C^JJiLGB?)j}p5AJ>Z(FY&AetG}y?FaYI z-+T7xhd=nvKmO%k{_WrV;&1=<7k~BhzyGIy`g=eA@pnG{_|?7pXE#pwZrs?PP6w50 zE)ogZ9cJixA`A(GE*NpeVv&3yS1OeNM$kZj%Vu`>cX#%-$LoXBo5#{7=m~bK%NyM3SDv{4}SuVvUTr9Xokd>7cgtNEczk4A2`O2{Z@}Y5ab_ z2bj+aBW<-35C~J`Pfe^r@+vTxZ;XDMStlhgh4duKP!4kqh;;pvC%MzbtVbBu@lz?8xSIdDLrp@1gM7ONh9_Pu^{ zV{^2-x3NAQ)Ei|;Y%pqM@>RJ)0>c-t4@q-zg2bFItKDhxqK-;5dqSuy=!3A?Z5OA^;jideO2W72~{06@pczq+MdT3gVVl%9Y+kqI~Y;1a6q zyN&TydAwN|ZDxm?>A^;_Gl|v)RG~v~4I*79X75Qg$Yh-W%87%%g*fRR!}X&OxI~<2 z4Ubg#m$0ad3pt?SoR`k|n1U}_^2N)(bOWo5B8_RHK1t;}OrnIdHM-DFXPPOtn&2OO zP17c?Wlb*!-@mMuEUK2ZPMx3e`yw7s*y)Qn(U^i{B>){~Adg^K2bw|r91_fXsY)PR36X^mLL*8DzPP=5IXd6uy9$iPNCs{i%48X#z1!2YZKGrD_%@ zebE#ZWy5xlQRPvb{_Ab}tLEZ<&y=$(0$MF1)jIWZi()~&IH#NkUDPbC=vSrYHKR`- zNMMnCI9_H%1-=Pq36XLDdIAZ*%(^zGyt<-a)VbB}FhX&7rk>mh{y-@!@86z<+5xJ=jinHxk@BR{tzh+$Xd5Qk`k6x0w(g%3%lFY!}Yb z^<;O-zgylOv%*w?`PPW5c9M-g*PRqM54s!sol=vHvf!P(IPD9^VU+E2p?1Ah4U_|9 z6C^!e%nll&e7Ry`y45?nv2}WTuffm3h!B*AW-vcyvpF|a^v&xxub#jE;^~{$FW!Iuy<0brkB)X8Kfe3y+5J0r zZrr?iaCEfw$tN%W#eedP|Kwl(@^AjxU;e=#eeZ)0pFDhgc674YAJsa&%H~#oecJ7G zE2(tE*2|zm@|?6$-VQwQMGZ z2hnIWTqtIsGlZdFBFR7>s5dC(iWQw+0o^7}`lAUdory-{L@?y>qKMOLb-2yYJ-U5% z4~p1bW>B}!;X$2Fufyd*08?O8Y!=>6w!>H%c!8e<&Sc@=im?FOsMRXHL60~c;EG_d zZ?*EnX^YilwirzofF7M%t5m3DGR2x&tAH3gVs*OgKGcl{eTd6$vKnoO#R&!ZoF1PG zmVChP2G9vX9l>qWz#J4PAWnoP(`=%U=L$KlRLC}}OG!u_AKqL;k6;LLZ<-mJ`cdXYda2&v(+l2t-pne!L_~E!5ezte6-Xny+X`MEj%B}=v1 z3SPp85(I!+2yuF#HBpp*^3-m38%=ht-mFmRi0XXR=rv+p5Y14Xi_ILpQX3!(s&$wW4v%@^_ofXYH15T{(Jv|1fNoY8RH?ew5IVI!C3*hC7L zsgTQO)9DCBF<~kdj{=wud!3{God)p0POVwm+@74C9p1fnb9-lAOMQMA$R>&<_(_*)^&*U2AQ_BWv^oV0UjT!! zfIE?l03=y$z;7`ASCy)n8#njwJ-h|WM!OV_h74An-EGCg0lV9#5?(Bqs->W7YNhE$ zGU_xY1MrOweiJr}!DcqtfO1qT@@2I_0i)P(B3Np$ol$ALU7u`MCfg;Toc?;MJz^Sz zFi$ycB2^70t9Y^+O4bNK98oVRN4!xbUdw?n&o`G}vl5=&2^alT-WL`$QtXgRwv; zfs-jB%#siYFqjU}U0<8KD!F!5a{an=VP3YpsF18`6-tXiXSbMKc7;I$G_@pKT~oz!dES5DeN)x_=WcrQEI&yIEhboghD zO9L|T&+h;3e`e`U6O|s_+er5L=f=3hw$XR(7({+S(axZ1t-3EFSV8E{n;g*BRAXy$UA+*?cCQNdw{p zf&my2X0lv1#{r0pC;bmUdjI{`?>%^UUMz8Thk*)X`9caPXFTcj2aSAzMKQO{ZZeu+ zfXZJ|fWfHK=^#l$98KcEU^c@>nJ~BkSmU^4qgk15jEcn!4E(fu#nSRMrDn~J7{ieu z5Ey7QK~NEl2>U}}e~|QIAvYPpm;@1t6VW7@-RWeB<^&;2-s{f z>7iG%n!q1>{chkA2wUxDfRZ48PsZ!VJfL2`%gqxK;&j^p^3+L=tlMd>PlkX>ML>Xb67t4lz%T^n_aHV4^yn_co=zpiX|K1p zHV+T>n~esH^#T0!I=$6mbGbagH#8mf`vW%q8l%Hz1Lx(lSX~;eS*C}0$Aiw^_WF&Zz4Mzl&W;cFwl~&c=UR^VG|J^-xm0Y_Yk;T4Vjj>Fc&k<`0f{ym6{thI z-DtLIfP-!~;`71S&kr!@^YL?nn@nba8=cOe)c}9;@46$1!|8IEOgf9j5DfZbaXOPp zrGf8~QLq4%2>>LMNfb(%TCITJn!%v8+b#UKBIt*sV|Q2pM*FZ2-A=Vy0c|vD9q4{~ z-O*?;{&!GLv6Aif8shWCxqKQ9BuNF~Xb~iwgH8tmBLb~Ps{n=Hx!Iy$UYT25y0#`= zvO7#74;6}BF3*ZLrvQc!r^V^A!XO4Lz^M=-{BZ6W&1$Q|P;C@WZynx$bo=(*8{=s| zo{A_muurRMgGvfav$hCJ2y0Ag7!hhMT8&Ag)T^Xw`I2;HVQuN!%EGE!Tlkkpx-o}f zZZDknRKSh-y@;J@Aw1+57x+`0m| z;VuUV<|LTpduxjDbvw%I8r3S`5=+;p{HEz7%79P`aVVu*?BJP;YNn6!!<-BI$owY09T6%Xu zu`1OADe7f9{icQ!L7q%L=v5jv#=&Ash+#H8z7xuaN5bhiP`Iec@1s0KB80{{+obuY5X;tS|J4w5Ee~RSr z5E}?2{D3v#ECG=a1FQo9rCs*!+PALC-T~0Lu6TFNv~0&rR01tj6NOSdmt!&+CYz1s zaxu_iF;%bU2ZKhdRnBA*>2!?aV8|6sr=x{Jx>C*6>xEXkJQ}w*HhDKZnlxLTJWx)x z&T=`Dj=A#{vOQw^8{B9oJK4*PcQgIX6adX=hpP|y=WmXFmgxT5FXO`qIp(_4ba$QW zO|#wgYc&PW;R!0eYi_wQYv*)rCz4Dsx>BsM7bnYuK?@d zVPCn%6)SAMlmso5lZ|$+(aDu+sZ<8WdOl#C!MHk{REO);{iEUez1@2c5AHuYdi?Ch z!^g+>9v+?F-9Np(y>~QT-|qHCwOT9h#_UV7Ihj_XwW^Iylg6f>TU&Yu1}CfY3(^&d zQl`+UwPwB1ZnC*;SO}#UA{-^+=}57bY4ytEjn?+w;OKPY{-YZ&UOm`5oIsVv>y7Q* z{?7hjYp2`om-Y^ZZ$5tf(Wg(IzIO{MaD2A0cQl%8G>g?_B25-6$$AU+qL?ivgM=4x zTg-NY*=DfXO=LI(ltYF|{)H=_kD^HEzI(lPuirkoarnunZ$5bQ^8SO{zVj@#a zMiTtg9wd#2Nd6X**XKf9cGwq#S!=Ny5tkJw&`1*f#&0_a@{iGiwQSf-c^Dzd+yx_cieiw|) z=?I=oM!>bfDN(KF;T$NHv*6=mF$z$))vm(8zEsLUng~Mx;($hDWSWaX;_1fl_W6y; zdcR!G!tiEyYx3mr!}ni3fBEA1d(WOed~pB%-8;ZBH&4&@cK1$>PVSuF-Pzjh1D%Yg zz$N1$un53lr`PFB*T*IbOQUPc*s?}<#RH{^< zwHwp*4X}Ch^d^|yoNjGQH^Jrrey05ZPeHK0{t(=JrCQ2mlhFta9>@L8-qr@d&E~j2 z?9@lS797@YtI=-M+fA?vQUjU)p0 zPMF3c5g3@FE|<+_H@ZCz_}K)4@S}1gUpdT2T0J5mmQpwt)*`njoHNm4U z9BJ4Z2zpTrD&!2}UM5PwAukluOf=*`j4qEYNch{m`q^#hB5&V)aQpCNw_GdeExJ|t zicBqq<^0Orno^=QY4lc|(ZPSP)9!WH+;(7YwNWF}Dwb7i5{*=9k$ZM%6>2wl?QYzQ z(%?Rc00W&6hF~7E+s;3UY%yxhpa6{~wNWqEs#fIu#~PJ7g-WkjQ!dLiD{7;}7qYPh zve9M7n}zNuRqKZHH8flG72CmVBbX?mG2zqVv2rk0;Z>LtP?-Bzc={Mvhkr)r;zpIY z8mr^+#@Cu`hS)ZlZWE~{&UMIKKT;ki8dI)1PUSjGtQ4d&{A|TI>kX#7L2yj0KbS^? z91Iy;E(W2BM5>iYHskRI6RlEo5f5b{fjf{wf~*ryyU2`}&iQ%DDPnX1kO&PIu`qxR zuRuH~RrXV5A6fE(h6-*x=L%+BfeinIGRC@mai_trUDPgKm(N{YyS}DVYHb#s&8o3j z6gs0!rI#oGIQR>3N|QxtHd{Py7anlosLk(Enl%!wRA!KCY+9?&X7yQ(E`!0PGq|*% zCXYVApwTQ7W+`AD5phu3Z*Uss1jJd8FDC#vk=KLRN?*(m`MyZ^Y%I9JZiYYF?dJ zU0c-5EoiR4Bl+!X@^7nbQXlC^Wy4&KPIFYD5UbTQxqO^W)5Q{7Zxm|ve6f_~xLBHt zW-{?onQOL6)mpAp;UHY8X4~CLe^~DiYu!P))h*OpnQ|?aU||?;h^2kiZmcs&k9KmC z-TZhr&%Zo1P4_lL<;ey+Z5;l8o{*!A@4=|bf3BQu4!OpFYYubWNx3~L*L#Ipr%>;d zD$PQ+%=vH+_%NAzZA}S3vDG!z@{)8;u35D@jT93AxM4GqNGwRl0!$(RaFfo_uw=7T zw#amcrGt~n@!9nF=K9S$Tj%$8&d#Str=#7&&em>obGNy%(_G(bOtzYn?N)zUZw*Qz z#;Y_+^mdimrMLTS7LR2~zVznN!kMg@?s?c^=bF=la0pt{rv||PHvv>p5EF%J>MB` zHsNqUN~=@jL9ICHVUi@MFW|H}O+YzT#O(As0IJ9c;lq50(*fgl7zOU_?Si*?`0)OV z7tcQZ?4vgyzIyuX!DP~-s6aNG91h!~QK#Q;b~?3sy;v+{YSrR&eRzDd4}N+y?5Eje zJO-XI8sYDCgkd=7LIBaRSd=LgaxiATef#v*t&_d|ty--J*c6EpEMRdynJ*^OStgxh z@})$+oa73zL?#?b;!Fw$;z@AfbUs?BrmHO&vnP`oCYfg9Nje%2Q#5#ZugB-GJIyxe z9_>lg`HSB{s!Hl4&}Vk8`ROg|;L`qY`Va*a%>m8#;np3A{@UeD>W;J6QXCB-saCJvg*r|OMjt6c$Y zHp|Ucr9Ws+)_dbg4+3c}9uD)b>_AG$(ucim)ViJa`uh5mm&x(*;r)AeU%!6&#pfSG zgM9qaoA=&(diT!x;r_wK`gGVI?CtD5didzZ@#$zVZq%CTR2q(S2oKR=I-O4U_zM;7 ze4Z;6bI?AMG5GS~-tHze=JD|X`1qZjt;uBE0t~FxnoT%eyZzn(O!d0`TBV-L`GTGmr9_?-I?``evY>r0* zFxcyL#^WK-!n2bF4}(S(+%!_mnXGJd~Dqfyyxa1@-d zgd>7t0ly!00iXDNC?-7HD>(1j-oj1dKSHz>Sa55Ez6CDT+KnH-=U{pf_pdu@DTUI?N1OSGFyVpKC5`@0K zP-M%MOf*K=?0UD?Mn&*OyRv_@ee3+j{fBozH@4T^s7t1jN)(c1=@L*5unzpj)J7Hm zfoS+Kdu$FL0%~>JjEG5X)hf*@xltjrs=c3%%>}Q)X+i=nFA4bVv7?C5X;oWb+^SmB zC?!henhI1UQGikDl5|y~Sko9aD!p=PZGL|B%KYlLb(Xb2*pVrb-4R#sMvHYkm3PLo zj&#MFD*Ko`00jR$4X=4WUAWMqpDxWn2e2k7%mkR?zwkgNnnbEirrJcJ35XL&wnCX+ zxHyjGN0C$q&-AI%dc3)n>Fg9MBR11wV&xE>L#ZrEWPn|K0YUK$O5}oA+J~~UeLf8i&G0$o`GhGp&IoMP^p^t#NTG$2+J;xHpl{s95I+hliHoF1Fk4=8T-xRHS0 zO9h>{&+12%7M^nW3pozG9kn9?haI)qP^%rYSbRpH96T0C6ygz%4#h)W5?qbL;ssPv zE=U*V;Sk6ccMb~Bz-sz!vTZMs?@_+Q=He>pwKE;v{LPe`4$^h zqNZ{qKiwT}9gId>t$IJ7sYD|z8i*i1(h`h0iIg`G_h4}^8uM5K#ufeIs&Pr}l$%f; z08KE3MvMGysc@FS;y#41X4aP3LDJIxHY^MkEI zZ<@<=BiWzr=Kts4+x+uFsuGEpm{KzZa8PaM>fK_!TdsF1wRR;}&L+~(1YVsPxK$xn zOEdy#3B<+i(@JxXz)sodF*Xk8U)7o^qHQ8*8H)@lu z+GMjboEG|%9B8}GHadxBFV*a`?LnruUYzVU#ygGPw4AF!H-Y*o#OBqzgLZciSyQiG zUAnTWTv40UFjfK8S#{#%Rc5Eri@S(uAd({70ju7wFgO%J#y!}mPqx9Iq`3ma=D=Yy zxk9YjEexlP;d*_#-8s3vee>S_(b?wVjp@OSX|0_N5Qxd4lBySg$#rIh)oHM~fsEA} zgHmtNTAdbe!0iq26IECpK+}d$2+wA-t!4upPzD11KR`FoGwym@*5-mO8uHC-Q^ z-ZdI_^u{p^quEp<3aAhR=a@((Qx=oeg}4EGYLzMsulM$L zo;-Q<{Kb=d_s^#rV>TVnWD}KI4nQQGjRJ7gTG>{&2wDb6t0uT&G|lfXlg@)iE6r?g zQg08cjc&PA&14ISYysFP20(+8ULS_Id=|uI1f&C$i6%l!JeVuRtIZ6TW0D-1EkF_R zQZ-qrry&vo*#ZMRUGHQ&{X&0S?N6$mQMK5}W=bqqOs8_mcqSf6(qxSEhkOpV&F-?= zoE95mc6lA~6jLZ?GudRdTG-iM-`!px_FB7}lRIZ8w~i0a4tDRJo;<#D>)HLgFCRa6 z^Ze=OAHDwZ_rCMHKl=Vpe)K)Snu#!j)XDMw^Y@;7=c~_t^5gIS@CV<0@%#zk3;66- zvs$Z`2K~;_;qHU`cRqOi^3}^{PoF%zbAI#2jl5IIQUPy-2s$iwG!i0cqN@e)XW&mG6fpP$72E*2H)E7tf!;rcS$E$mJ`g@^rHP_~GNn51-sRyFKiWqLCOL2zlK;pT`%(Fd(~L zw+-wxT_4@Pb>rUMTQ|>+p*8NDpPt`7J3qe#Ezs+AfpS2`))WD0{P0wESt`j4&-H zoWlSRKvDbqyZ7$hefjeFvuBSVKe;bVq4@+x1&hWI{rHd$4^oL8pWWF#DIzFoCrScv!2Z-Z~R`6&UC$pFxH!bs@U$}aG?V8-6FuQCP z7XmbHhaS%5x4C?F7(e>`4%Fwsylw(TBe*LBl;coYHB!9{xKoelZGI~tj>TuT`YjI3 zX7!nkF1KMf)vGItWrqs0vr>vdt68w&#E0ItJn z4y7CIc8$rTHJc1pi^`xuiU_hBnU^d|loF%EK*dA(8aLc*jd$AZNx9HW#wogRId@zoj}myHl%Pc|QGwTt}C zhy)c+P)U}~wui*o?MD z++?>Z>UgIz+Af1m_NrS)&CR2x_(@KFlBY?r`1AeBPnyY}pEy&&VAzX>T;6~a+_@k3 z<5Va>1ib;&?sA%JR;^L1*2&E_t=(w^^`eeglFXM<^;W*o&exjR?ywB>u({ja+UxBe z4i9gvpWNEmKOXkR#b%%DKyl-2Z#_HQEKGJvgK4faWGihZS0~GDra4NF_o|cqT5qFR z?WHqShD!Qf0ke-lFv_d3sFq}lYLm+BG{JA#=zy`2TBel&_rRdq;kO1OekM&qVyj1I z_vta(S?O@?ak)@qE3Mr6PH(!?@ANCp9`w_>T07V37pJ?u-Q#g@TrJkwWHyWvh|#W; zYZe#z$K~IdTYYy`u^`tO9>@aEcYK2k;~{a!EX_X4bR z+RdHq>8+b5&)<9W@WDAC4(Q48-i?!eSc-w8!<~cuZScfLhY$m!@G)eJgvnGQkx8d> z*-Sp0t(0o(hnRY+l>}IP?w$e<&vOg|w?sd2J`_tWi zXH=_n%GGYA+O3w`<#MxBY7_x_qR9x!5CH=9qAri$nPg+tda2$hkH@`p7|P$eu{r7Q zZcXmpI=z4M^v;c=`)4;E0(0Ct1J(i1`S9g?pMChj7oU9i)t8@s{@F)geEu=O4e0Ox z-j9CvXMg<1fAssm`;#Ah@4H`o_~!lFw@wca_{%onwjbQ*LGzQ3-+c7p>-S&5k+^$y zb}W3Nbq5q${?7RsV9=fOTW4oCzySm99335w$D?w&%tWJJaE~r+YtIeg? zTVx8|(yC%juGbkHdZQDR|3a@TWOv~(IL65&P>v6S-%k(?U|5i!3pW-g%lxNW3gv1! znT&<0P%0VAq>~AT%BJGue*1WL``+0N*wfEGcy+qJQ_g|Uj3*enQ7Mo3=WS|mM(ywI zJ$(4^lTSYS{`bH8qaS|%$3Fu7-shiv{OsxDz1^L9t&+=RvRnq3cw>Fz;r&M+y#MCo z4?j6QIfE`EfCk+zj}utUW~WFZlV(fBT))?b761eUaD4dS&dswEk@F4?_5?TI8w>`3 zIA>>PH_vXK9-YF^rd%k)a&xk|Io{aW+_`;r^X{$NXD2rfcXl^NqfV__&SegEHeWt@ z^!oYJ4_-Wd{`mgm2ecA z12KEN2oA$u3Zo-9FeNm2n8xuC8pM5gi07MVj7lUU$t06ZMnQpc0B#D!3}~^G1z4taNt12s9nas+p%<|sb_TJmm$D4c4x%PPico0c|1PKBlMw}U%5obag zfFlF8Exj-3=+!adCB94^WR@qJl5M}NZg(&U}-T-vfcn@bRsHmR2L-7 zXwng5JXpp{WP`~Q^Dwbm=tF>vyw%Wtzle~;9CS!i&3S!>o@H<_$F14 zFwGd(AwW5~aVk5YV5PFg7e;KRL8Z!ZIv=HG5rZWzqG%=n#0jRo$enUxB8ufAcp(M> zD^U@NWP>Od0OiDhHDYkatl2c_2;hbgf)I&(I9ZG&?)neW_qW*Y`v&C$cs>v>%(xR5 zeQ{yNwL~dG7r_A`XT-d$n|msMG$((mFe=P$tI=UKSS?U30(7h{uWhDRuM_bBar`(E zrXxNqXb(AcPQA<|S6Gy4n_34=ic6<)X!I_fJ!qSW$7}LNJgj^|>7sT{Vpx=0B$l8)NO|xK zO7c;Z@c6H!Gn9i4ZR!BhE?ewLZ-tsgC_YXn~QTryxd}dGQ*9^c&j?zszJc|V7)Tgu8%fr&0((G z%H(S)zCfk;cnEV-Eko~ryT<>|$Li4X4(ol>cW#~vCehJRaPVs%_^683tL9Sa?7*-Ve6{S&Tgo89_ zN8-U?G+?mmlp48Kr?%OwLBBs73L>EZ%cSbHN~c{P4ZDz2p>ZD$+Jk-z8pGY4b%^b) z)y<9R>U20B^@fAapx>TO2K`<;l_X=)Fjz;(a*!{omD1M6?&1E)<@wd=$=S)t$(uKC zK7Rb-=H_a3b(~6(bP{iND*aKT*(o)TbrKlZaqIgeS35D>D7xb z-@f|v=H-j)%d7K~*RO7W`jc<|_#ghgfAB|t@bjO2_tjTle0cx*_V()H{P_Cn{N;3YipB@jn(ONT(4K} zx}7#Em05ojKATOZm=J>M4JIHCKnG3$htsE28y6+YC5cL*HkoZci`{Ruc&v_~!xMFS zV=iAj980qT!{svBLN-?_;z>$n(CJJD1PvwAiBh?k&4Mv#mPsUOg22!e86UK3Cwp5j zuFgMyc?*B(?ZxT-)_S*5P18g{;Ai)Ziuqc#44?A&_~`ZPmtTMV6)5L-f9IFK{KZdS zy}TXtyU7IQuv2YCUVm$2^XBTWlyiM`)9(%hUc@mX;0xHTcBf-DIu4Fug}ew5 z|MMW8xLS-eGV}F`2N%TSMOgxdww(f`OAxw>+1`^ z&GpUI(eXa~(zowlfBf>pw?F>s%dft8`~KDSv&+--qvO+qjjh#kwMf$VUC;N~kV_aI z!-+U7qgVvo1F|vOOlGUeVAh!|I;YDTLOcW+Nv7~bG7d-(a}2|h(O3wqLy+JbV%GnO zj>DJH7!rww&`1!LF)U0{@mayZGpSU9Wz&Mda~wPCCwKQOdg}krljP|HzPUD<^%Xlm zIyv4uJ3EAJcXV`cbhLjz(|Dy?0PdV$97EjC#@B=G_aCC&sa0zQh(@#2YF9elYOi01 zsMd1%LZ(pU;Lq^-93+Kxdd=zDczttqeRFMNYyITx`0)53$)>C>o8Dqj>D3CYQmIp_ z^h&K+1Ig@vQjX1Q1LZgZ4vWufa2d6Bjnb@?8DvtubkT2;rQMIEPwqN-EU#$gN;uB# zCZp48wA-|1lUxf88xTsXoAvOXDMx44sdON!rTLY|%ZjHegTx&&QyCN`-L8;c?~p3Y z3woE#5!RteH<=Al0+KF9`5KvPC5t^K*GXm@WV#fkX0`}Gkh6|EvkN?N!58IRWFg2j zuypC@RN#@tO5nkq+!=OT@jDbYf{-%GugQHmVm_(cDSQ%f7~A=0)EWrMqR#`_r5O< za7SfPKaoCtxcq2dJ`ZJ;-Dh+7?KZF7;<9^!eiVy2yk7V}&Mhtd;K7f6`1s+2xhGGS z7GD3Uh5k~&vQn*CuQtx6n%9^$dYjJTh6L%(mYMdr+?iHteUUGdYyo5PF%gv0&txhj zB}V96j1;2bq|Xz#*-@hteN4 z$(udtB&F02#&B zsL&VyHTZIiYxHvvxk?&-iee%$DgY_p>eegu5~*g($;@x|f6$==?RL zVj)qeq-!m{(GlAHe7&8mG%~Q>>gOODU7^|YdHsk=W13r(FG^H$mB|j3TEtJJ36df4L>!}H5ger%>W(;kt|S&}?dD;_3_!w<<{mp94beL`?t?-K7aq=&8yc}7nd)e zzkK`p9mLD$uTG9m*Hc;vMAo%R&0=5`f@b#g%^J-hFs`b9=Q8ziw;w?Be+O z%bRx}UcY>Od;RR<;_4J$fp3+og$V2*o6+TQ1jGI~5hG|EjfI2ZKmhT({Vux;3N5qI z2G%jy9424Dg~dal0+0<9s&BXHyJIl`6Sa*t%=ucDGq?)+)6!K8 zG$^$eEwqMqpWPjDK}IyY;Lp{nt!k}Zt9R-RE`!dYS6ej-+lq;|E*Yd!y0{ZCmUVMFmpq(sC-YIJ6ys||zMU-f+1iLN57>Msk*UV$TnNwl??yEC!3vQJ#sz6Nm~(BpV9z!7v{P^Zr?n9L^uj&iWTqg>b4I&D8O1lghOc5bz0wCdJ*&pnhi^ z&`&g7L6ar$5I8JA0CDb=L*!;M1LaWpFqMl$(teXqtFb9`4vpDugyukN(k`qlEv-nF zSELe|Os-Mt;28B;-BC|~2qHA%#k|&_)!;E`om!L6(c*WKW4?wV&^<)p~2yN|zIBG@FmHg&0@H z(uF83qLhHfxsac5*bu$WEmu3FdXMs6InIa;VKY8Cgj33=5uY>Qg1W`xHs9UGGTQwXlnkvJ2|n&C9{;xYt|T*u{bISv+k>RkLKbmld6>Sqha^(VCU@g5Mp&YY~S^k zg%=?cLuvuj?C)&>fX+^jZm!RvnEw338~AR5#`8I$*KP0ZZk?VUAMBl+onF3v`R>)r zw>LMpFJHcT`}Xa|#(FN7<+yZ)OC-}cnTX<47z%YX=JtgwHka1!(K~zwJc;BgOsURQ z+hVPguXW)70PAE6wG12*tPmH9RJp;_yL@|)tF+icE!pU0JL7z#pRM({)^IiyBt&Z@ z!uo7Xfm)*6X6rp5GFxggcZ0kaJCkC2RDfL!n5I~i&C``mp)sttC+$+Rn8`zR46lrXbV{u$0K1h5C%ITkiKU#e<5MNnBxY+ z4wS)Gn^AAjn9O>35ej;aPeVcP^*Mn!257lWI=x=4*K2e-jY+G5wKxaCgo}Qkb zon2I_^<}k6qERUfI+vic9i&prlZ&6>9B9 zxmk~rxYgy*8FUuAg`n_qrMS7d3cBSoDFQe)r3dpT7L~Ued1 z$_p7T%S={>M<@HI7bnLj2Rr*)TRZD(o6~x$#t9iTh5%*!h&PI(35H6rv=8x`9VVOG z>hRi}J_jt}OS9czw(G49gWYL>63lAT>kUesUT(4K><*(93)tF94qfx)ns0{|)&8;;!7D3s~R<#X>!8Mdv)6BoC*9Gw z-5)f1efVybPQ-kEJ4r>dLaJ02o9$|^-zk<0_k)4Maxfa)JbyM>n+nBz7>mqimY&^9 zwK=>%8`HgVj1D6tHdvACWD?c#igrb5R#|*jSJ>^1`kaW%=r(C=x_Jg){xAOCvdgHp z=NP5j5<;z2s&o(vHT+-9YDl*c8g&Hi63y~M$%Ef| z@|zDNKa?2eLzIgx$GK`e+aPjn8gNtSCd4+$H{$6sO67xu;0NN|LkG}+W&M8I8c5iq z9AF}xEa7+-MbrM-jS|`$N(E6S9AQyE={5PakZ6rQl{;pQvB5YWCd3FR2Vwp95oBgp zZqRHXDu%FpIF>_TB`O4CLNGq-4-`&SV)w)mfjI3%zLf;%2n~{}#s5QKTrI{{BdKyY zajzWkjp!#tAWo1jATuP@h-@Rll*u6Bwg*klpw$_$yZj(d-I8ocrc&q(0C20-ZC9JM zGNat+F*w3DSHxjQtR|nq=$(Z~77!#!g5@Tc0bR;3r5GWmXhU_Y{LTQv~EXpP2 z{G+8GEvpvPW(6cRFAAy7Z1Y&WK=`oV6ZAQKF4*--o#NuZAc&6o@!}JyMy|E!A;4Hh zr`hDTSiDxPO()SvG*-1eXvNuRzR7`dCOhr!TDjiO=4v!oiZg`>Tf+Dnl`O8&cAMPc(85X_t8;^k%*0w^O^(rk`Q@)!golE98?J7274Q#=_V0V4dks zeY#Tv>kQTlz13WIdOyN4U+XdXIw@9hu}+k`sn#Uh9E;T+A5RAzLBoCTW0J*aj>HnN zKr{e3#uapfy<7ng98MOO1qv9G1C#@0j3p5BQW*>)mOu;+^$(x^=AvR=YtevcRYnzr z!l00-CCjR%70r^?rgEcpci8R>S^}6GO$59VyCYz9ASO@58ln9ZY>gt7Z}II(wY%2n ztk;WOF_k0D9{sX%j-X@EeAS?_6SJu##iSEZsRLOq&X2DyPhoig1@B!i5J)8N-@W?c z^S6+vVg35*3|>4q*xuXQ+S}c1HmjnTX}9Ye8&hcauddJbb`CGjuD|={CqMq~XK$b` zfBEYD`}gDVC=?1n3g@$FCPOFEI6+6yn9uDqo2<|TEy*?W3f-bRXijoiwwMIjfNv_T zyij5pfd-5Mg)@0VC{y`bqSQ)*X$p;0woFvJT<7jm4aEIQp$@N8LWSmwutQ^+JPu!S z1tMFb%B@VjCsf*ep`PZ86zuC1k7Y}#YPZ+~<&4{WkqhHcM0@N$n|0Q6*J!rsjTWum zsB$>W(P&73JU8lYtPWR4y*!u3fnC^I!b(CtrQ_#q$@}P#zbG0vZWAT~;X5p)NOD^pM8v@XKQepJlK(3hsdy zHClzqtbefOR02Osgz4~P?5S6kRDtCwpb~5`&g2(di_$J zZbhqB7{f$G@A0`4Noq0~Y;CR%`fY({f?h`<%O3A-L7X1!yn1#CKKSKNz5ys4?QXT| z6+Xjc`Anq@pJ_I1UANoW+S<6ezWDgXyJt7&$47f7Af)Sy@4o%|_kZ=ffADu_)9L@} zcYp79|JLvP>?c3}`1z;TFW=nXx_b5E_37~`sHItNbXx81?2bu!bvl0e;@OAyZ{V1O z1M+l+^5e79liQoC*Ds!*93Jj$ZtZSuZ>+A}Jqg#ozmT&wTJ5)bjdH!)Xs?bYTWjmv z>l<5ZYdah30G*qQ)2p+S=hx?7ynprS!|V62Zf>tY?0e^DM;Di;o7?N)m=v2xq^WwV zI+*l&qYnJCTC19`utz~TJfBG> z>1wqM)&b>!b?z_Z0B&maQZCQKahVmETD=It@hMoZRK;p72g`CrD3*96>@gUXUY`}i zgHXq0MK+nHeF2|LAy=wZR=cg%sNcSLzOlVks#U|Wh{5;rHjiKL>fmE(<5!Oa-6- z8i;1<5D~V9GS%>%8-iqRHqH3Ga$=k}n(+o`yD6wL1=TLh8cqii1v1V@gS6ifu^W6w zliy+q+H4`a(PxyKS5^!QE5><)SLG*M;gmndhtW(Be1md9ln(}34+JO&d=oFA@j@8O zBX}W97STjG$^c>-q|lj0L+?Vq68|tB~ennQD|Nqsc;u$^{5v zrW{HP(s?9VjAUwnB%m83Gyo<6ci8F)+dW~YC**=dQ>K>cj5?>=_4a#Nvq994P!b7EjED&_PNd*m63WMnhzP&XRPN@?$=uOE1$&ATvp|%dmuy z-SwHU`Aq(Z+u^e~{kBll4^`uAM|f<=7oBJS*snIIB(nh_=hY^)#ceS-O?vRU+idn) zZ2^bgIqTn}v1y!$Ba%c?d9pq%tnPIo#@mhNP{@PZ3K7177ds4F!DAV}54TxEI&(l{ z4eI>3BSd*UF?#@a&yqYS*?3yOARsB`s=p z1E4e7EJMsL?M!mzb~-JhNde)@SgDh2O@z*Bp*<;ra!fABE^0@>5>G{Gj*3zd58^dC zOcuAz6Y^W#4lSJEmf5L2n?Tn+Qx1?9C4&eKrM+Ecl091b43q>IJ24+2J!1=?Irk0B}nUI1VFe894HX1k1TXVV!+8k+a%j zP@8pXvj$oZ5Oy#Ygz%w02t0vh1g22Um1>1-o`dyFmSMB$G@la7c~Fi}DiBH9$S zO6Ekd)oe^BV>p(+`TFC_7dJqdq&fv(r-rATwS@!Ja3ZMfADrjkUXJcbF7sGIGYxC+1 zuyS^NesQ$74~QA{hM=77HPF}*Sf|_QfOYQfTg|@Pt~c8C`k>nxfLPj%QLnwRI=VPJ zeDm_=%P(Gk`uz2qSI=I*zJ2xjc71DAC}jCu1|V3h<_pz4=rEZ{q_`x_&`~0W#v`yq zVu&Z`hJcdQ<#$43uF%ToB~PU)iO#GEM0`Xl9*ze+A*a=Cbo#6~g(lNDorq_+WT`9` ziaZeFejZF%7E8kF+Guxov)gT!%7tPv-)z=bS0`(0)5&DCx3_zFd3ktvIGIf9^@b?I zX3iCh#q#W5>7F#dPC4~*QOG2TSff%n*x5Ka+CMtnhu@pa3HQ&+cf0M4&9$3n7l%hs zsP^Ea+#RMQn@N@{`DUw9Zo+>xYOS8n7cvY>I$fp}>73D|^at#TWE|cci%0A( zyHp`lYSf?{v5*Id4klxvkoO}&jX|fq_x1lp53NYn$;Sc*5ESUq1Gff z%Jfd1H|jx1$abN8lN)X}r@Ni$Zo9WuYK_FkFk2h&r7n}H;5Z*blb!(KKxlU)N^61FI}btzBbu8!SFEh$j&D`Z2c?vB5GS;Gmpr8M3Qe zX;^dxjqzkKE#RP>L?(tO!|?>d2ow+p3h`uyBvTlKH{{ft)mjrA)v^`UlG-Q>#e9I6 z!D^>BZI#>kT#aW7sX{Z?7}VGt6D6Z$n!uBBchF^Y=(Sdr!J%=296}}+VhG|^EbUH; zLB0|zw5dujS?Q&!eWpI-YJINK&6GQQxh*g`8YM#pyH0C;q%%MMd;jQr|NXyx^5s8J zxP3|-S5_MGvy-{s+xzT)z4IIY?+3=hv9*$`%ZL|8VFPE(mos!$N>^;sX=jg9H{_QuZ67R1KJ z+WPt`w6KFguTT^z8lMf#=d^fzPMnBBi`;Bg0XqFbyWOepZ0+yu9G;zA9PAx78?E7R z^x?zj=jUhHEXVQ8Y)mgj5m&)3p`7{F+?lWh+2-ATDOt@c-IopHH6D%N{qxy8-Khpe;t z8VkM|tih)#6&oC&97}|}VXMWZ1y}jP4m=f01E`7_z^K}!T9nN{T6j3W{A5M82*gqA zj&zckj(c0{<9@3)Y}L0X!<&=Ck1wC!o*W&nO`o40e|&NK{_5iPaDQ(y zTJ3cv{myJ0x^@i|`1u!a!8$Kq-fV16frgMl3Pk}T!=*qrOG>rE03@;N?JkqkYxRUQ zX6Ld}zaZ1jt!O|tGOb0TGA=3fvrrl(YO_>ll^g8KYU7g?WhhS7`y-kYJmHAd>oqzZ z7LUUK4MFn02CbIg;eq5E4Tj_47!?KIP-#Le^386oH*9qW&0avmho^X z@B)cb=_FGslzW~2`szlv-7DrxlHC9&9V^(KSa$bYqRC6^U) z*=!*v@)?FAuym3XvMfmM^my;$Ar(b>f>HYinuU@^mUEf{>;_!JcU&#SRskh;~fd(!+G<&1kRF_ZGUZ22sEcC`QO>f-A1 z9L{PmRJB?zl?p7I2Jwu>{r;faXjHS=3>chY6L6BlhwJtlD5Ok)}M21gAVqu%ZrckRifDo56m0|khVX0navKfCkq@VSnnGJKSHfT%^ zi!0zUJFV~~ghHoM>Qx{fxlWqQdS=~tg;|dreD*ANFv|M9xJ_nRdZKvvRPh9Ui4%1@ z!funtD$&Y+xbWz~^891z(t>hjQMEEBpL?|O;73cpy`X-i_o(im;|Nf$P|_3Of|!UR ztS`v8BiUd~3`KZ9L`(<}dF1Xw&fOzjO_HkDM-5l1A6(pd_W151Pmfovq2WsOzs3^@=Yh%+&N%x(7Qv^J&H zXP`1MzLd-q=m_Pvd9}fqlVo69VGu+z93ul58BDVAY6HqdG06}KIOek{$Z9UH&E}j< zV`+7p{b3Iyq{_`wwOy%ps*ORj)UL1vE>|lwhV3YgYfJ`D$R8nMel*}g+`fnhC4)2% zsVEMN5UNC}lc~r188gh z^XuRE**8Bp+Im_Q6-mxSBwSP~^0PM&|I>@#UjHia@BjH<`}cqO*Zwy@`;9;O_``g~ zkjS7^#?JuYiZrCsTrHKW&TfS;IgHK6(;`N)2uixGK8?XCv-;FFzsBNK*#ooZz&&BB z)vI%bY=M}M&XAcrq|cbc=Y;cD3g@8NXtZ0wI(Dzi>bB1+nft*%eehFev)iDvsR257 zp;DPuTDuPRIGTW?HT8qT-K~?8ql=5PXV0#$t}aebkB7rP&$Ir3$7I%7ZASPJXan=; zlgQw}-)g&9s?R$A#_5

erO@J)ZU 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

68`C`Xv_ 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 z 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 IM6N<$f_MbnrvLx| literal 0 HcmV?d00001 diff --git a/doc/img/HeatMap_plugin_power.png b/doc/img/HeatMap_plugin_power.png new file mode 100644 index 0000000000000000000000000000000000000000..2c920daea795babc87e0a022f7ec4ec95968841c GIT binary patch literal 10240 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