diff options
29 files changed, 837 insertions, 645 deletions
@@ -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. @@ -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{(}{(}g; - $body =~ s{)}{)}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 { % } % 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' %>&from=<%= $journey->{dep_name} %>&to=<%= $journey->{arr_name} %>&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' %>&from=<%= $journey->{dep_name} %>&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"> |