summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--cpanfile2
-rw-r--r--cpanfile.snapshot978
-rw-r--r--examples/travelynx.conf11
-rwxr-xr-xlib/Travelynx.pm2
-rw-r--r--lib/Travelynx/Command/database.pm12
-rw-r--r--lib/Travelynx/Command/work.pm50
-rw-r--r--lib/Travelynx/Controller/Account.pm22
-rwxr-xr-xlib/Travelynx/Controller/Api.pm2
-rwxr-xr-xlib/Travelynx/Controller/Profile.pm13
-rwxr-xr-xlib/Travelynx/Controller/Traveling.pm79
-rw-r--r--lib/Travelynx/Helper/HAFAS.pm103
-rw-r--r--lib/Travelynx/Model/InTransit.pm2
-rwxr-xr-xlib/Travelynx/Model/Journeys.pm11
-rw-r--r--public/service-worker.js24
-rw-r--r--public/static/css/material-icons.css8
-rw-r--r--public/static/js/travelynx-actions.js3
-rw-r--r--public/static/js/travelynx-actions.min.js2
-rw-r--r--public/static/manifest.json12
l---------public/static/v82 (renamed from public/static/v80)0
-rw-r--r--templates/_checked_in.html.ep18
-rw-r--r--templates/_public_status_card.html.ep9
-rw-r--r--templates/bad_gateway.html.ep8
-rw-r--r--templates/changelog.html.ep31
-rw-r--r--templates/gateway_timeout.html.ep27
-rw-r--r--templates/landingpage.html.ep8
-rw-r--r--templates/layouts/default.html.ep2
-rw-r--r--templates/select_backend.html.ep18
-rw-r--r--templates/traewelling.html.ep12
29 files changed, 837 insertions, 645 deletions
diff --git a/README.md b/README.md
index dd32d3b..07ac66e 100644
--- a/README.md
+++ b/README.md
@@ -2,12 +2,15 @@ travelynx - Railway Travel Logger
---
[travelynx](https://finalrewind.org/projects/travelynx/) allows checking into
-and out of individual trains, thus providing a log of your railway journeys
-annotated with real-time delays and service messages. It supports german
-railways and trains exposed by the Deutsche Bahn [IRIS
+individual public transit vehicles (e.g. buses, ferries, trams, trains) across
+most of Germany, Switzerland, Austria, Luxembourg, Ireland, and parts of the
+USA. Thus, it provides a log of your railway journeys annotated with real-time
+delays and service messages, if available. It supports german railways and
+trains exposed by the Deutsche Bahn [IRIS
Interface](https://finalrewind.org/projects/Travel-Status-DE-IRIS/) as well as
-local transit and some trains outside of germany exposed by the Deutsche Bahn
-[HAFAS Interface](https://finalrewind.org/projects/Travel-Status-DE-DeutscheBahn/).
+regional and local transit exposed by supported [HAFAS
+Instances](https://finalrewind.org/projects/Travel-Status-DE-HAFAS/). Support
+for EFA instances and bahn.de is under way.
You can use the public instance on [travelynx.de](https://travelynx.de) or
host your own. See the Installation and Setup notes below.
diff --git a/cpanfile b/cpanfile
index 673b738..c230118 100644
--- a/cpanfile
+++ b/cpanfile
@@ -6,6 +6,8 @@ requires 'DateTime::Format::Strptime';
requires 'Email::Sender::Simple';
requires 'GIS::Distance';
requires 'GIS::Distance::Fast';
+requires 'IO::Socket::Socks', '>= 0.64';
+requires 'IO::Socket::SSL', '>= 2.009';
requires 'List::UtilsBy';
requires 'Math::Polygon';
requires 'MIME::Entity';
diff --git a/cpanfile.snapshot b/cpanfile.snapshot
index dcaa96b..18ba180 100644
--- a/cpanfile.snapshot
+++ b/cpanfile.snapshot
@@ -226,10 +226,10 @@ DISTRIBUTIONS
Canary::Stability 2013
requirements:
ExtUtils::MakeMaker 0
- Capture-Tiny-0.48
- pathname: D/DA/DAGOLDEN/Capture-Tiny-0.48.tar.gz
+ Capture-Tiny-0.50
+ pathname: D/DA/DAGOLDEN/Capture-Tiny-0.50.tar.gz
provides:
- Capture::Tiny 0.48
+ Capture::Tiny 0.50
requirements:
Carp 0
Exporter 0
@@ -382,8 +382,8 @@ DISTRIBUTIONS
Test::More 0.88
Time::HiRes 0
version 0
- DBI-1.645
- pathname: H/HM/HMBRAND/DBI-1.645.tgz
+ DBI-1.647
+ pathname: H/HM/HMBRAND/DBI-1.647.tgz
provides:
Bundle::DBI 12.008696
DBD::DBM 0.08
@@ -439,7 +439,7 @@ DISTRIBUTIONS
DBD::Sponge::dr 12.010003
DBD::Sponge::st 12.010003
DBDI 12.015129
- DBI 1.645
+ DBI 1.647
DBI::Const::GetInfo::ANSI 2.008697
DBI::Const::GetInfo::ODBC 2.011374
DBI::Const::GetInfoReturn 2.008697
@@ -479,7 +479,7 @@ DISTRIBUTIONS
DBI::SQL::Nano::Table_ 1.015544
DBI::Util::CacheMemory 0.010315
DBI::Util::_accessor 0.009479
- DBI::common 1.645
+ DBI::common 1.647
requirements:
ExtUtils::MakeMaker 6.48
Test::Simple 0.90
@@ -586,334 +586,334 @@ DISTRIBUTIONS
perl 5.008004
strict 0
warnings 0
- DateTime-TimeZone-2.63
- pathname: D/DR/DROLSKY/DateTime-TimeZone-2.63.tar.gz
- provides:
- DateTime::TimeZone 2.63
- DateTime::TimeZone::Africa::Abidjan 2.63
- DateTime::TimeZone::Africa::Algiers 2.63
- DateTime::TimeZone::Africa::Bissau 2.63
- DateTime::TimeZone::Africa::Cairo 2.63
- DateTime::TimeZone::Africa::Casablanca 2.63
- DateTime::TimeZone::Africa::Ceuta 2.63
- DateTime::TimeZone::Africa::El_Aaiun 2.63
- DateTime::TimeZone::Africa::Johannesburg 2.63
- DateTime::TimeZone::Africa::Juba 2.63
- DateTime::TimeZone::Africa::Khartoum 2.63
- DateTime::TimeZone::Africa::Lagos 2.63
- DateTime::TimeZone::Africa::Maputo 2.63
- DateTime::TimeZone::Africa::Monrovia 2.63
- DateTime::TimeZone::Africa::Nairobi 2.63
- DateTime::TimeZone::Africa::Ndjamena 2.63
- DateTime::TimeZone::Africa::Sao_Tome 2.63
- DateTime::TimeZone::Africa::Tripoli 2.63
- DateTime::TimeZone::Africa::Tunis 2.63
- DateTime::TimeZone::Africa::Windhoek 2.63
- DateTime::TimeZone::America::Adak 2.63
- DateTime::TimeZone::America::Anchorage 2.63
- DateTime::TimeZone::America::Araguaina 2.63
- DateTime::TimeZone::America::Argentina::Buenos_Aires 2.63
- DateTime::TimeZone::America::Argentina::Catamarca 2.63
- DateTime::TimeZone::America::Argentina::Cordoba 2.63
- DateTime::TimeZone::America::Argentina::Jujuy 2.63
- DateTime::TimeZone::America::Argentina::La_Rioja 2.63
- DateTime::TimeZone::America::Argentina::Mendoza 2.63
- DateTime::TimeZone::America::Argentina::Rio_Gallegos 2.63
- DateTime::TimeZone::America::Argentina::Salta 2.63
- DateTime::TimeZone::America::Argentina::San_Juan 2.63
- DateTime::TimeZone::America::Argentina::San_Luis 2.63
- DateTime::TimeZone::America::Argentina::Tucuman 2.63
- DateTime::TimeZone::America::Argentina::Ushuaia 2.63
- DateTime::TimeZone::America::Asuncion 2.63
- DateTime::TimeZone::America::Bahia 2.63
- DateTime::TimeZone::America::Bahia_Banderas 2.63
- DateTime::TimeZone::America::Barbados 2.63
- DateTime::TimeZone::America::Belem 2.63
- DateTime::TimeZone::America::Belize 2.63
- DateTime::TimeZone::America::Boa_Vista 2.63
- DateTime::TimeZone::America::Bogota 2.63
- DateTime::TimeZone::America::Boise 2.63
- DateTime::TimeZone::America::Cambridge_Bay 2.63
- DateTime::TimeZone::America::Campo_Grande 2.63
- DateTime::TimeZone::America::Cancun 2.63
- DateTime::TimeZone::America::Caracas 2.63
- DateTime::TimeZone::America::Cayenne 2.63
- DateTime::TimeZone::America::Chicago 2.63
- DateTime::TimeZone::America::Chihuahua 2.63
- DateTime::TimeZone::America::Ciudad_Juarez 2.63
- DateTime::TimeZone::America::Costa_Rica 2.63
- DateTime::TimeZone::America::Cuiaba 2.63
- DateTime::TimeZone::America::Danmarkshavn 2.63
- DateTime::TimeZone::America::Dawson 2.63
- DateTime::TimeZone::America::Dawson_Creek 2.63
- DateTime::TimeZone::America::Denver 2.63
- DateTime::TimeZone::America::Detroit 2.63
- DateTime::TimeZone::America::Edmonton 2.63
- DateTime::TimeZone::America::Eirunepe 2.63
- DateTime::TimeZone::America::El_Salvador 2.63
- DateTime::TimeZone::America::Fort_Nelson 2.63
- DateTime::TimeZone::America::Fortaleza 2.63
- DateTime::TimeZone::America::Glace_Bay 2.63
- DateTime::TimeZone::America::Goose_Bay 2.63
- DateTime::TimeZone::America::Grand_Turk 2.63
- DateTime::TimeZone::America::Guatemala 2.63
- DateTime::TimeZone::America::Guayaquil 2.63
- DateTime::TimeZone::America::Guyana 2.63
- DateTime::TimeZone::America::Halifax 2.63
- DateTime::TimeZone::America::Havana 2.63
- DateTime::TimeZone::America::Hermosillo 2.63
- DateTime::TimeZone::America::Indiana::Indianapolis 2.63
- DateTime::TimeZone::America::Indiana::Knox 2.63
- DateTime::TimeZone::America::Indiana::Marengo 2.63
- DateTime::TimeZone::America::Indiana::Petersburg 2.63
- DateTime::TimeZone::America::Indiana::Tell_City 2.63
- DateTime::TimeZone::America::Indiana::Vevay 2.63
- DateTime::TimeZone::America::Indiana::Vincennes 2.63
- DateTime::TimeZone::America::Indiana::Winamac 2.63
- DateTime::TimeZone::America::Inuvik 2.63
- DateTime::TimeZone::America::Iqaluit 2.63
- DateTime::TimeZone::America::Jamaica 2.63
- DateTime::TimeZone::America::Juneau 2.63
- DateTime::TimeZone::America::Kentucky::Louisville 2.63
- DateTime::TimeZone::America::Kentucky::Monticello 2.63
- DateTime::TimeZone::America::La_Paz 2.63
- DateTime::TimeZone::America::Lima 2.63
- DateTime::TimeZone::America::Los_Angeles 2.63
- DateTime::TimeZone::America::Maceio 2.63
- DateTime::TimeZone::America::Managua 2.63
- DateTime::TimeZone::America::Manaus 2.63
- DateTime::TimeZone::America::Martinique 2.63
- DateTime::TimeZone::America::Matamoros 2.63
- DateTime::TimeZone::America::Mazatlan 2.63
- DateTime::TimeZone::America::Menominee 2.63
- DateTime::TimeZone::America::Merida 2.63
- DateTime::TimeZone::America::Metlakatla 2.63
- DateTime::TimeZone::America::Mexico_City 2.63
- DateTime::TimeZone::America::Miquelon 2.63
- DateTime::TimeZone::America::Moncton 2.63
- DateTime::TimeZone::America::Monterrey 2.63
- DateTime::TimeZone::America::Montevideo 2.63
- DateTime::TimeZone::America::New_York 2.63
- DateTime::TimeZone::America::Nome 2.63
- DateTime::TimeZone::America::Noronha 2.63
- DateTime::TimeZone::America::North_Dakota::Beulah 2.63
- DateTime::TimeZone::America::North_Dakota::Center 2.63
- DateTime::TimeZone::America::North_Dakota::New_Salem 2.63
- DateTime::TimeZone::America::Nuuk 2.63
- DateTime::TimeZone::America::Ojinaga 2.63
- DateTime::TimeZone::America::Panama 2.63
- DateTime::TimeZone::America::Paramaribo 2.63
- DateTime::TimeZone::America::Phoenix 2.63
- DateTime::TimeZone::America::Port_au_Prince 2.63
- DateTime::TimeZone::America::Porto_Velho 2.63
- DateTime::TimeZone::America::Puerto_Rico 2.63
- DateTime::TimeZone::America::Punta_Arenas 2.63
- DateTime::TimeZone::America::Rankin_Inlet 2.63
- DateTime::TimeZone::America::Recife 2.63
- DateTime::TimeZone::America::Regina 2.63
- DateTime::TimeZone::America::Resolute 2.63
- DateTime::TimeZone::America::Rio_Branco 2.63
- DateTime::TimeZone::America::Santarem 2.63
- DateTime::TimeZone::America::Santiago 2.63
- DateTime::TimeZone::America::Santo_Domingo 2.63
- DateTime::TimeZone::America::Sao_Paulo 2.63
- DateTime::TimeZone::America::Scoresbysund 2.63
- DateTime::TimeZone::America::Sitka 2.63
- DateTime::TimeZone::America::St_Johns 2.63
- DateTime::TimeZone::America::Swift_Current 2.63
- DateTime::TimeZone::America::Tegucigalpa 2.63
- DateTime::TimeZone::America::Thule 2.63
- DateTime::TimeZone::America::Tijuana 2.63
- DateTime::TimeZone::America::Toronto 2.63
- DateTime::TimeZone::America::Vancouver 2.63
- DateTime::TimeZone::America::Whitehorse 2.63
- DateTime::TimeZone::America::Winnipeg 2.63
- DateTime::TimeZone::America::Yakutat 2.63
- DateTime::TimeZone::Antarctica::Casey 2.63
- DateTime::TimeZone::Antarctica::Davis 2.63
- DateTime::TimeZone::Antarctica::Macquarie 2.63
- DateTime::TimeZone::Antarctica::Mawson 2.63
- DateTime::TimeZone::Antarctica::Palmer 2.63
- DateTime::TimeZone::Antarctica::Rothera 2.63
- DateTime::TimeZone::Antarctica::Troll 2.63
- DateTime::TimeZone::Antarctica::Vostok 2.63
- DateTime::TimeZone::Asia::Almaty 2.63
- DateTime::TimeZone::Asia::Amman 2.63
- DateTime::TimeZone::Asia::Anadyr 2.63
- DateTime::TimeZone::Asia::Aqtau 2.63
- DateTime::TimeZone::Asia::Aqtobe 2.63
- DateTime::TimeZone::Asia::Ashgabat 2.63
- DateTime::TimeZone::Asia::Atyrau 2.63
- DateTime::TimeZone::Asia::Baghdad 2.63
- DateTime::TimeZone::Asia::Baku 2.63
- DateTime::TimeZone::Asia::Bangkok 2.63
- DateTime::TimeZone::Asia::Barnaul 2.63
- DateTime::TimeZone::Asia::Beirut 2.63
- DateTime::TimeZone::Asia::Bishkek 2.63
- DateTime::TimeZone::Asia::Chita 2.63
- DateTime::TimeZone::Asia::Colombo 2.63
- DateTime::TimeZone::Asia::Damascus 2.63
- DateTime::TimeZone::Asia::Dhaka 2.63
- DateTime::TimeZone::Asia::Dili 2.63
- DateTime::TimeZone::Asia::Dubai 2.63
- DateTime::TimeZone::Asia::Dushanbe 2.63
- DateTime::TimeZone::Asia::Famagusta 2.63
- DateTime::TimeZone::Asia::Gaza 2.63
- DateTime::TimeZone::Asia::Hebron 2.63
- DateTime::TimeZone::Asia::Ho_Chi_Minh 2.63
- DateTime::TimeZone::Asia::Hong_Kong 2.63
- DateTime::TimeZone::Asia::Hovd 2.63
- DateTime::TimeZone::Asia::Irkutsk 2.63
- DateTime::TimeZone::Asia::Jakarta 2.63
- DateTime::TimeZone::Asia::Jayapura 2.63
- DateTime::TimeZone::Asia::Jerusalem 2.63
- DateTime::TimeZone::Asia::Kabul 2.63
- DateTime::TimeZone::Asia::Kamchatka 2.63
- DateTime::TimeZone::Asia::Karachi 2.63
- DateTime::TimeZone::Asia::Kathmandu 2.63
- DateTime::TimeZone::Asia::Khandyga 2.63
- DateTime::TimeZone::Asia::Kolkata 2.63
- DateTime::TimeZone::Asia::Krasnoyarsk 2.63
- DateTime::TimeZone::Asia::Kuching 2.63
- DateTime::TimeZone::Asia::Macau 2.63
- DateTime::TimeZone::Asia::Magadan 2.63
- DateTime::TimeZone::Asia::Makassar 2.63
- DateTime::TimeZone::Asia::Manila 2.63
- DateTime::TimeZone::Asia::Nicosia 2.63
- DateTime::TimeZone::Asia::Novokuznetsk 2.63
- DateTime::TimeZone::Asia::Novosibirsk 2.63
- DateTime::TimeZone::Asia::Omsk 2.63
- DateTime::TimeZone::Asia::Oral 2.63
- DateTime::TimeZone::Asia::Pontianak 2.63
- DateTime::TimeZone::Asia::Pyongyang 2.63
- DateTime::TimeZone::Asia::Qatar 2.63
- DateTime::TimeZone::Asia::Qostanay 2.63
- DateTime::TimeZone::Asia::Qyzylorda 2.63
- DateTime::TimeZone::Asia::Riyadh 2.63
- DateTime::TimeZone::Asia::Sakhalin 2.63
- DateTime::TimeZone::Asia::Samarkand 2.63
- DateTime::TimeZone::Asia::Seoul 2.63
- DateTime::TimeZone::Asia::Shanghai 2.63
- DateTime::TimeZone::Asia::Singapore 2.63
- DateTime::TimeZone::Asia::Srednekolymsk 2.63
- DateTime::TimeZone::Asia::Taipei 2.63
- DateTime::TimeZone::Asia::Tashkent 2.63
- DateTime::TimeZone::Asia::Tbilisi 2.63
- DateTime::TimeZone::Asia::Tehran 2.63
- DateTime::TimeZone::Asia::Thimphu 2.63
- DateTime::TimeZone::Asia::Tokyo 2.63
- DateTime::TimeZone::Asia::Tomsk 2.63
- DateTime::TimeZone::Asia::Ulaanbaatar 2.63
- DateTime::TimeZone::Asia::Urumqi 2.63
- DateTime::TimeZone::Asia::Ust_Nera 2.63
- DateTime::TimeZone::Asia::Vladivostok 2.63
- DateTime::TimeZone::Asia::Yakutsk 2.63
- DateTime::TimeZone::Asia::Yangon 2.63
- DateTime::TimeZone::Asia::Yekaterinburg 2.63
- DateTime::TimeZone::Asia::Yerevan 2.63
- DateTime::TimeZone::Atlantic::Azores 2.63
- DateTime::TimeZone::Atlantic::Bermuda 2.63
- DateTime::TimeZone::Atlantic::Canary 2.63
- DateTime::TimeZone::Atlantic::Cape_Verde 2.63
- DateTime::TimeZone::Atlantic::Faroe 2.63
- DateTime::TimeZone::Atlantic::Madeira 2.63
- DateTime::TimeZone::Atlantic::South_Georgia 2.63
- DateTime::TimeZone::Atlantic::Stanley 2.63
- DateTime::TimeZone::Australia::Adelaide 2.63
- DateTime::TimeZone::Australia::Brisbane 2.63
- DateTime::TimeZone::Australia::Broken_Hill 2.63
- DateTime::TimeZone::Australia::Darwin 2.63
- DateTime::TimeZone::Australia::Eucla 2.63
- DateTime::TimeZone::Australia::Hobart 2.63
- DateTime::TimeZone::Australia::Lindeman 2.63
- DateTime::TimeZone::Australia::Lord_Howe 2.63
- DateTime::TimeZone::Australia::Melbourne 2.63
- DateTime::TimeZone::Australia::Perth 2.63
- DateTime::TimeZone::Australia::Sydney 2.63
- DateTime::TimeZone::Catalog 2.63
- DateTime::TimeZone::Europe::Andorra 2.63
- DateTime::TimeZone::Europe::Astrakhan 2.63
- DateTime::TimeZone::Europe::Athens 2.63
- DateTime::TimeZone::Europe::Belgrade 2.63
- DateTime::TimeZone::Europe::Berlin 2.63
- DateTime::TimeZone::Europe::Brussels 2.63
- DateTime::TimeZone::Europe::Bucharest 2.63
- DateTime::TimeZone::Europe::Budapest 2.63
- DateTime::TimeZone::Europe::Chisinau 2.63
- DateTime::TimeZone::Europe::Dublin 2.63
- DateTime::TimeZone::Europe::Gibraltar 2.63
- DateTime::TimeZone::Europe::Helsinki 2.63
- DateTime::TimeZone::Europe::Istanbul 2.63
- DateTime::TimeZone::Europe::Kaliningrad 2.63
- DateTime::TimeZone::Europe::Kirov 2.63
- DateTime::TimeZone::Europe::Kyiv 2.63
- DateTime::TimeZone::Europe::Lisbon 2.63
- DateTime::TimeZone::Europe::London 2.63
- DateTime::TimeZone::Europe::Madrid 2.63
- DateTime::TimeZone::Europe::Malta 2.63
- DateTime::TimeZone::Europe::Minsk 2.63
- DateTime::TimeZone::Europe::Moscow 2.63
- DateTime::TimeZone::Europe::Paris 2.63
- DateTime::TimeZone::Europe::Prague 2.63
- DateTime::TimeZone::Europe::Riga 2.63
- DateTime::TimeZone::Europe::Rome 2.63
- DateTime::TimeZone::Europe::Samara 2.63
- DateTime::TimeZone::Europe::Saratov 2.63
- DateTime::TimeZone::Europe::Simferopol 2.63
- DateTime::TimeZone::Europe::Sofia 2.63
- DateTime::TimeZone::Europe::Tallinn 2.63
- DateTime::TimeZone::Europe::Tirane 2.63
- DateTime::TimeZone::Europe::Ulyanovsk 2.63
- DateTime::TimeZone::Europe::Vienna 2.63
- DateTime::TimeZone::Europe::Vilnius 2.63
- DateTime::TimeZone::Europe::Volgograd 2.63
- DateTime::TimeZone::Europe::Warsaw 2.63
- DateTime::TimeZone::Europe::Zurich 2.63
- DateTime::TimeZone::Floating 2.63
- DateTime::TimeZone::Indian::Chagos 2.63
- DateTime::TimeZone::Indian::Maldives 2.63
- DateTime::TimeZone::Indian::Mauritius 2.63
- DateTime::TimeZone::Local 2.63
- DateTime::TimeZone::Local::Android 2.63
- DateTime::TimeZone::Local::Unix 2.63
- DateTime::TimeZone::Local::VMS 2.63
- DateTime::TimeZone::OffsetOnly 2.63
- DateTime::TimeZone::OlsonDB 2.63
- DateTime::TimeZone::OlsonDB::Change 2.63
- DateTime::TimeZone::OlsonDB::Observance 2.63
- DateTime::TimeZone::OlsonDB::Rule 2.63
- DateTime::TimeZone::OlsonDB::Zone 2.63
- DateTime::TimeZone::Pacific::Apia 2.63
- DateTime::TimeZone::Pacific::Auckland 2.63
- DateTime::TimeZone::Pacific::Bougainville 2.63
- DateTime::TimeZone::Pacific::Chatham 2.63
- DateTime::TimeZone::Pacific::Easter 2.63
- DateTime::TimeZone::Pacific::Efate 2.63
- DateTime::TimeZone::Pacific::Fakaofo 2.63
- DateTime::TimeZone::Pacific::Fiji 2.63
- DateTime::TimeZone::Pacific::Galapagos 2.63
- DateTime::TimeZone::Pacific::Gambier 2.63
- DateTime::TimeZone::Pacific::Guadalcanal 2.63
- DateTime::TimeZone::Pacific::Guam 2.63
- DateTime::TimeZone::Pacific::Honolulu 2.63
- DateTime::TimeZone::Pacific::Kanton 2.63
- DateTime::TimeZone::Pacific::Kiritimati 2.63
- DateTime::TimeZone::Pacific::Kosrae 2.63
- DateTime::TimeZone::Pacific::Kwajalein 2.63
- DateTime::TimeZone::Pacific::Marquesas 2.63
- DateTime::TimeZone::Pacific::Nauru 2.63
- DateTime::TimeZone::Pacific::Niue 2.63
- DateTime::TimeZone::Pacific::Norfolk 2.63
- DateTime::TimeZone::Pacific::Noumea 2.63
- DateTime::TimeZone::Pacific::Pago_Pago 2.63
- DateTime::TimeZone::Pacific::Palau 2.63
- DateTime::TimeZone::Pacific::Pitcairn 2.63
- DateTime::TimeZone::Pacific::Port_Moresby 2.63
- DateTime::TimeZone::Pacific::Rarotonga 2.63
- DateTime::TimeZone::Pacific::Tahiti 2.63
- DateTime::TimeZone::Pacific::Tarawa 2.63
- DateTime::TimeZone::Pacific::Tongatapu 2.63
- DateTime::TimeZone::UTC 2.63
+ DateTime-TimeZone-2.64
+ pathname: D/DR/DROLSKY/DateTime-TimeZone-2.64.tar.gz
+ provides:
+ DateTime::TimeZone 2.64
+ DateTime::TimeZone::Africa::Abidjan 2.64
+ DateTime::TimeZone::Africa::Algiers 2.64
+ DateTime::TimeZone::Africa::Bissau 2.64
+ DateTime::TimeZone::Africa::Cairo 2.64
+ DateTime::TimeZone::Africa::Casablanca 2.64
+ DateTime::TimeZone::Africa::Ceuta 2.64
+ DateTime::TimeZone::Africa::El_Aaiun 2.64
+ DateTime::TimeZone::Africa::Johannesburg 2.64
+ DateTime::TimeZone::Africa::Juba 2.64
+ DateTime::TimeZone::Africa::Khartoum 2.64
+ DateTime::TimeZone::Africa::Lagos 2.64
+ DateTime::TimeZone::Africa::Maputo 2.64
+ DateTime::TimeZone::Africa::Monrovia 2.64
+ DateTime::TimeZone::Africa::Nairobi 2.64
+ DateTime::TimeZone::Africa::Ndjamena 2.64
+ DateTime::TimeZone::Africa::Sao_Tome 2.64
+ DateTime::TimeZone::Africa::Tripoli 2.64
+ DateTime::TimeZone::Africa::Tunis 2.64
+ DateTime::TimeZone::Africa::Windhoek 2.64
+ DateTime::TimeZone::America::Adak 2.64
+ DateTime::TimeZone::America::Anchorage 2.64
+ DateTime::TimeZone::America::Araguaina 2.64
+ DateTime::TimeZone::America::Argentina::Buenos_Aires 2.64
+ DateTime::TimeZone::America::Argentina::Catamarca 2.64
+ DateTime::TimeZone::America::Argentina::Cordoba 2.64
+ DateTime::TimeZone::America::Argentina::Jujuy 2.64
+ DateTime::TimeZone::America::Argentina::La_Rioja 2.64
+ DateTime::TimeZone::America::Argentina::Mendoza 2.64
+ DateTime::TimeZone::America::Argentina::Rio_Gallegos 2.64
+ DateTime::TimeZone::America::Argentina::Salta 2.64
+ DateTime::TimeZone::America::Argentina::San_Juan 2.64
+ DateTime::TimeZone::America::Argentina::San_Luis 2.64
+ DateTime::TimeZone::America::Argentina::Tucuman 2.64
+ DateTime::TimeZone::America::Argentina::Ushuaia 2.64
+ DateTime::TimeZone::America::Asuncion 2.64
+ DateTime::TimeZone::America::Bahia 2.64
+ DateTime::TimeZone::America::Bahia_Banderas 2.64
+ DateTime::TimeZone::America::Barbados 2.64
+ DateTime::TimeZone::America::Belem 2.64
+ DateTime::TimeZone::America::Belize 2.64
+ DateTime::TimeZone::America::Boa_Vista 2.64
+ DateTime::TimeZone::America::Bogota 2.64
+ DateTime::TimeZone::America::Boise 2.64
+ DateTime::TimeZone::America::Cambridge_Bay 2.64
+ DateTime::TimeZone::America::Campo_Grande 2.64
+ DateTime::TimeZone::America::Cancun 2.64
+ DateTime::TimeZone::America::Caracas 2.64
+ DateTime::TimeZone::America::Cayenne 2.64
+ DateTime::TimeZone::America::Chicago 2.64
+ DateTime::TimeZone::America::Chihuahua 2.64
+ DateTime::TimeZone::America::Ciudad_Juarez 2.64
+ DateTime::TimeZone::America::Costa_Rica 2.64
+ DateTime::TimeZone::America::Cuiaba 2.64
+ DateTime::TimeZone::America::Danmarkshavn 2.64
+ DateTime::TimeZone::America::Dawson 2.64
+ DateTime::TimeZone::America::Dawson_Creek 2.64
+ DateTime::TimeZone::America::Denver 2.64
+ DateTime::TimeZone::America::Detroit 2.64
+ DateTime::TimeZone::America::Edmonton 2.64
+ DateTime::TimeZone::America::Eirunepe 2.64
+ DateTime::TimeZone::America::El_Salvador 2.64
+ DateTime::TimeZone::America::Fort_Nelson 2.64
+ DateTime::TimeZone::America::Fortaleza 2.64
+ DateTime::TimeZone::America::Glace_Bay 2.64
+ DateTime::TimeZone::America::Goose_Bay 2.64
+ DateTime::TimeZone::America::Grand_Turk 2.64
+ DateTime::TimeZone::America::Guatemala 2.64
+ DateTime::TimeZone::America::Guayaquil 2.64
+ DateTime::TimeZone::America::Guyana 2.64
+ DateTime::TimeZone::America::Halifax 2.64
+ DateTime::TimeZone::America::Havana 2.64
+ DateTime::TimeZone::America::Hermosillo 2.64
+ DateTime::TimeZone::America::Indiana::Indianapolis 2.64
+ DateTime::TimeZone::America::Indiana::Knox 2.64
+ DateTime::TimeZone::America::Indiana::Marengo 2.64
+ DateTime::TimeZone::America::Indiana::Petersburg 2.64
+ DateTime::TimeZone::America::Indiana::Tell_City 2.64
+ DateTime::TimeZone::America::Indiana::Vevay 2.64
+ DateTime::TimeZone::America::Indiana::Vincennes 2.64
+ DateTime::TimeZone::America::Indiana::Winamac 2.64
+ DateTime::TimeZone::America::Inuvik 2.64
+ DateTime::TimeZone::America::Iqaluit 2.64
+ DateTime::TimeZone::America::Jamaica 2.64
+ DateTime::TimeZone::America::Juneau 2.64
+ DateTime::TimeZone::America::Kentucky::Louisville 2.64
+ DateTime::TimeZone::America::Kentucky::Monticello 2.64
+ DateTime::TimeZone::America::La_Paz 2.64
+ DateTime::TimeZone::America::Lima 2.64
+ DateTime::TimeZone::America::Los_Angeles 2.64
+ DateTime::TimeZone::America::Maceio 2.64
+ DateTime::TimeZone::America::Managua 2.64
+ DateTime::TimeZone::America::Manaus 2.64
+ DateTime::TimeZone::America::Martinique 2.64
+ DateTime::TimeZone::America::Matamoros 2.64
+ DateTime::TimeZone::America::Mazatlan 2.64
+ DateTime::TimeZone::America::Menominee 2.64
+ DateTime::TimeZone::America::Merida 2.64
+ DateTime::TimeZone::America::Metlakatla 2.64
+ DateTime::TimeZone::America::Mexico_City 2.64
+ DateTime::TimeZone::America::Miquelon 2.64
+ DateTime::TimeZone::America::Moncton 2.64
+ DateTime::TimeZone::America::Monterrey 2.64
+ DateTime::TimeZone::America::Montevideo 2.64
+ DateTime::TimeZone::America::New_York 2.64
+ DateTime::TimeZone::America::Nome 2.64
+ DateTime::TimeZone::America::Noronha 2.64
+ DateTime::TimeZone::America::North_Dakota::Beulah 2.64
+ DateTime::TimeZone::America::North_Dakota::Center 2.64
+ DateTime::TimeZone::America::North_Dakota::New_Salem 2.64
+ DateTime::TimeZone::America::Nuuk 2.64
+ DateTime::TimeZone::America::Ojinaga 2.64
+ DateTime::TimeZone::America::Panama 2.64
+ DateTime::TimeZone::America::Paramaribo 2.64
+ DateTime::TimeZone::America::Phoenix 2.64
+ DateTime::TimeZone::America::Port_au_Prince 2.64
+ DateTime::TimeZone::America::Porto_Velho 2.64
+ DateTime::TimeZone::America::Puerto_Rico 2.64
+ DateTime::TimeZone::America::Punta_Arenas 2.64
+ DateTime::TimeZone::America::Rankin_Inlet 2.64
+ DateTime::TimeZone::America::Recife 2.64
+ DateTime::TimeZone::America::Regina 2.64
+ DateTime::TimeZone::America::Resolute 2.64
+ DateTime::TimeZone::America::Rio_Branco 2.64
+ DateTime::TimeZone::America::Santarem 2.64
+ DateTime::TimeZone::America::Santiago 2.64
+ DateTime::TimeZone::America::Santo_Domingo 2.64
+ DateTime::TimeZone::America::Sao_Paulo 2.64
+ DateTime::TimeZone::America::Scoresbysund 2.64
+ DateTime::TimeZone::America::Sitka 2.64
+ DateTime::TimeZone::America::St_Johns 2.64
+ DateTime::TimeZone::America::Swift_Current 2.64
+ DateTime::TimeZone::America::Tegucigalpa 2.64
+ DateTime::TimeZone::America::Thule 2.64
+ DateTime::TimeZone::America::Tijuana 2.64
+ DateTime::TimeZone::America::Toronto 2.64
+ DateTime::TimeZone::America::Vancouver 2.64
+ DateTime::TimeZone::America::Whitehorse 2.64
+ DateTime::TimeZone::America::Winnipeg 2.64
+ DateTime::TimeZone::America::Yakutat 2.64
+ DateTime::TimeZone::Antarctica::Casey 2.64
+ DateTime::TimeZone::Antarctica::Davis 2.64
+ DateTime::TimeZone::Antarctica::Macquarie 2.64
+ DateTime::TimeZone::Antarctica::Mawson 2.64
+ DateTime::TimeZone::Antarctica::Palmer 2.64
+ DateTime::TimeZone::Antarctica::Rothera 2.64
+ DateTime::TimeZone::Antarctica::Troll 2.64
+ DateTime::TimeZone::Antarctica::Vostok 2.64
+ DateTime::TimeZone::Asia::Almaty 2.64
+ DateTime::TimeZone::Asia::Amman 2.64
+ DateTime::TimeZone::Asia::Anadyr 2.64
+ DateTime::TimeZone::Asia::Aqtau 2.64
+ DateTime::TimeZone::Asia::Aqtobe 2.64
+ DateTime::TimeZone::Asia::Ashgabat 2.64
+ DateTime::TimeZone::Asia::Atyrau 2.64
+ DateTime::TimeZone::Asia::Baghdad 2.64
+ DateTime::TimeZone::Asia::Baku 2.64
+ DateTime::TimeZone::Asia::Bangkok 2.64
+ DateTime::TimeZone::Asia::Barnaul 2.64
+ DateTime::TimeZone::Asia::Beirut 2.64
+ DateTime::TimeZone::Asia::Bishkek 2.64
+ DateTime::TimeZone::Asia::Chita 2.64
+ DateTime::TimeZone::Asia::Colombo 2.64
+ DateTime::TimeZone::Asia::Damascus 2.64
+ DateTime::TimeZone::Asia::Dhaka 2.64
+ DateTime::TimeZone::Asia::Dili 2.64
+ DateTime::TimeZone::Asia::Dubai 2.64
+ DateTime::TimeZone::Asia::Dushanbe 2.64
+ DateTime::TimeZone::Asia::Famagusta 2.64
+ DateTime::TimeZone::Asia::Gaza 2.64
+ DateTime::TimeZone::Asia::Hebron 2.64
+ DateTime::TimeZone::Asia::Ho_Chi_Minh 2.64
+ DateTime::TimeZone::Asia::Hong_Kong 2.64
+ DateTime::TimeZone::Asia::Hovd 2.64
+ DateTime::TimeZone::Asia::Irkutsk 2.64
+ DateTime::TimeZone::Asia::Jakarta 2.64
+ DateTime::TimeZone::Asia::Jayapura 2.64
+ DateTime::TimeZone::Asia::Jerusalem 2.64
+ DateTime::TimeZone::Asia::Kabul 2.64
+ DateTime::TimeZone::Asia::Kamchatka 2.64
+ DateTime::TimeZone::Asia::Karachi 2.64
+ DateTime::TimeZone::Asia::Kathmandu 2.64
+ DateTime::TimeZone::Asia::Khandyga 2.64
+ DateTime::TimeZone::Asia::Kolkata 2.64
+ DateTime::TimeZone::Asia::Krasnoyarsk 2.64
+ DateTime::TimeZone::Asia::Kuching 2.64
+ DateTime::TimeZone::Asia::Macau 2.64
+ DateTime::TimeZone::Asia::Magadan 2.64
+ DateTime::TimeZone::Asia::Makassar 2.64
+ DateTime::TimeZone::Asia::Manila 2.64
+ DateTime::TimeZone::Asia::Nicosia 2.64
+ DateTime::TimeZone::Asia::Novokuznetsk 2.64
+ DateTime::TimeZone::Asia::Novosibirsk 2.64
+ DateTime::TimeZone::Asia::Omsk 2.64
+ DateTime::TimeZone::Asia::Oral 2.64
+ DateTime::TimeZone::Asia::Pontianak 2.64
+ DateTime::TimeZone::Asia::Pyongyang 2.64
+ DateTime::TimeZone::Asia::Qatar 2.64
+ DateTime::TimeZone::Asia::Qostanay 2.64
+ DateTime::TimeZone::Asia::Qyzylorda 2.64
+ DateTime::TimeZone::Asia::Riyadh 2.64
+ DateTime::TimeZone::Asia::Sakhalin 2.64
+ DateTime::TimeZone::Asia::Samarkand 2.64
+ DateTime::TimeZone::Asia::Seoul 2.64
+ DateTime::TimeZone::Asia::Shanghai 2.64
+ DateTime::TimeZone::Asia::Singapore 2.64
+ DateTime::TimeZone::Asia::Srednekolymsk 2.64
+ DateTime::TimeZone::Asia::Taipei 2.64
+ DateTime::TimeZone::Asia::Tashkent 2.64
+ DateTime::TimeZone::Asia::Tbilisi 2.64
+ DateTime::TimeZone::Asia::Tehran 2.64
+ DateTime::TimeZone::Asia::Thimphu 2.64
+ DateTime::TimeZone::Asia::Tokyo 2.64
+ DateTime::TimeZone::Asia::Tomsk 2.64
+ DateTime::TimeZone::Asia::Ulaanbaatar 2.64
+ DateTime::TimeZone::Asia::Urumqi 2.64
+ DateTime::TimeZone::Asia::Ust_Nera 2.64
+ DateTime::TimeZone::Asia::Vladivostok 2.64
+ DateTime::TimeZone::Asia::Yakutsk 2.64
+ DateTime::TimeZone::Asia::Yangon 2.64
+ DateTime::TimeZone::Asia::Yekaterinburg 2.64
+ DateTime::TimeZone::Asia::Yerevan 2.64
+ DateTime::TimeZone::Atlantic::Azores 2.64
+ DateTime::TimeZone::Atlantic::Bermuda 2.64
+ DateTime::TimeZone::Atlantic::Canary 2.64
+ DateTime::TimeZone::Atlantic::Cape_Verde 2.64
+ DateTime::TimeZone::Atlantic::Faroe 2.64
+ DateTime::TimeZone::Atlantic::Madeira 2.64
+ DateTime::TimeZone::Atlantic::South_Georgia 2.64
+ DateTime::TimeZone::Atlantic::Stanley 2.64
+ DateTime::TimeZone::Australia::Adelaide 2.64
+ DateTime::TimeZone::Australia::Brisbane 2.64
+ DateTime::TimeZone::Australia::Broken_Hill 2.64
+ DateTime::TimeZone::Australia::Darwin 2.64
+ DateTime::TimeZone::Australia::Eucla 2.64
+ DateTime::TimeZone::Australia::Hobart 2.64
+ DateTime::TimeZone::Australia::Lindeman 2.64
+ DateTime::TimeZone::Australia::Lord_Howe 2.64
+ DateTime::TimeZone::Australia::Melbourne 2.64
+ DateTime::TimeZone::Australia::Perth 2.64
+ DateTime::TimeZone::Australia::Sydney 2.64
+ DateTime::TimeZone::Catalog 2.64
+ DateTime::TimeZone::Europe::Andorra 2.64
+ DateTime::TimeZone::Europe::Astrakhan 2.64
+ DateTime::TimeZone::Europe::Athens 2.64
+ DateTime::TimeZone::Europe::Belgrade 2.64
+ DateTime::TimeZone::Europe::Berlin 2.64
+ DateTime::TimeZone::Europe::Brussels 2.64
+ DateTime::TimeZone::Europe::Bucharest 2.64
+ DateTime::TimeZone::Europe::Budapest 2.64
+ DateTime::TimeZone::Europe::Chisinau 2.64
+ DateTime::TimeZone::Europe::Dublin 2.64
+ DateTime::TimeZone::Europe::Gibraltar 2.64
+ DateTime::TimeZone::Europe::Helsinki 2.64
+ DateTime::TimeZone::Europe::Istanbul 2.64
+ DateTime::TimeZone::Europe::Kaliningrad 2.64
+ DateTime::TimeZone::Europe::Kirov 2.64
+ DateTime::TimeZone::Europe::Kyiv 2.64
+ DateTime::TimeZone::Europe::Lisbon 2.64
+ DateTime::TimeZone::Europe::London 2.64
+ DateTime::TimeZone::Europe::Madrid 2.64
+ DateTime::TimeZone::Europe::Malta 2.64
+ DateTime::TimeZone::Europe::Minsk 2.64
+ DateTime::TimeZone::Europe::Moscow 2.64
+ DateTime::TimeZone::Europe::Paris 2.64
+ DateTime::TimeZone::Europe::Prague 2.64
+ DateTime::TimeZone::Europe::Riga 2.64
+ DateTime::TimeZone::Europe::Rome 2.64
+ DateTime::TimeZone::Europe::Samara 2.64
+ DateTime::TimeZone::Europe::Saratov 2.64
+ DateTime::TimeZone::Europe::Simferopol 2.64
+ DateTime::TimeZone::Europe::Sofia 2.64
+ DateTime::TimeZone::Europe::Tallinn 2.64
+ DateTime::TimeZone::Europe::Tirane 2.64
+ DateTime::TimeZone::Europe::Ulyanovsk 2.64
+ DateTime::TimeZone::Europe::Vienna 2.64
+ DateTime::TimeZone::Europe::Vilnius 2.64
+ DateTime::TimeZone::Europe::Volgograd 2.64
+ DateTime::TimeZone::Europe::Warsaw 2.64
+ DateTime::TimeZone::Europe::Zurich 2.64
+ DateTime::TimeZone::Floating 2.64
+ DateTime::TimeZone::Indian::Chagos 2.64
+ DateTime::TimeZone::Indian::Maldives 2.64
+ DateTime::TimeZone::Indian::Mauritius 2.64
+ DateTime::TimeZone::Local 2.64
+ DateTime::TimeZone::Local::Android 2.64
+ DateTime::TimeZone::Local::Unix 2.64
+ DateTime::TimeZone::Local::VMS 2.64
+ DateTime::TimeZone::OffsetOnly 2.64
+ DateTime::TimeZone::OlsonDB 2.64
+ DateTime::TimeZone::OlsonDB::Change 2.64
+ DateTime::TimeZone::OlsonDB::Observance 2.64
+ DateTime::TimeZone::OlsonDB::Rule 2.64
+ DateTime::TimeZone::OlsonDB::Zone 2.64
+ DateTime::TimeZone::Pacific::Apia 2.64
+ DateTime::TimeZone::Pacific::Auckland 2.64
+ DateTime::TimeZone::Pacific::Bougainville 2.64
+ DateTime::TimeZone::Pacific::Chatham 2.64
+ DateTime::TimeZone::Pacific::Easter 2.64
+ DateTime::TimeZone::Pacific::Efate 2.64
+ DateTime::TimeZone::Pacific::Fakaofo 2.64
+ DateTime::TimeZone::Pacific::Fiji 2.64
+ DateTime::TimeZone::Pacific::Galapagos 2.64
+ DateTime::TimeZone::Pacific::Gambier 2.64
+ DateTime::TimeZone::Pacific::Guadalcanal 2.64
+ DateTime::TimeZone::Pacific::Guam 2.64
+ DateTime::TimeZone::Pacific::Honolulu 2.64
+ DateTime::TimeZone::Pacific::Kanton 2.64
+ DateTime::TimeZone::Pacific::Kiritimati 2.64
+ DateTime::TimeZone::Pacific::Kosrae 2.64
+ DateTime::TimeZone::Pacific::Kwajalein 2.64
+ DateTime::TimeZone::Pacific::Marquesas 2.64
+ DateTime::TimeZone::Pacific::Nauru 2.64
+ DateTime::TimeZone::Pacific::Niue 2.64
+ DateTime::TimeZone::Pacific::Norfolk 2.64
+ DateTime::TimeZone::Pacific::Noumea 2.64
+ DateTime::TimeZone::Pacific::Pago_Pago 2.64
+ DateTime::TimeZone::Pacific::Palau 2.64
+ DateTime::TimeZone::Pacific::Pitcairn 2.64
+ DateTime::TimeZone::Pacific::Port_Moresby 2.64
+ DateTime::TimeZone::Pacific::Rarotonga 2.64
+ DateTime::TimeZone::Pacific::Tahiti 2.64
+ DateTime::TimeZone::Pacific::Tarawa 2.64
+ DateTime::TimeZone::Pacific::Tongatapu 2.64
+ DateTime::TimeZone::UTC 2.64
requirements:
Class::Singleton 1.03
Cwd 3
@@ -1460,6 +1460,20 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 0
Net::SSLeay 1.46
Scalar::Util 0
+ IO-Socket-Socks-0.74
+ pathname: O/OL/OLEG/IO-Socket-Socks-0.74.tar.gz
+ provides:
+ IO::Socket::Socks 0.74
+ IO::Socket::Socks::Debug 0.74
+ IO::Socket::Socks::Error 0.74
+ IO::Socket::Socks::ReadOnlyVar 0.74
+ IO::Socket::Socks::SocketClassVar 0.74
+ requirements:
+ ExtUtils::MakeMaker 6.52
+ IO::Select 0
+ Socket 1.94
+ Test::More 0.88
+ constant 1.03
IO-String-1.08
pathname: G/GA/GAAS/IO-String-1.08.tar.gz
provides:
@@ -1614,38 +1628,38 @@ DISTRIBUTIONS
requirements:
ExtUtils::MakeMaker 0
perl 5.006
- MailTools-2.21
- pathname: M/MA/MARKOV/MailTools-2.21.tar.gz
- provides:
- Mail::Address 2.21
- Mail::Cap 2.21
- Mail::Field 2.21
- Mail::Field::AddrList 2.21
- Mail::Field::Date 2.21
- Mail::Field::Generic 2.21
- Mail::Filter 2.21
- Mail::Header 2.21
- Mail::Internet 2.21
- Mail::Mailer 2.21
- Mail::Mailer::qmail 2.21
- Mail::Mailer::rfc822 2.21
- Mail::Mailer::sendmail 2.21
- Mail::Mailer::smtp 2.21
- Mail::Mailer::smtp::pipe 2.21
- Mail::Mailer::smtps 2.21
- Mail::Mailer::smtps::pipe 2.21
- Mail::Mailer::testfile 2.21
- Mail::Mailer::testfile::pipe 2.21
- Mail::Send 2.21
- Mail::Util 2.21
- MailTools 2.21
+ MailTools-2.22
+ pathname: M/MA/MARKOV/MailTools-2.22.tar.gz
+ provides:
+ Mail::Address 2.22
+ Mail::Cap 2.22
+ Mail::Field 2.22
+ Mail::Field::AddrList 2.22
+ Mail::Field::Date 2.22
+ Mail::Field::Generic 2.22
+ Mail::Filter 2.22
+ Mail::Header 2.22
+ Mail::Internet 2.22
+ Mail::Mailer 2.22
+ Mail::Mailer::qmail 2.22
+ Mail::Mailer::rfc822 2.22
+ Mail::Mailer::sendmail 2.22
+ Mail::Mailer::smtp 2.22
+ Mail::Mailer::smtp::pipe 2.22
+ Mail::Mailer::smtps 2.22
+ Mail::Mailer::smtps::pipe 2.22
+ Mail::Mailer::testfile 2.22
+ Mail::Mailer::testfile::pipe 2.22
+ Mail::Send 2.22
+ Mail::Util 2.22
+ MailTools 2.22
requirements:
Date::Format 0
Date::Parse 0
ExtUtils::MakeMaker 0
IO::Handle 0
Net::Domain 1.05
- Net::SMTP 1.03
+ Net::SMTP 1.28
Test::More 0
Math-Polygon-1.10
pathname: M/MA/MARKOV/Math-Polygon-1.10.tar.gz
@@ -1742,11 +1756,11 @@ DISTRIBUTIONS
Try::Tiny 0
strict 0
warnings 0
- Module-Pluggable-6.2
- pathname: S/SI/SIMONW/Module-Pluggable-6.2.tar.gz
+ Module-Pluggable-6.3
+ pathname: S/SI/SIMONW/Module-Pluggable-6.3.tar.gz
provides:
Devel::InnerPackage 0.4
- Module::Pluggable 6.2
+ Module::Pluggable 6.3
Module::Pluggable::Object 5.2
requirements:
Exporter 5.57
@@ -1784,8 +1798,8 @@ DISTRIBUTIONS
Mojolicious 8.50
SQL::Abstract::Pg 1.0
perl 5.016
- Mojolicious-9.38
- pathname: S/SR/SRI/Mojolicious-9.38.tar.gz
+ Mojolicious-9.39
+ pathname: S/SR/SRI/Mojolicious-9.39.tar.gz
provides:
Mojo undef
Mojo::Asset undef
@@ -1854,7 +1868,7 @@ DISTRIBUTIONS
Mojo::UserAgent::Transactor undef
Mojo::Util undef
Mojo::WebSocket undef
- Mojolicious 9.38
+ Mojolicious 9.39
Mojolicious::Command undef
Mojolicious::Command::Author::cpanify undef
Mojolicious::Command::Author::generate undef
@@ -2142,52 +2156,53 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 0
SQL::Abstract 2.0
perl 5.016
- Specio-0.48
- pathname: D/DR/DROLSKY/Specio-0.48.tar.gz
- provides:
- Specio 0.48
- Specio::Coercion 0.48
- Specio::Constraint::AnyCan 0.48
- Specio::Constraint::AnyDoes 0.48
- Specio::Constraint::AnyIsa 0.48
- Specio::Constraint::Enum 0.48
- Specio::Constraint::Intersection 0.48
- Specio::Constraint::ObjectCan 0.48
- Specio::Constraint::ObjectDoes 0.48
- Specio::Constraint::ObjectIsa 0.48
- Specio::Constraint::Parameterizable 0.48
- Specio::Constraint::Parameterized 0.48
- Specio::Constraint::Role::CanType 0.48
- Specio::Constraint::Role::DoesType 0.48
- Specio::Constraint::Role::Interface 0.48
- Specio::Constraint::Role::IsaType 0.48
- Specio::Constraint::Simple 0.48
- Specio::Constraint::Structurable 0.48
- Specio::Constraint::Structured 0.48
- Specio::Constraint::Union 0.48
- Specio::Declare 0.48
- Specio::DeclaredAt 0.48
- Specio::Exception 0.48
- Specio::Exporter 0.48
- Specio::Helpers 0.48
- Specio::Library::Builtins 0.48
- Specio::Library::Numeric 0.48
- Specio::Library::Perl 0.48
- Specio::Library::String 0.48
- Specio::Library::Structured 0.48
- Specio::Library::Structured::Dict 0.48
- Specio::Library::Structured::Map 0.48
- Specio::Library::Structured::Tuple 0.48
- Specio::OO 0.48
- Specio::PartialDump 0.48
- Specio::Registry 0.48
- Specio::Role::Inlinable 0.48
- Specio::Subs 0.48
- Specio::TypeChecks 0.48
- Test::Specio 0.48
+ Specio-0.49
+ pathname: D/DR/DROLSKY/Specio-0.49.tar.gz
+ provides:
+ Specio 0.49
+ Specio::Coercion 0.49
+ Specio::Constraint::AnyCan 0.49
+ Specio::Constraint::AnyDoes 0.49
+ Specio::Constraint::AnyIsa 0.49
+ Specio::Constraint::Enum 0.49
+ Specio::Constraint::Intersection 0.49
+ Specio::Constraint::ObjectCan 0.49
+ Specio::Constraint::ObjectDoes 0.49
+ Specio::Constraint::ObjectIsa 0.49
+ Specio::Constraint::Parameterizable 0.49
+ Specio::Constraint::Parameterized 0.49
+ Specio::Constraint::Role::CanType 0.49
+ Specio::Constraint::Role::DoesType 0.49
+ Specio::Constraint::Role::Interface 0.49
+ Specio::Constraint::Role::IsaType 0.49
+ Specio::Constraint::Simple 0.49
+ Specio::Constraint::Structurable 0.49
+ Specio::Constraint::Structured 0.49
+ Specio::Constraint::Union 0.49
+ Specio::Declare 0.49
+ Specio::DeclaredAt 0.49
+ Specio::Exception 0.49
+ Specio::Exporter 0.49
+ Specio::Helpers 0.49
+ Specio::Library::Builtins 0.49
+ Specio::Library::Numeric 0.49
+ Specio::Library::Perl 0.49
+ Specio::Library::String 0.49
+ Specio::Library::Structured 0.49
+ Specio::Library::Structured::Dict 0.49
+ Specio::Library::Structured::Map 0.49
+ Specio::Library::Structured::Tuple 0.49
+ Specio::OO 0.49
+ Specio::PartialDump 0.49
+ Specio::Registry 0.49
+ Specio::Role::Inlinable 0.49
+ Specio::Subs 0.49
+ Specio::TypeChecks 0.49
+ Test::Specio 0.49
requirements:
B 0
Carp 0
+ Clone 0
Devel::StackTrace 0
Eval::Closure 0
Exporter 0
@@ -2199,7 +2214,6 @@ DISTRIBUTIONS
Role::Tiny 1.003003
Role::Tiny::With 0
Scalar::Util 0
- Storable 0
Sub::Quote 0
Test::Fatal 0
Test::More 0.96
@@ -2397,12 +2411,12 @@ DISTRIBUTIONS
Test::Builder::Tester 1.02
Test::More 0.62
perl 5.008
- Text-CSV-2.04
- pathname: I/IS/ISHIGAKI/Text-CSV-2.04.tar.gz
+ Text-CSV-2.05
+ pathname: I/IS/ISHIGAKI/Text-CSV-2.05.tar.gz
provides:
- Text::CSV 2.04
- Text::CSV::ErrorDiag 2.04
- Text::CSV_PP 2.04
+ Text::CSV 2.05
+ Text::CSV::ErrorDiag 2.05
+ Text::CSV_PP 2.05
requirements:
ExtUtils::MakeMaker 0
IO::Handle 0
@@ -2552,19 +2566,18 @@ DISTRIBUTIONS
Test::Pod 0
Travel::Status::DE::IRIS 1.2
perl v5.20.0
- Travel-Status-DE-DeutscheBahn-6.11
- pathname: D/DE/DERF/Travel-Status-DE-DeutscheBahn-6.11.tar.gz
- provides:
- Travel::Status::DE::DeutscheBahn 6.11
- Travel::Status::DE::HAFAS 6.11
- Travel::Status::DE::HAFAS::Journey 6.11
- Travel::Status::DE::HAFAS::Location 6.11
- Travel::Status::DE::HAFAS::Message 6.11
- Travel::Status::DE::HAFAS::Polyline 6.11
- Travel::Status::DE::HAFAS::Product 6.11
- Travel::Status::DE::HAFAS::Services 6.11
- Travel::Status::DE::HAFAS::Stop 6.11
- Travel::Status::DE::HAFAS::StopFinder 6.11
+ Travel-Status-DE-HAFAS-6.18
+ pathname: D/DE/DERF/Travel-Status-DE-HAFAS-6.18.tar.gz
+ provides:
+ Travel::Status::DE::HAFAS 6.18
+ Travel::Status::DE::HAFAS::Journey 6.18
+ Travel::Status::DE::HAFAS::Location 6.18
+ Travel::Status::DE::HAFAS::Message 6.18
+ Travel::Status::DE::HAFAS::Polyline 6.18
+ Travel::Status::DE::HAFAS::Product 6.18
+ Travel::Status::DE::HAFAS::Services 6.18
+ Travel::Status::DE::HAFAS::Stop 6.18
+ Travel::Status::DE::HAFAS::StopFinder 6.18
requirements:
Carp 0
Class::Accessor 0.16
@@ -2636,57 +2649,62 @@ DISTRIBUTIONS
requirements:
ExtUtils::MakeMaker 0
common::sense 0
- URI-5.29
- pathname: O/OA/OALDERS/URI-5.29.tar.gz
- provides:
- URI 5.29
- URI::Escape 5.29
- URI::Heuristic 5.29
- URI::IRI 5.29
- URI::QueryParam 5.29
- URI::Split 5.29
- URI::URL 5.29
- URI::WithBase 5.29
- URI::data 5.29
- URI::file 5.29
- URI::file::Base 5.29
- URI::file::FAT 5.29
- URI::file::Mac 5.29
- URI::file::OS2 5.29
- URI::file::QNX 5.29
- URI::file::Unix 5.29
- URI::file::Win32 5.29
- URI::ftp 5.29
- URI::geo 5.29
- URI::gopher 5.29
- URI::http 5.29
- URI::https 5.29
- URI::icap 5.29
- URI::icaps 5.29
- URI::ldap 5.29
- URI::ldapi 5.29
- URI::ldaps 5.29
- URI::mailto 5.29
- URI::mms 5.29
- URI::news 5.29
- URI::nntp 5.29
- URI::nntps 5.29
- URI::otpauth 5.29
- URI::pop 5.29
- URI::rlogin 5.29
- URI::rsync 5.29
- URI::rtsp 5.29
- URI::rtspu 5.29
- URI::sftp 5.29
- URI::sip 5.29
- URI::sips 5.29
- URI::snews 5.29
- URI::ssh 5.29
- URI::telnet 5.29
- URI::tn3270 5.29
- URI::urn 5.29
- URI::urn::isbn 5.29
- URI::urn::oid 5.29
+ URI-5.31
+ pathname: O/OA/OALDERS/URI-5.31.tar.gz
+ provides:
+ URI 5.31
+ URI::Escape 5.31
+ URI::Heuristic 5.31
+ URI::IRI 5.31
+ URI::QueryParam 5.31
+ URI::Split 5.31
+ URI::URL 5.31
+ URI::WithBase 5.31
+ URI::data 5.31
+ URI::file 5.31
+ URI::file::Base 5.31
+ URI::file::FAT 5.31
+ URI::file::Mac 5.31
+ URI::file::OS2 5.31
+ URI::file::QNX 5.31
+ URI::file::Unix 5.31
+ URI::file::Win32 5.31
+ URI::ftp 5.31
+ URI::ftpes 5.31
+ URI::ftps 5.31
+ URI::geo 5.31
+ URI::gopher 5.31
+ URI::http 5.31
+ URI::https 5.31
+ URI::icap 5.31
+ URI::icaps 5.31
+ URI::irc 5.31
+ URI::ircs 5.31
+ URI::ldap 5.31
+ URI::ldapi 5.31
+ URI::ldaps 5.31
+ URI::mailto 5.31
+ URI::mms 5.31
+ URI::news 5.31
+ URI::nntp 5.31
+ URI::nntps 5.31
+ URI::otpauth 5.31
+ URI::pop 5.31
+ URI::rlogin 5.31
+ URI::rsync 5.31
+ URI::rtsp 5.31
+ URI::rtspu 5.31
+ URI::scp 5.31
+ URI::sftp 5.31
+ URI::sip 5.31
+ URI::sips 5.31
+ URI::snews 5.31
+ URI::ssh 5.31
+ URI::telnet 5.31
+ URI::tn3270 5.31
+ URI::urn 5.31
+ URI::urn::isbn 5.31
+ URI::urn::oid 5.31
requirements:
Carp 0
Cwd 0
diff --git a/examples/travelynx.conf b/examples/travelynx.conf
index f8eaac0..c7c4f89 100644
--- a/examples/travelynx.conf
+++ b/examples/travelynx.conf
@@ -35,6 +35,17 @@
password => die("Changeme!"),
},
+ # Settings specific to HAFAS backends.
+ # For instance, the PKP backend is hidden behind a GeoIP filter, hence
+ # travelynx only supports it if travelynx.conf either indicates that it
+ # is reachable or specifies a proxy.
+ hafas => {
+ PKP => {
+ # geoip_ok => 1, # <- EITHER THIS
+ # proxy => 'socks://...', # <- OR THIS
+ },
+ },
+
# These settings control the amount and (re)spawn behaviour of travelynx
# worker processes as well as IP, port, and PID file. They are suitable for
# up to a few dozen concurrent users. If your site has more traffic, you
diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm
index e154e8d..32d1e2f 100755
--- a/lib/Travelynx.pm
+++ b/lib/Travelynx.pm
@@ -221,6 +221,7 @@ sub startup {
my ($self) = @_;
state $hafas = Travelynx::Helper::HAFAS->new(
log => $self->app->log,
+ service_config => $self->app->config->{hafas},
main_cache => $self->app->cache_iris_main,
realtime_cache => $self->app->cache_iris_rt,
root_url => $self->base_url_for('/')->to_abs,
@@ -2013,6 +2014,7 @@ sub startup {
$self->log->debug(
"... checked in : $traewelling->{dep_name} $traewelling->{dep_eva} -> $traewelling->{arr_name} $traewelling->{arr_eva}"
);
+ $self->users->mark_seen( uid => $uid );
my $user_status = $self->get_user_status($uid);
if ( $user_status->{checked_in} ) {
$self->log->debug(
diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm
index a7d13a8..6ba80a3 100644
--- a/lib/Travelynx/Command/database.pm
+++ b/lib/Travelynx/Command/database.pm
@@ -2689,6 +2689,18 @@ qq{select distinct checkout_station_id from in_transit where backend_id = 0;}
}
);
},
+
+ # v58 -> v59
+ # DB HAFAS is dead. Default to DB IRIS for now.
+ sub {
+ my ($db) = @_;
+ $db->query(
+ qq{
+ alter table users alter column backend_id set default 0;
+ update schema_version set version = 59;
+ }
+ );
+ },
);
sub sync_stations {
diff --git a/lib/Travelynx/Command/work.pm b/lib/Travelynx/Command/work.pm
index 98f478a..5385e9b 100644
--- a/lib/Travelynx/Command/work.pm
+++ b/lib/Travelynx/Command/work.pm
@@ -6,6 +6,8 @@ package Travelynx::Command::work;
use Mojo::Base 'Mojolicious::Command';
use Mojo::Promise;
+use utf8;
+
use DateTime;
use JSON;
use List::Util;
@@ -83,22 +85,27 @@ sub run {
dep_eva => $dep,
arr_eva => $arr
);
- if ( $entry->{backend_id} <= 1
- and $journey->class <= 16
- and $found_dep->rt_dep->epoch > $now->epoch )
- {
- $self->app->add_wagonorder(
- uid => $uid,
- train_id => $journey->id,
- is_departure => 1,
- eva => $dep,
- datetime => $found_dep->sched_dep,
- train_type => $journey->type,
- train_no => $journey->number,
- );
- $self->app->add_stationinfo( $uid, 1,
- $journey->id, $found_dep->loc->eva );
- }
+ }
+ if (
+ $found_dep->sched_dep
+ and ( $entry->{backend_id} <= 1
+ or $entry->{backend_name} eq 'VRN'
+ or $entry->{backend_name} eq 'ÖBB' )
+ and $journey->class <= 16
+ and $found_dep->dep->epoch > $now->epoch
+ )
+ {
+ $self->app->add_wagonorder(
+ uid => $uid,
+ train_id => $journey->id,
+ is_departure => 1,
+ eva => $dep,
+ datetime => $found_dep->sched_dep,
+ train_type => $journey->type =~ s{ +$}{}r,
+ train_no => $journey->number,
+ );
+ $self->app->add_stationinfo( $uid, 1,
+ $journey->id, $found_dep->loc->eva );
}
if ( $found_arr and $found_arr->rt_arr ) {
@@ -109,10 +116,15 @@ sub run {
dep_eva => $dep,
arr_eva => $arr
);
- if ( $entry->{backend_id} <= 1
+ if (
+ (
+ $entry->{backend_id} <= 1
+ or $entry->{backend_name} eq 'VRN'
+ or $entry->{backend_name} eq 'ÖBB'
+ )
and $journey->class <= 16
- and $found_arr->rt_arr->epoch - $now->epoch
- < 600 )
+ and $found_arr->arr->epoch - $now->epoch < 600
+ )
{
$self->app->add_wagonorder(
uid => $uid,
diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm
index faaad0a..1c54aec 100644
--- a/lib/Travelynx/Controller/Account.pm
+++ b/lib/Travelynx/Controller/Account.pm
@@ -1070,7 +1070,27 @@ sub backend_form {
$backend->{homepage} = 'https://www.bahn.de';
}
elsif ( $backend->{hafas} ) {
- if ( my $s = $self->hafas->get_service( $backend->{name} ) ) {
+
+ # These backends lack a journey endpoint or are no longer
+ # operational and are thus useless for travelynx
+ if ( $backend->{name} eq 'Resrobot'
+ or $backend->{name} eq 'TPG'
+ or $backend->{name} eq 'DB' )
+ {
+ $type = undef;
+ }
+
+ # PKP is behind a GeoIP filter. Only list it if travelynx.conf
+ # indicates that our IP is allowed or provides a proxy.
+ elsif (
+ $backend->{name} eq 'PKP'
+ and not( $self->app->config->{hafas}{PKP}{geoip_ok}
+ or $self->app->config->{hafas}{PKP}{proxy} )
+ )
+ {
+ $type = undef;
+ }
+ elsif ( my $s = $self->hafas->get_service( $backend->{name} ) ) {
$type = 'HAFAS';
$backend->{longname} = $s->{name};
$backend->{homepage} = $s->{homepage};
diff --git a/lib/Travelynx/Controller/Api.pm b/lib/Travelynx/Controller/Api.pm
index b732810..f31195a 100755
--- a/lib/Travelynx/Controller/Api.pm
+++ b/lib/Travelynx/Controller/Api.pm
@@ -51,6 +51,8 @@ sub documentation {
sub get_v1 {
my ($self) = @_;
+ $self->res->headers->access_control_allow_origin(q{*});
+
my $api_action = $self->stash('user_action');
my $api_token = $self->stash('token');
if ( $api_action !~ qr{ ^ (?: status | history | action ) $ }x ) {
diff --git a/lib/Travelynx/Controller/Profile.pm b/lib/Travelynx/Controller/Profile.pm
index a5f394f..c35642d 100755
--- a/lib/Travelynx/Controller/Profile.pm
+++ b/lib/Travelynx/Controller/Profile.pm
@@ -231,12 +231,13 @@ sub journey_details {
}
my $journey = $self->journeys->get_single(
- uid => $user->{id},
- journey_id => $journey_id,
- verbose => 1,
- with_datetime => 1,
- with_polyline => 1,
- with_visibility => 1,
+ uid => $user->{id},
+ journey_id => $journey_id,
+ verbose => 1,
+ with_datetime => 1,
+ with_route_datetime => 1,
+ with_polyline => 1,
+ with_visibility => 1,
);
if ( not $journey ) {
diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm
index 0a94a1e..dd16c45 100755
--- a/lib/Travelynx/Controller/Traveling.pm
+++ b/lib/Travelynx/Controller/Traveling.pm
@@ -10,6 +10,7 @@ use DateTime::Format::Strptime;
use List::Util qw(uniq min max);
use List::UtilsBy qw(max_by uniq_by);
use List::MoreUtils qw(first_index);
+use Mojo::UserAgent;
use Mojo::Promise;
use Text::CSV;
use Travel::Status::DE::IRIS::Stations;
@@ -529,9 +530,16 @@ sub geolocation {
if ($hafas_service) {
$self->render_later;
+ my $agent = $self->ua;
+ if ( my $proxy = $self->app->config->{hafas}{$hafas_service}{proxy} ) {
+ $agent = Mojo::UserAgent->new;
+ $agent->proxy->http($proxy);
+ $agent->proxy->https($proxy);
+ }
+
Travel::Status::DE::HAFAS->new_p(
promise => 'Mojo::Promise',
- user_agent => $self->ua,
+ user_agent => $agent,
service => $hafas_service,
geoSearch => {
lat => $lat,
@@ -951,11 +959,13 @@ sub station {
@results = map { $_->[0] }
sort { $b->[1] <=> $a->[1] }
map { [ $_, $_->datetime->epoch ] } $status->results;
- $self->stations->add_meta(
- eva => $status->station->{eva},
- meta => $status->station->{evas} // [],
- hafas => $hafas_service,
- );
+ if ( $status->station->{eva} ) {
+ $self->stations->add_meta(
+ eva => $status->station->{eva},
+ meta => $status->station->{evas} // [],
+ hafas => $hafas_service,
+ );
+ }
$status = {
station_eva => $status->station->{eva},
station_name => (
@@ -1129,11 +1139,22 @@ sub station {
}
)->wait;
}
- elsif ( $err =~ m{svcRes} ) {
+ elsif ( $err
+ =~ m{svcRes|connection close|Service Temporarily Unavailable} )
+ {
$self->render(
'bad_gateway',
- message => $err,
- status => 502
+ message => $err,
+ status => 502,
+ select_new_backend => 1,
+ );
+ }
+ elsif ( $err =~ m{timeout}i ) {
+ $self->render(
+ 'gateway_timeout',
+ message => $err,
+ status => 504,
+ select_new_backend => 1,
);
}
else {
@@ -1158,9 +1179,10 @@ sub redirect_to_station {
sub cancelled {
my ($self) = @_;
my @journeys = $self->journeys->get(
- uid => $self->current_user->{id},
- cancelled => 1,
- with_datetime => 1
+ uid => $self->current_user->{id},
+ cancelled => 1,
+ with_datetime => 1,
+ with_route_datetime => 1
);
$self->respond_to(
@@ -1687,12 +1709,13 @@ sub journey_details {
}
my $journey = $self->journeys->get_single(
- uid => $uid,
- journey_id => $journey_id,
- verbose => 1,
- with_datetime => 1,
- with_polyline => 1,
- with_visibility => 1,
+ uid => $uid,
+ journey_id => $journey_id,
+ verbose => 1,
+ with_datetime => 1,
+ with_route_datetime => 1,
+ with_polyline => 1,
+ with_visibility => 1,
);
if ($journey) {
@@ -1915,10 +1938,11 @@ sub edit_journey {
}
my $journey = $self->journeys->get_single(
- uid => $uid,
- journey_id => $journey_id,
- verbose => 1,
- with_datetime => 1,
+ uid => $uid,
+ journey_id => $journey_id,
+ verbose => 1,
+ with_datetime => 1,
+ with_route_datetime => 1,
);
if ( not $journey ) {
@@ -2019,11 +2043,12 @@ sub edit_journey {
if ( not $error ) {
$journey = $self->journeys->get_single(
- uid => $uid,
- db => $db,
- journey_id => $journey_id,
- verbose => 1,
- with_datetime => 1,
+ uid => $uid,
+ db => $db,
+ journey_id => $journey_id,
+ verbose => 1,
+ with_datetime => 1,
+ with_route_datetime => 1,
);
$error = $self->journeys->sanity_check($journey);
}
diff --git a/lib/Travelynx/Helper/HAFAS.pm b/lib/Travelynx/Helper/HAFAS.pm
index a8ab395..5b5d343 100644
--- a/lib/Travelynx/Helper/HAFAS.pm
+++ b/lib/Travelynx/Helper/HAFAS.pm
@@ -12,6 +12,7 @@ use DateTime;
use Encode qw(decode);
use JSON;
use Mojo::Promise;
+use Mojo::UserAgent;
use Travel::Status::DE::HAFAS;
sub _epoch {
@@ -39,58 +40,18 @@ sub get_service {
return Travel::Status::DE::HAFAS::get_service($service);
}
-sub get_json_p {
- my ( $self, $url, %opt ) = @_;
-
- my $cache = $self->{main_cache};
- my $promise = Mojo::Promise->new;
+sub get_departures_p {
+ my ( $self, %opt ) = @_;
- if ( $opt{realtime} ) {
- $cache = $self->{realtime_cache};
- }
- $opt{encoding} //= 'ISO-8859-15';
+ $opt{service} //= 'VRN';
- if ( my $content = $cache->thaw($url) ) {
- return $promise->resolve($content);
+ my $agent = $self->{user_agent};
+ if ( my $proxy = $self->{service_config}{ $opt{service} }{proxy} ) {
+ $agent = Mojo::UserAgent->new;
+ $agent->proxy->http($proxy);
+ $agent->proxy->https($proxy);
}
- $self->{user_agent}->request_timeout(5)->get_p( $url => $self->{header} )
- ->then(
- sub {
- my ($tx) = @_;
-
- if ( my $err = $tx->error ) {
- $promise->reject(
-"hafas->get_json_p($url) returned HTTP $err->{code} $err->{message}"
- );
- return;
- }
-
- my $body = decode( $opt{encoding}, $tx->res->body );
-
- $body =~ s{^TSLs[.]sls = }{};
- $body =~ s{;$}{};
- $body =~ s{&#x0028;}{(}g;
- $body =~ s{&#x0029;}{)}g;
- my $json = JSON->new->decode($body);
- $cache->freeze( $url, $json );
- $promise->resolve($json);
- return;
- }
- )->catch(
- sub {
- my ($err) = @_;
- $self->{log}->info("hafas->get_json_p($url): $err");
- $promise->reject("hafas->get_json_p($url): $err");
- return;
- }
- )->wait;
- return $promise;
-}
-
-sub get_departures_p {
- my ( $self, %opt ) = @_;
-
my $when = (
$opt{timestamp}
? $opt{timestamp}->clone
@@ -104,19 +65,28 @@ sub get_departures_p {
results => 300,
cache => $self->{realtime_cache},
promise => 'Mojo::Promise',
- user_agent => $self->{user_agent}->request_timeout(5),
+ user_agent => $agent->request_timeout(5),
);
}
sub search_location_p {
my ( $self, %opt ) = @_;
+ $opt{service} //= 'VRN';
+
+ my $agent = $self->{user_agent};
+ if ( my $proxy = $self->{service_config}{ $opt{service} }{proxy} ) {
+ $agent = Mojo::UserAgent->new;
+ $agent->proxy->http($proxy);
+ $agent->proxy->https($proxy);
+ }
+
return Travel::Status::DE::HAFAS->new_p(
service => $opt{service},
locationSearch => $opt{query},
cache => $self->{realtime_cache},
promise => 'Mojo::Promise',
- user_agent => $self->{user_agent}->request_timeout(5),
+ user_agent => $agent->request_timeout(5),
);
}
@@ -129,13 +99,22 @@ sub get_tripid_p {
my $train_desc = $train->type . ' ' . $train->train_no;
$train_desc =~ s{^- }{};
+ $opt{service} //= 'VRN';
+
+ my $agent = $self->{user_agent};
+ if ( my $proxy = $self->{service_config}{ $opt{service} }{proxy} ) {
+ $agent = Mojo::UserAgent->new;
+ $agent->proxy->http($proxy);
+ $agent->proxy->https($proxy);
+ }
+
Travel::Status::DE::HAFAS->new_p(
service => $opt{service},
journeyMatch => $train_desc,
datetime => $train->start,
cache => $self->{realtime_cache},
promise => 'Mojo::Promise',
- user_agent => $self->{user_agent}->request_timeout(10),
+ user_agent => $agent->request_timeout(10),
)->then(
sub {
my ($hafas) = @_;
@@ -181,6 +160,15 @@ sub get_journey_p {
my $promise = Mojo::Promise->new;
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
+ $opt{service} //= 'VRN';
+
+ my $agent = $self->{user_agent};
+ if ( my $proxy = $self->{service_config}{ $opt{service} }{proxy} ) {
+ $agent = Mojo::UserAgent->new;
+ $agent->proxy->http($proxy);
+ $agent->proxy->https($proxy);
+ }
+
Travel::Status::DE::HAFAS->new_p(
service => $opt{service},
journey => {
@@ -189,7 +177,7 @@ sub get_journey_p {
with_polyline => $opt{with_polyline},
cache => $self->{realtime_cache},
promise => 'Mojo::Promise',
- user_agent => $self->{user_agent}->request_timeout(10),
+ user_agent => $agent->request_timeout(10),
)->then(
sub {
my ($hafas) = @_;
@@ -222,6 +210,15 @@ sub get_route_p {
my $promise = Mojo::Promise->new;
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
+ $opt{service} //= 'VRN';
+
+ my $agent = $self->{user_agent};
+ if ( my $proxy = $self->{service_config}{ $opt{service} }{proxy} ) {
+ $agent = Mojo::UserAgent->new;
+ $agent->proxy->http($proxy);
+ $agent->proxy->https($proxy);
+ }
+
Travel::Status::DE::HAFAS->new_p(
service => $opt{service},
journey => {
@@ -232,7 +229,7 @@ sub get_route_p {
with_polyline => $opt{with_polyline},
cache => $self->{realtime_cache},
promise => 'Mojo::Promise',
- user_agent => $self->{user_agent}->request_timeout(10),
+ user_agent => $agent->request_timeout(10),
)->then(
sub {
my ($hafas) = @_;
diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm
index 62e60f1..43ecb90 100644
--- a/lib/Travelynx/Model/InTransit.pm
+++ b/lib/Travelynx/Model/InTransit.pm
@@ -30,7 +30,7 @@ my %visibility_atoi = (
sub _epoch {
my ($dt) = @_;
- return $dt ? $dt->epoch : 0;
+ return $dt ? $dt->epoch : undef;
}
sub epoch_to_dt {
diff --git a/lib/Travelynx/Model/Journeys.pm b/lib/Travelynx/Model/Journeys.pm
index b80a441..905c426 100755
--- a/lib/Travelynx/Model/Journeys.pm
+++ b/lib/Travelynx/Model/Journeys.pm
@@ -301,10 +301,11 @@ sub update {
my $rows;
my $journey = $self->get_single(
- uid => $uid,
- db => $db,
- journey_id => $journey_id,
- with_datetime => 1,
+ uid => $uid,
+ db => $db,
+ journey_id => $journey_id,
+ with_datetime => 1,
+ with_route_datetime => 1,
);
eval {
@@ -656,6 +657,8 @@ sub get {
$ref->{checkout} = epoch_to_dt( $ref->{checkout_ts} );
$ref->{sched_arrival} = epoch_to_dt( $ref->{sched_arr_ts} );
$ref->{rt_arrival} = epoch_to_dt( $ref->{rt_arr_ts} );
+ }
+ if ( $opt{with_route_datetime} ) {
for my $stop ( @{ $ref->{route} } ) {
for my $k (qw(rt_arr rt_dep sched_arr sched_dep)) {
if ( $stop->[2]{$k} ) {
diff --git a/public/service-worker.js b/public/service-worker.js
index e3f7d51..f432faa 100644
--- a/public/service-worker.js
+++ b/public/service-worker.js
@@ -1,18 +1,18 @@
-const CACHE_NAME = 'static-cache-v81';
+const CACHE_NAME = 'static-cache-v82';
const FILES_TO_CACHE = [
'/favicon.ico',
'/offline.html',
- '/static/v81/css/light.min.css',
- '/static/v81/css/dark.min.css',
- '/static/v81/css/material-icons.css',
- '/static/v81/fonts/MaterialIcons-Regular.woff2',
- '/static/v81/fonts/MaterialIcons-Regular.woff',
- '/static/v81/fonts/MaterialIcons-Regular.ttf',
- '/static/v81/js/jquery-3.4.1.min.js',
- '/static/v81/js/materialize.min.js',
- '/static/v81/js/travelynx-actions.min.js',
- '/static/v81/js/autocomplete.min.js',
- '/static/v81/js/geolocation.min.js',
+ '/static/v82/css/light.min.css',
+ '/static/v82/css/dark.min.css',
+ '/static/v82/css/material-icons.css',
+ '/static/v82/fonts/MaterialIcons-Regular.woff2',
+ '/static/v82/fonts/MaterialIcons-Regular.woff',
+ '/static/v82/fonts/MaterialIcons-Regular.ttf',
+ '/static/v82/js/jquery-3.4.1.min.js',
+ '/static/v82/js/materialize.min.js',
+ '/static/v82/js/travelynx-actions.min.js',
+ '/static/v82/js/autocomplete.min.js',
+ '/static/v82/js/geolocation.min.js',
];
self.addEventListener('install', (evt) => {
diff --git a/public/static/css/material-icons.css b/public/static/css/material-icons.css
index 8a3d6f2..422d81e 100644
--- a/public/static/css/material-icons.css
+++ b/public/static/css/material-icons.css
@@ -2,12 +2,12 @@
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
- src: url(/static/v81/fonts/MaterialIcons-Regular.eot); /* For IE6-8 */
+ src: url(/static/v82/fonts/MaterialIcons-Regular.eot); /* For IE6-8 */
src: local('Material Icons'),
local('MaterialIcons-Regular'),
- url(/static/v81/fonts/MaterialIcons-Regular.woff2) format('woff2'),
- url(/static/v81/fonts/MaterialIcons-Regular.woff) format('woff'),
- url(/static/v81/fonts/MaterialIcons-Regular.ttf) format('truetype');
+ url(/static/v82/fonts/MaterialIcons-Regular.woff2) format('woff2'),
+ url(/static/v82/fonts/MaterialIcons-Regular.woff) format('woff'),
+ url(/static/v82/fonts/MaterialIcons-Regular.ttf) format('truetype');
}
.material-icons {
diff --git a/public/static/js/travelynx-actions.js b/public/static/js/travelynx-actions.js
index 5f58f29..d4ddf45 100644
--- a/public/static/js/travelynx-actions.js
+++ b/public/static/js/travelynx-actions.js
@@ -75,6 +75,9 @@ function hhmm(epoch) {
return (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m);
}
function odelay(sched, rt) {
+ if (sched == 0) {
+ return '';
+ }
if (sched < rt) {
return ' (+' + ((rt - sched) / 60) + ')';
}
diff --git a/public/static/js/travelynx-actions.min.js b/public/static/js/travelynx-actions.min.js
index 4e277e8..ff386bd 100644
--- a/public/static/js/travelynx-actions.min.js
+++ b/public/static/js/travelynx-actions.min.js
@@ -1 +1 @@
-var j_departure=0,j_duration=0,j_arrival=0,j_dest="",j_stops=[],j_token="";function setTheme(t){localStorage.setItem("theme",t),otherTheme.hasOwnProperty(t)||(t=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),addStyleSheet(t,"theme")}function upd_journey_data(){$(".countdown").each(function(){var t=$(this).data("token"),t=(t&&(j_token=t),$(this).data("journey")),t=(t&&(t=t.split(";"),j_departure=parseInt(t[0]),j_arrival=parseInt(t[1]),j_duration=j_arrival-j_departure),$(this).data("dest")),e=(t&&(j_dest=t),$(this).data("route"));if(e)for(var a in e=e.split("|"),j_stops=[],e){for(var n=e[a].split(";"),o=1;o<5;o++)n[o]=parseInt(n[o]);j_stops.push(n)}})}function upd_countdown(){var t=Date.now()/1e3;t<j_departure?$(".countdown").text("Abfahrt in "+Math.round((j_departure-t)/60)+" Minuten"):0<j_arrival&&(t<j_arrival?120<=(t=Math.round((j_arrival-t)/60))?$(".countdown").text("Ankunft in "+Math.floor(t/60)+" Stunden und "+t%60+" Minuten"):60<=t?$(".countdown").text("Ankunft in 1 Stunde und "+t%60+" Minuten"):$(".countdown").text("Ankunft in "+t+" Minuten"):$(".countdown").text("Ziel erreicht"))}function hhmm(t){var t=new Date(1e3*t),e=t.getHours(),t=t.getMinutes();return(e<10?"0"+e:e)+":"+(t<10?"0"+t:t)}function odelay(t,e){return t<e?" (+"+(e-t)/60+")":t==e?"":" ("+(e-t)/60+")"}function tvly_run(e,t,a){var n='<i class="material-icons">error</i>',o=e.data("tr")?$('<tr><td colspan="'+e.data("tr")+'"><div class="progress"><div class="indeterminate"></div></div></td></tr>'):$('<div class="progress"><div class="indeterminate"></div></div>');e.hide(),e.after(o),$.post("/action",t,function(t){t.success?$(location).attr("href",t.redirect_to):(M.toast({html:n+" "+t.error}),o.remove(),a&&a(),e.append(" "+n),e.show())})}function tvly_update(){$.get("/ajax/status_card.html",function(t){$(".statuscol").html(t),tvly_reg_handlers(),upd_journey_data(),setTimeout(tvly_update,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update,5e3)})}function tvly_update_public(){var t,e=0;$(".publicstatuscol").each(function(){t=$(this).data("user"),e=$(this).data("profile")}),$.get("/ajax/status/"+t+".html",{token:j_token,profile:e},function(t){$(".publicstatuscol").html(t),upd_journey_data(),setTimeout(tvly_update_public,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update_public,5e3)})}function tvly_update_timeline(){$.get("/timeline/in-transit",{ajax:1},function(t){$(".timeline-in-transit").html(t),setTimeout(tvly_update_timeline,6e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),setTimeout(tvly_update_timeline,1e4)})}function tvly_journey_progress(){var t=Date.now()/1e3,e=0;if(0<j_duration){for(stop in 1<(e=(e=1-(j_arrival-t)/j_duration)<0?0:e)&&(e=1),$(".progress .determinate").css("width",100*e+"%"),j_stops){var a=j_stops[stop][0],n=j_stops[stop][1],o=j_stops[stop][2],i=j_stops[stop][3],r=j_stops[stop][4];if(a==j_dest){$(".next-stop").html("");break}if(0!=o&&0<o-t){$(".next-stop").html(a+"<br/>"+hhmm(o)+odelay(n,o));break}if(0!=r&&0<r-t){0!=o?$(".next-stop").html(a+"<br/>"+hhmm(o)+" → "+hhmm(r)+odelay(i,r)):$(".next-stop").html(a+"<br/>"+hhmm(r)+odelay(i,r));break}}setTimeout(tvly_journey_progress,5e3)}}function tvly_reg_handlers(){$(".action-checkin").click(function(){var t=$(this),e={action:"checkin",hafas:t.data("hafas"),station:t.data("station"),train:t.data("train"),dest:t.data("dest"),ts:t.data("ts")};tvly_run(t,e)}),$(".action-checkout").click(function(){var t=$(this),e={action:"checkout",hafas:t.data("hafas"),station:t.data("station"),force:t.data("force")};tvly_run(t,e,function(){t.data("force")||(t.append(" – Ohne Echtzeitdaten auschecken?"),t.data("force",!0))})}),$(".action-undo").click(function(){var t=$(this),e=Date.now()/1e3,a=parseInt(t.data("checkints")),n={action:"undo",undo_id:t.data("id")},o=!0;(o=900<e-a?confirm("Checkin wirklich rückgängig machen? Er kann ggf. nicht wiederholt werden."):o)&&tvly_run(t,n)}),$(".action-cancelled-from").click(function(){var t=$(this),e={action:"cancelled_from",hafas:t.data("hafas"),station:t.data("station"),ts:t.data("ts"),train:t.data("train")};tvly_run(t,e)}),$(".action-cancelled-to").click(function(){var t=$(this),e={action:"cancelled_to",hafas:t.data("hafas"),station:t.data("station"),force:!0};tvly_run(t,e)}),$(".action-delete").click(function(){var t=$(this),e={action:"delete",id:t.data("id"),checkin:t.data("checkin"),checkout:t.data("checkout")};confirm("Diese Fahrt wirklich löschen? Der Eintrag wird sofort aus der Datenbank entfernt und kann nicht wiederhergestellt werden.")&&tvly_run(t,e)}),$(".action-share").click(function(){var t=$(this).data("text"),e=$(this).data("url");navigator.share?(shareObj={text:t},e&&(shareObj.url=e),navigator.share(shareObj)):(e&&(t+=" "+e),(e=document.createElement("textarea")).value=t,e.setAttribute("readonly",""),e.style.position="absolute",e.style.left="-9999px",document.body.appendChild(e),e.select(),e.setSelectionRange(0,99999),document.execCommand("copy"),document.body.removeChild(e),M.toast({html:"Text kopiert: „"+t+"“"}))})}$(document).ready(function(){tvly_reg_handlers(),$(".statuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update,4e4),setTimeout(tvly_journey_progress,5e3)),$(".publicstatuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update_public,4e4),setTimeout(tvly_journey_progress,5e3)),$(".timeline-in-transit .autorefresh").length&&setTimeout(tvly_update_timeline,6e4),$("a[href]").click(function(){$("nav .preloader-wrapper").addClass("active")}),$('a[href="#now"]').keydown(function(t){13==t.keyCode&&(t.preventDefault(),t.target.click())}),$('a[href="#now"]').click(function(t){t.preventDefault(),$("nav .preloader-wrapper").removeClass("active"),(now_el=$("#now")[0]).previousElementSibling.querySelector(".dep-time").focus(),now_el.scrollIntoView({behavior:"smooth",block:"center"})});var t=document.querySelectorAll(".carousel");M.Carousel.init(t,{fullWidth:!0,indicators:!0})});
+var j_departure=0,j_duration=0,j_arrival=0,j_dest="",j_stops=[],j_token="";function setTheme(t){localStorage.setItem("theme",t),otherTheme.hasOwnProperty(t)||(t=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),addStyleSheet(t,"theme")}function upd_journey_data(){$(".countdown").each(function(){var t=$(this).data("token"),t=(t&&(j_token=t),$(this).data("journey")),t=(t&&(t=t.split(";"),j_departure=parseInt(t[0]),j_arrival=parseInt(t[1]),j_duration=j_arrival-j_departure),$(this).data("dest")),e=(t&&(j_dest=t),$(this).data("route"));if(e)for(var a in e=e.split("|"),j_stops=[],e){for(var n=e[a].split(";"),o=1;o<5;o++)n[o]=parseInt(n[o]);j_stops.push(n)}})}function upd_countdown(){var t=Date.now()/1e3;t<j_departure?$(".countdown").text("Abfahrt in "+Math.round((j_departure-t)/60)+" Minuten"):0<j_arrival&&(t<j_arrival?120<=(t=Math.round((j_arrival-t)/60))?$(".countdown").text("Ankunft in "+Math.floor(t/60)+" Stunden und "+t%60+" Minuten"):60<=t?$(".countdown").text("Ankunft in 1 Stunde und "+t%60+" Minuten"):$(".countdown").text("Ankunft in "+t+" Minuten"):$(".countdown").text("Ziel erreicht"))}function hhmm(t){var t=new Date(1e3*t),e=t.getHours(),t=t.getMinutes();return(e<10?"0"+e:e)+":"+(t<10?"0"+t:t)}function odelay(t,e){return 0==t?"":t<e?" (+"+(e-t)/60+")":t==e?"":" ("+(e-t)/60+")"}function tvly_run(e,t,a){var n='<i class="material-icons">error</i>',o=e.data("tr")?$('<tr><td colspan="'+e.data("tr")+'"><div class="progress"><div class="indeterminate"></div></div></td></tr>'):$('<div class="progress"><div class="indeterminate"></div></div>');e.hide(),e.after(o),$.post("/action",t,function(t){t.success?$(location).attr("href",t.redirect_to):(M.toast({html:n+" "+t.error}),o.remove(),a&&a(),e.append(" "+n),e.show())})}function tvly_update(){$.get("/ajax/status_card.html",function(t){$(".statuscol").html(t),tvly_reg_handlers(),upd_journey_data(),setTimeout(tvly_update,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update,5e3)})}function tvly_update_public(){var t,e=0;$(".publicstatuscol").each(function(){t=$(this).data("user"),e=$(this).data("profile")}),$.get("/ajax/status/"+t+".html",{token:j_token,profile:e},function(t){$(".publicstatuscol").html(t),upd_journey_data(),setTimeout(tvly_update_public,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update_public,5e3)})}function tvly_update_timeline(){$.get("/timeline/in-transit",{ajax:1},function(t){$(".timeline-in-transit").html(t),setTimeout(tvly_update_timeline,6e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),setTimeout(tvly_update_timeline,1e4)})}function tvly_journey_progress(){var t=Date.now()/1e3,e=0;if(0<j_duration){for(stop in 1<(e=(e=1-(j_arrival-t)/j_duration)<0?0:e)&&(e=1),$(".progress .determinate").css("width",100*e+"%"),j_stops){var a=j_stops[stop][0],n=j_stops[stop][1],o=j_stops[stop][2],i=j_stops[stop][3],r=j_stops[stop][4];if(a==j_dest){$(".next-stop").html("");break}if(0!=o&&0<o-t){$(".next-stop").html(a+"<br/>"+hhmm(o)+odelay(n,o));break}if(0!=r&&0<r-t){0!=o?$(".next-stop").html(a+"<br/>"+hhmm(o)+" → "+hhmm(r)+odelay(i,r)):$(".next-stop").html(a+"<br/>"+hhmm(r)+odelay(i,r));break}}setTimeout(tvly_journey_progress,5e3)}}function tvly_reg_handlers(){$(".action-checkin").click(function(){var t=$(this),e={action:"checkin",hafas:t.data("hafas"),station:t.data("station"),train:t.data("train"),dest:t.data("dest"),ts:t.data("ts")};tvly_run(t,e)}),$(".action-checkout").click(function(){var t=$(this),e={action:"checkout",hafas:t.data("hafas"),station:t.data("station"),force:t.data("force")};tvly_run(t,e,function(){t.data("force")||(t.append(" – Ohne Echtzeitdaten auschecken?"),t.data("force",!0))})}),$(".action-undo").click(function(){var t=$(this),e=Date.now()/1e3,a=parseInt(t.data("checkints")),n={action:"undo",undo_id:t.data("id")},o=!0;(o=900<e-a?confirm("Checkin wirklich rückgängig machen? Er kann ggf. nicht wiederholt werden."):o)&&tvly_run(t,n)}),$(".action-cancelled-from").click(function(){var t=$(this),e={action:"cancelled_from",hafas:t.data("hafas"),station:t.data("station"),ts:t.data("ts"),train:t.data("train")};tvly_run(t,e)}),$(".action-cancelled-to").click(function(){var t=$(this),e={action:"cancelled_to",hafas:t.data("hafas"),station:t.data("station"),force:!0};tvly_run(t,e)}),$(".action-delete").click(function(){var t=$(this),e={action:"delete",id:t.data("id"),checkin:t.data("checkin"),checkout:t.data("checkout")};confirm("Diese Fahrt wirklich löschen? Der Eintrag wird sofort aus der Datenbank entfernt und kann nicht wiederhergestellt werden.")&&tvly_run(t,e)}),$(".action-share").click(function(){var t=$(this).data("text"),e=$(this).data("url");navigator.share?(shareObj={text:t},e&&(shareObj.url=e),navigator.share(shareObj)):(e&&(t+=" "+e),(e=document.createElement("textarea")).value=t,e.setAttribute("readonly",""),e.style.position="absolute",e.style.left="-9999px",document.body.appendChild(e),e.select(),e.setSelectionRange(0,99999),document.execCommand("copy"),document.body.removeChild(e),M.toast({html:"Text kopiert: „"+t+"“"}))})}$(document).ready(function(){tvly_reg_handlers(),$(".statuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update,4e4),setTimeout(tvly_journey_progress,5e3)),$(".publicstatuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update_public,4e4),setTimeout(tvly_journey_progress,5e3)),$(".timeline-in-transit .autorefresh").length&&setTimeout(tvly_update_timeline,6e4),$("a[href]").click(function(){$("nav .preloader-wrapper").addClass("active")}),$('a[href="#now"]').keydown(function(t){13==t.keyCode&&(t.preventDefault(),t.target.click())}),$('a[href="#now"]').click(function(t){t.preventDefault(),$("nav .preloader-wrapper").removeClass("active"),(now_el=$("#now")[0]).previousElementSibling.querySelector(".dep-time").focus(),now_el.scrollIntoView({behavior:"smooth",block:"center"})});var t=document.querySelectorAll(".carousel");M.Carousel.init(t,{fullWidth:!0,indicators:!0})});
diff --git a/public/static/manifest.json b/public/static/manifest.json
index 0079c6f..67f1dfc 100644
--- a/public/static/manifest.json
+++ b/public/static/manifest.json
@@ -3,27 +3,27 @@
"short_name": "Travelynx",
"scope": "/",
"icons": [{
- "src": "/static/v81/icons/icon-128x128.png",
+ "src": "/static/v82/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
}, {
- "src": "/static/v81/icons/icon-144x144.png",
+ "src": "/static/v82/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
}, {
- "src": "/static/v81/icons/icon-152x152.png",
+ "src": "/static/v82/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
}, {
- "src": "/static/v81/icons/icon-192x192.png",
+ "src": "/static/v82/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}, {
- "src": "/static/v81/icons/icon-256x256.png",
+ "src": "/static/v82/icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
}, {
- "src": "/static/v81/icons/icon-512x512.png",
+ "src": "/static/v82/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}],
diff --git a/public/static/v80 b/public/static/v82
index 945c9b4..945c9b4 120000
--- a/public/static/v80
+++ b/public/static/v82
diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep
index 797ff57..a5611e9 100644
--- a/templates/_checked_in.html.ep
+++ b/templates/_checked_in.html.ep
@@ -356,24 +356,20 @@
% }
</div>
<div class="card-action">
- % my $url = 'https://bahn.expert/details/';
- % if ($journey->{train_id} =~ m{[|]}) {
- % if ($journey->{train_type} and $journey->{train_no}) {
- % $url .= $journey->{train_type} . ' ' . $journey->{train_no};
- % }
- % $url .= '/' . $journey->{sched_departure}->epoch . '000?jid=' . $journey->{train_id} =~ s{#}{%23}gr;
- % }
- % else {
- % $url .= $journey->{train_type} . ' ' . $journey->{train_no} . '/' . $journey->{sched_departure}->epoch . '000?station=' . $journey->{dep_eva};
+ % my $url = 'https://dbf.finalrewind.org/z/';
+ % if ($journey->{is_hafas}) {
+ % $url .= $journey->{train_id} =~ s{#}{%23}gr . '?hafas=' . $journey->{backend_name};
+ <a style="margin-right: 0;" href="<%= $url %>"><i class="material-icons left" aria-hidden="true">timeline</i> Details</a>
% }
- % if ($journey->{backend_id} <= 1) {
+ % elsif ($journey->{extra_data}{trip_id}) {
+ % $url .= $journey->{extra_data}{trip_id} =~ s{#}{%23}gr;
<a style="margin-right: 0;" href="<%= $url %>"><i class="material-icons left" aria-hidden="true">timeline</i> Zuglauf</a>
% }
% else {
&nbsp;
% }
% if ($journey->{extra_data}{trip_id}) {
- <a class="right" style="margin-right: 0;" href="https://dbf.finalrewind.org/map/<%= $journey->{extra_data}{trip_id} =~ s{#}{%23}gr %>/<%= $journey->{train_line} || 0 %>?hafas=<%= $journey->{backend_name} // 'DB' %>&amp;from=<%= $journey->{dep_name} %>&amp;to=<%= $journey->{arr_name} %>&amp;dark=<%= (session('theme') and session('theme') eq 'dark') ? 1 : 0 %>"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
+ <a class="right" style="margin-right: 0;" href="https://dbf.finalrewind.org/map/<%= $journey->{extra_data}{trip_id} =~ s{#}{%23}gr %>/<%= $journey->{train_line} || 0 %>?hafas=<%= $journey->{backend_name} // 'VRN' %>&amp;from=<%= $journey->{dep_name} %>&amp;to=<%= $journey->{arr_name} %>"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
% }
</div>
</div>
diff --git a/templates/_public_status_card.html.ep b/templates/_public_status_card.html.ep
index 6dda46d..84708ef 100644
--- a/templates/_public_status_card.html.ep
+++ b/templates/_public_status_card.html.ep
@@ -168,8 +168,13 @@
<div class="card-action">
% if ($journey->{traewelling_url}) {
<a style="margin-right: 0;" href="<%= $journey->{traewelling_url} %>"><i class="material-icons left">timeline</i> Träwelling</a>
- % } elsif ($journey->{backend_id} <= 1) {
- % my $url = 'https://bahn.expert/details/' . $journey->{train_type} . ' ' . $journey->{train_no} . '/' . DateTime->now(time_zone => 'Europe/Berlin')->epoch . '000';
+ % }
+ % elsif ($journey->{is_hafas}) {
+ % my $url = 'https://dbf.finalrewind.org/z/' . $journey->{train_id} =~ s{#}{%23}gr . '?hafas=' . $journey->{backend_name};
+ <a style="margin-right: 0;" href="<%= $url %>"><i class="material-icons left">timeline</i> Details</a>
+ % }
+ % elsif ($journey->{extra_data}{trip_id}) {
+ % my $url = 'https://dbf.finalrewind.org/z/' . $journey->{extra_data}{trip_id} =~ s{#}{%23}gr;
<a style="margin-right: 0;" href="<%= $url %>"><i class="material-icons left">timeline</i> Zuglauf</a>
% }
% else {
diff --git a/templates/bad_gateway.html.ep b/templates/bad_gateway.html.ep
index 773cda8..07bf29e 100644
--- a/templates/bad_gateway.html.ep
+++ b/templates/bad_gateway.html.ep
@@ -5,7 +5,13 @@
<span class="card-title">502 Bad Gateway</span>
<p>
Das von travelynx genutzte Backend hat einen Fehler zurückgegeben.
- Oft sind diese temporär – versuche es in ein paar Sekunden bis Minuten noch einmal.
+ travelynx hat keine Möglichkeiten, diese Situation zu beheben.
+ % if (stash('select_new_backend')) {
+ Versuche es in ein paar Sekunden bis Minuten noch einmal oder <a href="/account/select_backend">wähle ein anderes Backend</a>.
+ % }
+ % else {
+ Versuche es in ein paar Sekunden bis Minuten noch einmal.
+ % }
</p>
</div>
</div>
diff --git a/templates/changelog.html.ep b/templates/changelog.html.ep
index ad3291a..3671666 100644
--- a/templates/changelog.html.ep
+++ b/templates/changelog.html.ep
@@ -2,6 +2,37 @@
<div class="row">
<div class="col s12 m1 l1">
+ 2.10
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Neue HAFAS-Backends: PKP, SaarVV.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Bug">warning</i> Das DB
+ HAFAS-Backend wurde am 8. Januar 2025 abgeschaltet und wird von
+ travelynx daher seit v2.9.11 nicht mehr angeboten. Als vorläufiger
+ Ersatz bietet sich das VRN HAFAS-Backend an. Eine Wieder-Anbindung
+ der DB mittels Travel::Status::DE::DBRIS ist in Arbeit. Bis dahin
+ ist keine Synchronisierung mit Traewelling möglich.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Administration">announcement</i>
+ Das PKP HAFAS befindet sich hinter einem GeoIP-Filter und wird
+ daher in travelynx-Installationen außerhalb von travelynx.de
+ standardmäßig nicht angeboten. Sofern die travelynx-Instanz auf
+ einer geeigneten IP-Adresse betrieben wird oder eine solche per
+ Proxy erreichbar ist, lässt es sich über einen Eintrag in
+ travelynx.conf aktivieren. Als Nebenwirkung davon kann auch auf
+ beliebige andere HAFAS-Instanzen bei Bedarf über einen
+ Instanz-spezifischen Proxy zugegriffen werden.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
2.9
</div>
<div class="col s12 m11 l11">
diff --git a/templates/gateway_timeout.html.ep b/templates/gateway_timeout.html.ep
new file mode 100644
index 0000000..9cf8690
--- /dev/null
+++ b/templates/gateway_timeout.html.ep
@@ -0,0 +1,27 @@
+<div class="row">
+ <div class="col s12">
+ <div class="card caution-color">
+ <div class="card-content white-text">
+ <span class="card-title">504 Gateway Timeout</span>
+ <p>
+ Das von travelynx genutzte Backend hat nicht rechtzeitig reagiert.
+ travelynx hat keine Möglichkeiten, diese Situation zu beheben.
+ % if (stash('select_new_backend')) {
+ Versuche es in ein paar Sekunden bis Minuten noch einmal oder <a href="/account/select_backend">wähle ein anderes Backend</a>.
+ % }
+ % else {
+ Versuche es in ein paar Sekunden bis Minuten noch einmal.
+ % }
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col s12">
+ <p>Details:</p>
+ <p style="font-family: monospace;">
+ %= $message
+ </p>
+ </div>
+</div>
diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep
index 68ff41c..8b6eb3f 100644
--- a/templates/landingpage.html.ep
+++ b/templates/landingpage.html.ep
@@ -89,9 +89,11 @@
<div class="row">
<div class="col s12">
<p>
- Travelynx erlaubt das Einchecken in Züge im Netz der Deutschen
- Bahn. So können die eigenen Fahrten später inklusive Echtzeitdaten
- und eingetragenen Servicemeldungen nachvollzogen und brennende
+ Travelynx erlaubt das Einchecken in Verkehrsmittel (Busse,
+ Bahnen, Züge) unter anderem in Deutschland, Österrich, der
+ Schweiz, Luxembourg, Irland und Teilen der USA. So können die
+ eigenen Fahrten später inklusive Echtzeitdaten und
+ eingetragenen Servicemeldungen nachvollzogen und brennende
Fragen wie „Wie viele Stunden war ich letzten Monat unterwegs?“
beantwortet werden.
</p>
diff --git a/templates/layouts/default.html.ep b/templates/layouts/default.html.ep
index fc31f49..e74a731 100644
--- a/templates/layouts/default.html.ep
+++ b/templates/layouts/default.html.ep
@@ -13,7 +13,7 @@
% while (my ($key, $value) = each %{stash('opengraph') // {}}) {
<meta property="og:<%= $key %>" content="<%= $value %>">
% }
- % my $av = 'v81'; # asset version
+ % my $av = 'v82'; # asset version
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-96x96.png" sizes="96x96">
diff --git a/templates/select_backend.html.ep b/templates/select_backend.html.ep
index db1674e..8af157d 100644
--- a/templates/select_backend.html.ep
+++ b/templates/select_backend.html.ep
@@ -3,6 +3,7 @@
<h2>Backend auswählen</h2>
<p style="text-align: justify;">
Das ausgewählte Backend bestimmt die Datenquelle für Fahrten in travelynx.
+ <a href="#help">Hilfe bei der Auswahl</a>.
</p>
</div>
</div>
@@ -31,18 +32,23 @@
%= end
<div class="row">
<div class="col s12">
- <h2>Details</h2>
+ <h2 id="help">Hilfe</h2>
<p>
- <strong>Deutsche Bahn</strong> ist eine gute Wahl für Nah-, Regional- und Fernverkehr in Deutschland und (teilweise) Nachbarländern.
- Hier stehen zumeist brauchbare Echtzeitdaten zur Verfügung; bei Zügen sind zusätzlich Kartendaten vorhanden.
+ Leider gibt es seit der Abschaltung des DB HAFAS am 8. Januar 2025 derzeit kein Backend, welches allgemein für Nah- und Fernverkehr in Deutschland nutzbar ist.
+ Der <strong>VRN</strong> kommt voraussichtlich am ehesten an Qualität und Umfang der im DB HAFAS verfügbaren Daten heran.
+ Im Übrigen muss je nach Verkehrsmittel, Region und Wünschen an die verfügbaren Daten hier ein geeignetes Backend ausgewählt werden.
+ Abhilfe ist in Arbeit.
</p>
<p>
- <strong>Deutsche Bahn (IRIS-TTS)</strong> unterstützt ausschließlich Schienenverkehr; im Gegensatz zum HAFAS sind hier detaillierte Verspätungsgründe verfügbar.
+ <strong>VRN</strong> ist eine gute Wahl für Nah-, Regional- und Fernverkehr in Deutschland. Hier gibt es meist Echtzeitdaten, allgemeine Meldungen, Wagenreihungen und Kartendaten.
+ <strong>Deutsche Bahn</strong> (IRIS-TTS) liefert Echtzeitdaten, Wagenreihungen und Verspätungsmeldungen für Regional- und Fernverkehr in Deutschland. In vielen Fällen sind auch allgemeine Meldungen und Kartendaten verfügbar.
+ <strong>ÖBB</strong> liefern Kartendaten und Wagenreihungen für Fernverkehr in Deutschland, jedoch keine Meldungen. Echtzeitdaten sind teilweise verfügbar.
</p>
<p>
- Die restlichen Backends können sich für Fahrten in den zugehörigen Verkehrsverbünden lohnen.
- Im Gegensatz zum Deutsche Bahn-HAFAS haben sie oft besser gepflegte Echtzeitdaten und liefern in vielen (aber nicht allen) Fällen auch Kartendaten für Nahverkehrsmittel wie Busse oder Stadtbahnen.
+ Die restlichen Backends lohnen sich für Fahrten in den zugehörigen Verkehrsverbünden bzw. Ländern.
+ Im Gegensatz zu IRIS-TTS liefern sie in vielen (aber nicht allen) Fällen auch Kartendaten für die dem Verbund zugehörigen Verkehrsmittel.
In Einzelfällen (z.B. BVG) sind sogar Auslastungsdaten eingepflegt.
+ Bei Fahrten außerhalb von Deutschland und der Schweiz ist <strong>ÖBB</strong> zumeist die beste Wahl.
</p>
</div>
</div>
diff --git a/templates/traewelling.html.ep b/templates/traewelling.html.ep
index 1e0d65d..ee8f023 100644
--- a/templates/traewelling.html.ep
+++ b/templates/traewelling.html.ep
@@ -43,9 +43,16 @@
<div class="row">
<div class="col s12">
- <div class="card purple">
+ <div class="card caution-color">
<div class="card-content white-text">
- <span class="card-title">Eingeschränkte Synchronisierung</span>
+ <span class="card-title">Derzeit keine Synchronisierung möglich</span>
+ <p>
+ Seit Abschaltung des DB HAFAS am 8. Januar 2024 ist leider keine Synchronisierung zwischen Träwelling und travelynx möglich.
+ Träwelling nutzt seitdem eine zu großen Teilen mit dem DB HAFAS kompatible bahn.de-API, während travelynx derzeit ersatzweise das VRN HAFAS nutzt.
+ Da die von diesen APIs genutzten Reise-IDs nicht miteinander kompatibel sind, können Checkins nicht synchronisiert werden.
+ Eine Einbindung der bahn.de-API in travelynx (und damit eine Wiederherstellung der Synchronisierungsmöglichkeiten) ist in Arbeit, kann jedoch durchaus noch einige Wochen bis Monate in Anspruch nehmen.
+ </p>
+ <!--
<p>
Träwelling und travelynx setzen unterschiedliche Schwerpunkte und haben unterschiedliche Features.
Kombiniert mit der Vielzahl an möglichen Randfällen heißt das, dass die Synchronisierung nicht immer funktioniert.
@@ -55,6 +62,7 @@
Bei hohen Verspätungen, Ausfällen und nachträglichen Checkin-Änderungen ist die Synchronisierung u.U. nicht möglich und muss von Hand vorgenommen werden.
travelynx-Hooks werden bei via Träwelling vorgenommenen Checkins nicht ausgelöst.
</p>
+ -->
</div>
<div class="card-action">
<a href="https://github.com/derf/travelynx/issues" class="waves-effect waves-light btn-flat white-text">