sub-project for enabler

This commit is contained in:
Andreas Schildbach 2012-02-23 14:03:41 +01:00
parent ad4fa14c98
commit f80bba6934
167 changed files with 0 additions and 0 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import de.schildbach.pte.dto.Point;
import de.schildbach.pte.dto.Style;
/**
* @author Andreas Schildbach
*/
public abstract class AbstractNetworkProvider implements NetworkProvider
{
public Style lineStyle(final String line)
{
if (line.length() == 0)
return null;
return StandardColors.LINES.get(line.charAt(0));
}
public Point[] getArea()
{
return null;
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class AtcProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.ATC;
private final static String API_BASE = "http://tpweb.atc.bo.it/atc2/"; // "http://82.187.83.50/TravelPlanner/"
public AtcProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class AvvProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.AVV;
public static final String OLD_NETWORK_ID = "efa.avv-augsburg.de";
private final static String API_BASE = "http://efa.avv-augsburg.de/avv/";
public AvvProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,558 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Connection;
import de.schildbach.pte.dto.GetConnectionDetailsResult;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryConnectionsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.ResultHeader;
import de.schildbach.pte.exception.SessionExpiredException;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public final class BahnProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.DB;
public static final String OLD_NETWORK_ID = "mobile.bahn.de";
private static final String API_BASE = "http://mobile.bahn.de/bin/mobil/";
public BahnProvider()
{
super("http://reiseauskunft.bahn.de/bin/extxml.exe", 14, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.NEARBY_STATIONS || capability == Capability.DEPARTURES || capability == Capability.AUTOCOMPLETE_ONE_LINE
|| capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
throw new UnsupportedOperationException();
}
private final static Pattern P_NEARBY_STATIONS_BY_STATION = Pattern
.compile("<a href=\"http://mobile\\.bahn\\.de/bin/mobil/bhftafel.exe/dn[^\"]*?evaId=(\\d*)&[^\"]*?\">([^<]*)</a>");
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_nv=get_stopweight|yes");
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("bhftafel.exe/dn");
uri.append("?near=Anzeigen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
final CharSequence page = ParserUtils.scrape(uri.toString());
final Matcher m = P_NEARBY_STATIONS_BY_STATION.matcher(page);
final List<Location> stations = new ArrayList<Location>();
while (m.find())
{
final int sId = Integer.parseInt(m.group(1));
final String sName = ParserUtils.resolveEntities(m.group(2).trim());
final Location station = new Location(LocationType.STATION, sId, null, sName);
stations.add(station);
}
if (maxStations == 0 || maxStations >= stations.size())
return new NearbyStationsResult(null, stations);
else
return new NearbyStationsResult(null, stations.subList(0, maxStations));
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
private static final String AUTOCOMPLETE_URI = API_BASE + "ajax-getstop.exe/dn?getstop=1&REQ0JourneyStopsS0A=255&S=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
private String connectionsQueryUri(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products)
{
final Calendar c = new GregorianCalendar(timeZone());
c.setTime(date);
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("query.exe/dox");
uri.append("?REQ0HafasOptimize1=0:1");
uri.append("&REQ0JourneyStopsS0ID=").append(ParserUtils.urlEncode(locationId(from)));
uri.append("&REQ0JourneyStopsZ0ID=").append(ParserUtils.urlEncode(locationId(to)));
if (via != null)
{
// workaround, for there does not seem to be a REQ0JourneyStops1.0ID parameter
uri.append("&REQ0JourneyStops1.0A=").append(locationType(via));
if (via.type == LocationType.STATION && via.hasId() && isValidStationId(via.id))
{
uri.append("&REQ0JourneyStops1.0L=").append(via.id);
}
else if (via.hasLocation())
{
uri.append("&REQ0JourneyStops1.0X=").append(via.lon);
uri.append("&REQ0JourneyStops1.0Y=").append(via.lat);
if (via.name == null)
uri.append("&REQ0JourneyStops1.0O=").append(
ParserUtils.urlEncode(String.format(Locale.ENGLISH, "%.6f, %.6f", via.lat / 1E6, via.lon / 1E6)));
}
else if (via.name != null)
{
uri.append("&REQ0JourneyStops1.0G=").append(ParserUtils.urlEncode(via.name));
if (via.type != LocationType.ANY)
uri.append('!');
}
}
uri.append("&REQ0HafasSearchForw=").append(dep ? "1" : "0");
uri.append("&REQ0JourneyDate=").append(
String.format("%02d.%02d.%02d", c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.MONTH) + 1, c.get(Calendar.YEAR) - 2000));
uri.append("&REQ0JourneyTime=").append(String.format("%02d:%02d", c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)));
uri.append("&REQ0Tariff_Class=2");
uri.append("&REQ0Tariff_TravellerAge.1=35");
uri.append("&REQ0Tariff_TravellerReductionClass.1=0");
uri.append("&existOptimizePrice=1");
uri.append("&existProductNahverkehr=yes");
uri.append("&start=Suchen");
if (products != null)
{
for (final char p : products.toCharArray())
{
if (p == 'I')
{
uri.append("&REQ0JourneyProduct_prod_section_0_0=1&REQ0JourneyProduct_prod_section_0_1=1");
if (via != null)
uri.append("&REQ0JourneyProduct_prod_section_1_0=1&REQ0JourneyProduct_prod_section_1_1=1");
}
if (p == 'R')
{
uri.append("&REQ0JourneyProduct_prod_section_0_2=1&REQ0JourneyProduct_prod_section_0_3=1");
if (via != null)
uri.append("&REQ0JourneyProduct_prod_section_1_2=1&REQ0JourneyProduct_prod_section_1_3=1");
}
if (p == 'S')
{
uri.append("&REQ0JourneyProduct_prod_section_0_4=1");
if (via != null)
uri.append("&REQ0JourneyProduct_prod_section_1_4=1");
}
if (p == 'U')
{
uri.append("&REQ0JourneyProduct_prod_section_0_7=1");
if (via != null)
uri.append("&REQ0JourneyProduct_prod_section_1_7=1");
}
if (p == 'T')
{
uri.append("&REQ0JourneyProduct_prod_section_0_8=1");
if (via != null)
uri.append("&REQ0JourneyProduct_prod_section_1_8=1");
}
if (p == 'B')
{
uri.append("&REQ0JourneyProduct_prod_section_0_5=1");
if (via != null)
uri.append("&REQ0JourneyProduct_prod_section_1_5=1");
}
if (p == 'P')
{
uri.append("&REQ0JourneyProduct_prod_section_0_9=1");
if (via != null)
uri.append("&REQ0JourneyProduct_prod_section_1_9=1");
}
if (p == 'F')
{
uri.append("&REQ0JourneyProduct_prod_section_0_6=1");
if (via != null)
uri.append("&REQ0JourneyProduct_prod_section_1_6=1");
}
// FIXME if (p == 'C')
}
}
return uri.toString();
}
private static final Pattern P_PRE_ADDRESS = Pattern.compile(
"<select name=\"(REQ0JourneyStopsS0K|REQ0JourneyStopsZ0K|REQ0JourneyStops1\\.0K)\"[^>]*>(.*?)</select>", Pattern.DOTALL);
private static final Pattern P_ADDRESSES = Pattern.compile("<option[^>]*>\\s*(.*?)\\s*</option>", Pattern.DOTALL);
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern
.compile("(zu dicht beieinander|mehrfach vorhanden oder identisch)|(keine geeigneten Haltestellen)|(keine Verbindung gefunden)|(derzeit nur Ausk&#252;nfte vom)|(zwischenzeitlich nicht mehr gespeichert)");
@Override
public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed, final Accessibility accessibility) throws IOException
{
final String uri = connectionsQueryUri(from, via, to, date, dep, products);
final CharSequence page = ParserUtils.scrape(uri);
List<Location> fromAddresses = null;
List<Location> viaAddresses = null;
List<Location> toAddresses = null;
final Matcher mPreAddress = P_PRE_ADDRESS.matcher(page);
while (mPreAddress.find())
{
final String type = mPreAddress.group(1);
final String options = mPreAddress.group(2);
final Matcher mAddresses = P_ADDRESSES.matcher(options);
final List<Location> addresses = new ArrayList<Location>();
while (mAddresses.find())
{
final String address = ParserUtils.resolveEntities(mAddresses.group(1)).trim();
if (!addresses.contains(address))
addresses.add(new Location(LocationType.ANY, 0, null, address + "!"));
}
if (type.equals("REQ0JourneyStopsS0K"))
fromAddresses = addresses;
else if (type.equals("REQ0JourneyStopsZ0K"))
toAddresses = addresses;
else if (type.equals("REQ0JourneyStops1.0K"))
viaAddresses = addresses;
else
throw new IllegalStateException(type);
}
if (fromAddresses != null || viaAddresses != null || toAddresses != null)
return new QueryConnectionsResult(new ResultHeader(SERVER_PRODUCT), fromAddresses, viaAddresses, toAddresses);
else
return queryConnections(uri, page);
}
@Override
public QueryConnectionsResult queryMoreConnections(final String uri, final boolean next) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
// TODO handle next/prev
return queryConnections(uri, page);
}
private static final Pattern P_CONNECTIONS_HEAD = Pattern.compile(".*?" //
+ "von: <span class=\"bold\">([^<]*)</span>.*?" // from
+ "nach: <span class=\"bold\">([^<]*)</span>.*?" // to
+ "Datum: <span class=\"bold\">.., (\\d{2}\\.\\d{2}\\.\\d{2})</span>.*?" // currentDate
+ "(?:<a href=\"([^\"]*)\"><img [^>]*>\\s*Fr&#252;her.*?)?" // linkEarlier
+ "(?:<a class=\"noBG\" href=\"([^\"]*)\"><img [^>]*>\\s*Sp&#228;ter.*?)?" // linkLater
, Pattern.DOTALL);
private static final Pattern P_CONNECTIONS_COARSE = Pattern.compile("<tr><td class=\"overview timelink\">(.+?)</td></tr>", Pattern.DOTALL);
private static final Pattern P_CONNECTIONS_FINE = Pattern.compile(".*?" //
+ "<a href=\"(http://mobile.bahn.de/bin/mobil/query2?.exe/dox[^\"]*?)\">" // link
+ "(\\d{1,2}:\\d{2})<br />(\\d{1,2}:\\d{2})</a></td>.+?" // departureTime, arrivalTime
+ "<td class=\"overview iphonepfeil\">(.*?)<br />.*?" // line
, Pattern.DOTALL);
private QueryConnectionsResult queryConnections(final String uri, final CharSequence page) throws IOException
{
final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(page);
if (mError.find())
{
if (mError.group(1) != null)
return new QueryConnectionsResult(null, QueryConnectionsResult.Status.TOO_CLOSE);
if (mError.group(2) != null)
return new QueryConnectionsResult(null, QueryConnectionsResult.Status.UNRESOLVABLE_ADDRESS);
if (mError.group(3) != null)
return new QueryConnectionsResult(null, QueryConnectionsResult.Status.NO_CONNECTIONS);
if (mError.group(4) != null)
return new QueryConnectionsResult(null, QueryConnectionsResult.Status.INVALID_DATE);
if (mError.group(5) != null)
throw new SessionExpiredException();
}
final Matcher mHead = P_CONNECTIONS_HEAD.matcher(page);
if (mHead.matches())
{
final Location from = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mHead.group(1)));
final Location to = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mHead.group(2)));
final Calendar currentDate = new GregorianCalendar(timeZone());
currentDate.clear();
ParserUtils.parseGermanDate(currentDate, mHead.group(3));
// final String linkEarlier = mHead.group(4) != null ? ParserUtils.resolveEntities(mHead.group(4)) : null;
final String linkLater = mHead.group(5) != null ? ParserUtils.resolveEntities(mHead.group(5)) : null;
final List<Connection> connections = new ArrayList<Connection>();
final Matcher mConCoarse = P_CONNECTIONS_COARSE.matcher(page);
while (mConCoarse.find())
{
final Matcher mConFine = P_CONNECTIONS_FINE.matcher(mConCoarse.group(1));
if (mConFine.matches())
{
final String link = ParserUtils.resolveEntities(mConFine.group(1));
final Connection connection = new Connection(AbstractHafasProvider.extractConnectionId(link), link, from, to, null, null, null);
connections.add(connection);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mConCoarse.group(1) + "' on " + uri);
}
}
return new QueryConnectionsResult(new ResultHeader(SERVER_PRODUCT), uri, from, null, to, linkLater, connections);
}
else
{
throw new IOException(page.toString());
}
}
private static final Pattern P_CONNECTION_DETAILS_HEAD = Pattern.compile(".*?" //
+ "<span class=\"bold\">Verbindungsdetails</span>(.*?)<div class=\"rline\"></div>.*?", Pattern.DOTALL);
private static final Pattern P_CONNECTION_DETAILS_COARSE = Pattern.compile("<div class=\"rline haupt(?: rline)?\"[^>]*>\n(.+?>\n)</div>",
Pattern.DOTALL);
static final Pattern P_CONNECTION_DETAILS_FINE = Pattern.compile("<span class=\"bold\">\\s*(.+?)\\s*</span>.*?" // departure
+ "(?:" //
+ "<span class=\"bold\">\\s*(.+?)\\s*</span>.*?" // line
+ "ab\\s+(?:<span[^>]*>.*?</span>)?\\s*(\\d{1,2}:\\d{2})\\s*(?:<span[^>]*>.*?</span>)?" // departureTime
+ "\\s*(?:Gl\\. (.+?))?\\s*\n" // departurePosition
+ "am\\s+(\\d{2}\\.\\d{2}\\.\\d{2}).*?" // departureDate
+ "<span class=\"bold\">\\s*(.+?)\\s*</span><br />.*?" // arrival
+ "an\\s+(?:<span[^>]*>.*?</span>)?\\s*(\\d{1,2}:\\d{2})\\s*(?:<span[^>]*>.*?</span>)?" // arrivalTime
+ "\\s*(?:Gl\\. (.+?))?\\s*\n" // arrivalPosition
+ "am\\s+(\\d{2}\\.\\d{2}\\.\\d{2}).*?" // arrivalDate
+ "|" //
+ "(\\d+) Min\\..*?" // footway
+ "<span class=\"bold\">\\s*(.+?)\\s*</span><br />\n" // arrival
+ "|" //
+ "&#220;bergang.*?" //
+ "<span class=\"bold\">\\s*(.+?)\\s*</span><br />\n" // arrival
+ ")", Pattern.DOTALL);
private static final Pattern P_CONNECTION_DETAILS_ERROR = Pattern.compile("(zwischenzeitlich nicht mehr gespeichert)");
private static final Pattern P_CONNECTION_DETAILS_MESSAGES = Pattern
.compile("<div class=\"him\">|Dauer: \\d+:\\d+|Anschlusszug nicht mehr rechtzeitig|Anschlusszug jedoch erreicht werden|nur teilweise dargestellt|L&#228;ngerer Aufenthalt|&#228;quivalentem Bahnhof|Bahnhof wird mehrfach durchfahren|Aktuelle Informationen zu der Verbindung");
@Override
public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
final Matcher mError = P_CONNECTION_DETAILS_ERROR.matcher(page);
if (mError.find())
{
if (mError.group(1) != null)
throw new SessionExpiredException();
}
final Matcher mHead = P_CONNECTION_DETAILS_HEAD.matcher(page);
if (mHead.matches())
{
final List<Connection.Part> parts = new ArrayList<Connection.Part>(4);
Location firstDeparture = null;
Location lastArrival = null;
final Matcher mDetCoarse = P_CONNECTION_DETAILS_COARSE.matcher(mHead.group(1));
while (mDetCoarse.find())
{
final String section = mDetCoarse.group(1);
if (P_CONNECTION_DETAILS_MESSAGES.matcher(section).find())
{
// ignore message for now
}
else
{
final Matcher mDetFine = P_CONNECTION_DETAILS_FINE.matcher(section);
if (mDetFine.matches())
{
final Location departure = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(1)));
if (departure != null && firstDeparture == null)
firstDeparture = departure;
if (mDetFine.group(2) != null)
{
final Line line = parseLineWithoutType(ParserUtils.resolveEntities(mDetFine.group(2)));
final Calendar departureTime = new GregorianCalendar(timeZone());
departureTime.clear();
ParserUtils.parseEuropeanTime(departureTime, mDetFine.group(3));
ParserUtils.parseGermanDate(departureTime, mDetFine.group(5));
final String departurePosition = ParserUtils.resolveEntities(mDetFine.group(4));
final Location arrival = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(6)));
final Calendar arrivalTime = new GregorianCalendar(timeZone());
arrivalTime.clear();
ParserUtils.parseEuropeanTime(arrivalTime, mDetFine.group(7));
ParserUtils.parseGermanDate(arrivalTime, mDetFine.group(9));
final String arrivalPosition = ParserUtils.resolveEntities(mDetFine.group(8));
parts.add(new Connection.Trip(line, null, departureTime.getTime(), null, departurePosition, departure, arrivalTime
.getTime(), null, arrivalPosition, arrival, null, null));
lastArrival = arrival;
}
else if (mDetFine.group(10) != null)
{
final String min = mDetFine.group(10);
final Location arrival = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(11)));
if (parts.size() > 0 && parts.get(parts.size() - 1) instanceof Connection.Footway)
{
final Connection.Footway lastFootway = (Connection.Footway) parts.remove(parts.size() - 1);
parts.add(new Connection.Footway(lastFootway.min + Integer.parseInt(min), lastFootway.departure, arrival, null));
}
else
{
parts.add(new Connection.Footway(Integer.parseInt(min), departure, arrival, null));
}
lastArrival = arrival;
}
else
{
final Location arrival = new Location(LocationType.ANY, 0, null, ParserUtils.resolveEntities(mDetFine.group(12)));
parts.add(new Connection.Footway(0, departure, arrival, null));
}
}
else
{
throw new IllegalArgumentException("cannot parse '" + section + "' on " + uri);
}
}
}
return new GetConnectionDetailsResult(new GregorianCalendar(timeZone()).getTime(), new Connection(
AbstractHafasProvider.extractConnectionId(uri), uri, firstDeparture, lastArrival, parts, null, null));
}
else
{
throw new IOException(page.toString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
@Override
protected char normalizeType(String type)
{
final String ucType = type.toUpperCase();
if ("DZ".equals(ucType)) // Dampfzug
return 'R';
if ("LTT".equals(ucType))
return 'B';
if (ucType.startsWith("RFB")) // Rufbus
return 'P';
final char t = super.normalizeType(type);
if (t != 0)
return t;
if ("E".equals(ucType))
return '?';
return 0;
}
private static final Pattern P_LINE_NUMBER = Pattern.compile("\\d{2,5}");
@Override
protected final Line parseLineWithoutType(final String line)
{
if ("Schw-B".equals(line)) // Schwebebahn, gilt als "Straßenbahn besonderer Bauart"
return newLine('T' + line);
if (P_LINE_RUSSIA.matcher(line).matches())
return newLine('R' + line);
if (P_LINE_NUMBER.matcher(line).matches())
return newLine('?' + line);
if ("---".equals(line))
return newLine('?' + line);
return super.parseLineWithoutType(line);
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class BayernProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.BAYERN;
private final static String API_BASE = "http://vm-bayern-fahrplan03.defas-fgi.de:81/standard/";
public BayernProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class BsagProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.BSAG;
private final static String API_BASE = "http://62.206.133.180/bsag/";
public BsagProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class BsvagProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.BSVAG;
public static final String OLD_NETWORK_ID = "212.68.73.240";
private final static String API_BASE = "http://212.68.73.240/bsvag/";
public BsvagProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class BvbProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.BVB;
public static final String OLD_NETWORK_ID = "www.efa-bvb.ch";
private final static String API_BASE = "http://www.efa-bvb.ch/bvb/";
public BvbProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,47 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class DingProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.DING;
public static final String OLD_NETWORK_ID = "www.ding-ulm.de";
private final static String API_BASE = "http://www.ding-ulm.de/ding2/"; // http://www.ding.eu/swu
public DingProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,209 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class DsbProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.DSB;
private static final String API_BASE = "http://mobil.rejseplanen.dk/mobil-bin/";
// http://dk.hafas.de/bin/fat/
// http://mobil.rejseplanen.dk/mobil-bin/
public DsbProvider()
{
super(API_BASE + "query.exe/dn", 11, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Intercity
productBits.setCharAt(1, '1'); // InterCityExpress
}
else if (product == 'R')
{
productBits.setCharAt(2, '1'); // Regionalzug
productBits.setCharAt(3, '1'); // sonstige Züge
}
else if (product == 'S')
{
productBits.setCharAt(4, '1'); // S-Bahn
}
else if (product == 'U')
{
productBits.setCharAt(10, '1'); // U-Bahn
}
else if (product == 'T')
{
}
else if (product == 'B')
{
productBits.setCharAt(5, '1'); // Bus
productBits.setCharAt(6, '1'); // ExpressBus
productBits.setCharAt(7, '1'); // Nachtbus
}
else if (product == 'P')
{
productBits.setCharAt(8, '1'); // Telebus/andere
}
else if (product == 'F')
{
productBits.setCharAt(9, '1'); // Schiff
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final String NEARBY_STATIONS_BY_COORDINATE_URI = "http://xmlopen.rejseplanen.dk/bin/rest.exe/stopsNearby?coordX=%d&coordY=%d";
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
if (location.hasLocation())
{
final StringBuilder uri = new StringBuilder(String.format(NEARBY_STATIONS_BY_COORDINATE_URI, location.lon, location.lat));
if (maxStations != 0)
uri.append("&maxNumber=").append(maxStations);
if (maxDistance != 0)
uri.append("&maxRadius=").append(maxDistance);
final List<Location> locations = xmlLocationList(uri.toString());
return new NearbyStationsResult(null, locations);
}
else if (location.type == LocationType.STATION && location.hasId())
{
final StringBuilder uri = new StringBuilder(API_BASE);
uri.append("stboard.exe/mn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0");
uri.append("&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: '" + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/mn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = "http://xmlopen.rejseplanen.dk/bin/rest.exe/location.name?input=%s";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return xmlLocationList(uri);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("ICL".equals(ucType))
return 'I';
if ("ØR".equals(ucType))
return 'R';
if ("RA".equals(ucType))
return 'R';
if ("RX".equals(ucType))
return 'R';
if ("PP".equals(ucType))
return 'R';
if ("S-TOG".equals(ucType))
return 'S';
if ("BYBUS".equals(ucType))
return 'B';
if ("X-BUS".equals(ucType))
return 'B';
if ("HV-BUS".equals(ucType)) // Havnebus
return 'B';
if ("T-BUS".equals(ucType)) // Togbus
return 'B';
if ("TELEBUS".equals(ucType))
return 'P';
if ("TELETAXI".equals(ucType))
return 'P';
if ("FÆRGE".equals(ucType))
return 'F';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.TimeZone;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class DubProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.DUB;
public static final String OLD_NETWORK_ID = "wojhati.rta.ae";
private final static String API_BASE = "http://wojhati.rta.ae/dub/";
public DubProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("Asia/Dubai");
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.HashMap;
import java.util.Map;
import de.schildbach.pte.dto.Style;
/**
* @author Andreas Schildbach
*/
public class GvhProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.GVH;
public static final String OLD_NETWORK_ID = "mobil.gvh.de";
private static final String API_BASE = "http://mobil.efa.de/mobile3/";
public GvhProvider(final String additionalQueryParameter)
{
super(API_BASE, additionalQueryParameter);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
private static final Map<String, Style> LINES = new HashMap<String, Style>();
static
{
// Hamburg
LINES.put("SS1", new Style(Style.parseColor("#00933B"), Style.WHITE));
LINES.put("SS11", new Style(Style.WHITE, Style.parseColor("#00933B"), Style.parseColor("#00933B")));
LINES.put("SS2", new Style(Style.WHITE, Style.parseColor("#9D271A"), Style.parseColor("#9D271A")));
LINES.put("SS21", new Style(Style.parseColor("#9D271A"), Style.WHITE));
LINES.put("SS3", new Style(Style.parseColor("#411273"), Style.WHITE));
LINES.put("SS31", new Style(Style.parseColor("#411273"), Style.WHITE));
LINES.put("UU1", new Style(Style.parseColor("#044895"), Style.WHITE));
LINES.put("UU2", new Style(Style.parseColor("#DC2B19"), Style.WHITE));
LINES.put("UU3", new Style(Style.parseColor("#EE9D16"), Style.WHITE));
LINES.put("UU4", new Style(Style.parseColor("#13A59D"), Style.WHITE));
}
@Override
public Style lineStyle(final String line)
{
final Style style = LINES.get(line);
if (style != null)
return style;
else
return super.lineStyle(line);
}
}

View file

@ -0,0 +1,405 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Departure;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.dto.ResultHeader;
import de.schildbach.pte.dto.StationDepartures;
import de.schildbach.pte.dto.Style;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class InvgProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.INVG;
private static final String API_BASE = "http://fpa.invg.de/bin/";
private static final String API_URI = "http://fpa.invg.de/bin/extxml.exe";
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public InvgProvider()
{
super(API_URI, 10, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.DEPARTURES)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
throw new UnsupportedOperationException();
}
private static final String[] PLACES = { "Ingolstadt", "München" };
@Override
protected String[] splitPlaceAndName(final String name)
{
for (final String place : PLACES)
{
if (name.startsWith(place + " ") || name.startsWith(place + "-"))
return new String[] { place, name.substring(place.length() + 1) };
else if (name.startsWith(place + ", "))
return new String[] { place, name.substring(place.length() + 2) };
}
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn?near=Anzeigen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
private String departuresQueryUri(final int stationId, final int maxDepartures)
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?input=").append(stationId);
uri.append("&boardType=dep");
uri.append("&productsFilter=").append(allProductsString());
if (maxDepartures != 0)
uri.append("&maxJourneys=").append(maxDepartures);
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&start=yes");
return uri.toString();
}
private static final Pattern P_DEPARTURES_HEAD_COARSE = Pattern
.compile(
".*?" //
+ "(?:" //
+ "<div class=\"summary clearfix\">.*?<div class=\"block\">.*?(<div>.*?</div>.*?<div class=\"last\">.*?</div>).*?</div>.*?" //
+ "<div class=\"linkGroup\">.*?input=(\\d+).*?" // locationId
+ "(?:<table class=\"resultTable\" cellspacing=\"0\">(.*?)</table>|(verkehren an dieser Haltestelle keine))"//
+ "|(Eingabe kann nicht interpretiert)|(Verbindung zum Server konnte leider nicht hergestellt werden|kann vom Server derzeit leider nicht bearbeitet werden))" //
+ ".*?" //
, Pattern.DOTALL);
private static final Pattern P_DEPARTURES_HEAD_FINE = Pattern.compile(".*?" //
+ "<span class=\"output\">(.*?)<.*?" // location
+ "<span class=\"output\">\n(\\d{2}\\.\\d{2}\\.\\d{2}),\n" // date
+ "Abfahrt (\\d{1,2}:\\d{2}).*?" // time
, Pattern.DOTALL);
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<tr class=\"(depboard-\\w*)\">(.*?)</tr>", Pattern.DOTALL);
private static final Pattern P_DEPARTURES_FINE = Pattern.compile(".*?" //
+ "<td class=\"time\">(\\d{1,2}:\\d{2})</td>\n" // plannedTime
+ "(?:<td class=\"[\\w ]*prognosis[\\w ]*\">\n" //
+ "(?:&nbsp;|<span class=\"rtLimit\\d\">(p&#252;nktlich|\\d{1,2}:\\d{2})</span>)\n</td>\n" // predictedTime
+ ")?.*?" //
+ "<img class=\"product\" src=\"/hafas-res/img/products/(\\w+)_pic\\.gif\"[^>]*>\\s*(.*?)\\s*</.*?" // type,
// line
+ "<strong>\n" //
+ "<a href=\"http://fpa\\.invg\\.de/bin/stboard\\.exe/dn\\?input=(\\d+)&[^>]*>" // destinationId
+ "\\s*(.*?)\\s*</a>\n" // destination
+ "</strong>.*?" //
+ "(?:<td class=\"center sepline top\">\n(" + ParserUtils.P_PLATFORM + ").*?)?" // position
, Pattern.DOTALL);
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final ResultHeader header = new ResultHeader(SERVER_PRODUCT);
final QueryDeparturesResult result = new QueryDeparturesResult(header);
// scrape page
final String uri = departuresQueryUri(stationId, maxDepartures);
final CharSequence page = ParserUtils.scrape(uri);
// parse page
final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page);
if (mHeadCoarse.matches())
{
// messages
if (mHeadCoarse.group(4) != null)
{
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId),
Collections.<Departure> emptyList(), null));
return result;
}
else if (mHeadCoarse.group(5) != null)
return new QueryDeparturesResult(header, Status.INVALID_STATION);
else if (mHeadCoarse.group(6) != null)
return new QueryDeparturesResult(header, Status.SERVICE_DOWN);
final int locationId = Integer.parseInt(mHeadCoarse.group(2));
final Matcher mHeadFine = P_DEPARTURES_HEAD_FINE.matcher(mHeadCoarse.group(1));
if (mHeadFine.matches())
{
final String location = ParserUtils.resolveEntities(mHeadFine.group(1));
final Calendar currentTime = new GregorianCalendar(timeZone());
currentTime.clear();
ParserUtils.parseGermanDate(currentTime, mHeadFine.group(2));
ParserUtils.parseEuropeanTime(currentTime, mHeadFine.group(3));
final List<Departure> departures = new ArrayList<Departure>(8);
String oldZebra = null;
final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mHeadCoarse.group(3));
while (mDepCoarse.find())
{
final String zebra = mDepCoarse.group(1);
if (oldZebra != null && zebra.equals(oldZebra))
throw new IllegalArgumentException("missed row? last:" + zebra);
else
oldZebra = zebra;
final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(2));
if (mDepFine.matches())
{
final Calendar plannedTime = new GregorianCalendar(timeZone());
plannedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseEuropeanTime(plannedTime, mDepFine.group(1));
if (plannedTime.getTimeInMillis() - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
plannedTime.add(Calendar.DAY_OF_MONTH, 1);
final Calendar predictedTime;
final String prognosis = ParserUtils.resolveEntities(mDepFine.group(2));
if (prognosis != null)
{
predictedTime = new GregorianCalendar(timeZone());
if (prognosis.equals("pünktlich"))
{
predictedTime.setTimeInMillis(plannedTime.getTimeInMillis());
}
else
{
predictedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseEuropeanTime(predictedTime, prognosis);
}
}
else
{
predictedTime = null;
}
final String lineType = mDepFine.group(3);
final Line line = parseLine(lineType, ParserUtils.resolveEntities(mDepFine.group(4)), false);
final int destinationId = mDepFine.group(5) != null ? Integer.parseInt(mDepFine.group(5)) : 0;
final String destinationName = ParserUtils.resolveEntities(mDepFine.group(6));
final Location destination = new Location(destinationId > 0 ? LocationType.STATION : LocationType.ANY, destinationId, null,
destinationName);
final String position = mDepFine.group(7) != null ? "Gl. " + ParserUtils.resolveEntities(mDepFine.group(7)) : null;
final Departure dep = new Departure(plannedTime.getTime(), predictedTime != null ? predictedTime.getTime() : null, line,
position, destination, null, null);
if (!departures.contains(dep))
departures.add(dep);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(2) + "' on " + stationId);
}
}
final String[] placeAndName = splitPlaceAndName(location);
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, locationId, placeAndName[0], placeAndName[1]),
departures, null));
return result;
}
else
{
throw new IllegalArgumentException("cannot parse '" + mHeadCoarse.group(1) + "' on " + stationId);
}
}
else
{
throw new IllegalArgumentException("cannot parse '" + page + "' on " + stationId);
}
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlMLcReq(constraint);
}
protected static final Pattern P_NORMALIZE_LINE_BUS = Pattern.compile("Bus\\s*(\\d+)");
protected static final Pattern P_NORMALIZE_LINE_NACHTBUS = Pattern.compile("Bus\\s*N\\s*(\\d+)");
protected static final Pattern P_NORMALIZE_LINE_BUS_S = Pattern.compile("Bus\\s*S\\s*(\\d+)");
protected static final Pattern P_NORMALIZE_LINE_BUS_X = Pattern.compile("Bus\\s*X\\s*(\\d+)");
@Override
protected Line parseLine(final String type, final String line, final boolean wheelchairAccess)
{
if ("1".equals(type))
{
final Matcher mBus = P_NORMALIZE_LINE_BUS.matcher(line);
if (mBus.matches())
{
final String lineStr = "B" + mBus.group(1);
return new Line(null, lineStr, lineStyle(lineStr));
}
final Matcher mNachtbus = P_NORMALIZE_LINE_NACHTBUS.matcher(line);
if (mNachtbus.matches())
{
final String lineStr = "BN" + mNachtbus.group(1);
return new Line(null, lineStr, lineStyle(lineStr));
}
final Matcher mBusS = P_NORMALIZE_LINE_BUS_S.matcher(line);
if (mBusS.matches())
{
final String lineStr = "BS" + mBusS.group(1);
return new Line(null, lineStr, lineStyle(lineStr));
}
final Matcher mBusX = P_NORMALIZE_LINE_BUS_X.matcher(line);
if (mBusX.matches())
{
final String lineStr = "BX" + mBusX.group(1);
return new Line(null, lineStr, lineStyle(lineStr));
}
}
return super.parseLine(type, line, wheelchairAccess);
}
@Override
protected char normalizeType(final String type)
{
if ("1".equals(type))
return 'B';
return 0;
}
private static final Map<String, Style> LINES = new HashMap<String, Style>();
static
{
LINES.put("B10", new Style(Style.parseColor("#DA2510"), Style.WHITE));
LINES.put("B11", new Style(Style.parseColor("#EE9B78"), Style.BLACK));
LINES.put("B15", new Style(Style.parseColor("#84C326"), Style.BLACK));
LINES.put("B16", new Style(Style.parseColor("#5D452E"), Style.WHITE));
LINES.put("B17", new Style(Style.parseColor("#AAAAAA"), Style.BLACK));
LINES.put("B20", new Style(Style.parseColor("#EA891C"), Style.BLACK));
LINES.put("B21", new Style(Style.parseColor("#31B2EA"), Style.BLACK));
LINES.put("B25", new Style(Style.parseColor("#7F65A0"), Style.WHITE));
LINES.put("B26", new Style(Style.parseColor("#00BF73"), Style.WHITE));
LINES.put("B30", new Style(Style.parseColor("#901E78"), Style.WHITE));
LINES.put("B31", new Style(Style.parseColor("#DCE722"), Style.BLACK));
LINES.put("B40", new Style(Style.parseColor("#009240"), Style.WHITE));
LINES.put("B41", new Style(Style.parseColor("#7BC5B1"), Style.BLACK));
LINES.put("B44", new Style(Style.parseColor("#EA77A6"), Style.WHITE));
LINES.put("B50", new Style(Style.parseColor("#FACF00"), Style.BLACK));
LINES.put("B53", new Style(Style.parseColor("#BEB405"), Style.BLACK));
LINES.put("B55", new Style(Style.parseColor("#FFF500"), Style.BLACK));
LINES.put("B60", new Style(Style.parseColor("#0072B7"), Style.WHITE));
LINES.put("B61", new Style(Style.rgb(204, 184, 122), Style.BLACK));
LINES.put("B62", new Style(Style.rgb(204, 184, 122), Style.BLACK));
LINES.put("B65", new Style(Style.parseColor("#B7DDD2"), Style.BLACK));
LINES.put("B70", new Style(Style.parseColor("#D49016"), Style.BLACK));
LINES.put("B71", new Style(Style.parseColor("#996600"), Style.BLACK));
LINES.put("B85", new Style(Style.parseColor("#F6BAD3"), Style.BLACK));
LINES.put("B9221", new Style(Style.rgb(217, 217, 255), Style.BLACK));
LINES.put("B9226", new Style(Style.rgb(191, 255, 255), Style.BLACK));
LINES.put("BN1", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN2", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN3", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN4", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN5", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN6", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN7", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN8", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN9", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN10", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN11", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN12", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN13", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN14", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN15", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN16", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN17", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN18", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BN19", new Style(Style.parseColor("#00116C"), Style.WHITE));
LINES.put("BS1", new Style(Style.rgb(178, 25, 0), Style.WHITE));
LINES.put("BS2", new Style(Style.rgb(178, 25, 0), Style.WHITE));
LINES.put("BS3", new Style(Style.rgb(178, 25, 0), Style.WHITE));
LINES.put("BS4", new Style(Style.rgb(178, 25, 0), Style.WHITE));
LINES.put("BS5", new Style(Style.rgb(178, 25, 0), Style.WHITE));
LINES.put("BS6", new Style(Style.rgb(178, 25, 0), Style.WHITE));
LINES.put("BS7", new Style(Style.rgb(178, 25, 0), Style.WHITE));
LINES.put("BS8", new Style(Style.rgb(178, 25, 0), Style.WHITE));
// BX109?
LINES.put("BX11", new Style(Style.parseColor("#EE9B78"), Style.BLACK));
LINES.put("BX80", new Style(Style.parseColor("#FFFF40"), Style.BLACK));
}
@Override
public Style lineStyle(final String line)
{
final Style style = LINES.get(line);
if (style != null)
return style;
else
return super.lineStyle(line);
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class IvbProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.IVB;
public static final String OLD_NETWORK_ID = "efa.ivb.at";
private final static String API_BASE = "http://efa.ivb.at/ivb/";
public IvbProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.HashMap;
import java.util.Map;
import de.schildbach.pte.dto.Style;
import de.schildbach.pte.dto.Style.Shape;
/**
* @author Andreas Schildbach
*/
public class KvvProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.KVV;
public static final String OLD_NETWORK_ID = "213.144.24.66";
private final static String API_BASE = "http://213.144.24.66/kvv/"; // http://213.144.24.66/kvv2/
public KvvProvider()
{
super(API_BASE, null);
}
public KvvProvider(final String apiBase)
{
super(apiBase, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected String parseLine(final String mot, final String name, final String longName, final String noTrainName)
{
if (name.endsWith(" (VBK)")) // Verkehrsbetriebe Karlsruhe
return super.parseLine(mot, name.substring(0, name.length() - 6), longName, noTrainName);
else
return super.parseLine(mot, name, longName, noTrainName);
}
private static final Map<String, Style> LINES = new HashMap<String, Style>();
static
{
// S-Bahn
LINES.put("SS1", new Style(Style.parseColor("#00a76d"), Style.WHITE));
LINES.put("SS11", new Style(Style.parseColor("#00a76d"), Style.WHITE));
LINES.put("SS2", new Style(Style.parseColor("#a066aa"), Style.WHITE));
LINES.put("SS3", new Style(Style.parseColor("#00a99d"), Style.WHITE));
LINES.put("SS31", new Style(Style.parseColor("#00a99d"), Style.WHITE));
LINES.put("SS32", new Style(Style.parseColor("#00a99d"), Style.WHITE));
LINES.put("SS33", new Style(Style.parseColor("#00a99d"), Style.WHITE));
LINES.put("SS4", new Style(Style.parseColor("#9f184c"), Style.WHITE));
LINES.put("SS41", new Style(Style.parseColor("#9f184c"), Style.WHITE));
LINES.put("SS5", new Style(Style.parseColor("#f69795"), Style.BLACK));
LINES.put("SS51", new Style(Style.parseColor("#f69795"), Style.BLACK));
LINES.put("SS52", new Style(Style.parseColor("#f69795"), Style.BLACK));
LINES.put("SS6", new Style(Style.parseColor("#282268"), Style.WHITE));
LINES.put("SS7", new Style(Style.parseColor("#fff200"), Style.BLACK));
LINES.put("SS9", new Style(Style.parseColor("#fab49b"), Style.BLACK));
// Tram
LINES.put("T1", new Style(Shape.RECT, Style.parseColor("#ed1c24"), Style.WHITE));
LINES.put("T2", new Style(Shape.RECT, Style.parseColor("#0071bc"), Style.WHITE));
LINES.put("T2E", new Style(Shape.RECT, Style.parseColor("#0071bc"), Style.WHITE));
LINES.put("T3", new Style(Shape.RECT, Style.parseColor("#947139"), Style.WHITE));
LINES.put("T4", new Style(Shape.RECT, Style.parseColor("#ffcb04"), Style.BLACK));
LINES.put("T5", new Style(Shape.RECT, Style.parseColor("#00c0f3"), Style.WHITE));
LINES.put("T6", new Style(Shape.RECT, Style.parseColor("#80c342"), Style.WHITE));
LINES.put("T7", new Style(Shape.RECT, Style.parseColor("#58595b"), Style.WHITE));
LINES.put("T8", new Style(Shape.RECT, Style.parseColor("#f7931d"), Style.BLACK));
// Bus - only used on bus plan
// LINES.put("B21", new Style(Shape.CIRCLE, Style.parseColor("#2e3092"), Style.WHITE));
// LINES.put("B22", new Style(Shape.CIRCLE, Style.parseColor("#00aeef"), Style.WHITE));
// LINES.put("B23", new Style(Shape.CIRCLE, Style.parseColor("#56c5d0"), Style.WHITE));
// LINES.put("B24", new Style(Shape.CIRCLE, Style.parseColor("#a1d1e6"), Style.WHITE));
// LINES.put("B26", new Style(Shape.CIRCLE, Style.parseColor("#2e3092"), Style.WHITE));
// LINES.put("B27", new Style(Shape.CIRCLE, Style.parseColor("#00aeef"), Style.WHITE));
// LINES.put("B30", new Style(Shape.CIRCLE, Style.parseColor("#adbc72"), Style.WHITE));
// LINES.put("B31", new Style(Shape.CIRCLE, Style.parseColor("#62bb46"), Style.WHITE));
// LINES.put("B32", new Style(Shape.CIRCLE, Style.parseColor("#177752"), Style.WHITE));
// LINES.put("B42", new Style(Shape.CIRCLE, Style.parseColor("#177752"), Style.WHITE));
// LINES.put("B44", new Style(Shape.CIRCLE, Style.parseColor("#62bb46"), Style.WHITE));
// LINES.put("B47", new Style(Shape.CIRCLE, Style.parseColor("#adbc72"), Style.WHITE));
// LINES.put("B50", new Style(Shape.CIRCLE, Style.parseColor("#a25641"), Style.WHITE));
// LINES.put("B51", new Style(Shape.CIRCLE, Style.parseColor("#d2ab67"), Style.WHITE));
// LINES.put("B52", new Style(Shape.CIRCLE, Style.parseColor("#a25641"), Style.WHITE));
// LINES.put("B55", new Style(Shape.CIRCLE, Style.parseColor("#806a50"), Style.WHITE));
// LINES.put("B60", new Style(Shape.CIRCLE, Style.parseColor("#806a50"), Style.WHITE));
// LINES.put("B62", new Style(Shape.CIRCLE, Style.parseColor("#d2ab67"), Style.WHITE));
// LINES.put("B70", new Style(Shape.CIRCLE, Style.parseColor("#574187"), Style.WHITE));
// LINES.put("B71", new Style(Shape.CIRCLE, Style.parseColor("#874487"), Style.WHITE));
// LINES.put("B72", new Style(Shape.CIRCLE, Style.parseColor("#9b95c9"), Style.WHITE));
// LINES.put("B73", new Style(Shape.CIRCLE, Style.parseColor("#574187"), Style.WHITE));
// LINES.put("B74", new Style(Shape.CIRCLE, Style.parseColor("#9b95c9"), Style.WHITE));
// LINES.put("B75", new Style(Shape.CIRCLE, Style.parseColor("#874487"), Style.WHITE));
// LINES.put("B107", new Style(Shape.CIRCLE, Style.parseColor("#9d9fa1"), Style.WHITE));
// LINES.put("B118", new Style(Shape.CIRCLE, Style.parseColor("#9d9fa1"), Style.WHITE));
// LINES.put("B123", new Style(Shape.CIRCLE, Style.parseColor("#9d9fa1"), Style.WHITE));
// Nightliner
LINES.put("BNL3", new Style(Style.parseColor("#947139"), Style.WHITE));
LINES.put("BNL4", new Style(Style.parseColor("#ffcb04"), Style.BLACK));
LINES.put("BNL5", new Style(Style.parseColor("#00c0f3"), Style.WHITE));
LINES.put("BNL6", new Style(Style.parseColor("#80c342"), Style.WHITE));
// Anruf-Linien-Taxi
LINES.put("BALT6", new Style(Shape.RECT, Style.BLACK, Style.YELLOW));
LINES.put("BALT11", new Style(Shape.RECT, Style.BLACK, Style.YELLOW));
LINES.put("BALT12", new Style(Shape.RECT, Style.BLACK, Style.YELLOW));
LINES.put("BALT13", new Style(Shape.RECT, Style.BLACK, Style.YELLOW));
LINES.put("BALT14", new Style(Shape.RECT, Style.BLACK, Style.YELLOW));
LINES.put("BALT16", new Style(Shape.RECT, Style.BLACK, Style.YELLOW));
}
@Override
public Style lineStyle(final String line)
{
final Style style = LINES.get(line);
if (style != null)
return style;
else
return super.lineStyle(line);
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class LinzProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.LINZ;
public static final String OLD_NETWORK_ID = "www.linzag.at";
public static final String API_BASE = "http://www.linzag.at/linz/"; // open data: http://www.linzag.at/static/
public LinzProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public final class LocationUtils
{
/**
* @param lat1
* latitude of origin point in decimal degrees
* @param lon1
* longitude of origin point in deceimal degrees
* @param lat2
* latitude of destination point in decimal degrees
* @param lon2
* longitude of destination point in decimal degrees
*
* @return distance in meters
*/
public static float computeDistance(double lat1, double lon1, double lat2, double lon2)
{
// Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
// using the "Inverse Formula" (section 4)
final int MAXITERS = 20;
// Convert lat/long to radians
lat1 *= Math.PI / 180.0;
lat2 *= Math.PI / 180.0;
lon1 *= Math.PI / 180.0;
lon2 *= Math.PI / 180.0;
final double a = 6378137.0; // WGS84 major axis
final double b = 6356752.3142; // WGS84 semi-major axis
final double f = (a - b) / a;
final double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
final double L = lon2 - lon1;
double A = 0.0;
final double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
final double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
final double cosU1 = Math.cos(U1);
final double cosU2 = Math.cos(U2);
final double sinU1 = Math.sin(U1);
final double sinU2 = Math.sin(U2);
final double cosU1cosU2 = cosU1 * cosU2;
final double sinU1sinU2 = sinU1 * sinU2;
double sigma = 0.0;
double deltaSigma = 0.0;
double cosSqAlpha = 0.0;
double cos2SM = 0.0;
double cosSigma = 0.0;
double sinSigma = 0.0;
double cosLambda = 0.0;
double sinLambda = 0.0;
double lambda = L; // initial guess
for (int iter = 0; iter < MAXITERS; iter++)
{
final double lambdaOrig = lambda;
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
final double t1 = cosU2 * sinLambda;
final double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
final double sinSqSigma = t1 * t1 + t2 * t2; // (14)
sinSigma = Math.sqrt(sinSqSigma);
cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
sigma = Math.atan2(sinSigma, cosSigma); // (16)
final double sinAlpha = (sinSigma == 0) ? 0.0 : cosU1cosU2 * sinLambda / sinSigma; // (17)
cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
cos2SM = (cosSqAlpha == 0) ? 0.0 : cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
final double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
A = 1 + (uSquared / 16384.0) * // (3)
(4096.0 + uSquared * (-768 + uSquared * (320.0 - 175.0 * uSquared)));
final double B = (uSquared / 1024.0) * // (4)
(256.0 + uSquared * (-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
final double C = (f / 16.0) * cosSqAlpha * (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
final double cos2SMSq = cos2SM * cos2SM;
deltaSigma = B
* sinSigma
* // (6)
(cos2SM + (B / 4.0)
* (cosSigma * (-1.0 + 2.0 * cos2SMSq) - (B / 6.0) * cos2SM * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0 + 4.0 * cos2SMSq)));
lambda = L + (1.0 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SM + C * cosSigma * (-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
final double delta = (lambda - lambdaOrig) / lambda;
if (Math.abs(delta) < 1.0e-12)
break;
}
return (float) (b * A * (sigma - deltaSigma));
}
}

View file

@ -0,0 +1,154 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
/**
* @author Andreas Schildbach
*/
public class LuProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.LU;
private static final String API_BASE = "http://mobiliteitszentral.hafas.de/hafas/";
public LuProvider()
{
super(API_BASE + "query.exe/dn", 10, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Hochgeschwindigkeitszug
productBits.setCharAt(1, '1'); // IC/EC
productBits.setCharAt(2, '1'); // Fernverkehrszug
}
else if (product == 'R')
{
productBits.setCharAt(3, '1'); // Regionalverkehrszug
}
else if (product == 'S')
{
productBits.setCharAt(4, '1'); // S-Bahn
}
else if (product == 'U')
{
productBits.setCharAt(7, '1'); // U-Bahn
}
else if (product == 'T')
{
productBits.setCharAt(8, '1'); // Straßenbahn
}
else if (product == 'B')
{
productBits.setCharAt(5, '1'); // Bus
}
else if (product == 'P')
{
productBits.setCharAt(9, '1'); // AST/Rufbus
}
else if (product == 'F')
{
productBits.setCharAt(6, '1'); // Schiff
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
if (location.type == LocationType.STATION && location.hasId())
{
final StringBuilder uri = new StringBuilder(API_BASE);
uri.append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlMLcReq(constraint);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("CRE".equals(ucType))
return 'R';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class MariborProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.MARIBOR;
public static final String OLD_NETWORK_ID = "164.8.32.183";
private final static String API_BASE = "http://164.8.32.183/slo/";
public MariborProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import de.schildbach.pte.dto.Style;
/**
* @author Andreas Schildbach
*/
public class MetProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.MET;
private final static String API_BASE = "http://jp.metlinkmelbourne.com.au/metlink/";
public MetProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("Australia/Melbourne");
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
private static final Map<Character, Style> LINES = new HashMap<Character, Style>();
static
{
LINES.put('R', new Style(Style.parseColor("#a24ba3"), Style.WHITE));
LINES.put('S', new Style(Style.parseColor("#3a75c4"), Style.WHITE));
LINES.put('T', new Style(Style.parseColor("#5bbf21"), Style.WHITE));
LINES.put('B', new Style(Style.parseColor("#f77f00"), Style.WHITE));
}
@Override
public Style lineStyle(final String line)
{
// TODO NightRider buses (buses with numbers > 940): #f26522
final Style style = LINES.get(line.charAt(0));
if (style != null)
return style;
else
return super.lineStyle(line);
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class MvgProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.MVG;
private static final String API_BASE = "http://mobil.mvg-online.de/";
public MvgProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.HashMap;
import java.util.Map;
import de.schildbach.pte.dto.Point;
import de.schildbach.pte.dto.Style;
/**
* @author Andreas Schildbach
*/
public class MvvProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.MVV;
public static final String OLD_NETWORK_ID = "efa.mvv-muenchen.de";
private static final String API_BASE = "http://efa.mvv-muenchen.de/mobile/";
public MvvProvider()
{
super(API_BASE, null, false);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
private static final Map<String, Style> LINES = new HashMap<String, Style>();
static
{
LINES.put("SS1", new Style(Style.parseColor("#00ccff"), Style.WHITE));
LINES.put("SS2", new Style(Style.parseColor("#66cc00"), Style.WHITE));
LINES.put("SS3", new Style(Style.parseColor("#880099"), Style.WHITE));
LINES.put("SS4", new Style(Style.parseColor("#ff0033"), Style.WHITE));
LINES.put("SS6", new Style(Style.parseColor("#00aa66"), Style.WHITE));
LINES.put("SS7", new Style(Style.parseColor("#993333"), Style.WHITE));
LINES.put("SS8", new Style(Style.BLACK, Style.parseColor("#ffcc00")));
LINES.put("SS20", new Style(Style.BLACK, Style.parseColor("#ffaaaa")));
LINES.put("SS27", new Style(Style.parseColor("#ffaaaa"), Style.WHITE));
LINES.put("SA", new Style(Style.parseColor("#231f20"), Style.WHITE));
LINES.put("T12", new Style(Style.parseColor("#883388"), Style.WHITE));
LINES.put("T15", new Style(Style.parseColor("#3366CC"), Style.WHITE));
LINES.put("T16", new Style(Style.parseColor("#CC8833"), Style.WHITE));
LINES.put("T17", new Style(Style.parseColor("#993333"), Style.WHITE));
LINES.put("T18", new Style(Style.parseColor("#66bb33"), Style.WHITE));
LINES.put("T19", new Style(Style.parseColor("#cc0000"), Style.WHITE));
LINES.put("T20", new Style(Style.parseColor("#00bbee"), Style.WHITE));
LINES.put("T21", new Style(Style.parseColor("#33aa99"), Style.WHITE));
LINES.put("T23", new Style(Style.parseColor("#fff000"), Style.WHITE));
LINES.put("T25", new Style(Style.parseColor("#ff9999"), Style.WHITE));
LINES.put("T27", new Style(Style.parseColor("#ff6600"), Style.WHITE));
LINES.put("TN17", new Style(Style.parseColor("#999999"), Style.parseColor("#ffff00")));
LINES.put("TN19", new Style(Style.parseColor("#999999"), Style.parseColor("#ffff00")));
LINES.put("TN20", new Style(Style.parseColor("#999999"), Style.parseColor("#ffff00")));
LINES.put("TN27", new Style(Style.parseColor("#999999"), Style.parseColor("#ffff00")));
LINES.put("UU1", new Style(Style.parseColor("#227700"), Style.WHITE));
LINES.put("UU2", new Style(Style.parseColor("#bb0000"), Style.WHITE));
LINES.put("UU2E", new Style(Style.parseColor("#bb0000"), Style.WHITE));
LINES.put("UU3", new Style(Style.parseColor("#ee8800"), Style.WHITE));
LINES.put("UU4", new Style(Style.parseColor("#00ccaa"), Style.WHITE));
LINES.put("UU5", new Style(Style.parseColor("#bb7700"), Style.WHITE));
LINES.put("UU6", new Style(Style.parseColor("#0000cc"), Style.WHITE));
}
@Override
public Style lineStyle(final String line)
{
final Style style = LINES.get(line);
if (style != null)
return style;
else
return super.lineStyle(line);
}
@Override
public Point[] getArea()
{
return new Point[] { new Point(48.140377f, 11.560643f) };
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class NaldoProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.NALDO;
public static final String OLD_NETWORK_ID = "efa.naldo.de";
private final static String API_BASE = "http://efa.naldo.de/naldo/";
public NaldoProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,205 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
/**
* @author Andreas Schildbach
*/
public class NasaProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.NASA;
public static final String OLD_NETWORK_ID = "www.nasa.de";
private static final String API_BASE = "http://reiseauskunft.insa.de/bin/";
public NasaProvider()
{
super(API_BASE + "query.exe/dn", 8, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // ICE
productBits.setCharAt(1, '1'); // IC/EC
}
else if (product == 'R')
{
productBits.setCharAt(3, '1'); // RE/RB
productBits.setCharAt(7, '1'); // Tourismus-Züge
productBits.setCharAt(2, '1'); // undokumentiert
}
else if (product == 'S' || product == 'U')
{
productBits.setCharAt(4, '1'); // S/U
}
else if (product == 'T')
{
productBits.setCharAt(5, '1'); // Straßenbahn
}
else if (product == 'B' || product == 'P')
{
productBits.setCharAt(6, '1'); // Bus
}
else if (product == 'F' || product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final String[] PLACES = { "Leipzig", "Halle (Saale)", "Halle" };
@Override
protected String[] splitPlaceAndName(final String name)
{
for (final String place : PLACES)
{
if (name.startsWith(place + " ") || name.startsWith(place + "-"))
return new String[] { place, name.substring(place.length() + 1) };
else if (name.startsWith(place + ", "))
return new String[] { place, name.substring(place.length() + 2) };
}
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn?near=Anzeigen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlMLcReq(constraint);
}
private static final Pattern P_LINE_NUMBER = Pattern.compile("\\d{4,}");
@Override
protected Line parseLineWithoutType(final String line)
{
if (P_LINE_NUMBER.matcher(line).matches())
return newLine('?' + line);
return super.parseLineWithoutType(line);
}
@Override
protected Line parseLineAndType(final String line)
{
return parseLineWithoutType(line);
}
@Override
protected char normalizeType(String type)
{
final String ucType = type.toUpperCase();
if ("ECW".equals(ucType))
return 'I';
if ("IXB".equals(ucType)) // ICE International
return 'I';
if ("DPF".equals(ucType)) // mit Dampflok bespannter Zug
return 'R';
if ("DAM".equals(ucType)) // Harzer Schmalspurbahnen: mit Dampflok bespannter Zug
return 'R';
if ("TW".equals(ucType)) // Harzer Schmalspurbahnen: Triebwagen
return 'R';
if ("RR".equals(ucType)) // Polen
return 'R';
if ("BAHN".equals(ucType))
return 'R';
if ("ZUGBAHN".equals(ucType))
return 'R';
if ("DAMPFZUG".equals(ucType))
return 'R';
if ("E".equals(ucType)) // Stadtbahn Karlsruhe: S4/S31/xxxxx
return 'S';
if ("BSV".equals(ucType))
return 'B';
if ("RUFBUS".equals(ucType)) // Rufbus
return 'B';
if ("RBS".equals(ucType)) // Rufbus
return 'B';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public enum NetworkId
{
// Europe
RT,
// Germany
DB, BVG, VBB, RMV, NVV, BAYERN, MVV, INVG, AVV, VGN, VVM, VMV, HVV, SH, GVH, BSVAG, BSAG, VBN, NASA, VVO, VMS, VGS, VRR, VRS, MVG, NPH, VRN, VRT, VVS, NALDO, DING, KVV, VAGFR, NVBW,
// Austria
OEBB, VOR, LINZ, SVV, VVT, VMOBIL, IVB, STV,
// Switzerland
SBB, BVB, VBL, ZVV,
// Belgium
SNCB,
// Netherlands
NS,
// Denmark
DSB,
// Sweden
SE, STOCKHOLM,
// Norway
NRI,
// Luxembourg
LU,
// United Kingdom
TFL, TLEM, TLEA, TLSE, TLSW,
// Slovenia
MARIBOR,
// Poland
PL,
// Italy
ATC,
// United Arab Emirates
DUB,
// United States
SF, SEPTA,
// Australia
SYDNEY, MET
}

View file

@ -0,0 +1,158 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import de.schildbach.pte.dto.GetConnectionDetailsResult;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.Point;
import de.schildbach.pte.dto.QueryConnectionsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.Style;
/**
* Interface to be implemented by providers of transportation networks
*
* @author Andreas Schildbach
*/
public interface NetworkProvider
{
public enum Capability
{
AUTOCOMPLETE_ONE_LINE, NEARBY_STATIONS, DEPARTURES, CONNECTIONS
}
public enum WalkSpeed
{
SLOW, NORMAL, FAST
}
public enum Accessibility
{
NEUTRAL, LIMITED, BARRIER_FREE
}
NetworkId id();
boolean hasCapabilities(Capability... capabilities);
/**
* Determine stations near to given location. At least one of stationId or lat/lon pair must be present.
*
* @param location
* location to determine nearby stations (optional)
* @param maxDistance
* maximum distance in meters, or {@code 0}
* @param maxStations
* maximum number of stations, or {@code 0}
* @return nearby stations
* @throws IOException
*/
NearbyStationsResult queryNearbyStations(Location location, int maxDistance, int maxStations) throws IOException;
/**
* Get departures at a given station, probably live
*
* @param stationId
* id of the station
* @param maxDepartures
* maximum number of departures to get or {@code 0}
* @param equivs
* also query equivalent stations?
* @return result object containing the departures
* @throws IOException
*/
QueryDeparturesResult queryDepartures(int stationId, int maxDepartures, boolean equivs) throws IOException;
/**
* Meant for auto-completion of station names, like in an {@link android.widget.AutoCompleteTextView}
*
* @param constraint
* input by user so far
* @return auto-complete suggestions
* @throws IOException
*/
List<Location> autocompleteStations(CharSequence constraint) throws IOException;
/**
* Query connections, asking for any ambiguousnesses
*
* @param from
* location to route from, mandatory
* @param via
* location to route via, may be {@code null}
* @param to
* location to route to, mandatory
* @param date
* desired date for departing, mandatory
* @param dep
* date is departure date? {@code true} for departure, {@code false} for arrival
* @param products
* products to take into account
* @param walkSpeed
* how fast can you walk?
* @param accessibility
* how accessible do you need the route to be?
* @return result object that can contain alternatives to clear up ambiguousnesses, or contains possible connections
* @throws IOException
*/
QueryConnectionsResult queryConnections(Location from, Location via, Location to, Date date, boolean dep, String products, WalkSpeed walkSpeed,
Accessibility accessibility) throws IOException;
/**
* Query more connections (e.g. earlier or later)
*
* @param context
* context to query more connections from
* @param next
* {@code true} for get next connections, {@code false} for get previous connections
* @return result object that contains possible connections
* @throws IOException
*/
QueryConnectionsResult queryMoreConnections(String context, boolean next) throws IOException;
/**
* Get details about a connection
*
* @param connectionUri
* uri returned via {@link NetworkProvider#queryConnections}
* @return result object containing the details of the connection
* @throws IOException
*/
GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException;
/**
* Get style of line
*
* @param line
* line to get style of
* @return object containing background, foreground and border (optional) colors
*/
Style lineStyle(String line);
/**
* Gets the primary covered area of the network
*
* @return array containing points of a polygon (special case: just one coordinate defines just a center point)
*/
Point[] getArea();
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class NphProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.NPH;
private static final String API_BASE = "http://efa.nph.de/nph/";
public NphProvider()
{
super(API_BASE, null, false);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,213 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class NriProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.NRI;
private static final String API_BASE = "http://hafas.websrv05.reiseinfo.no/bin/dev/nri/";
public NriProvider()
{
super(API_BASE + "query.exe/on", 8, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Flugzeug
}
else if (product == 'R')
{
productBits.setCharAt(1, '1'); // Regionalverkehrszug
productBits.setCharAt(7, '1'); // Tourismus-Züge
productBits.setCharAt(2, '1'); // undokumentiert
}
else if (product == 'S' || product == 'T')
{
productBits.setCharAt(3, '1'); // Stadtbahn
}
else if (product == 'U')
{
productBits.setCharAt(4, '1'); // U-Bahn
}
else if (product == 'B' || product == 'P')
{
productBits.setCharAt(2, '1'); // Bus
}
else if (product == 'F')
{
productBits.setCharAt(5, '1'); // Express-Boot
productBits.setCharAt(6, '1'); // Schiff
productBits.setCharAt(7, '1'); // Fähre
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final String[] PLACES = { "Oslo", "Bergen" };
@Override
protected String[] splitPlaceAndName(final String name)
{
for (final String place : PLACES)
if (name.startsWith(place + " "))
return new String[] { place, name.substring(place.length() + 1) };
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/ony");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 150);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/on");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0");
uri.append("&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/on");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE
+ "ajax-getstop.exe/ony?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=255&REQ0JourneyStopsS0B=5&REQ0JourneyStopsB=12&getstop=1&noSession=yes&REQ0JourneyStopsS0G=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected Line parseLineAndType(final String line)
{
return parseLineWithoutType(line);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("AIR".equals(ucType))
return 'I';
if ("TRA".equals(ucType))
return 'R';
if ("TRAIN".equals(ucType))
return 'R';
if ("U".equals(ucType))
return 'U';
if ("TRAM".equals(ucType))
return 'T';
if ("MTR".equals(ucType))
return 'T';
if (ucType.startsWith("BUS"))
return 'B';
if ("EXP".equals(ucType))
return 'F';
if ("EXP.BOAT".equals(ucType))
return 'F';
if ("FERRY".equals(ucType))
return 'F';
if ("FER".equals(ucType))
return 'F';
if ("SHIP".equals(ucType))
return 'F';
if ("SHI".equals(ucType))
return 'F';
return 0;
}
}

View file

@ -0,0 +1,230 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Departure;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.dto.ResultHeader;
import de.schildbach.pte.dto.StationDepartures;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class NsProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.NS;
public static final String OLD_NETWORK_ID = "hafas.bene-system.com";
private static final String API_URI = "http://hafas.bene-system.com/bin/extxml.exe"; // http://plannerint.b-rail.be/bin/extxml.exe
private static final String API_BASE = "http://hari.b-rail.be/HAFAS/bin/"; // FIXME!
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public NsProvider()
{
super(API_URI, 6, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.DEPARTURES)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
throw new UnsupportedOperationException();
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
if (location.type == LocationType.STATION && location.hasId())
{
final StringBuilder uri = new StringBuilder(API_BASE);
uri.append("stboard.exe/en");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
private String departuresQueryUri(final int stationId, final int maxDepartures)
{
final StringBuilder uri = new StringBuilder();
uri.append("http://hari.b-rail.be/hari3/webserver1/bin/stboard.exe/dox");
uri.append("?input=").append(stationId);
uri.append("&boardType=dep");
uri.append("&maxJourneys=").append(maxDepartures != 0 ? maxDepartures : 50); // maximum taken from SNCB site
uri.append("&productsFilter=").append(allProductsString());
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&start=yes");
return uri.toString();
}
private static final Pattern P_DEPARTURES_HEAD_COARSE = Pattern.compile(".*?" //
+ "(?:" //
+ "<div id=\"hfs_content\">\r\n" //
+ "<p class=\"qs\">\r\n(.*?)\r\n</p>\r\n" // head
+ "(.*?)\r\n</div>" // departures
+ "|(Eingabe kann nicht interpretiert)|(Verbindung zum Server konnte leider nicht hergestellt werden))" //
+ ".*?", Pattern.DOTALL);
private static final Pattern P_DEPARTURES_HEAD_FINE = Pattern.compile("" //
+ "<strong>(.*?)</strong><br />\r\n" // location
+ "Abfahrt (\\d{1,2}:\\d{2}),\r\n" // time
+ "(\\d{2}/\\d{2}/\\d{2})" // date
, Pattern.DOTALL);
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<p class=\"journey\">\r\n(.*?)</p>", Pattern.DOTALL);
private static final Pattern P_DEPARTURES_FINE = Pattern.compile(".*?" //
+ "<strong>(.*?)</strong>.*?" // line
+ "&gt;&gt;\r\n" //
+ "(.*?)\r\n" // destination
+ "<br />\r\n" //
+ "<strong>(\\d{1,2}:\\d{2})</strong>\r\n" // time
+ "(?:<span class=\"delay\">([+-]?\\d+|Ausfall)</span>\r\n)?" // delay
, Pattern.DOTALL);
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final ResultHeader header = new ResultHeader(SERVER_PRODUCT);
final QueryDeparturesResult result = new QueryDeparturesResult(header);
// scrape page
final String uri = departuresQueryUri(stationId, maxDepartures);
final CharSequence page = ParserUtils.scrape(uri);
// parse page
final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page);
if (mHeadCoarse.matches())
{
// messages
if (mHeadCoarse.group(3) != null)
return new QueryDeparturesResult(header, Status.INVALID_STATION);
else if (mHeadCoarse.group(4) != null)
return new QueryDeparturesResult(header, Status.SERVICE_DOWN);
final Matcher mHeadFine = P_DEPARTURES_HEAD_FINE.matcher(mHeadCoarse.group(1));
if (mHeadFine.matches())
{
final String location = ParserUtils.resolveEntities(mHeadFine.group(1));
final Calendar currentTime = new GregorianCalendar(timeZone());
currentTime.clear();
ParserUtils.parseEuropeanTime(currentTime, mHeadFine.group(2));
ParserUtils.parseGermanDate(currentTime, mHeadFine.group(3));
final List<Departure> departures = new ArrayList<Departure>(8);
final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mHeadCoarse.group(2));
while (mDepCoarse.find())
{
final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(1));
if (mDepFine.matches())
{
final Line line = parseLineWithoutType(ParserUtils.resolveEntities(mDepFine.group(1)));
final String destinationName = ParserUtils.resolveEntities(mDepFine.group(2));
final Location destination = new Location(LocationType.ANY, 0, null, destinationName);
final Calendar parsedTime = new GregorianCalendar(timeZone());
parsedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseEuropeanTime(parsedTime, mDepFine.group(3));
if (parsedTime.getTimeInMillis() - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
parsedTime.add(Calendar.DAY_OF_MONTH, 1);
mDepFine.group(4); // TODO delay
final Departure dep = new Departure(parsedTime.getTime(), null, line, null, destination, null, null);
if (!departures.contains(dep))
departures.add(dep);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(1) + "' on " + stationId);
}
}
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId, null, location), departures, null));
return result;
}
else
{
throw new IllegalArgumentException("cannot parse '" + mHeadCoarse.group(1) + "' on " + stationId);
}
}
else
{
throw new IllegalArgumentException("cannot parse '" + page + "' on " + stationId);
}
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
throw new UnsupportedOperationException();
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if (ucType.equals("L"))
return 'R';
if (ucType.equals("CR"))
return 'R';
if (ucType.equals("ICT")) // Brügge
return 'R';
if (ucType.equals("TRN")) // Mons
return 'R';
if (ucType.equals("MÉT"))
return 'U';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class NvbwProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.NVBW;
private final static String API_BASE = "http://www.efa-bw.de/nvbw/"; // http://www.efa-bw.de/android/
public NvbwProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,174 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
/**
* @author Andreas Schildbach
*/
public class NvvProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.NVV;
private static final String API_BASE = "http://auskunft.nvv.de/nvv/bin/jp/";
public NvvProvider()
{
super(API_BASE + "query.exe/dn", 17, null, "UTF-8", "UTF-8");
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Zug ICE
productBits.setCharAt(1, '1'); // Zug
}
else if (product == 'R')
{
productBits.setCharAt(2, '1'); // Zug Nahverkehr
productBits.setCharAt(10, '1'); // RegioTram
}
else if (product == 'S')
{
productBits.setCharAt(3, '1'); // S-Bahn
}
else if (product == 'U')
{
productBits.setCharAt(4, '1'); // U-Bahn
}
else if (product == 'T')
{
productBits.setCharAt(5, '1'); // Tram
}
else if (product == 'B')
{
productBits.setCharAt(6, '1'); // Niederflurbus
productBits.setCharAt(7, '1'); // Bus
}
else if (product == 'P')
{
productBits.setCharAt(9, '1'); // Anruf-Sammel-Taxi
}
else if (product == 'F')
{
productBits.setCharAt(8, '1'); // Schiff
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final String[] PLACES = { "Kassel" };
@Override
protected String[] splitPlaceAndName(final String name)
{
for (final String place : PLACES)
if (name.startsWith(place + " ") || name.startsWith(place + "-"))
return new String[] { place, name.substring(place.length() + 1) };
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/en?near=Anzeigen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
throw new UnsupportedOperationException();
// return xmlQueryDepartures(uri.toString(), stationId);
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlMLcReq(constraint);
}
@Override
protected char normalizeType(final String type)
{
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,284 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class OebbProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.OEBB;
public static final String OLD_NETWORK_ID = "fahrplan.oebb.at";
private static final String API_BASE = "http://fahrplan.oebb.at/bin/";
private static final String URL_ENCODING = "ISO-8859-1";
public OebbProvider()
{
super(API_BASE + "query.exe/dn", 12, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.NEARBY_STATIONS || capability == Capability.DEPARTURES || capability == Capability.AUTOCOMPLETE_ONE_LINE
|| capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected char intToProduct(final int value)
{
if (value == 1)
return 'I';
if (value == 2)
return 'I';
if (value == 4)
return 'I';
if (value == 8)
return 'R';
if (value == 16)
return 'R';
if (value == 32)
return 'S';
if (value == 64)
return 'B';
if (value == 128)
return 'F';
if (value == 256)
return 'U';
if (value == 512)
return 'T';
if (value == 1024) // Autoreisezug
return 'I';
if (value == 2048)
return 'P';
throw new IllegalArgumentException("cannot handle: " + value);
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // railjet/ICE
productBits.setCharAt(1, '1'); // ÖBB EC/ÖBB IC
productBits.setCharAt(2, '1'); // EC/IC
productBits.setCharAt(10, '1'); // Autoreisezug
}
else if (product == 'R')
{
productBits.setCharAt(3, '1'); // D/EN
productBits.setCharAt(4, '1'); // REX/R
}
else if (product == 'S')
{
productBits.setCharAt(5, '1'); // S-Bahnen
}
else if (product == 'U')
{
productBits.setCharAt(8, '1'); // U-Bahn
}
else if (product == 'T')
{
productBits.setCharAt(9, '1'); // Straßenbahn
}
else if (product == 'B')
{
productBits.setCharAt(6, '1'); // Busse
}
else if (product == 'P')
{
productBits.setCharAt(11, '1'); // Anrufpflichtige Verkehre
}
else if (product == 'F')
{
productBits.setCharAt(7, '1'); // Schiffe
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn?near=Suchen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE
+ "ajax-getstop.exe/dny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=255&REQ0JourneyStopsB=12&S=%s?&js=true&";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), URL_ENCODING));
return jsonGetStops(uri);
}
private static final Map<WalkSpeed, String> WALKSPEED_MAP = new HashMap<WalkSpeed, String>();
static
{
WALKSPEED_MAP.put(WalkSpeed.SLOW, "115");
WALKSPEED_MAP.put(WalkSpeed.NORMAL, "100");
WALKSPEED_MAP.put(WalkSpeed.FAST, "85");
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if (ucType.equals("RR")) // Finnland, Connections only?
return 'I';
if (ucType.equals("EE")) // Rumänien, Connections only?
return 'I';
if (ucType.equals("OZ")) // Schweden, Oeresundzug, Connections only?
return 'I';
if (ucType.equals("UUU")) // Italien, Nacht, Connections only?
return 'I';
if (ucType.equals("S2")) // Helsinki-Turku, Connections only?
return 'R';
if (ucType.equals("RE")) // RegionalExpress Deutschland
return 'R';
if (ucType.equals("DPN")) // Connections only? TODO nicht evtl. doch eher ne S-Bahn?
return 'R';
if (ucType.equals("E")) // Budapest, Ungarn
return 'R';
if (ucType.equals("IP")) // Ozd, Ungarn
return 'R';
if (ucType.equals("N")) // Frankreich, Tours
return 'R';
if (ucType.equals("DPF")) // VX=Vogtland Express, Connections only?
return 'R';
// if (ucType.equals("SBE")) // Zittau-Seifhennersdorf, via JSON API
// return 'R';
if ("UAU".equals(ucType)) // Rußland
return 'R';
if (ucType.equals("RSB")) // Schnellbahn Wien
return 'S';
// if (ucType.equals("DPN")) // S3 Bad Reichenhall-Freilassing, via JSON API
// return 'S';
if (ucType.equals("LKB")) // Connections only?
return 'T';
// if (ucType.equals("WLB")) // via JSON API
// return 'T';
if (ucType.equals("OBU")) // Connections only?
return 'B';
if (ucType.equals("ICB")) // ÖBB ICBus
return 'B';
if (ucType.equals("BSV")) // Deutschland, Connections only?
return 'B';
if (ucType.equals("O-BUS")) // Stadtbus
return 'B';
if (ucType.equals("SCH")) // Connections only?
return 'F';
if (ucType.equals("F")) // Fähre
return 'F';
if (ucType.equals("LIF"))
return 'C';
if (ucType.equals("SSB")) // Graz Schlossbergbahn
return 'C';
// if (ucType.equals("HBB")) // Innsbruck Hungerburgbahn, via JSON API
// return 'C';
final char t = super.normalizeType(type);
if (t != 0)
return t;
if (ucType.equals("U70")) // U.K., Connections only?
return '?';
if (ucType.equals("X70")) // U.K., Connections only?
return '?';
if (ucType.equals("R84")) // U.K., Connections only?
return '?';
if (ucType.equals("S84")) // U.K., Connections only?
return '?';
if (ucType.equals("T84")) // U.K., Connections only?
return '?';
return 0;
}
}

View file

@ -0,0 +1,194 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
/**
* @author Andreas Schildbach
*/
public class PlProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.PL;
private static final String API_BASE = "http://rozklad.sitkol.pl/bin/";
public PlProvider()
{
super(API_BASE + "query.exe/pn", 7, null, null, "UTF-8");
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Hochgeschwindigkeitszug
productBits.setCharAt(1, '1'); // EC/IC/EIC/Ex
}
else if (product == 'R')
{
productBits.setCharAt(2, '1'); // TLK/IR/D
productBits.setCharAt(3, '1'); // Regionalverkehrszug
}
else if (product == 'S' || product == 'T')
{
productBits.setCharAt(5, '1'); // Stadtbahn
}
else if (product == 'U')
{
productBits.setCharAt(6, '1'); // U-Bahn
}
else if (product == 'B' || product == 'P')
{
productBits.setCharAt(4, '1'); // Bus
}
else if (product == 'F' || product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final String[] PLACES = { "Warszawa", "Kraków" };
@Override
protected String[] splitPlaceAndName(final String name)
{
for (final String place : PLACES)
{
if (name.endsWith(", " + place))
return new String[] { place, name.substring(0, name.length() - place.length() - 2) };
if (name.startsWith(place + " ") || name.startsWith(place + "-"))
return new String[] { place, name.substring(place.length() + 1) };
}
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
if (location.type == LocationType.STATION && location.hasId())
{
final StringBuilder uri = new StringBuilder(API_BASE);
uri.append("stboard.exe/pn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0");
uri.append("&L=vs_java3");
// &inputTripelId=A%3d1%40O%3dCopenhagen%20Airport%40X%3d12646941%40Y%3d55629753%40U%3d86%40L%3d900000011%40B%3d1
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/pn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlMLcReq(constraint);
}
private static final Pattern P_NORMALIZE_LINE_RUSSIA = Pattern.compile("(?:D\\s*)?(\\d{1,3}(?:[A-Z]{2}|Y))");
private static final Pattern P_NORMALIZE_LINE_NUMBER = Pattern.compile("\\d{2,5}");
@Override
protected Line parseLineWithoutType(String line)
{
// replace badly encoded character (stations 8530643 and 8530644)
if (line.equals("F\u0084hre"))
line = "Fähre";
final Matcher mRussia = P_NORMALIZE_LINE_RUSSIA.matcher(line);
if (mRussia.matches())
return newLine('R' + mRussia.group(1));
if (P_NORMALIZE_LINE_NUMBER.matcher(line).matches())
return newLine('R' + line);
return super.parseLineWithoutType(line);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("REG".equals(ucType))
return 'R';
if ("AR".equals(ucType)) // Arriva Polaczen
return 'R';
if ("N".equals(ucType)) // St. Pierre des Corps - Tours
return 'R';
if ("METRO".equals(ucType))
return 'U';
final char t = super.normalizeType(type);
if (t != 0)
return t;
if ("E".equals(ucType))
return '?';
return 0;
}
}

View file

@ -0,0 +1,351 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Departure;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.dto.ResultHeader;
import de.schildbach.pte.dto.StationDepartures;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class RmvProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.RMV;
public static final String OLD_NETWORK_ID = "mobil.rmv.de";
private static final String API_BASE = "http://www.rmv.de/auskunft/bin/jp/";
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public RmvProvider()
{
super(API_BASE + "query.exe/dn", 16, null, "UTF-8", null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // ICE
productBits.setCharAt(1, '1'); // Zug, scheinbar IC?
}
else if (product == 'R')
{
productBits.setCharAt(2, '1'); // Zug
productBits.setCharAt(10, '1'); // Zug
}
else if (product == 'S')
{
productBits.setCharAt(3, '1'); // S-Bahn
}
else if (product == 'U')
{
productBits.setCharAt(4, '1'); // U-Bahn
}
else if (product == 'T')
{
productBits.setCharAt(5, '1'); // Straßenbahn
}
else if (product == 'B')
{
productBits.setCharAt(6, '1'); // Niederflurbus
productBits.setCharAt(7, '1'); // Bus
}
else if (product == 'P')
{
productBits.setCharAt(9, '1'); // AST/Rufbus
}
else if (product == 'F')
{
productBits.setCharAt(8, '1'); // Fähre/Schiff
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final String[] PLACES = { "Frankfurt (Main)", "Offenbach (Main)", "Mainz", "Wiesbaden", "Marburg", "Kassel", "Hanau", "Göttingen",
"Darmstadt", "Aschaffenburg", "Berlin", "Fulda" };
@Override
protected String[] splitPlaceAndName(final String name)
{
for (final String place : PLACES)
if (name.startsWith(place + " ") || name.startsWith(place + "-"))
return new String[] { place, name.substring(place.length() + 1) };
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_nv=get_stopweight|yes");
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn?L=vs_rmv&near=Anzeigen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
private String departuresQueryUri(final int stationId, final int maxDepartures)
{
final Calendar c = new GregorianCalendar(timeZone());
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dox");
uri.append("?input=").append(stationId);
uri.append("&boardType=dep"); // show departures
uri.append("&maxJourneys=").append(maxDepartures != 0 ? maxDepartures : 50); // maximum taken from RMV site
uri.append("&date=").append(
String.format("%02d.%02d.%02d", c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.MONTH) + 1, c.get(Calendar.YEAR) - 2000));
uri.append("&time=").append(String.format("%02d:%02d", c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)));
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&start=yes");
return uri.toString();
}
private static final Pattern P_DEPARTURES_HEAD_COARSE = Pattern.compile(".*?" //
+ "(?:" //
+ "<p class=\"qs\">\n(.*?)</p>\n" // head
+ "(.*?)<p class=\"links\">.*?" // departures
+ "input=(\\d+).*?" // locationId
+ "|(Eingabe kann nicht interpretiert|Eingabe ist nicht eindeutig)" // messages
+ "|(Internal Error)" // messages
+ ").*?", Pattern.DOTALL);
private static final Pattern P_DEPARTURES_HEAD_FINE = Pattern.compile("" //
+ "<b>(.*?)</b><br />.*?" //
+ "Abfahrt (\\d+:\\d+).*?" //
+ "Uhr, (\\d+\\.\\d+\\.\\d+).*?" //
, Pattern.DOTALL);
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<p class=\"sq\">\n(.+?)</p>", Pattern.DOTALL);
private static final Pattern P_DEPARTURES_FINE = Pattern.compile("" //
+ "<b>([^<]*)</b>\n" // line
+ "&gt;&gt;\n" //
+ "([^\n]*)\n" // destination
+ "<br />\n" //
+ "<b>(\\d{1,2}:\\d{2})</b>\n" // plannedTime
+ "(?:keine Prognose verf&#252;gbar\n)?" //
+ "(?:<span class=\"red\">ca\\. (\\d{1,2}:\\d{2})</span>\n)?" // predictedTime
+ "(?:<span class=\"red\">heute (Gl\\. " + ParserUtils.P_PLATFORM + ")</span><br />\n)?" // predictedPosition
+ "(?:(Gl\\. " + ParserUtils.P_PLATFORM + ")<br />\n)?" // position
+ "(?:<span class=\"red\">([^>]*)</span>\n)?" // message
+ "(?:<img src=\".+?\" alt=\"\" />\n<b>[^<]*</b>\n<br />\n)*" // (messages)
+ ".*?", Pattern.DOTALL);
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final ResultHeader header = new ResultHeader(SERVER_PRODUCT);
final QueryDeparturesResult result = new QueryDeparturesResult(header);
// scrape page
final String uri = departuresQueryUri(stationId, maxDepartures);
final CharSequence page = ParserUtils.scrape(uri);
// parse page
final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page);
if (mHeadCoarse.matches())
{
// messages
if (mHeadCoarse.group(4) != null)
return new QueryDeparturesResult(header, Status.INVALID_STATION);
else if (mHeadCoarse.group(5) != null)
return new QueryDeparturesResult(header, Status.SERVICE_DOWN);
final int locationId = Integer.parseInt(mHeadCoarse.group(3));
final Matcher mHeadFine = P_DEPARTURES_HEAD_FINE.matcher(mHeadCoarse.group(1));
if (mHeadFine.matches())
{
final String location = ParserUtils.resolveEntities(mHeadFine.group(1));
final Calendar currentTime = new GregorianCalendar(timeZone());
currentTime.clear();
ParserUtils.parseEuropeanTime(currentTime, mHeadFine.group(2));
ParserUtils.parseGermanDate(currentTime, mHeadFine.group(3));
final List<Departure> departures = new ArrayList<Departure>(8);
final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mHeadCoarse.group(2));
while (mDepCoarse.find())
{
final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(1));
if (mDepFine.matches())
{
final Line line = parseLineWithoutType(ParserUtils.resolveEntities(mDepFine.group(1)));
final String destinationName = ParserUtils.resolveEntities(mDepFine.group(2));
final Location destination = new Location(LocationType.ANY, 0, null, destinationName);
final Calendar plannedTime = new GregorianCalendar(timeZone());
plannedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseEuropeanTime(plannedTime, mDepFine.group(3));
if (plannedTime.getTimeInMillis() - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
plannedTime.add(Calendar.DAY_OF_MONTH, 1);
final Calendar predictedTime;
if (mDepFine.group(4) != null)
{
predictedTime = new GregorianCalendar(timeZone());
predictedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseEuropeanTime(predictedTime, mDepFine.group(4));
if (predictedTime.getTimeInMillis() - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
predictedTime.add(Calendar.DAY_OF_MONTH, 1);
}
else
{
predictedTime = null;
}
final String position = ParserUtils.resolveEntities(ParserUtils.selectNotNull(mDepFine.group(5), mDepFine.group(6)));
final Departure dep = new Departure(plannedTime.getTime(), predictedTime != null ? predictedTime.getTime() : null, line,
position, destination, null, null);
if (!departures.contains(dep))
departures.add(dep);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(1) + "' on " + stationId);
}
}
final String[] placeAndName = splitPlaceAndName(location);
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, locationId, placeAndName[0], placeAndName[1]),
departures, null));
return result;
}
else
{
throw new IllegalArgumentException("cannot parse '" + mHeadCoarse.group(1) + "' on " + stationId);
}
}
else
{
throw new IllegalArgumentException("cannot parse '" + page + "' on " + stationId);
}
}
private static final String AUTOCOMPLETE_URI = API_BASE + "ajax-getstop.exe/dn?getstop=1&REQ0JourneyStopsS0A=255&S=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected Line parseLineWithoutType(final String line)
{
if ("11".equals(line))
return newLine("T11");
if ("12".equals(line))
return newLine("T12");
return super.parseLineWithoutType(line);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("U-BAHN".equals(ucType))
return 'U';
if ("B".equals(ucType))
return 'B';
if ("BUFB".equals(ucType)) // BuFB
return 'B';
if ("BUVB".equals(ucType)) // BuVB
return 'B';
if ("LTAXI".equals(ucType))
return 'B';
if ("BN".equals(ucType)) // BN Venus
return 'B';
if ("ASOF".equals(ucType))
return 'B';
if ("AT".equals(ucType)) // Anschluß Sammel Taxi, Anmeldung nicht erforderlich
return 'B';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,183 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class RtProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.RT;
private static final String API_BASE = "http://railteam.hafas.de/bin/";
public RtProvider()
{
super(API_BASE + "query.exe/dn", 10, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Hochgeschwindigkeitszug
productBits.setCharAt(1, '1'); // IC/EC
productBits.setCharAt(2, '1'); // Fernverkehrszug
}
else if (product == 'R')
{
productBits.setCharAt(3, '1'); // Regionalverkehrszug
}
else if (product == 'S')
{
productBits.setCharAt(4, '1'); // S-Bahn
}
else if (product == 'U')
{
productBits.setCharAt(7, '1'); // U-Bahn
}
else if (product == 'T')
{
productBits.setCharAt(8, '1'); // Stadtbahn
}
else if (product == 'B')
{
productBits.setCharAt(5, '1'); // Bus
}
else if (product == 'P')
{
productBits.setCharAt(9, '1'); // Anruf-Sammel-Taxi
}
else if (product == 'F')
{
productBits.setCharAt(6, '1'); // Schiff
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0");
uri.append("&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE + "ajax-getstop.exe/dn?getstop=1&REQ0JourneyStopsS0A=255&S=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("E".equals(ucType)) // Romania, Croatia
return 'R';
if ("N".equals(ucType)) // Frankreich, Tours
return 'R';
final char t = super.normalizeType(type);
if (t != 0)
return t;
if (ucType.equals("U70"))
return '?';
if (ucType.equals("X70"))
return '?';
if (ucType.equals("T84"))
return '?';
return 0;
}
}

View file

@ -0,0 +1,183 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class SbbProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.SBB;
public static final String OLD_NETWORK_ID = "fahrplan.sbb.ch";
private static final String API_BASE = "http://fahrplan.sbb.ch/bin/";
private static final String API_URI = "http://fahrplan.sbb.ch/bin/extxml.exe"; // xmlfahrplan.sbb.ch
public SbbProvider(final String accessId)
{
super(API_URI, 10, accessId);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // ICE/TGV/IRJ
productBits.setCharAt(1, '1'); // EC/IC
}
else if (product == 'R')
{
productBits.setCharAt(2, '1'); // IR
productBits.setCharAt(3, '1'); // RE/D
productBits.setCharAt(8, '1'); // ARZ/EXT
}
else if (product == 'S')
{
productBits.setCharAt(5, '1'); // S/SN/R
}
else if (product == 'U' || product == 'T')
{
productBits.setCharAt(9, '1'); // Tram/Metro
}
else if (product == 'B' || product == 'P')
{
productBits.setCharAt(6, '1'); // Bus
}
else if (product == 'F')
{
productBits.setCharAt(4, '1'); // Schiff
}
else if (product == 'C')
{
productBits.setCharAt(7, '1'); // Seilbahn
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0");
uri.append("&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE + "ajax-getstop.exe/dn?getstop=1&REQ0JourneyStopsS0A=255&S=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("IN".equals(ucType)) // Italien Roma-Lecce
return 'I';
if ("E".equals(ucType))
return 'R';
if ("T".equals(ucType))
return 'R';
if ("M".equals(ucType)) // Metro Wien
return 'U';
if ("TX".equals(ucType))
return 'B';
if ("NFO".equals(ucType))
return 'B';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,219 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class SeProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.SE;
private static final String API_BASE = "http://reseplanerare.resrobot.se/bin/"; // http://api.vasttrafik.se/bin/query.exe/sn
public SeProvider()
{
super(API_BASE + "query.exe/sn", 14, null, "UTF-8", null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES)
return true;
return false;
}
@Override
protected char intToProduct(final int value)
{
if (value == 1) // Flyg
return 'I';
if (value == 2) // X2000
return 'I';
if (value == 4)
return 'R';
if (value == 8) // Expressbus
return 'B';
if (value == 16)
return 'R';
if (value == 32) // Tunnelbana
return 'U';
if (value == 64) // Spårvagn
return 'T';
if (value == 128)
return 'B';
if (value == 256)
return 'F';
if (value == 512) // Länstaxi
return 'F';
if (value == 1024) // Future
return 'R';
throw new IllegalArgumentException("cannot handle: " + value);
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Flyg
productBits.setCharAt(1, '1'); // Snabbtåg
}
else if (product == 'R')
{
productBits.setCharAt(2, '1'); // Tåg
productBits.setCharAt(4, '1'); // Lokaltåg
}
else if (product == 'S')
{
}
else if (product == 'U')
{
productBits.setCharAt(5, '1'); // Tunnelbana
}
else if (product == 'T')
{
productBits.setCharAt(6, '1'); // Spårvagn
}
else if (product == 'B')
{
productBits.setCharAt(3, '1'); // Expressbuss
productBits.setCharAt(7, '1'); // Buss
}
else if (product == 'P')
{
}
else if (product == 'F')
{
productBits.setCharAt(8, '1'); // Båt
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final Pattern P_SPLIT_NAME_KN = Pattern.compile("(.*?) \\((.*?) kn\\)");
@Override
protected String[] splitPlaceAndName(final String name)
{
final Matcher m = P_SPLIT_NAME_KN.matcher(name);
if (m.matches())
return new String[] { m.group(2), m.group(1) };
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/sny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 150);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/sn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/sn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE
+ "ajax-getstop.exe/sny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=7&getstop=1&noSession=yes&REQ0JourneyStopsB=12&REQ0JourneyStopsS0G=&S=%s";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
private static final Pattern P_NORMALIZE_LINE_BUS = Pattern.compile("Buss\\s*(.*)");
private static final Pattern P_NORMALIZE_LINE_SUBWAY = Pattern.compile("Tunnelbana\\s*(.*)");
@Override
protected Line parseLineAndType(final String line)
{
final Matcher mBus = P_NORMALIZE_LINE_BUS.matcher(line);
if (mBus.matches())
return newLine('B' + mBus.group(1));
final Matcher mSubway = P_NORMALIZE_LINE_SUBWAY.matcher(line);
if (mSubway.matches())
return newLine("UT" + mSubway.group(1));
return newLine('?' + line);
}
}

View file

@ -0,0 +1,345 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Departure;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.dto.ResultHeader;
import de.schildbach.pte.dto.StationDepartures;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class SeptaProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.SEPTA;
private static final String API_BASE = "http://airs1.septa.org/bin/";
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public SeptaProvider()
{
super(API_BASE + "query.exe/en", 4, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("EST");
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
}
else if (product == 'R' || product == 'S')
{
productBits.setCharAt(3, '1'); // Regional Rail
}
else if (product == 'U')
{
productBits.setCharAt(0, '1'); // Subway
}
else if (product == 'T')
{
productBits.setCharAt(1, '1'); // Trolley
}
else if (product == 'B')
{
productBits.setCharAt(2, '1'); // Bus
}
else if (product == 'P' || product == 'F' || product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final Pattern P_SPLIT_ADDRESS = Pattern.compile("(.*),\\s+([^,]+\\s+\\d{4,5})");
@Override
protected String[] splitPlaceAndName(final String name)
{
final Matcher matcher = P_SPLIT_ADDRESS.matcher(name);
if (matcher.matches())
return new String[] { matcher.group(2), matcher.group(1) };
else
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/en?near=Anzeigen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
private String departuresQueryUri(final int stationId, final int maxDepartures)
{
final Calendar now = new GregorianCalendar(timeZone());
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/en");
uri.append("?input=").append(stationId);
uri.append("&boardType=dep");
uri.append("&time=").append(
ParserUtils.urlEncode(String.format("%02d:%02d %s", now.get(Calendar.HOUR), now.get(Calendar.MINUTE),
now.get(Calendar.AM_PM) == Calendar.AM ? "am" : "pm")));
uri.append("&date=").append(
String.format("%02d%02d%04d", now.get(Calendar.MONTH) + 1, now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.YEAR)));
uri.append("&productsFilter=").append(allProductsString());
if (maxDepartures != 0)
uri.append("&maxJourneys=").append(maxDepartures);
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&start=yes");
return uri.toString();
}
private static final Pattern P_DEPARTURES_PAGE_COARSE = Pattern
.compile(
".*?" //
+ "(?:" //
+ "<div class=\"hfsTitleText\">([^<]*)<.*?" // location
+ "\n(\\d{2}/\\d{2}/\\d{4})[^\n]*\n" // date
+ "Departure (\\d{1,2}:\\d{2} [AP]M)\n.*?" // time
+ "(?:<table class=\"resultTable\"[^>]*>(.+?)</table>|(No trains in this space of time))" //
+ "|(input cannot be interpreted)|(Verbindung zum Server konnte leider nicht hergestellt werden|kann vom Server derzeit leider nicht bearbeitet werden))" //
+ ".*?" //
, Pattern.DOTALL);
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<tr class=\"(depboard-\\w*)\">(.*?)</tr>", Pattern.DOTALL);
private static final Pattern P_DEPARTURES_FINE = Pattern.compile(".*?" //
+ "<td class=\"time\">(\\d{1,2}:\\d{2} [AP]M)</td>\n" // plannedTime
+ "(?:<td class=\"[\\w ]*prognosis[\\w ]*\">\n" //
+ "(?:&nbsp;|<span class=\"rtLimit\\d\">(p&#252;nktlich|\\d{1,2}:\\d{2})</span>)\n</td>\n" // predictedTime
+ ")?.*?" //
+ "<img class=\"product\" src=\"/hafas-res/img/products/(\\w+)_pic\\.gif\" width=\"\\d+\" height=\"\\d+\" alt=\"([^\"]*)\".*?" // type,
// line
+ "<strong>\n" //
+ "<a href=\"http://airs1\\.septa\\.org/bin/stboard\\.exe/en\\?input=(\\d+)&[^>]*>" // destinationId
+ "\\s*(.*?)\\s*</a>\n" // destination
+ "</strong>.*?" //
+ "(?:<td class=\"center sepline top\">\n(" + ParserUtils.P_PLATFORM + ").*?)?" // position
, Pattern.DOTALL);
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final ResultHeader header = new ResultHeader(SERVER_PRODUCT);
final QueryDeparturesResult result = new QueryDeparturesResult(header);
// scrape page
final String uri = departuresQueryUri(stationId, maxDepartures);
final CharSequence page = ParserUtils.scrape(uri);
// parse page
final Matcher mPageCoarse = P_DEPARTURES_PAGE_COARSE.matcher(page);
if (mPageCoarse.matches())
{
// messages
if (mPageCoarse.group(5) != null)
{
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId),
Collections.<Departure> emptyList(), null));
return result;
}
else if (mPageCoarse.group(6) != null)
return new QueryDeparturesResult(header, Status.INVALID_STATION);
else if (mPageCoarse.group(7) != null)
return new QueryDeparturesResult(header, Status.SERVICE_DOWN);
final String location = ParserUtils.resolveEntities(mPageCoarse.group(1));
final Calendar currentTime = new GregorianCalendar(timeZone());
currentTime.clear();
ParserUtils.parseAmericanDate(currentTime, mPageCoarse.group(2));
ParserUtils.parseAmericanTime(currentTime, mPageCoarse.group(3));
final List<Departure> departures = new ArrayList<Departure>(8);
String oldZebra = null;
final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mPageCoarse.group(4));
while (mDepCoarse.find())
{
final String zebra = mDepCoarse.group(1);
if (oldZebra != null && zebra.equals(oldZebra))
throw new IllegalArgumentException("missed row? last:" + zebra);
else
oldZebra = zebra;
final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(2));
if (mDepFine.matches())
{
final Calendar plannedTime = new GregorianCalendar(timeZone());
plannedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseAmericanTime(plannedTime, mDepFine.group(1));
if (plannedTime.getTimeInMillis() - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
plannedTime.add(Calendar.DAY_OF_MONTH, 1);
final Calendar predictedTime;
final String prognosis = ParserUtils.resolveEntities(mDepFine.group(2));
if (prognosis != null)
{
predictedTime = new GregorianCalendar(timeZone());
if (prognosis.equals("pünktlich"))
{
predictedTime.setTimeInMillis(plannedTime.getTimeInMillis());
}
else
{
predictedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseAmericanTime(predictedTime, prognosis);
}
}
else
{
predictedTime = null;
}
final String lineType = mDepFine.group(3);
final Line line = parseLine(lineType, ParserUtils.resolveEntities(mDepFine.group(4)), false);
final int destinationId = mDepFine.group(5) != null ? Integer.parseInt(mDepFine.group(5)) : 0;
final String destinationName = ParserUtils.resolveEntities(mDepFine.group(6));
final Location destination = new Location(destinationId > 0 ? LocationType.STATION : LocationType.ANY, destinationId, null,
destinationName);
final String position = mDepFine.group(7) != null ? "Gl. " + ParserUtils.resolveEntities(mDepFine.group(7)) : null;
final Departure dep = new Departure(plannedTime.getTime(), predictedTime != null ? predictedTime.getTime() : null, line,
position, destination, null, null);
if (!departures.contains(dep))
departures.add(dep);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(2) + "' on " + stationId);
}
}
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId, null, location), departures, null));
return result;
}
else
{
throw new IllegalArgumentException("cannot parse '" + page + "' on " + stationId);
}
}
private static final String AUTOCOMPLETE_URI = API_BASE
+ "ajax-getstop.exe/dny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=255&REQ0JourneyStopsB=12&S=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
// skip parsing of "common" lines, because this is America
// Regional
if (ucType.equals("RAI"))
return 'R';
// Subway
if (ucType.equals("BSS"))
return 'U';
if (ucType.equals("BSL"))
return 'U';
if (ucType.equals("MFL"))
return 'U';
// Tram
if (ucType.equals("TRM"))
return 'T';
if (ucType.equals("NHS")) // Tro NHSL
return 'T';
// Bus
if (ucType.equals("BUS"))
return 'B';
if (ucType.equals("TRO"))
return 'B';
// from Connections:
if (ucType.equals("RAIL"))
return 'R';
if (ucType.equals("SUBWAY"))
return 'U';
if (ucType.equals("TROLLEY"))
return 'B';
return 0;
}
}

View file

@ -0,0 +1,113 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import de.schildbach.pte.dto.Style;
/**
* @author Andreas Schildbach
*/
public class SfProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.SF;
private final static String API_BASE = "http://tripplanner.transit.511.org/mtc/";
public SfProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("America/Los_Angeles");
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected String normalizeLocationName(final String name)
{
if (name == null || name.length() == 0)
return null;
return super.normalizeLocationName(name).replace("$XINT$", "&");
}
@Override
protected String parseLine(final String mot, final String name, final String longName, final String noTrainName)
{
if ("NORTHBOUND".equals(name))
return "?" + name;
else if ("SOUTHBOUND".equals(name))
return "?" + name;
else if ("EASTBOUND".equals(name))
return "?" + name;
else if ("WESTBOUND".equals(name))
return "?" + name;
else
return super.parseLine(mot, name, longName, noTrainName);
}
private static final Map<String, Style> LINES = new HashMap<String, Style>();
static
{
// BART
LINES.put("RDaly City / Dublin Pleasanton", new Style(Style.parseColor("#00AEEF"), Style.WHITE));
LINES.put("RDulin Pleasanton / Daly City", new Style(Style.parseColor("#00AEEF"), Style.WHITE));
LINES.put("RSFO / Pittsburg Bay Point", new Style(Style.parseColor("#FFE800"), Style.BLACK));
LINES.put("RPittsburg Bay Point / SFO", new Style(Style.parseColor("#FFE800"), Style.BLACK));
LINES.put("RDaly City / Fremont", new Style(Style.parseColor("#4EBF49"), Style.WHITE));
LINES.put("RFremont / Daly City", new Style(Style.parseColor("#4EBF49"), Style.WHITE));
LINES.put("RFremont / Richmond", new Style(Style.parseColor("#FAA61A"), Style.WHITE));
LINES.put("RRichmond / Fremont", new Style(Style.parseColor("#FAA61A"), Style.WHITE));
LINES.put("RMillbrae / Richmond", new Style(Style.parseColor("#F81A23"), Style.WHITE));
LINES.put("RRichmond / Millbrae", new Style(Style.parseColor("#F81A23"), Style.WHITE));
}
@Override
public Style lineStyle(final String line)
{
final Style style = LINES.get(line);
if (style != null)
return style;
else
return super.lineStyle(line);
}
}

View file

@ -0,0 +1,278 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Departure;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.dto.ResultHeader;
import de.schildbach.pte.dto.StationDepartures;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class ShProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.SH;
private static final String API_BASE = "http://scout.hafas.de/bin/";
// http://nah.sh.hafas.de/bin/
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public ShProvider()
{
super(API_BASE + "query.exe/dn", 10, null, null, "UTF-8");
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Hochgeschwindigkeitszug
productBits.setCharAt(1, '1'); // IC/EC
productBits.setCharAt(2, '1'); // Fernverkehrszug
}
else if (product == 'R')
{
productBits.setCharAt(3, '1'); // Regionalverkehrszug
}
else if (product == 'S')
{
productBits.setCharAt(4, '1'); // S-Bahn
}
else if (product == 'U')
{
productBits.setCharAt(7, '1'); // U-Bahn
}
else if (product == 'T')
{
productBits.setCharAt(8, '1'); // Stadtbahn
}
else if (product == 'B')
{
productBits.setCharAt(5, '1'); // Bus
}
else if (product == 'P')
{
productBits.setCharAt(9, '1'); // Anruf-Sammel-Taxi
}
else if (product == 'F')
{
productBits.setCharAt(6, '1'); // Schiff
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn?near=Anzeigen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
private String departuresQueryUri(final int stationId, final int maxDepartures)
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?input=").append(stationId);
uri.append("&boardType=dep");
uri.append("&productsFilter=").append(allProductsString());
if (maxDepartures != 0)
uri.append("&maxJourneys=").append(maxDepartures);
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&start=yes");
return uri.toString();
}
private static final Pattern P_DEPARTURES_HEAD_COARSE = Pattern.compile(".*?" //
+ "(?:" //
+ "Bhf\\./Haltest\\.:</span>\\n<span class=\"output\">([^<]*)<.*?" // location
+ "Fahrplan:</span>\\n<span class=\"output\">\n" //
+ "(\\d{2}\\.\\d{2}\\.\\d{2})[^\n]*,\n" // date
+ "Abfahrt (\\d{1,2}:\\d{2}).*?" // time
+ "<table class=\"resultTable\"[^>]*>(.+?)</table>" // content
+ "|(verkehren an dieser Haltestelle keine)" //
+ "|(Eingabe kann nicht interpretiert)" //
+ "|(Verbindung zum Server konnte leider nicht hergestellt werden|kann vom Server derzeit leider nicht bearbeitet werden))" //
+ ".*?" //
, Pattern.DOTALL);
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<tr class=\"(depboard-\\w*)\">(.*?)</tr>", Pattern.DOTALL);
private static final Pattern P_DEPARTURES_FINE = Pattern.compile("\n" //
+ "<td class=\"time\">(\\d{1,2}:\\d{2}).*?" // plannedTime
+ "<img class=\"product\" src=\"/hafas-res/[^\"]*?(\\w+)_pic\\.png\"[^>]*>\\s*([^<]*)<.*?" // type,line
+ "<a href=\"http://nah\\.sh\\.hafas\\.de/bin/stboard\\.exe/dn\\?input=(\\d+)&[^>]*>\n" // destinationId
+ "([^\n]*)\n.*?" // destination
+ "(?:<td class=\"center sepline top\">\n(" + ParserUtils.P_PLATFORM + ").*?)?" // position
, Pattern.DOTALL);
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final ResultHeader header = new ResultHeader(SERVER_PRODUCT);
final QueryDeparturesResult result = new QueryDeparturesResult(header);
// scrape page
final String uri = departuresQueryUri(stationId, maxDepartures);
final CharSequence page = ParserUtils.scrape(uri);
// parse page
final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page);
if (mHeadCoarse.matches())
{
// messages
if (mHeadCoarse.group(5) != null)
{
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId),
Collections.<Departure> emptyList(), null));
return result;
}
else if (mHeadCoarse.group(6) != null)
return new QueryDeparturesResult(header, Status.INVALID_STATION);
else if (mHeadCoarse.group(7) != null)
return new QueryDeparturesResult(header, Status.SERVICE_DOWN);
final String location = ParserUtils.resolveEntities(mHeadCoarse.group(1));
final Calendar currentTime = new GregorianCalendar(timeZone());
currentTime.clear();
ParserUtils.parseGermanDate(currentTime, mHeadCoarse.group(2));
ParserUtils.parseEuropeanTime(currentTime, mHeadCoarse.group(3));
final List<Departure> departures = new ArrayList<Departure>(8);
String oldZebra = null;
final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mHeadCoarse.group(4));
while (mDepCoarse.find())
{
final String zebra = mDepCoarse.group(1);
if (oldZebra != null && zebra.equals(oldZebra))
throw new IllegalArgumentException("missed row? last:" + zebra);
else
oldZebra = zebra;
final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(2));
if (mDepFine.matches())
{
final Calendar plannedTime = new GregorianCalendar(timeZone());
plannedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseEuropeanTime(plannedTime, mDepFine.group(1));
if (plannedTime.getTimeInMillis() - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
plannedTime.add(Calendar.DAY_OF_MONTH, 1);
final String lineType = mDepFine.group(2);
final Line line = parseLine(lineType, ParserUtils.resolveEntities(mDepFine.group(3).trim()), false);
final int destinationId = mDepFine.group(4) != null ? Integer.parseInt(mDepFine.group(4)) : 0;
final String destinationName = ParserUtils.resolveEntities(mDepFine.group(5));
final Location destination = new Location(destinationId > 0 ? LocationType.STATION : LocationType.ANY, destinationId, null,
destinationName);
final String position = mDepFine.group(6) != null ? "Gl. " + ParserUtils.resolveEntities(mDepFine.group(6)) : null;
final Departure dep = new Departure(plannedTime.getTime(), null, line, position, destination, null, null);
if (!departures.contains(dep))
departures.add(dep);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(2) + "' on " + stationId);
}
}
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId, null, location), departures, null));
return result;
}
else
{
throw new IllegalArgumentException("cannot parse '" + page + "' on " + stationId);
}
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlMLcReq(constraint);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("KBS".equals(ucType))
return 'B';
if ("KB1".equals(ucType))
return 'B';
if ("KLB".equals(ucType))
return 'B';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,183 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class SncbProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.SNCB;
public static final String OLD_NETWORK_ID = "hari.b-rail.be";
private static final String API_BASE = "http://hari.b-rail.be/Hafas/bin/";
private static final String API_URI = "http://hari.b-rail.be/Hafas/bin/extxml.exe";
public SncbProvider()
{
super(API_URI, 16, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Hochgeschwindigkeitszug
productBits.setCharAt(2, '1'); // IC/IR/P/ICT
}
else if (product == 'R' || product == 'S')
{
productBits.setCharAt(6, '1'); // Zug
}
else if (product == 'U')
{
productBits.setCharAt(8, '1'); // Metro
}
else if (product == 'T')
{
productBits.setCharAt(10, '1'); // Stadtbahn
}
else if (product == 'B' || product == 'P')
{
productBits.setCharAt(9, '1'); // Bus
}
else if (product == 'F' || product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final String[] PLACES = { "Antwerpen", "Gent", "Charleroi", "Liege", "Liège", "Brussel" };
@Override
protected String[] splitPlaceAndName(final String name)
{
for (final String place : PLACES)
if (name.startsWith(place + " ") || name.startsWith(place + "-"))
return new String[] { place, name.substring(place.length() + 1) };
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/nn?near=Zoek");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/nn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE
+ "ajax-getstop.exe/nny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=255&REQ0JourneyStopsB=12&S=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if (ucType.startsWith("IC "))
return 'I';
if ("THALYS".equals(ucType)) // Thalys
return 'I';
if (ucType.startsWith("IR "))
return 'R';
if ("L".equals(ucType))
return 'R';
if ("CR".equals(ucType))
return 'R';
if ("ICT".equals(ucType)) // Brügge
return 'R';
if ("TRN".equals(ucType)) // Mons
return 'R';
if ("MÉT".equals(ucType))
return 'U';
if ("MÉTRO".equals(ucType))
return 'U';
if ("TRAMWAY".equals(ucType))
return 'T';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.HashMap;
import java.util.Map;
import de.schildbach.pte.dto.Style;
import de.schildbach.pte.dto.Style.Shape;
/**
* @author Andreas Schildbach
*/
public class StandardColors
{
public static final Map<Character, Style> LINES = new HashMap<Character, Style>();
static
{
LINES.put('I', new Style(Shape.RECT, Style.WHITE, Style.RED, Style.RED));
LINES.put('R', new Style(Shape.RECT, Style.GRAY, Style.WHITE));
LINES.put('S', new Style(Shape.CIRCLE, Style.parseColor("#006e34"), Style.WHITE));
LINES.put('U', new Style(Shape.RECT, Style.parseColor("#003090"), Style.WHITE));
LINES.put('T', new Style(Shape.RECT, Style.parseColor("#cc0000"), Style.WHITE));
LINES.put('B', new Style(Style.parseColor("#993399"), Style.WHITE));
LINES.put('F', new Style(Shape.CIRCLE, Style.BLUE, Style.WHITE));
LINES.put('?', new Style(Style.DKGRAY, Style.WHITE));
}
}

View file

@ -0,0 +1,207 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class StockholmProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.STOCKHOLM;
private static final String API_BASE = "http://reseplanerare.trafiken.nu/bin/";
public StockholmProvider()
{
super(API_BASE + "query.exe/sn", 7, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
}
else if (product == 'R')
{
productBits.setCharAt(2, '1'); // Lokalbanor
}
else if (product == 'S')
{
productBits.setCharAt(0, '1'); // Pendeltåg
}
else if (product == 'U')
{
productBits.setCharAt(1, '1'); // Tunnelbana
}
else if (product == 'T')
{
}
else if (product == 'B')
{
productBits.setCharAt(3, '1'); // Bussar
productBits.setCharAt(4, '1'); // Flygbussar
}
else if (product == 'P')
{
}
else if (product == 'F')
{
productBits.setCharAt(6, '1'); // Waxholmsbåtar
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final Pattern P_SPLIT_NAME_PAREN = Pattern.compile("(.*?) \\((.{4,}?)\\)");
@Override
protected String[] splitPlaceAndName(final String name)
{
final Matcher mParen = P_SPLIT_NAME_PAREN.matcher(name);
if (mParen.matches())
return new String[] { mParen.group(2), mParen.group(1) };
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/sny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/sn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/sn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE
+ "ajax-getstop.exe/sny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=7&getstop=1&noSession=yes&REQ0JourneyStopsB=12&REQ0JourneyStopsS0G=&S=%s";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("TRAIN".equals(ucType))
return 'R';
if ("NÄRTRAFIKEN".equals(ucType))
return 'R';
if ("LOKALTÅG".equals(ucType))
return 'R';
if ("PENDELTÅG".equals(ucType))
return 'S';
if ("METRO".equals(ucType))
return 'U';
if ("TUNNELBANA".equals(ucType))
return 'U';
if ("TRAM".equals(ucType))
return 'T';
if ("BUS".equals(ucType))
return 'B';
if ("BUSS".equals(ucType))
return 'B';
if ("FLYG".equals(ucType))
return 'B';
if ("SHIP".equals(ucType))
return 'F';
if ("BÅT".equals(ucType))
return 'F';
return 0;
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class StvProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.STV;
public static final String OLD_NETWORK_ID = "fahrplan.verbundlinie.at";
private final static String API_BASE = "http://fahrplan.verbundlinie.at/stv/";
public StvProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class SvvProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.SVV;
public static final String OLD_NETWORK_ID = "efa.svv-info.at";
private final static String API_BASE = "http://efa.svv-info.at/svv/";
public SvvProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.TimeZone;
/**
* @author Andreas Schildbach
*/
public class SydneyProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.SYDNEY;
private final static String API_BASE = "http://mobile.131500.com.au/TripPlanner/mobile/";
public SydneyProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("Australia/Sydney");
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,96 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import de.schildbach.pte.dto.Style;
/**
* @author Andreas Schildbach
*/
public class TflProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.TFL;
public static final String OLD_NETWORK_ID = "journeyplanner.tfl.gov.uk";
private static final String API_BASE = "http://journeyplanner.tfl.gov.uk/user/";
public TflProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("Europe/London");
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
private static final Map<String, Style> LINES = new HashMap<String, Style>();
static
{
// London
LINES.put("UBakerloo", new Style(Style.parseColor("#9D5324"), Style.WHITE));
LINES.put("UCentral", new Style(Style.parseColor("#D52B1E"), Style.WHITE));
LINES.put("UCircle", new Style(Style.parseColor("#FECB00"), Style.BLACK));
LINES.put("UDistrict", new Style(Style.parseColor("#007934"), Style.WHITE));
LINES.put("UEast London", new Style(Style.parseColor("#FFA100"), Style.WHITE));
LINES.put("UHammersmith & City", new Style(Style.parseColor("#C5858F"), Style.BLACK));
LINES.put("UJubilee", new Style(Style.parseColor("#818A8F"), Style.WHITE));
LINES.put("UMetropolitan", new Style(Style.parseColor("#850057"), Style.WHITE));
LINES.put("UNorthern", new Style(Style.BLACK, Style.WHITE));
LINES.put("UPicadilly", new Style(Style.parseColor("#0018A8"), Style.WHITE));
LINES.put("UVictoria", new Style(Style.parseColor("#00A1DE"), Style.WHITE));
LINES.put("UWaterloo & City", new Style(Style.parseColor("#76D2B6"), Style.BLACK));
LINES.put("SDLR", new Style(Style.parseColor("#00B2A9"), Style.WHITE));
LINES.put("SLO", new Style(Style.parseColor("#f46f1a"), Style.WHITE));
LINES.put("TTramlink 1", new Style(Style.rgb(193, 215, 46), Style.WHITE));
LINES.put("TTramlink 2", new Style(Style.rgb(193, 215, 46), Style.WHITE));
LINES.put("TTramlink 3", new Style(Style.rgb(124, 194, 66), Style.BLACK));
}
@Override
public Style lineStyle(final String line)
{
final Style style = LINES.get(line);
if (style != null)
return style;
if (line.startsWith("SLO"))
return LINES.get("SLO");
return super.lineStyle(line);
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.TimeZone;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class TleaProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.TLEA;
public static final String OLD_NETWORK_ID = "www.travelineeastanglia.org.uk";
private final static String API_BASE = "http://www.travelineeastanglia.org.uk/ea/";
public TleaProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("Europe/London");
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.ANY, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.TimeZone;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class TlemProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.TLEM;
public static final String OLD_NETWORK_ID = "www.travelineeastmidlands.co.uk";
private final static String API_BASE = "http://www.travelineeastmidlands.co.uk/em/";
public TlemProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("Europe/London");
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.ANY, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.TimeZone;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class TlseProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.TLSE;
public static final String OLD_NETWORK_ID = "www.travelinesoutheast.org.uk";
private final static String API_BASE = "http://www.travelinesoutheast.org.uk/se/";
public TlseProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("Europe/London");
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.ANY, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.TimeZone;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class TlswProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.TLSW;
private final static String API_BASE = "http://www.travelinesw.com/swe/";
public TlswProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
@Override
protected TimeZone timeZone()
{
return TimeZone.getTimeZone("Europe/London");
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.ANY, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class VagfrProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VAGFR;
private final static String API_BASE = "http://efa.vag-freiburg.de/vagfr/";
public VagfrProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,175 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class VbbProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VBB;
private static final String API_BASE = "http://www.vbb-fahrinfo.de/hafas/";
public VbbProvider()
{
super(API_BASE + "query.exe/dn", 7, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.DEPARTURES || capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(5, '1');
}
else if (product == 'R')
{
productBits.setCharAt(6, '1');
}
else if (product == 'S')
{
productBits.setCharAt(0, '1');
}
else if (product == 'U')
{
productBits.setCharAt(1, '1');
}
else if (product == 'T')
{
productBits.setCharAt(2, '1');
}
else if (product == 'B' || product == 'P')
{
productBits.setCharAt(3, '1');
}
else if (product == 'F')
{
productBits.setCharAt(4, '1');
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final Pattern P_SPLIT_NAME_PAREN = Pattern.compile("(.*?) \\((.{4,}?)\\)(?: \\((U|S|S\\+U)\\))?");
private static final Pattern P_SPLIT_NAME_COMMA = Pattern.compile("([^,]*), ([^,]*)");
@Override
protected String[] splitPlaceAndName(final String name)
{
final Matcher mParen = P_SPLIT_NAME_PAREN.matcher(name);
if (mParen.matches())
{
final String su = mParen.group(3);
return new String[] { mParen.group(2), mParen.group(1) + (su != null ? " (" + su + ")" : "") };
}
final Matcher mComma = P_SPLIT_NAME_COMMA.matcher(name);
if (mComma.matches())
return new String[] { mComma.group(1), mComma.group(2) };
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0");
uri.append("&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: '" + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE + "ajax-getstop.exe/dn?getstop=1&REQ0JourneyStopsS0A=255&S=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class VblProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VBL;
private final static String API_BASE = "http://mobil.vbl.ch/vblmobil/";
public VblProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,186 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class VbnProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VBN;
private static final String API_BASE = "http://www.fahrplaner.de/hafas/";
public VbnProvider()
{
super(API_BASE + "query.exe/dn", 10, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Hochgeschwindigkeitszug
productBits.setCharAt(1, '1'); // IC/EC
productBits.setCharAt(2, '1'); // Fernverkehrszug
}
else if (product == 'R')
{
productBits.setCharAt(3, '1'); // Regionalverkehrszug
}
else if (product == 'S')
{
productBits.setCharAt(4, '1'); // S-Bahn
}
else if (product == 'U')
{
productBits.setCharAt(7, '1'); // U-Bahn
}
else if (product == 'T')
{
productBits.setCharAt(8, '1'); // Stadtbahn
}
else if (product == 'B')
{
productBits.setCharAt(5, '1'); // Bus
}
else if (product == 'P')
{
productBits.setCharAt(9, '1'); // Anruf-Sammel-Taxi
}
else if (product == 'F')
{
productBits.setCharAt(6, '1'); // Schiff
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0");
uri.append("&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
private static final String AUTOCOMPLETE_URI = API_BASE
+ "ajax-getstop.exe/dny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=255&REQ0JourneyStopsS0B=5&REQ0JourneyStopsB=12&getstop=1&noSession=yes&REQ0JourneyStopsS0G=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if ("P".equals(ucType)) // Brohltalbahn
return 'R';
if ("TB".equals(ucType))
return 'B';
if ("RFTAST".equals(ucType))
return 'B';
if ("BUSFÄHRE".equals(ucType)) // Blexen - Bremerhaven
return 'F';
if ("SEILB".equals(ucType))
return 'C';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.util.Date;
import de.schildbach.pte.dto.Location;
/**
* @author Andreas Schildbach
*/
public class VgnProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VGN;
private static final String DEPARTURE_MONITOR_ENDPOINT = "XML_DM_REQUEST";
private static final String TRIP_ENDPOINT = "XML_TRIP_REQUEST2";
public VgnProvider(final String apiBase)
{
super(apiBase, DEPARTURE_MONITOR_ENDPOINT, TRIP_ENDPOINT, null, false, false);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected String xsltTripRequest2Uri(final Location from, final Location via, final Location to, final Date date, final boolean dep,
final String products, final WalkSpeed walkSpeed, final Accessibility accessibility)
{
return super.xsltTripRequest2Uri(from, via, to, date, dep, products, walkSpeed, accessibility) + "&itdLPxx_showTariffLevel=1";
}
}

View file

@ -0,0 +1,335 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.schildbach.pte.dto.Departure;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
import de.schildbach.pte.dto.QueryDeparturesResult.Status;
import de.schildbach.pte.dto.ResultHeader;
import de.schildbach.pte.dto.StationDepartures;
import de.schildbach.pte.util.ParserUtils;
/**
* @author Andreas Schildbach
*/
public class VgsProvider extends AbstractHafasProvider
{
public static final String OLD_NETWORK_ID = "www.vgs-online.de";
private static final String API_BASE = "http://www.vgs-online.de/cgi-bin/"; // "http://www.saarfahrplan.de/cgi-bin/";
private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000;
public VgsProvider()
{
super(API_BASE + "query.exe/dn", 11, null);
}
public NetworkId id()
{
return NetworkId.VGS;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // Hochgeschwindigkeitszug
productBits.setCharAt(1, '1'); // IC/EC
productBits.setCharAt(2, '1'); // Fernverkehrszug
}
else if (product == 'R')
{
productBits.setCharAt(3, '1'); // Regionalverkehrszug
}
else if (product == 'S')
{
productBits.setCharAt(4, '1'); // S-Bahn
}
else if (product == 'U')
{
productBits.setCharAt(5, '1'); // U-Bahn
}
else if (product == 'T')
{
productBits.setCharAt(6, '1'); // Stadtbahn
}
else if (product == 'B')
{
productBits.setCharAt(7, '1'); // Bus
productBits.setCharAt(10, '1'); // Schulbus
}
else if (product == 'P')
{
productBits.setCharAt(9, '1'); // Anruf-Sammel-Taxi
}
else if (product == 'F')
{
productBits.setCharAt(8, '1'); // Schiff
}
else if (product == 'C')
{
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 200);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn?near=Anzeigen");
uri.append("&distance=").append(maxDistance != 0 ? maxDistance / 1000 : 50);
uri.append("&input=").append(location.id);
return htmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
private String departuresQueryUri(final int stationId, final int maxDepartures)
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?input=").append(stationId);
uri.append("&boardType=dep");
uri.append("&productsFilter=").append(allProductsString());
if (maxDepartures != 0)
uri.append("&maxJourneys=").append(maxDepartures);
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&start=yes");
return uri.toString();
}
private static final Pattern P_DEPARTURES_HEAD_COARSE = Pattern
.compile(
".*?" //
+ "(?:" //
+ "<table class=\"hafasResult\"[^>]*>(.+?)</table>.*?" //
+ "(?:<table cellspacing=\"0\" class=\"hafasResult\"[^>]*>(.+?)</table>|(verkehren an dieser Haltestelle keine))"//
+ "|(Eingabe kann nicht interpretiert)|(Verbindung zum Server konnte leider nicht hergestellt werden|kann vom Server derzeit leider nicht bearbeitet werden))" //
+ ".*?" //
, Pattern.DOTALL);
private static final Pattern P_DEPARTURES_HEAD_FINE = Pattern.compile(".*?" //
+ "<td class=\"querysummary screennowrap\">\\s*(.*?)\\s*<.*?" // location
+ "(\\d{2}\\.\\d{2}\\.\\d{2}).*?" // date
+ "Abfahrt (\\d{1,2}:\\d{2}).*?" // time
, Pattern.DOTALL);
private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("<tr class=\"(depboard-\\w*)\">(.*?)</tr>", Pattern.DOTALL);
private static final Pattern P_DEPARTURES_FINE = Pattern.compile(".*?" //
+ "<td class=\"[\\w ]*\">(\\d{1,2}:\\d{2})</td>\n" // plannedTime
+ "(?:<td class=\"[\\w ]*prognosis[\\w ]*\">\n" //
+ "(?:&nbsp;|<span class=\"rtLimit\\d\">(p&#252;nktlich|\\d{1,2}:\\d{2})</span>)\n</td>\n" // predictedTime
+ ")?.*?" //
+ "<img src=\"/hafas-res/img/(\\w+)_pic\\.gif\"[^>]*>\\s*(.*?)\\s*<.*?" // type, line
+ "<span class=\"bold\">\n" //
+ "<a href=\"http://www\\.saarfahrplan\\.de/cgi-bin/stboard\\.exe/dn\\?input=(\\d+)&[^>]*>" // destinationId
+ "\\s*(.*?)\\s*</a>\n" // destination
+ "</span>.*?" //
+ "(?:<td class=\"center sepline top\">\n(" + ParserUtils.P_PLATFORM + ").*?)?" // position
, Pattern.DOTALL);
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final ResultHeader header = new ResultHeader(SERVER_PRODUCT);
final QueryDeparturesResult result = new QueryDeparturesResult(header);
// scrape page
final String uri = departuresQueryUri(stationId, maxDepartures);
final CharSequence page = ParserUtils.scrape(uri);
// parse page
final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page);
if (mHeadCoarse.matches())
{
// messages
if (mHeadCoarse.group(3) != null)
{
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId),
Collections.<Departure> emptyList(), null));
return result;
}
else if (mHeadCoarse.group(4) != null)
return new QueryDeparturesResult(header, Status.INVALID_STATION);
else if (mHeadCoarse.group(5) != null)
return new QueryDeparturesResult(header, Status.SERVICE_DOWN);
final Matcher mHeadFine = P_DEPARTURES_HEAD_FINE.matcher(mHeadCoarse.group(1));
if (mHeadFine.matches())
{
final String location = ParserUtils.resolveEntities(mHeadFine.group(1));
final Calendar currentTime = new GregorianCalendar(timeZone());
currentTime.clear();
ParserUtils.parseGermanDate(currentTime, mHeadFine.group(2));
ParserUtils.parseEuropeanTime(currentTime, mHeadFine.group(3));
final List<Departure> departures = new ArrayList<Departure>(8);
String oldZebra = null;
final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mHeadCoarse.group(2));
while (mDepCoarse.find())
{
final String zebra = mDepCoarse.group(1);
if (oldZebra != null && zebra.equals(oldZebra))
throw new IllegalArgumentException("missed row? last:" + zebra);
else
oldZebra = zebra;
final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(2));
if (mDepFine.matches())
{
final Calendar plannedTime = new GregorianCalendar(timeZone());
plannedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseEuropeanTime(plannedTime, mDepFine.group(1));
if (plannedTime.getTimeInMillis() - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
plannedTime.add(Calendar.DAY_OF_MONTH, 1);
final Calendar predictedTime;
final String prognosis = ParserUtils.resolveEntities(mDepFine.group(2));
if (prognosis != null)
{
predictedTime = new GregorianCalendar(timeZone());
if (!prognosis.equals("pünktlich"))
{
predictedTime.setTimeInMillis(plannedTime.getTimeInMillis());
}
else
{
predictedTime.setTimeInMillis(currentTime.getTimeInMillis());
ParserUtils.parseEuropeanTime(predictedTime, prognosis);
}
}
else
{
predictedTime = null;
}
final String lineType = mDepFine.group(3);
final Line line = parseLine(lineType, ParserUtils.resolveEntities(mDepFine.group(4)), false);
final int destinationId = mDepFine.group(5) != null ? Integer.parseInt(mDepFine.group(5)) : 0;
final String destinationName = ParserUtils.resolveEntities(mDepFine.group(6));
final Location destination = new Location(destinationId > 0 ? LocationType.STATION : LocationType.ANY, destinationId, null,
destinationName);
final String position = mDepFine.group(7) != null ? "Gl. " + ParserUtils.resolveEntities(mDepFine.group(7)) : null;
final Departure dep = new Departure(plannedTime.getTime(), predictedTime != null ? predictedTime.getTime() : null, line,
position, destination, null, null);
if (!departures.contains(dep))
departures.add(dep);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(2) + "' on " + stationId);
}
}
result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId, null, location), departures, null));
return result;
}
else
{
throw new IllegalArgumentException("cannot parse '" + mHeadCoarse.group(1) + "' on " + stationId);
}
}
else
{
throw new IllegalArgumentException("cannot parse '" + page + "' on " + stationId);
}
}
private static final String AUTOCOMPLETE_URI = API_BASE
+ "ajax-getstop.exe/eny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=1&getstop=1&noSession=yes&REQ0JourneyStopsB=12&REQ0JourneyStopsS0G=%s?&js=true&";
private static final String ENCODING = "ISO-8859-1";
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
final String uri = String.format(AUTOCOMPLETE_URI, ParserUtils.urlEncode(constraint.toString(), ENCODING));
return jsonGetStops(uri);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if (ucType.equals("E")) // Stadtbahn Karlsruhe: S4/S31/xxxxx
return 'S';
if (ucType.equals("BSS"))
return 'B';
if (ucType.equals("BOV"))
return 'B';
final char t = super.normalizeType(type);
if (t != 0)
return t;
if (ucType.equals("T84")) // U.K.
return '?';
return 0;
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* Verkehrsverbund Vorarlberg
*
* @author Andreas Schildbach
*/
public class VmobilProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VMOBIL;
private final static String API_BASE = "http://efaneu.vmobil.at/vvvmobile/";
public VmobilProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class VmsProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VMS;
public static final String OLD_NETWORK_ID = "www.vms-aktuell.de";
private static final String API_BASE = "http://www.vms-aktuell.de/vms/";
public VmsProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.ANY, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class VmvProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VMV;
public static final String OLD_NETWORK_ID = "80.146.180.107";
private static final String API_BASE = "http://80.146.180.107/delfi/"; // http://80.146.180.107/vmv/
public VmvProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class VorProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VOR;
public static final String OLD_NETWORK_ID = "efa.vor.at";
private final static String API_BASE = "http://efa.vor.at/wvb/";
public VorProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class VrnProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VRN;
public static final String OLD_NETWORK_ID = "fahrplanauskunft.vrn.de";
private static final String API_BASE = "http://fahrplanauskunft.vrn.de/vrn_mobile/";
public VrnProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,132 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.Style;
/**
* @author Andreas Schildbach
*/
public class VrrProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VRR;
public static final String OLD_NETWORK_ID = "efa3.vrr.de";
private static final String API_BASE = "http://app.vrr.de/standard/";
public VrrProvider()
{
super(API_BASE, null, null, null, false, true);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.ANY, 0, null, constraint.toString()));
}
private static final Map<String, Style> LINES = new HashMap<String, Style>();
static
{
// Busse Bonn
LINES.put("B63", new Style(Style.parseColor("#0065ae"), Style.WHITE));
LINES.put("B16", new Style(Style.parseColor("#0065ae"), Style.WHITE));
LINES.put("B66", new Style(Style.parseColor("#0065ae"), Style.WHITE));
LINES.put("B67", new Style(Style.parseColor("#0065ae"), Style.WHITE));
LINES.put("B68", new Style(Style.parseColor("#0065ae"), Style.WHITE));
LINES.put("B18", new Style(Style.parseColor("#0065ae"), Style.WHITE));
LINES.put("B61", new Style(Style.parseColor("#e4000b"), Style.WHITE));
LINES.put("B62", new Style(Style.parseColor("#e4000b"), Style.WHITE));
LINES.put("B65", new Style(Style.parseColor("#e4000b"), Style.WHITE));
LINES.put("BSB55", new Style(Style.parseColor("#00919e"), Style.WHITE));
LINES.put("BSB60", new Style(Style.parseColor("#8f9867"), Style.WHITE));
LINES.put("BSB69", new Style(Style.parseColor("#db5f1f"), Style.WHITE));
LINES.put("B529", new Style(Style.parseColor("#2e2383"), Style.WHITE));
LINES.put("B537", new Style(Style.parseColor("#2e2383"), Style.WHITE));
LINES.put("B541", new Style(Style.parseColor("#2e2383"), Style.WHITE));
LINES.put("B550", new Style(Style.parseColor("#2e2383"), Style.WHITE));
LINES.put("B163", new Style(Style.parseColor("#2e2383"), Style.WHITE));
LINES.put("B551", new Style(Style.parseColor("#2e2383"), Style.WHITE));
LINES.put("B600", new Style(Style.parseColor("#817db7"), Style.WHITE));
LINES.put("B601", new Style(Style.parseColor("#831b82"), Style.WHITE));
LINES.put("B602", new Style(Style.parseColor("#dd6ba6"), Style.WHITE));
LINES.put("B603", new Style(Style.parseColor("#e6007d"), Style.WHITE));
LINES.put("B604", new Style(Style.parseColor("#009f5d"), Style.WHITE));
LINES.put("B605", new Style(Style.parseColor("#007b3b"), Style.WHITE));
LINES.put("B606", new Style(Style.parseColor("#9cbf11"), Style.WHITE));
LINES.put("B607", new Style(Style.parseColor("#60ad2a"), Style.WHITE));
LINES.put("B608", new Style(Style.parseColor("#f8a600"), Style.WHITE));
LINES.put("B609", new Style(Style.parseColor("#ef7100"), Style.WHITE));
LINES.put("B610", new Style(Style.parseColor("#3ec1f1"), Style.WHITE));
LINES.put("B611", new Style(Style.parseColor("#0099db"), Style.WHITE));
LINES.put("B612", new Style(Style.parseColor("#ce9d53"), Style.WHITE));
LINES.put("B613", new Style(Style.parseColor("#7b3600"), Style.WHITE));
LINES.put("B614", new Style(Style.parseColor("#806839"), Style.WHITE));
LINES.put("B615", new Style(Style.parseColor("#532700"), Style.WHITE));
LINES.put("B630", new Style(Style.parseColor("#c41950"), Style.WHITE));
LINES.put("B631", new Style(Style.parseColor("#9b1c44"), Style.WHITE));
LINES.put("B633", new Style(Style.parseColor("#88cdc7"), Style.WHITE));
LINES.put("B635", new Style(Style.parseColor("#cec800"), Style.WHITE));
LINES.put("B636", new Style(Style.parseColor("#af0223"), Style.WHITE));
LINES.put("B637", new Style(Style.parseColor("#e3572a"), Style.WHITE));
LINES.put("B638", new Style(Style.parseColor("#af5836"), Style.WHITE));
LINES.put("B640", new Style(Style.parseColor("#004f81"), Style.WHITE));
LINES.put("BT650", new Style(Style.parseColor("#54baa2"), Style.WHITE));
LINES.put("BT651", new Style(Style.parseColor("#005738"), Style.WHITE));
LINES.put("BT680", new Style(Style.parseColor("#4e6578"), Style.WHITE));
LINES.put("B800", new Style(Style.parseColor("#4e6578"), Style.WHITE));
LINES.put("B812", new Style(Style.parseColor("#4e6578"), Style.WHITE));
LINES.put("B843", new Style(Style.parseColor("#4e6578"), Style.WHITE));
LINES.put("B845", new Style(Style.parseColor("#4e6578"), Style.WHITE));
LINES.put("B852", new Style(Style.parseColor("#4e6578"), Style.WHITE));
LINES.put("B855", new Style(Style.parseColor("#4e6578"), Style.WHITE));
LINES.put("B856", new Style(Style.parseColor("#4e6578"), Style.WHITE));
LINES.put("B857", new Style(Style.parseColor("#4e6578"), Style.WHITE));
}
@Override
public Style lineStyle(final String line)
{
final Style style = LINES.get(line);
if (style != null)
return style;
else
return super.lineStyle(line);
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class VrtProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VRT;
private final static String API_BASE = "http://efa9.vrn.de/vrt/";
public VrtProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.ANY, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class VvmProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VVM;
private final static String API_BASE = "http://efa.mobilitaetsverbund.de/web/";
public VvmProvider()
{
super(API_BASE, null, null, null, false, true);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.ANY, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
/**
* @author Andreas Schildbach
*/
public class VvoProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VVO;
public static final String OLD_NETWORK_ID = "efa.vvo-online.de";
private final static String API_BASE = "http://efa.vvo-online.de:8080/dvb/";
public VvoProvider()
{
super(API_BASE, null);
}
public VvoProvider(final String apiBase)
{
super(apiBase, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlStopfinderRequest(new Location(LocationType.STATION, 0, null, constraint.toString()));
}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import de.schildbach.pte.dto.Point;
/**
* @author Andreas Schildbach
*/
public class VvsProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VVS;
public static final String OLD_NETWORK_ID = "mobil.vvs.de";
private static final String API_BASE = "http://mobil.vvs.de/mobile/"; // http://www2.vvs.de/vvs/
public VvsProvider()
{
super(API_BASE, null, true);
}
public VvsProvider(final String apiBase)
{
super(apiBase, null, true);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(final Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
public Point[] getArea()
{
return new Point[] { new Point(48.784068f, 9.181713f) };
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
/**
* @author Andreas Schildbach
*/
public class VvtProvider extends AbstractEfaProvider
{
public static final NetworkId NETWORK_ID = NetworkId.VVT;
private final static String API_BASE = "http://efa.vvt.at/vvtadr/";
public VvtProvider()
{
super(API_BASE, null);
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.AUTOCOMPLETE_ONE_LINE || capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
}

View file

@ -0,0 +1,271 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import de.schildbach.pte.dto.Line;
import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.NearbyStationsResult;
import de.schildbach.pte.dto.QueryDeparturesResult;
/**
* @author Andreas Schildbach
*/
public class ZvvProvider extends AbstractHafasProvider
{
public static final NetworkId NETWORK_ID = NetworkId.ZVV;
private static final String API_BASE = "http://onlinev2.fahrplan.zvv.ch/bin/"; // http://online.fahrplan.zvv.ch/bin/
public ZvvProvider()
{
super(API_BASE + "query.exe/dn", 10, null, "UTF-8", "UTF-8");
}
public NetworkId id()
{
return NETWORK_ID;
}
public boolean hasCapabilities(Capability... capabilities)
{
for (final Capability capability : capabilities)
if (capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS)
return true;
return false;
}
@Override
protected char intToProduct(final int value)
{
if (value == 1)
return 'I';
if (value == 2)
return 'I';
if (value == 4)
return 'R';
if (value == 8)
return 'R';
if (value == 16)
return 'F';
if (value == 32)
return 'S';
if (value == 64)
return 'B';
if (value == 128)
return 'C';
if (value == 256)
return 'U';
if (value == 512)
return 'T';
throw new IllegalArgumentException("cannot handle: " + value);
}
@Override
protected void setProductBits(final StringBuilder productBits, final char product)
{
if (product == 'I')
{
productBits.setCharAt(0, '1'); // ICE/EN/CNL/CIS/ES/MET/NZ/PEN/TGV/THA/X2
productBits.setCharAt(1, '1'); // EuroCity/InterCity/InterCityNight/SuperCity
}
else if (product == 'R')
{
productBits.setCharAt(2, '1'); // InterRegio
productBits.setCharAt(3, '1'); // Schnellzug/RegioExpress
}
else if (product == 'S')
{
productBits.setCharAt(5, '1'); // S-Bahn/StadtExpress/Eilzug/Regionalzug
}
else if (product == 'U')
{
}
else if (product == 'T')
{
productBits.setCharAt(9, '1'); // Tram
}
else if (product == 'B' || product == 'P')
{
productBits.setCharAt(6, '1'); // Postauto/Bus
}
else if (product == 'F')
{
productBits.setCharAt(4, '1'); // Schiff/Fähre/Dampfschiff
}
else if (product == 'C')
{
productBits.setCharAt(7, '1'); // Luftseilbahn/Standseilbahn/Bergbahn
}
else
{
throw new IllegalArgumentException("cannot handle: " + product);
}
}
private static final String[] PLACES = { "Zürich" };
@Override
protected String[] splitPlaceAndName(final String name)
{
for (final String place : PLACES)
{
if (name.startsWith(place + ", "))
return new String[] { place, name.substring(place.length() + 2) };
}
return super.splitPlaceAndName(name);
}
public NearbyStationsResult queryNearbyStations(final Location location, final int maxDistance, final int maxStations) throws IOException
{
final StringBuilder uri = new StringBuilder(API_BASE);
if (location.hasLocation())
{
uri.append("query.exe/dny");
uri.append("?performLocating=2&tpl=stop2json");
uri.append("&look_maxno=").append(maxStations != 0 ? maxStations : 150);
uri.append("&look_maxdist=").append(maxDistance != 0 ? maxDistance : 5000);
uri.append("&look_stopclass=").append(allProductsInt());
uri.append("&look_x=").append(location.lon);
uri.append("&look_y=").append(location.lat);
return jsonNearbyStations(uri.toString());
}
else if (location.type == LocationType.STATION && location.hasId())
{
uri.append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&input=").append(location.id);
uri.append("&sTI=1&start=yes&hcount=0");
uri.append("&L=vs_java3");
return xmlNearbyStations(uri.toString());
}
else
{
throw new IllegalArgumentException("cannot handle: " + location.toDebugString());
}
}
public QueryDeparturesResult queryDepartures(final int stationId, final int maxDepartures, final boolean equivs) throws IOException
{
final StringBuilder uri = new StringBuilder();
uri.append(API_BASE).append("stboard.exe/dn");
uri.append("?productsFilter=").append(allProductsString());
uri.append("&boardType=dep");
uri.append("&disableEquivs=yes"); // don't use nearby stations
uri.append("&maxJourneys=50"); // ignore maxDepartures because result contains other stations
uri.append("&start=yes");
uri.append("&L=vs_java3");
uri.append("&input=").append(stationId);
return xmlQueryDepartures(uri.toString(), stationId);
}
public List<Location> autocompleteStations(final CharSequence constraint) throws IOException
{
return xmlMLcReq(constraint);
}
@Override
protected Line parseLineAndType(final String lineAndType)
{
final Matcher m = P_NORMALIZE_LINE_AND_TYPE.matcher(lineAndType);
if (m.matches())
{
final String number = m.group(1).replaceAll("\\s+", " ");
final String type = m.group(2);
if ("Bus-NF".equals(type))
return newLine('B' + number, Line.Attr.WHEEL_CHAIR_ACCESS);
if ("Tro-NF".equals(type))
return newLine('B' + number, Line.Attr.WHEEL_CHAIR_ACCESS);
if ("Trm-NF".equals(type))
return newLine('T' + number, Line.Attr.WHEEL_CHAIR_ACCESS);
if (type.length() > 0)
{
final char normalizedType = normalizeType(type);
if (normalizedType != 0)
return newLine(normalizedType + number);
}
throw new IllegalStateException("cannot normalize type " + type + " number " + number + " line#type " + lineAndType);
}
throw new IllegalStateException("cannot normalize line#type " + lineAndType);
}
@Override
protected char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
// E-Bus: Bus, Tram oder Zug?
if ("S-BAHN".equals(ucType))
return 'S';
if ("T".equals(ucType))
return 'T';
if ("TRM".equals(ucType))
return 'T';
if ("TRM-NF".equals(ucType)) // Niederflur
return 'T';
if ("BUS-NF".equals(ucType)) // Niederflur
return 'B';
if ("TRO-NF".equals(ucType)) // Niederflur
return 'B';
if ("N".equals(ucType)) // Nachtbus
return 'B';
if ("BUXI".equals(ucType))
return 'B';
if ("TX".equals(ucType))
return 'B';
if ("E-BUS".equals(ucType))
return 'B';
if ("TROLLEY".equals(ucType))
return 'B';
if ("D-SCHIFF".equals(ucType))
return 'F';
if ("BERGBAHN".equals(ucType))
return 'C';
if ("UNB".equals(ucType))
return '?';
if ("???".equals(ucType))
return '?';
final char t = super.normalizeType(type);
if (t != 0)
return t;
return 0;
}
}

View file

@ -0,0 +1,283 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* @author Andreas Schildbach
*/
public final class Connection implements Serializable
{
private static final long serialVersionUID = 2508466068307110312L;
public final String id;
public final String link;
public final Location from;
public final Location to;
public final List<Part> parts;
public final List<Fare> fares;
public final int[] capacity;
public Connection(final String id, final String link, final Location from, final Location to, final List<Part> parts, final List<Fare> fares,
final int[] capacity)
{
this.id = id;
this.link = link;
this.from = from;
this.to = to;
this.parts = parts;
this.fares = fares;
this.capacity = capacity;
}
public Date getFirstDepartureTime()
{
if (parts != null)
{
int mins = 0;
for (final Part part : parts)
{
if (part instanceof Footway)
mins += ((Footway) part).min;
else if (part instanceof Trip)
return new Date(((Trip) part).getDepartureTime().getTime() - 1000 * 60 * mins);
}
}
return null;
}
public Trip getFirstTrip()
{
if (parts != null)
for (final Part part : parts)
if (part instanceof Trip)
return (Trip) part;
return null;
}
public Date getFirstTripDepartureTime()
{
final Trip firstTrip = getFirstTrip();
if (firstTrip != null)
return firstTrip.getDepartureTime();
else
return null;
}
public Date getLastArrivalTime()
{
if (parts != null)
{
int mins = 0;
for (int i = parts.size() - 1; i >= 0; i--)
{
final Part part = parts.get(i);
if (part instanceof Footway)
mins += ((Footway) part).min;
else if (part instanceof Trip)
return new Date(((Trip) part).getArrivalTime().getTime() + 1000 * 60 * mins);
}
}
return null;
}
public Trip getLastTrip()
{
if (parts != null)
{
for (int i = parts.size() - 1; i >= 0; i--)
{
final Part part = parts.get(i);
if (part instanceof Trip)
return (Trip) part;
}
}
return null;
}
public Date getLastTripArrivalTime()
{
final Trip lastTrip = getLastTrip();
if (lastTrip != null)
return lastTrip.getArrivalTime();
else
return null;
}
@Override
public String toString()
{
final SimpleDateFormat FORMAT = new SimpleDateFormat("E HH:mm");
final StringBuilder str = new StringBuilder(id);
str.append(' ');
final Date firstTripDepartureTime = getFirstTripDepartureTime();
str.append(firstTripDepartureTime != null ? FORMAT.format(firstTripDepartureTime) : "null");
str.append('-');
final Date lastTripArrivalTime = getLastTripArrivalTime();
str.append(lastTripArrivalTime != null ? FORMAT.format(lastTripArrivalTime) : "null");
return str.toString();
}
@Override
public boolean equals(Object o)
{
if (o == this)
return true;
if (!(o instanceof Connection))
return false;
final Connection other = (Connection) o;
return id.equals(other.id);
}
@Override
public int hashCode()
{
return id.hashCode();
}
public static class Part implements Serializable
{
private static final long serialVersionUID = 8498461220084523265L;
public final Location departure;
public final Location arrival;
public List<Point> path;
public Part(final Location departure, final Location arrival, final List<Point> path)
{
this.departure = departure;
this.arrival = arrival;
this.path = path;
}
}
public final static class Trip extends Part
{
private static final long serialVersionUID = 1312066446239817422L;
public final Line line;
public final Location destination;
public final Date departureTime; // TODO rename to plannedDepartureTime
public final Date predictedDepartureTime;
public final String departurePosition;
public final Date arrivalTime; // TODO rename to plannedArrivalTime
public final Date predictedArrivalTime;
public final String arrivalPosition;
public final List<Stop> intermediateStops;
public Trip(final Line line, final Location destination, final Date plannedDepartureTime, final Date predictedDepartureTime,
final String departurePosition, final Location departure, final Date plannedArrivalTime, final Date predictedArrivalTime,
final String arrivalPosition, final Location arrival, final List<Stop> intermediateStops, final List<Point> path)
{
super(departure, arrival, path);
this.line = line;
this.destination = destination;
this.departureTime = plannedDepartureTime;
this.predictedDepartureTime = predictedDepartureTime;
this.departurePosition = departurePosition;
this.arrivalTime = plannedArrivalTime;
this.predictedArrivalTime = predictedArrivalTime;
this.arrivalPosition = arrivalPosition;
this.intermediateStops = intermediateStops;
}
public Date getDepartureTime()
{
if (predictedDepartureTime != null)
return predictedDepartureTime;
else if (departureTime != null)
return departureTime;
else
throw new IllegalStateException();
}
public boolean isDepartureTimePredicted()
{
return predictedDepartureTime != null;
}
public Date getArrivalTime()
{
if (predictedArrivalTime != null)
return predictedArrivalTime;
else if (arrivalTime != null)
return arrivalTime;
else
throw new IllegalStateException();
}
public boolean isArrivalTimePredicted()
{
return predictedArrivalTime != null;
}
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder(getClass().getName() + "[");
builder.append("line=").append(line);
if (destination != null)
{
builder.append(",");
builder.append("destination=").append(destination.toDebugString());
}
builder.append(",");
builder.append("departure=").append(departureTime).append("/").append(departurePosition).append("/").append(departure.toDebugString());
builder.append(",");
builder.append("arrival=").append(arrivalTime).append("/").append(arrivalPosition).append("/").append(arrival.toDebugString());
builder.append("]");
return builder.toString();
}
}
public final static class Footway extends Part
{
public final int min;
public Footway(final int min, final Location departure, final Location arrival, final List<Point> path)
{
super(departure, arrival, path);
this.min = min;
}
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder(getClass().getName() + "[");
builder.append("min=").append(min);
builder.append(",");
builder.append("departure=").append(departure.toDebugString());
builder.append(",");
builder.append("arrival=").append(arrival.toDebugString());
builder.append("]");
return builder.toString();
}
}
}

View file

@ -0,0 +1,112 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.util.Date;
/**
* @author Andreas Schildbach
*/
public final class Departure
{
final public Date plannedTime;
final public Date predictedTime;
final public Line line;
final public String position;
final public Location destination;
final public int[] capacity;
final public String message;
public Departure(final Date plannedTime, final Date predictedTime, final Line line, final String position, final Location destination,
final int[] capacity, final String message)
{
this.plannedTime = plannedTime;
this.predictedTime = predictedTime;
this.line = line;
this.position = position;
this.destination = destination;
this.capacity = capacity;
this.message = message;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder("Departure(");
builder.append(plannedTime != null ? plannedTime : "null");
builder.append(",");
builder.append(predictedTime != null ? predictedTime : "null");
builder.append(",");
builder.append(line != null ? line : "null");
builder.append(",");
builder.append(position != null ? position : "null");
builder.append(",");
builder.append(destination != null ? destination : "null");
builder.append(")");
return builder.toString();
}
@Override
public boolean equals(final Object o)
{
if (o == this)
return true;
if (!(o instanceof Departure))
return false;
final Departure other = (Departure) o;
if (!nullSafeEquals(this.plannedTime, other.plannedTime))
return false;
if (!nullSafeEquals(this.predictedTime, other.predictedTime))
return false;
if (!nullSafeEquals(this.line, other.line))
return false;
if (!nullSafeEquals(this.destination, other.destination))
return false;
return true;
}
@Override
public int hashCode()
{
int hashCode = 0;
hashCode += nullSafeHashCode(plannedTime);
hashCode *= 29;
hashCode += nullSafeHashCode(predictedTime);
hashCode *= 29;
hashCode += nullSafeHashCode(line);
hashCode *= 29;
hashCode += nullSafeHashCode(destination);
return hashCode;
}
private boolean nullSafeEquals(final Object o1, final Object o2)
{
if (o1 == null && o2 == null)
return true;
if (o1 != null && o1.equals(o2))
return true;
return false;
}
private int nullSafeHashCode(final Object o)
{
if (o == null)
return 0;
return o.hashCode();
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
import java.util.Currency;
/**
* @author Andreas Schildbach
*/
public final class Fare implements Serializable
{
public enum Type
{
ADULT, CHILD, YOUTH, STUDENT, MILITARY, SENIOR, DISABLED
}
public final String network;
public final Type type;
public final Currency currency;
public final float fare;
public final String unitName;
public final String units;
public Fare(final String network, final Type type, final Currency currency, final float fare, final String unitName, final String units)
{
this.network = network;
this.type = type;
this.currency = currency;
this.fare = fare;
this.unitName = unitName;
this.units = units;
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author Andreas Schildbach
*/
public final class GetConnectionDetailsResult
{
public final Date currentDate;
public final Connection connection;
public GetConnectionDetailsResult(Date currentDate, Connection connection)
{
this.currentDate = currentDate;
this.connection = connection;
}
@Override
public String toString()
{
final SimpleDateFormat FORMAT = new SimpleDateFormat("EE dd.MM.yy");
return FORMAT.format(currentDate) + "|" + connection.toString();
}
}

View file

@ -0,0 +1,117 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
import java.util.Set;
/**
* @author Andreas Schildbach
*/
public final class Line implements Serializable, Comparable<Line>
{
public enum Attr
{
CIRCLE_CLOCKWISE, CIRCLE_ANTICLOCKWISE, SERVICE_REPLACEMENT, LINE_AIRPORT, WHEEL_CHAIR_ACCESS
}
private static final long serialVersionUID = -5642533805998375070L;
final public String id;
final private transient char product; // TODO make true field
final public String label;
final public Style style;
final private Set<Attr> attrs;
private static final String PRODUCT_ORDER = "IRSUTBPFC?";
public Line(final String id, final String label, final Style style)
{
this(id, label, style, null);
}
public Line(final String id, final String label, final Style style, final Set<Attr> attrs)
{
this.id = id;
this.label = label;
this.style = style;
this.attrs = attrs;
product = label != null ? label.charAt(0) : '?';
}
public boolean hasAttr(final Attr attr)
{
return attrs != null && attrs.contains(attr);
}
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder("Line(");
builder.append(label);
builder.append(")");
return builder.toString();
}
@Override
public boolean equals(final Object o)
{
if (o == this)
return true;
if (!(o instanceof Line))
return false;
final Line other = (Line) o;
return nullSafeEquals(this.label, other.label);
}
@Override
public int hashCode()
{
return nullSafeHashCode(label);
}
public int compareTo(final Line other)
{
final int productThis = PRODUCT_ORDER.indexOf(this.product);
final int productOther = PRODUCT_ORDER.indexOf(other.product);
final int compareProduct = new Integer(productThis >= 0 ? productThis : Integer.MAX_VALUE).compareTo(productOther >= 0 ? productOther
: Integer.MAX_VALUE);
if (compareProduct != 0)
return compareProduct;
return this.label.compareTo(other.label);
}
private boolean nullSafeEquals(final Object o1, final Object o2)
{
if (o1 == null && o2 == null)
return true;
if (o1 != null && o1.equals(o2))
return true;
return false;
}
private int nullSafeHashCode(final Object o)
{
if (o == null)
return 0;
return o.hashCode();
}
}

View file

@ -0,0 +1,85 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
/**
* @author Andreas Schildbach
*/
public final class LineDestination
{
final public Line line;
final public Location destination;
public LineDestination(final Line line, final Location destination)
{
this.line = line;
this.destination = destination;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder("LineDestination(");
builder.append(line != null ? line : "null");
builder.append(",");
builder.append(destination != null ? destination : "null");
builder.append(")");
return builder.toString();
}
@Override
public boolean equals(final Object o)
{
if (o == this)
return true;
if (!(o instanceof LineDestination))
return false;
final LineDestination other = (LineDestination) o;
if (!nullSafeEquals(this.line, other.line))
return false;
if (!nullSafeEquals(this.destination, other.destination))
return false;
return true;
}
@Override
public int hashCode()
{
int hashCode = 0;
hashCode += nullSafeHashCode(line);
hashCode *= 29;
hashCode += nullSafeHashCode(destination);
return hashCode;
}
private boolean nullSafeEquals(final Object o1, final Object o2)
{
if (o1 == null && o2 == null)
return true;
if (o1 != null && o1.equals(o2))
return true;
return false;
}
private int nullSafeHashCode(final Object o)
{
if (o == null)
return 0;
return o.hashCode();
}
}

View file

@ -0,0 +1,167 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
/**
* @author Andreas Schildbach
*/
public final class Location implements Serializable
{
private static final long serialVersionUID = 2168486169241327168L;
public final LocationType type;
public final int id;
public final int lat, lon;
public final String place;
public final String name;
public Location(final LocationType type, final int id, final int lat, final int lon, final String place, final String name)
{
this.type = type;
this.id = id;
this.lat = lat;
this.lon = lon;
this.place = place;
this.name = name;
}
public Location(final LocationType type, final int id, final String place, final String name)
{
this.type = type;
this.id = id;
this.lat = 0;
this.lon = 0;
this.place = place;
this.name = name;
}
public Location(final LocationType type, final int id, final int lat, final int lon)
{
this.type = type;
this.id = id;
this.lat = lat;
this.lon = lon;
this.place = null;
this.name = null;
}
public Location(final LocationType type, final int id)
{
this.type = type;
this.id = id;
this.lat = 0;
this.lon = 0;
this.place = null;
this.name = null;
}
public Location(final LocationType type, final int lat, final int lon)
{
this.type = type;
this.id = 0;
this.lat = lat;
this.lon = lon;
this.place = null;
this.name = null;
}
public final boolean hasId()
{
return id != 0;
}
public final boolean hasLocation()
{
return lat != 0 || lon != 0;
}
public final String uniqueShortName()
{
if ("Bahnhof".equals(name) || "Dorf".equals(name) || "Kirche".equals(name))
return place + ", " + name;
else
return name;
}
@Override
public String toString()
{
return name; // invoked by AutoCompleteTextView in landscape orientation
}
public String toDebugString()
{
return "[" + type + " " + id + " " + lat + "/" + lon + " " + (place != null ? "'" + place + "'" : "null") + " '" + name + "']";
}
@Override
public boolean equals(Object o)
{
if (o == this)
return true;
if (!(o instanceof Location))
return false;
final Location other = (Location) o;
if (this.type != other.type)
return false;
if (this.id != 0 && this.id == other.id)
return true;
if (this.lat != 0 && this.lon != 0 && this.lat == other.lat && this.lon == other.lon)
return true;
if (!nullSafeEquals(this.name, other.name)) // only discriminate by name if no ids are given
return false;
return true;
}
@Override
public int hashCode()
{
int hashCode = 0;
hashCode += type.hashCode();
hashCode *= 29;
if (id != 0)
{
hashCode += id;
}
else if (lat != 0 || lon != 0)
{
hashCode += lat;
hashCode *= 29;
hashCode += lon;
}
return hashCode;
}
private boolean nullSafeEquals(final Object o1, final Object o2)
{
if (o1 == null && o2 == null)
return true;
if (o1 != null && o1.equals(o2))
return true;
return false;
}
private int nullSafeHashCode(final Object o)
{
if (o == null)
return 0;
return o.hashCode();
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
/**
* @author Andreas Schildbach
*/
public enum LocationType
{
ANY, STATION, POI, ADDRESS
}

View file

@ -0,0 +1,49 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.util.List;
/**
* @author Andreas Schildbach
*/
public final class NearbyStationsResult
{
public enum Status
{
OK, INVALID_STATION, SERVICE_DOWN
}
public final ResultHeader header;
public final Status status;
public final List<Location> stations;
public NearbyStationsResult(final ResultHeader header, final List<Location> stations)
{
this.header = header;
this.status = Status.OK;
this.stations = stations;
}
public NearbyStationsResult(final ResultHeader header, final Status status)
{
this.header = header;
this.status = status;
this.stations = null;
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
/**
* @author Andreas Schildbach
*/
public final class Point implements Serializable
{
public final int lat, lon;
public Point(final float lat, final float lon)
{
this.lat = (int) Math.round(lat * 1E6);
this.lon = (int) Math.round(lon * 1E6);
}
public Point(final int lat, final int lon)
{
this.lat = lat;
this.lon = lon;
}
@Override
public String toString()
{
return "[" + lat + "/" + lon + "]";
}
@Override
public boolean equals(final Object o)
{
if (o == this)
return true;
if (!(o instanceof Point))
return false;
final Point other = (Point) o;
if (this.lat != other.lat)
return false;
if (this.lon != other.lon)
return false;
return true;
}
@Override
public int hashCode()
{
return lat + 27 * lon;
}
}

View file

@ -0,0 +1,115 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
import java.util.List;
/**
* @author Andreas Schildbach
*/
public final class QueryConnectionsResult implements Serializable
{
public enum Status
{
OK, AMBIGUOUS, TOO_CLOSE, UNKNOWN_FROM, UNKNOWN_TO, UNRESOLVABLE_ADDRESS, NO_CONNECTIONS, INVALID_DATE, SERVICE_DOWN;
}
public final ResultHeader header;
public final Status status;
public final List<Location> ambiguousFrom;
public final List<Location> ambiguousVia;
public final List<Location> ambiguousTo;
public final String queryUri;
public final Location from;
public final Location via;
public final Location to;
public final String context;
public final List<Connection> connections;
public QueryConnectionsResult(final ResultHeader header, final String queryUri, final Location from, final Location via, final Location to,
final String context, final List<Connection> connections)
{
this.header = header;
this.status = Status.OK;
this.queryUri = queryUri;
this.from = from;
this.via = via;
this.to = to;
this.context = context;
this.connections = connections;
this.ambiguousFrom = null;
this.ambiguousVia = null;
this.ambiguousTo = null;
}
public QueryConnectionsResult(final ResultHeader header, final List<Location> ambiguousFrom, final List<Location> ambiguousVia,
final List<Location> ambiguousTo)
{
this.header = header;
this.status = Status.AMBIGUOUS;
this.ambiguousFrom = ambiguousFrom;
this.ambiguousVia = ambiguousVia;
this.ambiguousTo = ambiguousTo;
this.queryUri = null;
this.from = null;
this.via = null;
this.to = null;
this.context = null;
this.connections = null;
}
public QueryConnectionsResult(final ResultHeader header, final Status status)
{
this.header = header;
this.status = status;
this.ambiguousFrom = null;
this.ambiguousVia = null;
this.ambiguousTo = null;
this.queryUri = null;
this.from = null;
this.via = null;
this.to = null;
this.context = null;
this.connections = null;
}
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder(getClass().getName());
builder.append("[").append(this.status).append(": ");
if (connections != null)
builder.append(connections.size()).append(" connections " + connections + ", ");
if (ambiguousFrom != null)
builder.append(ambiguousFrom.size()).append(" ambiguous from, ");
if (ambiguousVia != null)
builder.append(ambiguousVia.size()).append(" ambiguous via, ");
if (ambiguousTo != null)
builder.append(ambiguousTo.size()).append(" ambiguous to, ");
if (builder.substring(builder.length() - 2).equals(", "))
builder.setLength(builder.length() - 2);
builder.append("]");
return builder.toString();
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.util.LinkedList;
import java.util.List;
/**
* @author Andreas Schildbach
*/
public final class QueryDeparturesResult
{
public enum Status
{
OK, INVALID_STATION, SERVICE_DOWN
}
public final ResultHeader header;
public final Status status;
public final List<StationDepartures> stationDepartures = new LinkedList<StationDepartures>();
public QueryDeparturesResult(final ResultHeader header)
{
this.header = header;
this.status = Status.OK;
}
public QueryDeparturesResult(final ResultHeader header, final Status status)
{
this.header = header;
this.status = status;
}
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder(getClass().getName());
builder.append("[").append(this.status);
builder.append(" ").append(stationDepartures);
builder.append("]");
return builder.toString();
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
/**
* @author Andreas Schildbach
*/
public final class ResultHeader implements Serializable
{
public final String serverProduct;
public final String serverVersion;
public final long serverTime;
public final String context;
public ResultHeader(final String serverProduct)
{
this.serverProduct = serverProduct;
this.serverVersion = null;
this.serverTime = 0;
this.context = null;
}
public ResultHeader(final String serverProduct, final String serverVersion, final long serverTime, final String context)
{
this.serverProduct = serverProduct;
this.serverVersion = serverVersion;
this.serverTime = serverTime;
this.context = context;
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.util.List;
/**
* @author Andreas Schildbach
*/
public final class StationDepartures
{
public final Location location;
public final List<Departure> departures;
public final List<LineDestination> lines;
public StationDepartures(final Location location, final List<Departure> departures, final List<LineDestination> lines)
{
this.location = location;
this.departures = departures;
this.lines = lines;
}
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder(getClass().getName());
builder.append("[");
if (location != null)
builder.append(location.toDebugString());
if (departures != null)
builder.append(" ").append(departures.size()).append(" departures");
builder.append("]");
return builder.toString();
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
import java.util.Date;
/**
* @author Andreas Schildbach
*/
public final class Stop implements Serializable
{
public final Location location;
public final String position;
public final Date time;
public Stop(final Location location, final String position, final Date time)
{
this.location = location;
this.position = position;
this.time = time;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder("Stop(");
builder.append(location);
builder.append(",");
builder.append(position != null ? position : "null");
builder.append(",");
builder.append(time != null ? time : "null");
builder.append(")");
return builder.toString();
}
}

View file

@ -0,0 +1,113 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.dto;
import java.io.Serializable;
/**
* @author Andreas Schildbach
*/
public class Style implements Serializable
{
private static final long serialVersionUID = 7145603493425043304L;
public final Shape shape;
public final int backgroundColor;
public final int foregroundColor;
public final int borderColor;
public enum Shape
{
RECT, ROUNDED, CIRCLE
}
public Style(final int backgroundColor, final int foregroundColor)
{
this.shape = Shape.ROUNDED;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
this.borderColor = 0;
}
public Style(final Shape shape, final int backgroundColor, final int foregroundColor)
{
this.shape = shape;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
this.borderColor = 0;
}
public Style(final Shape shape, final int backgroundColor, final int foregroundColor, final int borderColor)
{
this.shape = shape;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
this.borderColor = borderColor;
}
public Style(final int backgroundColor, final int foregroundColor, final int borderColor)
{
this.shape = Shape.ROUNDED;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
this.borderColor = borderColor;
}
public final boolean hasBorder()
{
return borderColor != 0;
}
public static final int BLACK = 0xFF000000;
public static final int DKGRAY = 0xFF444444;
public static final int GRAY = 0xFF888888;
public static final int LTGRAY = 0xFFCCCCCC;
public static final int WHITE = 0xFFFFFFFF;
public static final int RED = 0xFFFF0000;
public static final int GREEN = 0xFF00FF00;
public static final int BLUE = 0xFF0000FF;
public static final int YELLOW = 0xFFFFFF00;
public static final int CYAN = 0xFF00FFFF;
public static final int MAGENTA = 0xFFFF00FF;
public static final int TRANSPARENT = 0;
public static int parseColor(final String colorString)
{
if (colorString.charAt(0) == '#')
{
// Use a long to avoid rollovers on #ffXXXXXX
long color = Long.parseLong(colorString.substring(1), 16);
if (colorString.length() == 7)
{
// Set the alpha value
color |= 0x00000000ff000000;
}
else if (colorString.length() != 9)
{
throw new IllegalArgumentException("Unknown color");
}
return (int) color;
}
throw new IllegalArgumentException("Unknown color");
}
public static int rgb(final int red, final int green, final int blue)
{
return (0xFF << 24) | (red << 16) | (green << 8) | blue;
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.exception;
import java.io.IOException;
/**
* @author Andreas Schildbach
*/
public class ParserException extends IOException
{
public ParserException()
{
super();
}
public ParserException(final String message)
{
super(message);
}
public ParserException(final String message, final Throwable cause)
{
super(message);
super.initCause(cause);
}
public ParserException(final Throwable cause)
{
super(cause == null ? null : cause.toString());
super.initCause(cause);
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.exception;
import java.io.IOException;
/**
* @author Andreas Schildbach
*/
public class ProtocolException extends IOException
{
public ProtocolException()
{
super();
}
public ProtocolException(final String message)
{
super(message);
}
public ProtocolException(final String message, final Throwable cause)
{
super(message);
super.initCause(cause);
}
public ProtocolException(final Throwable cause)
{
super(cause == null ? null : cause.toString());
super.initCause(cause);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.exception;
import java.io.IOException;
/**
* @author Andreas Schildbach
*/
public class SessionExpiredException extends IOException
{
}

View file

@ -0,0 +1,54 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.exception;
import java.io.IOException;
import java.net.URL;
/**
* @author Andreas Schildbach
*/
public class UnexpectedRedirectException extends IOException
{
private final URL originalUrl;
private final URL redirectedUrl;
public UnexpectedRedirectException()
{
this.originalUrl = null;
this.redirectedUrl = null;
}
public UnexpectedRedirectException(final URL originalUrl, final URL redirectedUrl)
{
super(originalUrl + " -> " + redirectedUrl);
this.originalUrl = originalUrl;
this.redirectedUrl = redirectedUrl;
}
public URL getUrl()
{
return originalUrl;
}
public URL getRedirectedUrl()
{
return redirectedUrl;
}
}

View file

@ -0,0 +1,994 @@
/*
* Copyright 2010f, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundationf, either version 3 of the Licensef, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be usefulf,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If notf, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.geo;
import de.schildbach.pte.dto.Point;
/**
* @author Andreas Schildbach
*/
public final class Berlin
{
// from http://osmrm.openstreetmap.de/gpx.jsp?relation=62422
public final static Point[] BOUNDARY = new Point[] { new Point(52.418887f, 13.2166474f), new Point(52.4184941f, 13.2156715f),
new Point(52.4182921f, 13.2151616f), new Point(52.4178231f, 13.2137198f), new Point(52.4177191f, 13.2130529f),
new Point(52.4175632f, 13.212736f), new Point(52.4172392f, 13.2116502f), new Point(52.4171322f, 13.2112832f),
new Point(52.4166442f, 13.2092295f), new Point(52.4163162f, 13.2074058f), new Point(52.4161133f, 13.2058071f),
new Point(52.4159263f, 13.2045453f), new Point(52.4155793f, 13.2011218f), new Point(52.4155723f, 13.200086f),
new Point(52.4155603f, 13.199999f), new Point(52.4154883f, 13.1994641f), new Point(52.4155532f, 13.1979783f),
new Point(52.4155033f, 13.1976513f), new Point(52.4154417f, 13.1970788f), new Point(52.4154233f, 13.1968095f),
new Point(52.4153163f, 13.1965425f), new Point(52.4147103f, 13.1950247f), new Point(52.4114066f, 13.1857522f),
new Point(52.4113266f, 13.1855243f), new Point(52.4112576f, 13.1853293f), new Point(52.4095978f, 13.1802131f),
new Point(52.4075539f, 13.1737471f), new Point(52.407157f, 13.1725203f), new Point(52.4028733f, 13.1593384f),
new Point(52.4027314f, 13.1592015f), new Point(52.3999967f, 13.1592715f), new Point(52.3997757f, 13.1592765f),
new Point(52.3995767f, 13.1592325f), new Point(52.3988068f, 13.1587106f), new Point(52.3980279f, 13.1583087f),
new Point(52.3979616f, 13.1582656f), new Point(52.397288f, 13.1578278f), new Point(52.396769f, 13.1577588f),
new Point(52.396476f, 13.1578028f), new Point(52.3962891f, 13.1578378f), new Point(52.3963151f, 13.1581438f),
new Point(52.3965291f, 13.1604294f), new Point(52.397264f, 13.1682747f), new Point(52.397277f, 13.1683392f),
new Point(52.397586f, 13.1704289f), new Point(52.397719f, 13.1711608f), new Point(52.397521f, 13.1712567f),
new Point(52.3956553f, 13.1716037f), new Point(52.3946294f, 13.1693361f), new Point(52.3943924f, 13.1687502f),
new Point(52.3943624f, 13.1680713f), new Point(52.3941294f, 13.1629381f), new Point(52.3939613f, 13.1603165f),
new Point(52.3939383f, 13.1593086f), new Point(52.3942403f, 13.1563331f), new Point(52.3944952f, 13.1550493f),
new Point(52.3948162f, 13.1528816f), new Point(52.3952741f, 13.1477634f), new Point(52.3953881f, 13.1464676f),
new Point(52.3954421f, 13.1458726f), new Point(52.396022f, 13.1438409f), new Point(52.3962729f, 13.143554f),
new Point(52.3964069f, 13.143242f), new Point(52.3966439f, 13.14313f), new Point(52.3968879f, 13.143257f),
new Point(52.3972428f, 13.143234f), new Point(52.3969828f, 13.1419972f), new Point(52.3958919f, 13.1394346f),
new Point(52.39535f, 13.1383038f), new Point(52.393208f, 13.1341859f), new Point(52.391376f, 13.1315858f),
new Point(52.390418f, 13.1303833f), new Point(52.3888553f, 13.1329494f), new Point(52.3887792f, 13.1333874f),
new Point(52.3888388f, 13.1338155f), new Point(52.3887847f, 13.1341306f), new Point(52.3873129f, 13.1333577f),
new Point(52.3873778f, 13.1327048f), new Point(52.3874618f, 13.1319749f), new Point(52.3874268f, 13.131608f),
new Point(52.3872209f, 13.131306f), new Point(52.3871749f, 13.1312201f), new Point(52.3873738f, 13.1307381f),
new Point(52.3881597f, 13.1293993f), new Point(52.3882477f, 13.1292433f), new Point(52.3887547f, 13.1283255f),
new Point(52.3887928f, 13.1282613f), new Point(52.3894906f, 13.1270646f), new Point(52.3895366f, 13.1269806f),
new Point(52.3908714f, 13.1272636f), new Point(52.3916295f, 13.1275f), new Point(52.3916781f, 13.1283631f),
new Point(52.3917453f, 13.131102f), new Point(52.3916574f, 13.130982f), new Point(52.3907154f, 13.1297932f),
new Point(52.3905288f, 13.1301453f), new Point(52.3912877f, 13.1310338f), new Point(52.3916695f, 13.1314846f),
new Point(52.3918487f, 13.1317621f), new Point(52.3933282f, 13.1339915f), new Point(52.3959449f, 13.1387247f),
new Point(52.3959569f, 13.1384997f), new Point(52.3960829f, 13.1385897f), new Point(52.3960899f, 13.1383018f),
new Point(52.3960939f, 13.1381938f), new Point(52.3961209f, 13.1376019f), new Point(52.3961319f, 13.1372439f),
new Point(52.3961699f, 13.1357212f), new Point(52.3962349f, 13.1356942f), new Point(52.3973877f, 13.1351762f),
new Point(52.3976657f, 13.1380178f), new Point(52.3978637f, 13.1381038f), new Point(52.3981234f, 13.1368941f),
new Point(52.3982077f, 13.136318f), new Point(52.3986846f, 13.1347932f), new Point(52.3992525f, 13.1338354f),
new Point(52.3985546f, 13.1327226f), new Point(52.3968647f, 13.1288552f), new Point(52.3965248f, 13.1278883f),
new Point(52.3963998f, 13.1271765f), new Point(52.3965058f, 13.1258916f), new Point(52.3966667f, 13.1254547f),
new Point(52.3968877f, 13.1248358f), new Point(52.3973077f, 13.1242339f), new Point(52.3986615f, 13.1216592f),
new Point(52.3995384f, 13.1204504f), new Point(52.3999963f, 13.1199395f), new Point(52.4013162f, 13.1184707f),
new Point(52.4019921f, 13.1179137f), new Point(52.4020531f, 13.1174468f), new Point(52.402293f, 13.116163f),
new Point(52.4038108f, 13.1120476f), new Point(52.4039978f, 13.1116956f), new Point(52.4042228f, 13.1114727f),
new Point(52.4044447f, 13.1111927f), new Point(52.4051307f, 13.1111477f), new Point(52.4053866f, 13.1109047f),
new Point(52.4059666f, 13.1102748f), new Point(52.4064325f, 13.1096989f), new Point(52.4069124f, 13.10894f),
new Point(52.4071984f, 13.1083831f), new Point(52.4078845f, 13.109238f), new Point(52.4080199f, 13.1094067f),
new Point(52.4084437f, 13.1085733f), new Point(52.4086808f, 13.1064347f), new Point(52.4094906f, 13.1067725f),
new Point(52.4095325f, 13.1069834f), new Point(52.4095541f, 13.1070987f), new Point(52.4092871f, 13.1083947f),
new Point(52.4095068f, 13.1106032f), new Point(52.4103473f, 13.1103956f), new Point(52.4104205f, 13.1111396f),
new Point(52.4104721f, 13.1116853f), new Point(52.4114108f, 13.1113889f), new Point(52.4113705f, 13.1108785f),
new Point(52.4112963f, 13.1100898f), new Point(52.4129324f, 13.1095587f), new Point(52.4129339f, 13.1095146f),
new Point(52.4132573f, 13.1080804f), new Point(52.4133278f, 13.1077434f), new Point(52.4132807f, 13.1073574f),
new Point(52.4131917f, 13.1072887f), new Point(52.4130738f, 13.1072466f), new Point(52.4126758f, 13.1074155f),
new Point(52.4124902f, 13.1074862f), new Point(52.4122441f, 13.1075205f), new Point(52.411966f, 13.1074944f),
new Point(52.4104549f, 13.1072132f), new Point(52.4103385f, 13.1072119f), new Point(52.4100138f, 13.1072287f),
new Point(52.4099143f, 13.1071943f), new Point(52.4098148f, 13.1071428f), new Point(52.4097101f, 13.1070398f),
new Point(52.4096173f, 13.1068898f), new Point(52.409586f, 13.1067014f), new Point(52.4096711f, 13.1063313f),
new Point(52.4096131f, 13.1061293f), new Point(52.4096021f, 13.1059104f), new Point(52.4098771f, 13.1051725f),
new Point(52.4097541f, 13.1047325f), new Point(52.41006f, 13.1034077f), new Point(52.410521f, 13.1010531f),
new Point(52.4110139f, 13.1010811f), new Point(52.4120248f, 13.1010671f), new Point(52.4129627f, 13.1007261f),
new Point(52.4134356f, 13.1006631f), new Point(52.4136956f, 13.100879f), new Point(52.4137716f, 13.1005291f),
new Point(52.4137296f, 13.0999992f), new Point(52.4137216f, 13.0998692f), new Point(52.4134476f, 13.0985514f),
new Point(52.4131267f, 13.0973816f), new Point(52.4130736f, 13.0966027f), new Point(52.4130656f, 13.0965027f),
new Point(52.4128217f, 13.0964687f), new Point(52.4125967f, 13.0965987f), new Point(52.4119828f, 13.0972136f),
new Point(52.4114488f, 13.0978456f), new Point(52.4111469f, 13.0984545f), new Point(52.4110359f, 13.0987504f),
new Point(52.4107999f, 13.0988464f), new Point(52.410506f, 13.0987194f), new Point(52.410331f, 13.0985765f),
new Point(52.4101883f, 13.0988671f), new Point(52.409991f, 13.0985985f), new Point(52.409842f, 13.0980506f),
new Point(52.4098f, 13.0979856f), new Point(52.4094531f, 13.0973377f), new Point(52.4094191f, 13.0972407f),
new Point(52.4106129f, 13.0932053f), new Point(52.4107659f, 13.0928613f), new Point(52.4111968f, 13.0923044f),
new Point(52.4113228f, 13.0919355f), new Point(52.4113418f, 13.0918405f), new Point(52.4114218f, 13.0914025f),
new Point(52.4115398f, 13.0907626f), new Point(52.4124097f, 13.0903617f), new Point(52.4133936f, 13.0903306f),
new Point(52.4134776f, 13.0903166f), new Point(52.4135885f, 13.0902797f), new Point(52.4194711f, 13.088315f),
new Point(52.4217557f, 13.0957566f), new Point(52.4217787f, 13.0958256f), new Point(52.4219047f, 13.0959896f),
new Point(52.4224641f, 13.0967188f), new Point(52.4233465f, 13.0978693f), new Point(52.4235865f, 13.0980033f),
new Point(52.4243154f, 13.0983662f), new Point(52.4246394f, 13.0984122f), new Point(52.4252463f, 13.09944f),
new Point(52.4253143f, 13.0998509f), new Point(52.4253343f, 13.0999569f), new Point(52.4252993f, 13.1001749f),
new Point(52.4250973f, 13.1008918f), new Point(52.4246624f, 13.1015837f), new Point(52.4246624f, 13.1017927f),
new Point(52.4244104f, 13.1025535f), new Point(52.4242735f, 13.1034744f), new Point(52.4238425f, 13.1048342f),
new Point(52.4251774f, 13.1056761f), new Point(52.4255013f, 13.1069858f), new Point(52.4266272f, 13.1084496f),
new Point(52.42911f, 13.1131248f), new Point(52.4323796f, 13.1123399f), new Point(52.4329866f, 13.1141296f),
new Point(52.4360762f, 13.117429f), new Point(52.4362172f, 13.117579f), new Point(52.4375751f, 13.1215044f),
new Point(52.4378541f, 13.1223062f), new Point(52.438681f, 13.123406f), new Point(52.4396049f, 13.123376f),
new Point(52.441548f, 13.1201761f), new Point(52.4430632f, 13.1190008f), new Point(52.4432595f, 13.1188973f),
new Point(52.4436251f, 13.1190491f), new Point(52.4442202f, 13.118724f), new Point(52.4444968f, 13.1180738f),
new Point(52.4447833f, 13.1173695f), new Point(52.4451782f, 13.1164007f), new Point(52.4455068f, 13.1156759f),
new Point(52.4456785f, 13.1152709f), new Point(52.4470805f, 13.1136326f), new Point(52.4477079f, 13.1128902f),
new Point(52.4483602f, 13.1120635f), new Point(52.4489095f, 13.1113586f), new Point(52.4491547f, 13.1110223f),
new Point(52.4495317f, 13.1104998f), new Point(52.4499584f, 13.1100481f), new Point(52.450386f, 13.1096125f),
new Point(52.4508927f, 13.1084625f), new Point(52.4514794f, 13.1099158f), new Point(52.4520554f, 13.1104427f),
new Point(52.4527573f, 13.1111726f), new Point(52.4534172f, 13.1115825f), new Point(52.4537262f, 13.1118095f),
new Point(52.4539742f, 13.1119264f), new Point(52.4541612f, 13.1119714f), new Point(52.4577018f, 13.1125723f),
new Point(52.4589186f, 13.1123313f), new Point(52.4591666f, 13.1122343f), new Point(52.4601125f, 13.1104375f),
new Point(52.4620353f, 13.1112434f), new Point(52.4634351f, 13.1112733f), new Point(52.4638511f, 13.1112443f),
new Point(52.464614f, 13.1110323f), new Point(52.4658608f, 13.1105694f), new Point(52.4660218f, 13.1106774f),
new Point(52.4665858f, 13.1110633f), new Point(52.4676277f, 13.1119311f), new Point(52.4687145f, 13.1138098f),
new Point(52.4699584f, 13.1137538f), new Point(52.4716782f, 13.1159264f), new Point(52.4725481f, 13.1165433f),
new Point(52.473803f, 13.1172972f), new Point(52.4745399f, 13.1177581f), new Point(52.4746999f, 13.1178261f),
new Point(52.4748749f, 13.1178221f), new Point(52.4753138f, 13.1178211f), new Point(52.4772026f, 13.117819f),
new Point(52.4773436f, 13.117834f), new Point(52.4777366f, 13.1204286f), new Point(52.4781636f, 13.1233062f),
new Point(52.4786285f, 13.1263827f), new Point(52.4787015f, 13.1265716f), new Point(52.4787665f, 13.1267446f),
new Point(52.4789535f, 13.1271356f), new Point(52.4791475f, 13.1274575f), new Point(52.4798004f, 13.1285523f),
new Point(52.4810013f, 13.1301131f), new Point(52.4820052f, 13.1313888f), new Point(52.4834241f, 13.1331035f),
new Point(52.484324f, 13.1342423f), new Point(52.4853136f, 13.1354956f), new Point(52.4858698f, 13.1362f),
new Point(52.4868537f, 13.1374848f), new Point(52.4894934f, 13.1408262f), new Point(52.4915992f, 13.1435068f),
new Point(52.494121f, 13.1467752f), new Point(52.4959748f, 13.1491708f), new Point(52.4963258f, 13.1496047f),
new Point(52.4974006f, 13.1513704f), new Point(52.4981376f, 13.1523923f), new Point(52.4982476f, 13.1525442f),
new Point(52.4983166f, 13.1526382f), new Point(52.4984315f, 13.1527942f), new Point(52.4984995f, 13.1528882f),
new Point(52.4986105f, 13.1530402f), new Point(52.4986785f, 13.1531321f), new Point(52.4987935f, 13.1532891f),
new Point(52.4988625f, 13.1533831f), new Point(52.4989725f, 13.1535361f), new Point(52.4992245f, 13.153879f),
new Point(52.4993355f, 13.154029f), new Point(52.4994534f, 13.154189f), new Point(52.4995904f, 13.1543859f),
new Point(52.4996864f, 13.1545249f), new Point(52.4999994f, 13.1549788f), new Point(52.5010443f, 13.1565016f),
new Point(52.5015512f, 13.1572425f), new Point(52.5022072f, 13.1581693f), new Point(52.5026001f, 13.1587222f),
new Point(52.503688f, 13.1604499f), new Point(52.503917f, 13.1608139f), new Point(52.5058548f, 13.1636904f),
new Point(52.5059648f, 13.1638533f), new Point(52.5085245f, 13.1675837f), new Point(52.5088755f, 13.1678777f),
new Point(52.5092535f, 13.1686315f), new Point(52.5095474f, 13.1677577f), new Point(52.5097764f, 13.1670788f),
new Point(52.5106613f, 13.1644431f), new Point(52.5108172f, 13.1639732f), new Point(52.5108932f, 13.1637492f),
new Point(52.5111572f, 13.1630873f), new Point(52.5115152f, 13.1621935f), new Point(52.5120151f, 13.1609426f),
new Point(52.512645f, 13.1593609f), new Point(52.512771f, 13.1590479f), new Point(52.512839f, 13.158797f),
new Point(52.512881f, 13.158648f), new Point(52.5128965f, 13.1585289f), new Point(52.512954f, 13.1580881f),
new Point(52.5130409f, 13.1576151f), new Point(52.5131179f, 13.1573902f), new Point(52.5131939f, 13.1571542f),
new Point(52.5136099f, 13.1561403f), new Point(52.5137209f, 13.1558634f), new Point(52.5139418f, 13.1552865f),
new Point(52.5140518f, 13.1549915f), new Point(52.5144298f, 13.1540556f), new Point(52.5147317f, 13.1534307f),
new Point(52.5150247f, 13.1528268f), new Point(52.5152117f, 13.1524429f), new Point(52.5154066f, 13.1520389f),
new Point(52.5155136f, 13.151729f), new Point(52.5156776f, 13.151246f), new Point(52.5157806f, 13.1509401f),
new Point(52.5160285f, 13.1503382f), new Point(52.5167794f, 13.1484924f), new Point(52.5168824f, 13.1482435f),
new Point(52.5169434f, 13.1480625f), new Point(52.5171534f, 13.1474226f), new Point(52.5173254f, 13.1464107f),
new Point(52.5173714f, 13.1455949f), new Point(52.5175123f, 13.1454319f), new Point(52.5178593f, 13.1450289f),
new Point(52.5183362f, 13.144814f), new Point(52.5188662f, 13.144574f), new Point(52.5191751f, 13.144121f),
new Point(52.5193321f, 13.1436451f), new Point(52.5194881f, 13.1431512f), new Point(52.5196141f, 13.1431382f),
new Point(52.5196901f, 13.1427212f), new Point(52.5196751f, 13.1425403f), new Point(52.5195871f, 13.1415244f),
new Point(52.5195261f, 13.1411765f), new Point(52.5192551f, 13.1396527f), new Point(52.5190571f, 13.1385309f),
new Point(52.5189041f, 13.137689f), new Point(52.5187751f, 13.1367352f), new Point(52.5187331f, 13.1364432f),
new Point(52.5186911f, 13.1361483f), new Point(52.5185501f, 13.1348945f), new Point(52.5181491f, 13.1322129f),
new Point(52.5181002f, 13.1318989f), new Point(52.5180232f, 13.1310531f), new Point(52.5179851f, 13.1299262f),
new Point(52.5178632f, 13.1290984f), new Point(52.5177332f, 13.1282365f), new Point(52.5175312f, 13.1269317f),
new Point(52.5174822f, 13.1264898f), new Point(52.5174852f, 13.1261768f), new Point(52.5174972f, 13.125086f),
new Point(52.5174941f, 13.1250283f), new Point(52.5174092f, 13.1234222f), new Point(52.5173982f, 13.1232263f),
new Point(52.5172816f, 13.1209768f), new Point(52.5171122f, 13.1201667f), new Point(52.5170892f, 13.1192909f),
new Point(52.5170335f, 13.1187881f), new Point(52.5170204f, 13.118316f), new Point(52.5170335f, 13.1173933f),
new Point(52.518168f, 13.1178091f), new Point(52.518714f, 13.11795f), new Point(52.5191489f, 13.118062f),
new Point(52.5194849f, 13.118148f), new Point(52.5198738f, 13.1182859f), new Point(52.5206098f, 13.1185449f),
new Point(52.5218036f, 13.1188298f), new Point(52.5224296f, 13.1187168f), new Point(52.5227195f, 13.1187578f),
new Point(52.5231995f, 13.1187078f), new Point(52.5240854f, 13.1189348f), new Point(52.5255112f, 13.1189827f),
new Point(52.5260611f, 13.1190017f), new Point(52.5267701f, 13.1190817f), new Point(52.527091f, 13.1191207f),
new Point(52.527625f, 13.1191516f), new Point(52.528402f, 13.1191428f), new Point(52.5286634f, 13.1191745f),
new Point(52.5289929f, 13.1191989f), new Point(52.5295451f, 13.1192987f), new Point(52.5299303f, 13.1193494f),
new Point(52.5303187f, 13.1195865f), new Point(52.5307986f, 13.1197325f), new Point(52.5313891f, 13.1199718f),
new Point(52.5320345f, 13.1202144f), new Point(52.5327944f, 13.1206743f), new Point(52.5337783f, 13.1213252f),
new Point(52.5344802f, 13.1217921f), new Point(52.536406f, 13.1230578f), new Point(52.5371309f, 13.1234958f),
new Point(52.5375889f, 13.1236667f), new Point(52.5380806f, 13.1238432f), new Point(52.5386797f, 13.1240582f),
new Point(52.5387448f, 13.1240816f), new Point(52.5389887f, 13.1241626f), new Point(52.539079f, 13.1241935f),
new Point(52.5390997f, 13.1242006f), new Point(52.5401146f, 13.1245455f), new Point(52.5435132f, 13.1254153f),
new Point(52.5437572f, 13.1250984f), new Point(52.5443681f, 13.1252963f), new Point(52.5444901f, 13.1253353f),
new Point(52.5465689f, 13.1263051f), new Point(52.5485867f, 13.1272489f), new Point(52.5498266f, 13.1277748f),
new Point(52.5499905f, 13.1278458f), new Point(52.5521303f, 13.1288026f), new Point(52.554603f, 13.1299084f),
new Point(52.5559569f, 13.1305103f), new Point(52.5556709f, 13.1311232f), new Point(52.555121f, 13.13215f),
new Point(52.5540491f, 13.1333849f), new Point(52.5539231f, 13.1335338f), new Point(52.5532862f, 13.1345227f),
new Point(52.5528173f, 13.1357145f), new Point(52.5526003f, 13.1363654f), new Point(52.5525043f, 13.1370503f),
new Point(52.5524473f, 13.1385091f), new Point(52.5523214f, 13.1409897f), new Point(52.5522794f, 13.1415317f),
new Point(52.5522524f, 13.1416976f), new Point(52.5522414f, 13.1417826f), new Point(52.5521304f, 13.1425125f),
new Point(52.5520783f, 13.1431932f), new Point(52.5520694f, 13.1439283f), new Point(52.552169f, 13.1442466f),
new Point(52.5524894f, 13.1445152f), new Point(52.5525044f, 13.1449081f), new Point(52.5525774f, 13.1453221f),
new Point(52.5527904f, 13.145688f), new Point(52.5530573f, 13.145961f), new Point(52.5534353f, 13.1460459f),
new Point(52.5538663f, 13.1463419f), new Point(52.5543662f, 13.1469568f), new Point(52.5547408f, 13.1471301f),
new Point(52.5548272f, 13.1471457f), new Point(52.5553461f, 13.1472437f), new Point(52.555976f, 13.1471067f),
new Point(52.5570519f, 13.1467997f), new Point(52.5578758f, 13.1468127f), new Point(52.5585357f, 13.1467217f),
new Point(52.5588367f, 13.1465487f), new Point(52.5591267f, 13.1463188f), new Point(52.5593176f, 13.1461118f),
new Point(52.5602905f, 13.1459008f), new Point(52.5605535f, 13.1456528f), new Point(52.5607785f, 13.1459308f),
new Point(52.5610874f, 13.1465017f), new Point(52.5611904f, 13.1466897f), new Point(52.5613584f, 13.1470046f),
new Point(52.5614994f, 13.1471636f), new Point(52.5640291f, 13.1474535f), new Point(52.5644371f, 13.1475405f),
new Point(52.564803f, 13.1478124f), new Point(52.565635f, 13.1487473f), new Point(52.5660849f, 13.1491792f),
new Point(52.5669738f, 13.149938f), new Point(52.5677327f, 13.150223f), new Point(52.5691476f, 13.1510598f),
new Point(52.5697085f, 13.1510438f), new Point(52.5700135f, 13.1512208f), new Point(52.5702315f, 13.1518407f),
new Point(52.5704484f, 13.1521476f), new Point(52.5708794f, 13.1523376f), new Point(52.5719253f, 13.1526765f),
new Point(52.5724062f, 13.1525725f), new Point(52.5727412f, 13.1527115f), new Point(52.5730732f, 13.1531074f),
new Point(52.5732411f, 13.1532504f), new Point(52.574397f, 13.1532564f), new Point(52.574859f, 13.1534103f),
new Point(52.5750379f, 13.1534243f), new Point(52.5753969f, 13.1532853f), new Point(52.5757669f, 13.1534043f),
new Point(52.5767198f, 13.1532673f), new Point(52.5773383f, 13.1533769f), new Point(52.5775327f, 13.1534113f),
new Point(52.5781926f, 13.1531903f), new Point(52.5783226f, 13.1530393f), new Point(52.5789515f, 13.1529123f),
new Point(52.5798214f, 13.1523384f), new Point(52.5799434f, 13.1522584f), new Point(52.5805353f, 13.1518194f),
new Point(52.5813472f, 13.1513215f), new Point(52.5815152f, 13.1512215f), new Point(52.5821871f, 13.1511285f),
new Point(52.5825991f, 13.1506476f), new Point(52.582858f, 13.1500037f), new Point(52.582904f, 13.1498837f),
new Point(52.583255f, 13.1496707f), new Point(52.582812f, 13.147462f), new Point(52.5820681f, 13.1446435f),
new Point(52.5815991f, 13.1437906f), new Point(52.5815111f, 13.1428708f), new Point(52.5813511f, 13.1420879f),
new Point(52.5807832f, 13.1400212f), new Point(52.5804322f, 13.1391594f), new Point(52.5804892f, 13.1382545f),
new Point(52.5805192f, 13.1375126f), new Point(52.5801652f, 13.1359959f), new Point(52.5800662f, 13.135225f),
new Point(52.5796572f, 13.1325254f), new Point(52.5797342f, 13.1322904f), new Point(52.5797912f, 13.1321185f),
new Point(52.5801112f, 13.1317525f), new Point(52.5808481f, 13.1313685f), new Point(52.58171f, 13.1310876f),
new Point(52.5827699f, 13.1305426f), new Point(52.5830528f, 13.1302157f), new Point(52.5831748f, 13.1299837f),
new Point(52.5832738f, 13.1297297f), new Point(52.5832698f, 13.1294758f), new Point(52.5831518f, 13.128049f),
new Point(52.5859365f, 13.1293487f), new Point(52.5860165f, 13.1284729f), new Point(52.5872064f, 13.1286168f),
new Point(52.5871088f, 13.1294017f), new Point(52.5868634f, 13.1310894f), new Point(52.5868634f, 13.1311964f),
new Point(52.5869054f, 13.1327242f), new Point(52.5873364f, 13.1355338f), new Point(52.5874394f, 13.1358997f),
new Point(52.5887103f, 13.1380273f), new Point(52.5890412f, 13.1394291f), new Point(52.5896212f, 13.1434545f),
new Point(52.5906931f, 13.146252f), new Point(52.591746f, 13.1491446f), new Point(52.5935968f, 13.1516182f),
new Point(52.5937798f, 13.1518621f), new Point(52.5949657f, 13.1531839f), new Point(52.5956826f, 13.1538698f),
new Point(52.5958016f, 13.1539837f), new Point(52.5964915f, 13.1546096f), new Point(52.5968045f, 13.1549916f),
new Point(52.5970905f, 13.1554945f), new Point(52.5973735f, 13.1561824f), new Point(52.5976054f, 13.1570682f),
new Point(52.5980364f, 13.1594499f), new Point(52.5983154f, 13.1613396f), new Point(52.5987504f, 13.1643021f),
new Point(52.5987844f, 13.1645541f), new Point(52.5979035f, 13.1663318f), new Point(52.5976705f, 13.1668337f),
new Point(52.5971746f, 13.1675676f), new Point(52.5969916f, 13.1682116f), new Point(52.5967436f, 13.1701093f),
new Point(52.5961787f, 13.172287f), new Point(52.5959118f, 13.1727539f), new Point(52.5958508f, 13.1728609f),
new Point(52.5953278f, 13.1737508f), new Point(52.5951759f, 13.1744456f), new Point(52.5950119f, 13.1757405f),
new Point(52.5949319f, 13.1770583f), new Point(52.5949089f, 13.1781691f), new Point(52.5947709f, 13.178886f),
new Point(52.594493f, 13.1796519f), new Point(52.594207f, 13.1807167f), new Point(52.5940241f, 13.1814786f),
new Point(52.5938441f, 13.1824755f), new Point(52.5937761f, 13.1831704f), new Point(52.5936541f, 13.1837263f),
new Point(52.5934631f, 13.1843502f), new Point(52.5932532f, 13.1847461f), new Point(52.5925813f, 13.185702f),
new Point(52.5923333f, 13.1862109f), new Point(52.5920823f, 13.1869528f), new Point(52.5917924f, 13.1879267f),
new Point(52.5913874f, 13.1893145f), new Point(52.5910405f, 13.1899194f), new Point(52.5904685f, 13.1910342f),
new Point(52.5902896f, 13.1915922f), new Point(52.5900566f, 13.192725f), new Point(52.5898506f, 13.1939958f),
new Point(52.5895647f, 13.1966354f), new Point(52.5894117f, 13.1972813f), new Point(52.5893047f, 13.1978832f),
new Point(52.5890268f, 13.1986601f), new Point(52.5888968f, 13.1999989f), new Point(52.5888848f, 13.2001389f),
new Point(52.5887628f, 13.2006048f), new Point(52.5885148f, 13.2011387f), new Point(52.5884199f, 13.2013497f),
new Point(52.5882559f, 13.2017677f), new Point(52.5881189f, 13.2021146f), new Point(52.5880649f, 13.2022466f),
new Point(52.5878019f, 13.2029095f), new Point(52.586982f, 13.2052601f), new Point(52.5867749f, 13.2067153f),
new Point(52.5884305f, 13.2074663f), new Point(52.5882741f, 13.210921f), new Point(52.5872573f, 13.2171867f),
new Point(52.5875391f, 13.2173123f), new Point(52.5889919f, 13.2180572f), new Point(52.5907127f, 13.218873f),
new Point(52.5914059f, 13.2192115f), new Point(52.5924067f, 13.2188334f), new Point(52.593187f, 13.2181148f),
new Point(52.594958f, 13.2153168f), new Point(52.5955098f, 13.2141245f), new Point(52.5956684f, 13.2137426f),
new Point(52.596785f, 13.211336f), new Point(52.5971899f, 13.2105881f), new Point(52.5981168f, 13.2092073f),
new Point(52.5993607f, 13.2073525f), new Point(52.5999936f, 13.2067276f), new Point(52.6014394f, 13.2053018f),
new Point(52.6032742f, 13.2032571f), new Point(52.6038351f, 13.2024292f), new Point(52.6042811f, 13.2019053f),
new Point(52.605041f, 13.2014263f), new Point(52.605285f, 13.2013493f), new Point(52.6058799f, 13.2012623f),
new Point(52.6063298f, 13.2012543f), new Point(52.6067308f, 13.2013183f), new Point(52.6070018f, 13.2014623f),
new Point(52.6072147f, 13.2018012f), new Point(52.6073977f, 13.2020822f), new Point(52.6075807f, 13.2025471f),
new Point(52.6076917f, 13.20296f), new Point(52.6077947f, 13.203276f), new Point(52.6082447f, 13.2050017f),
new Point(52.6084966f, 13.2057276f), new Point(52.6087906f, 13.2062255f), new Point(52.6091526f, 13.2066244f),
new Point(52.6094695f, 13.2069384f), new Point(52.6101565f, 13.2076202f), new Point(52.6111934f, 13.2084201f),
new Point(52.6121853f, 13.209185f), new Point(52.6123572f, 13.2093159f), new Point(52.6156909f, 13.2120824f),
new Point(52.6176137f, 13.2135992f), new Point(52.6190895f, 13.2147639f), new Point(52.6193035f, 13.2152049f),
new Point(52.6201624f, 13.2167126f), new Point(52.6218862f, 13.2178754f), new Point(52.6222332f, 13.2181384f),
new Point(52.624591f, 13.219904f), new Point(52.6252199f, 13.22015f), new Point(52.6257998f, 13.220241f),
new Point(52.6269447f, 13.2203559f), new Point(52.6273716f, 13.2205319f), new Point(52.6278186f, 13.2205938f),
new Point(52.6282415f, 13.2205698f), new Point(52.6282036f, 13.2214377f), new Point(52.6281496f, 13.2226715f),
new Point(52.6281386f, 13.2229925f), new Point(52.6283596f, 13.2242653f), new Point(52.6282716f, 13.2246362f),
new Point(52.6281956f, 13.2251741f), new Point(52.6282986f, 13.2251531f), new Point(52.6282106f, 13.2255641f),
new Point(52.6282036f, 13.2256451f), new Point(52.6281916f, 13.225823f), new Point(52.6281916f, 13.226024f),
new Point(52.6277567f, 13.226087f), new Point(52.6277267f, 13.22644f), new Point(52.6275627f, 13.2274218f),
new Point(52.6275017f, 13.2280957f), new Point(52.6274407f, 13.2287746f), new Point(52.6273907f, 13.2299024f),
new Point(52.6273607f, 13.2305683f), new Point(52.6274287f, 13.2322691f), new Point(52.6275467f, 13.232579f),
new Point(52.6278027f, 13.2353846f), new Point(52.6279058f, 13.2400289f), new Point(52.6280467f, 13.2409337f),
new Point(52.6280817f, 13.2410877f), new Point(52.6281077f, 13.2411977f), new Point(52.6281427f, 13.2413447f),
new Point(52.6281957f, 13.2415596f), new Point(52.6282227f, 13.2416826f), new Point(52.6282607f, 13.2419236f),
new Point(52.6282607f, 13.2421446f), new Point(52.6283287f, 13.2425785f), new Point(52.6282607f, 13.2431214f),
new Point(52.6281498f, 13.2436193f), new Point(52.6273339f, 13.245961f), new Point(52.6273069f, 13.2462729f),
new Point(52.6272839f, 13.2469888f), new Point(52.6272689f, 13.2474708f), new Point(52.6274249f, 13.2476377f),
new Point(52.6273599f, 13.2479617f), new Point(52.6275469f, 13.2491375f), new Point(52.6275549f, 13.2494025f),
new Point(52.6274859f, 13.2499344f), new Point(52.6274179f, 13.2504533f), new Point(52.6273409f, 13.2521031f),
new Point(52.6273569f, 13.252667f), new Point(52.6275129f, 13.2539338f), new Point(52.6275239f, 13.2545227f),
new Point(52.6275629f, 13.2563794f), new Point(52.6276009f, 13.2567253f), new Point(52.6277419f, 13.2571963f),
new Point(52.6277419f, 13.2579492f), new Point(52.6277339f, 13.2596979f), new Point(52.6277989f, 13.2602388f),
new Point(52.627635f, 13.2614526f), new Point(52.627318f, 13.2626884f), new Point(52.627231f, 13.2635683f),
new Point(52.6268761f, 13.2643622f), new Point(52.627444f, 13.2643732f), new Point(52.6284129f, 13.2644781f),
new Point(52.6293168f, 13.2645581f), new Point(52.6300686f, 13.2645839f), new Point(52.6314766f, 13.264821f),
new Point(52.6321325f, 13.264894f), new Point(52.6325405f, 13.264907f), new Point(52.6334104f, 13.264981f),
new Point(52.6347152f, 13.2650869f), new Point(52.6352911f, 13.2648849f), new Point(52.636344f, 13.264438f),
new Point(52.636493f, 13.264348f), new Point(52.6371449f, 13.263959f), new Point(52.6375079f, 13.2636351f),
new Point(52.6383698f, 13.2628732f), new Point(52.6387627f, 13.2625832f), new Point(52.6389243f, 13.262464f),
new Point(52.6393457f, 13.2623362f), new Point(52.6397806f, 13.2622732f), new Point(52.6401185f, 13.2622121f),
new Point(52.6407195f, 13.2621412f), new Point(52.6406925f, 13.2623222f), new Point(52.6402806f, 13.2652497f),
new Point(52.6397384f, 13.2694211f), new Point(52.6397578f, 13.2697818f), new Point(52.6398587f, 13.2716395f),
new Point(52.640316f, 13.2742945f), new Point(52.6402307f, 13.2763331f), new Point(52.6402617f, 13.276921f),
new Point(52.6409177f, 13.2814863f), new Point(52.6410247f, 13.2827851f), new Point(52.6410857f, 13.283473f),
new Point(52.6411127f, 13.2837719f), new Point(52.6462741f, 13.2842407f), new Point(52.6479449f, 13.2844966f),
new Point(52.6484938f, 13.2841297f), new Point(52.6486728f, 13.2839457f), new Point(52.6483868f, 13.2845246f),
new Point(52.6503786f, 13.2848765f), new Point(52.6521554f, 13.2850634f), new Point(52.6525334f, 13.2851024f),
new Point(52.6526673f, 13.2819039f), new Point(52.6547121f, 13.2821348f), new Point(52.6548641f, 13.2821518f),
new Point(52.6569969f, 13.2823677f), new Point(52.6607614f, 13.2827516f), new Point(52.6606247f, 13.2831109f),
new Point(52.6605445f, 13.2838164f), new Point(52.6604685f, 13.2846083f), new Point(52.6603955f, 13.2853512f),
new Point(52.6602735f, 13.2859641f), new Point(52.6601175f, 13.286595f), new Point(52.6600366f, 13.286927f),
new Point(52.6599876f, 13.2872029f), new Point(52.6599606f, 13.2875489f), new Point(52.6599536f, 13.2877339f),
new Point(52.6599496f, 13.2878378f), new Point(52.6599566f, 13.2880458f), new Point(52.6599646f, 13.2881848f),
new Point(52.6600176f, 13.2885517f), new Point(52.6600146f, 13.2886287f), new Point(52.6599186f, 13.2898355f),
new Point(52.6594957f, 13.293071f), new Point(52.6593847f, 13.293517f), new Point(52.6593617f, 13.293608f),
new Point(52.6593507f, 13.2942969f), new Point(52.6593427f, 13.2946508f), new Point(52.6593427f, 13.2947238f),
new Point(52.6593507f, 13.2951277f), new Point(52.6593547f, 13.2952327f), new Point(52.6593657f, 13.2961426f),
new Point(52.6593635f, 13.2970963f), new Point(52.6593617f, 13.2979023f), new Point(52.6593617f, 13.299793f),
new Point(52.6593538f, 13.299999f), new Point(52.6593348f, 13.3006599f), new Point(52.6592318f, 13.3015838f),
new Point(52.6592358f, 13.3021837f), new Point(52.6592778f, 13.3028426f), new Point(52.6592928f, 13.3029705f),
new Point(52.6594648f, 13.3043393f), new Point(52.6596518f, 13.3070859f), new Point(52.6594418f, 13.3072619f),
new Point(52.6590609f, 13.3075998f), new Point(52.6588389f, 13.3078438f), new Point(52.658217f, 13.3089347f),
new Point(52.657985f, 13.3087857f), new Point(52.657512f, 13.3097236f), new Point(52.657554f, 13.3099545f),
new Point(52.6574771f, 13.3100745f), new Point(52.6573861f, 13.3101645f), new Point(52.6553214f, 13.3051668f),
new Point(52.6534524f, 13.3005481f), new Point(52.6471552f, 13.3059644f), new Point(52.6457733f, 13.3068043f),
new Point(52.6438436f, 13.3084481f), new Point(52.6439806f, 13.309196f), new Point(52.6438586f, 13.309222f),
new Point(52.6427837f, 13.3094336f), new Point(52.6426965f, 13.3089497f), new Point(52.642344f, 13.3091246f),
new Point(52.6419286f, 13.3091836f), new Point(52.6419091f, 13.3088242f), new Point(52.6412929f, 13.3089314f),
new Point(52.6411429f, 13.3087001f), new Point(52.6407079f, 13.3081732f), new Point(52.6401536f, 13.3081847f),
new Point(52.640067f, 13.3081192f), new Point(52.639987f, 13.3079123f), new Point(52.639979f, 13.3073133f),
new Point(52.6396878f, 13.3072749f), new Point(52.6395842f, 13.3062857f), new Point(52.6387171f, 13.3068384f),
new Point(52.6380705f, 13.3069552f), new Point(52.6376366f, 13.3070941f), new Point(52.6374773f, 13.3071444f),
new Point(52.6372523f, 13.3058956f), new Point(52.6371143f, 13.3058956f), new Point(52.6369883f, 13.3059396f),
new Point(52.6368448f, 13.3060545f), new Point(52.6362644f, 13.3064145f), new Point(52.6346011f, 13.307865f),
new Point(52.6327916f, 13.3094781f), new Point(52.6320789f, 13.309889f), new Point(52.631318f, 13.3100773f),
new Point(52.630828f, 13.3102001f), new Point(52.6306221f, 13.3101951f), new Point(52.6306339f, 13.3098498f),
new Point(52.6301411f, 13.3098132f), new Point(52.6300461f, 13.3103931f), new Point(52.6296952f, 13.3100862f),
new Point(52.6294582f, 13.3097532f), new Point(52.6291112f, 13.3088804f), new Point(52.6290192f, 13.3085254f),
new Point(52.6286803f, 13.3064298f), new Point(52.6285733f, 13.3060158f), new Point(52.6282183f, 13.305132f),
new Point(52.6279453f, 13.3036758f), new Point(52.6278199f, 13.3032371f), new Point(52.6276738f, 13.3028371f),
new Point(52.6275524f, 13.3025414f), new Point(52.6271932f, 13.302628f), new Point(52.6276048f, 13.3054465f),
new Point(52.6277767f, 13.3073907f), new Point(52.6279537f, 13.3085257f), new Point(52.6279738f, 13.3091481f),
new Point(52.6281099f, 13.3110059f), new Point(52.6281355f, 13.3113545f), new Point(52.6282046f, 13.3123518f),
new Point(52.628189f, 13.3130203f), new Point(52.6280066f, 13.3138348f), new Point(52.6276002f, 13.3151658f),
new Point(52.6273487f, 13.3163745f), new Point(52.6271921f, 13.3173636f), new Point(52.6267989f, 13.3188729f),
new Point(52.6266549f, 13.3195719f), new Point(52.6264963f, 13.322449f), new Point(52.6264342f, 13.3235972f),
new Point(52.626342f, 13.324182f), new Point(52.6260787f, 13.3250935f), new Point(52.6259385f, 13.325555f),
new Point(52.625821f, 13.3261969f), new Point(52.6257619f, 13.3266131f), new Point(52.6257155f, 13.3270345f),
new Point(52.6256858f, 13.3273813f), new Point(52.6254464f, 13.3286827f), new Point(52.6252489f, 13.3294264f),
new Point(52.6243805f, 13.3316253f), new Point(52.6240185f, 13.332555f), new Point(52.6242063f, 13.3328528f),
new Point(52.6225399f, 13.3366253f), new Point(52.6226802f, 13.3366558f), new Point(52.6228164f, 13.3369873f),
new Point(52.6229756f, 13.3374621f), new Point(52.6230502f, 13.3376671f), new Point(52.623086f, 13.3379154f),
new Point(52.6230912f, 13.338246f), new Point(52.6231682f, 13.338335f), new Point(52.6234271f, 13.338422f),
new Point(52.6234731f, 13.338586f), new Point(52.6234651f, 13.3388259f), new Point(52.6232972f, 13.3391799f),
new Point(52.6233622f, 13.3400808f), new Point(52.6232632f, 13.3406177f), new Point(52.6234162f, 13.3414795f),
new Point(52.6234202f, 13.3417155f), new Point(52.6233662f, 13.3421954f), new Point(52.6235192f, 13.3428203f),
new Point(52.6235422f, 13.3431143f), new Point(52.6235222f, 13.3434082f), new Point(52.6234755f, 13.3436017f),
new Point(52.6235898f, 13.3438045f), new Point(52.6237479f, 13.3440271f), new Point(52.6236431f, 13.3467587f),
new Point(52.6239042f, 13.351226f), new Point(52.6229883f, 13.351505f), new Point(52.6231033f, 13.351797f),
new Point(52.6231263f, 13.351944f), new Point(52.6231183f, 13.3521649f), new Point(52.6230233f, 13.3524709f),
new Point(52.6229503f, 13.3525039f), new Point(52.6227403f, 13.3525969f), new Point(52.6227063f, 13.3526888f),
new Point(52.6227403f, 13.3527808f), new Point(52.6227843f, 13.3527978f), new Point(52.6229653f, 13.3528678f),
new Point(52.6230113f, 13.3529218f), new Point(52.6231143f, 13.3531778f), new Point(52.6231943f, 13.3536167f),
new Point(52.6232253f, 13.3546105f), new Point(52.6232823f, 13.3547015f), new Point(52.6234193f, 13.3547705f),
new Point(52.6234773f, 13.3550295f), new Point(52.6235383f, 13.3551605f), new Point(52.6235683f, 13.3552304f),
new Point(52.6236453f, 13.3553564f), new Point(52.6236373f, 13.3554664f), new Point(52.6235033f, 13.3558753f),
new Point(52.6233473f, 13.3561003f), new Point(52.6233283f, 13.3563213f), new Point(52.6233623f, 13.3564123f),
new Point(52.6233433f, 13.3565602f), new Point(52.6232553f, 13.3568012f), new Point(52.6232443f, 13.3570962f),
new Point(52.6231493f, 13.3576881f), new Point(52.6233093f, 13.358034f), new Point(52.6233773f, 13.358254f),
new Point(52.6235193f, 13.3590789f), new Point(52.6240033f, 13.3595268f), new Point(52.6241182f, 13.3597457f),
new Point(52.6241632f, 13.3599837f), new Point(52.6241332f, 13.3603366f), new Point(52.6241332f, 13.3606486f),
new Point(52.6242132f, 13.3609206f), new Point(52.6243852f, 13.3611595f), new Point(52.6244192f, 13.3613575f),
new Point(52.6243772f, 13.3616724f), new Point(52.6244232f, 13.3618014f), new Point(52.6246822f, 13.3619974f),
new Point(52.6248732f, 13.3622333f), new Point(52.6249302f, 13.3623973f), new Point(52.6249912f, 13.3627713f),
new Point(52.6249842f, 13.3633352f), new Point(52.6249112f, 13.3635581f), new Point(52.6248422f, 13.3636091f),
new Point(52.6246902f, 13.3637171f), new Point(52.6246172f, 13.3637671f), new Point(52.6245982f, 13.3641161f),
new Point(52.6247012f, 13.364723f), new Point(52.6247812f, 13.3649589f), new Point(52.6249612f, 13.3653249f),
new Point(52.6251172f, 13.3649729f), new Point(52.6251702f, 13.3648559f), new Point(52.6252702f, 13.36464f),
new Point(52.6253991f, 13.364352f), new Point(52.6254261f, 13.3647389f), new Point(52.6255751f, 13.3650689f),
new Point(52.6253732f, 13.3654268f), new Point(52.6253042f, 13.3655458f), new Point(52.6253192f, 13.3659288f),
new Point(52.6254262f, 13.3660218f), new Point(52.6256511f, 13.3662127f), new Point(52.6255331f, 13.3664947f),
new Point(52.6254572f, 13.3667576f), new Point(52.6254722f, 13.3673126f), new Point(52.6256931f, 13.3670456f),
new Point(52.6258191f, 13.3670596f), new Point(52.6260141f, 13.3675015f), new Point(52.6259911f, 13.3676865f),
new Point(52.6258461f, 13.3677625f), new Point(52.6257851f, 13.3679664f), new Point(52.6257661f, 13.3680374f),
new Point(52.6257271f, 13.3681724f), new Point(52.6256851f, 13.3684524f), new Point(52.6257661f, 13.3687283f),
new Point(52.6261701f, 13.3695012f), new Point(52.6263381f, 13.3695912f), new Point(52.6264941f, 13.3697082f),
new Point(52.627047f, 13.3702661f), new Point(52.627414f, 13.370738f), new Point(52.62725f, 13.3710789f),
new Point(52.627238f, 13.3713889f), new Point(52.627322f, 13.3716858f), new Point(52.627341f, 13.3717588f),
new Point(52.627322f, 13.3720348f), new Point(52.627353f, 13.3721288f), new Point(52.627501f, 13.3724277f),
new Point(52.627631f, 13.3726447f), new Point(52.6279479f, 13.3740335f), new Point(52.6293628f, 13.3764481f),
new Point(52.6297218f, 13.377062f), new Point(52.6298778f, 13.3772299f), new Point(52.6306947f, 13.3763471f),
new Point(52.6313316f, 13.3756401f), new Point(52.6313616f, 13.3759231f), new Point(52.6314916f, 13.3761881f),
new Point(52.6316825f, 13.376375f), new Point(52.6329834f, 13.3776588f), new Point(52.6334444f, 13.3778488f),
new Point(52.6338953f, 13.3783667f), new Point(52.6343523f, 13.3788936f), new Point(52.6338953f, 13.3795235f),
new Point(52.6343713f, 13.3801034f), new Point(52.6346352f, 13.3803973f), new Point(52.6352032f, 13.38263f),
new Point(52.6355272f, 13.382445f), new Point(52.6355962f, 13.382354f), new Point(52.6356611f, 13.382266f),
new Point(52.6359781f, 13.3814122f), new Point(52.6360841f, 13.3814371f), new Point(52.6363711f, 13.3818631f),
new Point(52.6364471f, 13.382092f), new Point(52.6364891f, 13.382227f), new Point(52.6365501f, 13.382544f),
new Point(52.636569f, 13.3826499f), new Point(52.6365771f, 13.3827769f), new Point(52.6365841f, 13.3829619f),
new Point(52.6365541f, 13.3834048f), new Point(52.6364701f, 13.3839058f), new Point(52.6364431f, 13.3841617f),
new Point(52.6364201f, 13.3843407f), new Point(52.6364091f, 13.3844597f), new Point(52.6364281f, 13.3847136f),
new Point(52.6364471f, 13.3849756f), new Point(52.6365541f, 13.3855805f), new Point(52.636931f, 13.3869413f),
new Point(52.637084f, 13.3874622f), new Point(52.637206f, 13.3879191f), new Point(52.637317f, 13.3881951f),
new Point(52.637893f, 13.388912f), new Point(52.6381289f, 13.3892029f), new Point(52.6383159f, 13.3893299f),
new Point(52.6385149f, 13.3893399f), new Point(52.6389608f, 13.3895128f), new Point(52.6390518f, 13.3895738f),
new Point(52.6393198f, 13.3897528f), new Point(52.6394068f, 13.3898108f), new Point(52.6396738f, 13.3899038f),
new Point(52.6399177f, 13.3898968f), new Point(52.6401737f, 13.3898898f), new Point(52.6404257f, 13.3898838f),
new Point(52.6404947f, 13.3899057f), new Point(52.6405937f, 13.3899357f), new Point(52.6410286f, 13.3898687f),
new Point(52.6415696f, 13.3898547f), new Point(52.6418945f, 13.3899607f), new Point(52.6421155f, 13.3901487f),
new Point(52.6422565f, 13.3902627f), new Point(52.6423025f, 13.3903186f), new Point(52.6423525f, 13.3903756f),
new Point(52.6428174f, 13.3909205f), new Point(52.6428904f, 13.3910015f), new Point(52.6434694f, 13.3916874f),
new Point(52.6433744f, 13.3920803f), new Point(52.6436033f, 13.3921833f), new Point(52.6441713f, 13.3922293f),
new Point(52.6442783f, 13.3922373f), new Point(52.6443583f, 13.3922713f), new Point(52.6446222f, 13.3923773f),
new Point(52.6448662f, 13.3923903f), new Point(52.6451672f, 13.3925472f), new Point(52.6455141f, 13.3929032f),
new Point(52.6457701f, 13.3931591f), new Point(52.6459801f, 13.3932101f), new Point(52.646575f, 13.393872f),
new Point(52.646647f, 13.393966f), new Point(52.6467188f, 13.3938318f), new Point(52.646747f, 13.393779f),
new Point(52.647025f, 13.393996f), new Point(52.647201f, 13.3941389f), new Point(52.6474709f, 13.3942039f),
new Point(52.647258f, 13.3955007f), new Point(52.647254f, 13.3961836f), new Point(52.647304f, 13.3964956f),
new Point(52.6476429f, 13.3970225f), new Point(52.6478299f, 13.3966125f), new Point(52.6482379f, 13.3971175f),
new Point(52.6483449f, 13.3974124f), new Point(52.6483679f, 13.3976114f), new Point(52.6482729f, 13.3978304f),
new Point(52.6482189f, 13.3979653f), new Point(52.6479709f, 13.3982293f), new Point(52.647529f, 13.3988772f),
new Point(52.647109f, 13.3994881f), new Point(52.6467811f, 13.3999981f), new Point(52.6458392f, 13.4014749f),
new Point(52.6451633f, 13.4026737f), new Point(52.6447633f, 13.4034766f), new Point(52.6443204f, 13.4045024f),
new Point(52.6437784f, 13.4060092f), new Point(52.6437215f, 13.4061282f), new Point(52.6436145f, 13.4063832f),
new Point(52.6434165f, 13.4066821f), new Point(52.6433055f, 13.4068511f), new Point(52.6432215f, 13.4069551f),
new Point(52.6428896f, 13.407356f), new Point(52.6425656f, 13.407759f), new Point(52.6426956f, 13.4079729f),
new Point(52.6428246f, 13.4087588f), new Point(52.6430306f, 13.4100426f), new Point(52.6433896f, 13.4122933f),
new Point(52.6430536f, 13.4127732f), new Point(52.6426496f, 13.4133451f), new Point(52.6425847f, 13.4135311f),
new Point(52.6425197f, 13.413902f), new Point(52.6424817f, 13.4146039f), new Point(52.6424167f, 13.4147709f),
new Point(52.6422037f, 13.4148879f), new Point(52.6419017f, 13.4149329f), new Point(52.6416348f, 13.4149009f),
new Point(52.6412148f, 13.414542f), new Point(52.6410588f, 13.414509f), new Point(52.6409138f, 13.414605f),
new Point(52.6406699f, 13.4149619f), new Point(52.639377f, 13.4165637f), new Point(52.6390791f, 13.4171616f),
new Point(52.6377173f, 13.4201092f), new Point(52.6369586f, 13.4216601f), new Point(52.6356075f, 13.4244216f),
new Point(52.6367554f, 13.4266132f), new Point(52.6368014f, 13.4266992f), new Point(52.6369274f, 13.4267752f),
new Point(52.6369654f, 13.4270322f), new Point(52.6370534f, 13.4271962f), new Point(52.6371374f, 13.4274131f),
new Point(52.6372094f, 13.4276151f), new Point(52.6374574f, 13.428277f), new Point(52.6375034f, 13.4284969f),
new Point(52.6372934f, 13.4322884f), new Point(52.6373314f, 13.4326193f), new Point(52.6374694f, 13.4329853f),
new Point(52.6375874f, 13.4332332f), new Point(52.6380983f, 13.4343f), new Point(52.6385603f, 13.434245f),
new Point(52.6385903f, 13.4341801f), new Point(52.6386513f, 13.4340551f), new Point(52.6388773f, 13.4338161f),
new Point(52.6389832f, 13.4339411f), new Point(52.6393382f, 13.4337341f), new Point(52.6401391f, 13.4335441f),
new Point(52.64141f, 13.4332421f), new Point(52.6419059f, 13.4333041f), new Point(52.6431648f, 13.433564f),
new Point(52.6441607f, 13.433768f), new Point(52.6443436f, 13.433912f), new Point(52.6444576f, 13.4341859f),
new Point(52.6446716f, 13.4353657f), new Point(52.6448506f, 13.4363756f), new Point(52.6453576f, 13.4395881f),
new Point(52.6454346f, 13.439697f), new Point(52.6469754f, 13.440054f), new Point(52.6491082f, 13.4407158f),
new Point(52.6492222f, 13.4408338f), new Point(52.6493171f, 13.4413097f), new Point(52.6493171f, 13.4415727f),
new Point(52.6492222f, 13.4416417f), new Point(52.6490122f, 13.4416657f), new Point(52.6490352f, 13.4420776f),
new Point(52.6490542f, 13.4423795f), new Point(52.6491082f, 13.4425925f), new Point(52.6495011f, 13.4432134f),
new Point(52.6495431f, 13.4434264f), new Point(52.6495622f, 13.4453051f), new Point(52.6497451f, 13.446042f),
new Point(52.6499391f, 13.4465879f), new Point(52.6500611f, 13.4472078f), new Point(52.6500611f, 13.4477777f),
new Point(52.6499771f, 13.4497984f), new Point(52.6499772f, 13.4499164f), new Point(52.6499432f, 13.4506823f),
new Point(52.6498672f, 13.4513512f), new Point(52.6497832f, 13.4518341f), new Point(52.6495812f, 13.4520051f),
new Point(52.6493862f, 13.4520501f), new Point(52.6487933f, 13.4521153f), new Point(52.6487033f, 13.4530049f),
new Point(52.6484324f, 13.4565004f), new Point(52.6482194f, 13.4595469f), new Point(52.6486004f, 13.4603858f),
new Point(52.6487184f, 13.4608437f), new Point(52.6489934f, 13.4618886f), new Point(52.6490664f, 13.4619776f),
new Point(52.6497943f, 13.4625455f), new Point(52.6501412f, 13.4629404f), new Point(52.6504282f, 13.4634853f),
new Point(52.6505992f, 13.4641832f), new Point(52.6508052f, 13.4648051f), new Point(52.6510682f, 13.465252f),
new Point(52.6512741f, 13.4656219f), new Point(52.6515801f, 13.4664068f), new Point(52.6516671f, 13.4667178f),
new Point(52.6517211f, 13.4670147f), new Point(52.6517401f, 13.4676226f), new Point(52.6517091f, 13.4682145f),
new Point(52.6517671f, 13.4684895f), new Point(52.6517861f, 13.4687305f), new Point(52.6517441f, 13.4691014f),
new Point(52.6517471f, 13.4692844f), new Point(52.6519151f, 13.4699093f), new Point(52.6520341f, 13.4701272f),
new Point(52.6523041f, 13.4704142f), new Point(52.653037f, 13.47152f), new Point(52.653491f, 13.4723549f),
new Point(52.6537809f, 13.4732157f), new Point(52.6539529f, 13.4735987f), new Point(52.6541129f, 13.4737976f),
new Point(52.6542839f, 13.4739206f), new Point(52.6548298f, 13.4739816f), new Point(52.6551597f, 13.4741057f),
new Point(52.6555255f, 13.4741999f), new Point(52.6557549f, 13.4742109f), new Point(52.6560107f, 13.4740437f),
new Point(52.656272f, 13.4737189f), new Point(52.6565572f, 13.4734728f), new Point(52.6575368f, 13.4624211f),
new Point(52.661943f, 13.4538312f), new Point(52.6627057f, 13.450794f), new Point(52.6631957f, 13.4516228f),
new Point(52.6655658f, 13.4550426f), new Point(52.6657488f, 13.4555363f), new Point(52.6685212f, 13.4595604f),
new Point(52.6687041f, 13.4591855f), new Point(52.6689751f, 13.4594825f), new Point(52.6690661f, 13.4595854f),
new Point(52.6671452f, 13.465958f), new Point(52.6710614f, 13.4705037f), new Point(52.671039f, 13.470734f),
new Point(52.6750011f, 13.4754659f), new Point(52.6739001f, 13.4770944f), new Point(52.6754755f, 13.479568f),
new Point(52.6748807f, 13.4800747f), new Point(52.6711504f, 13.4763065f), new Point(52.6684443f, 13.4749591f),
new Point(52.6678804f, 13.47551f), new Point(52.6672774f, 13.475972f), new Point(52.6667245f, 13.475963f),
new Point(52.6676774f, 13.4779727f), new Point(52.6694023f, 13.4850065f), new Point(52.6696843f, 13.4860674f),
new Point(52.6703752f, 13.488128f), new Point(52.6699093f, 13.4884f), new Point(52.6698293f, 13.488384f),
new Point(52.6690164f, 13.4877731f), new Point(52.6681085f, 13.4874612f), new Point(52.6667086f, 13.4872143f),
new Point(52.6653449f, 13.4868738f), new Point(52.6638019f, 13.4865734f), new Point(52.6624821f, 13.4862805f),
new Point(52.659472f, 13.4853506f), new Point(52.6559208f, 13.4895092f), new Point(52.6557839f, 13.4897132f),
new Point(52.6555739f, 13.4900301f), new Point(52.6555169f, 13.4898831f), new Point(52.654727f, 13.491257f),
new Point(52.6541741f, 13.4922158f), new Point(52.6540291f, 13.4922208f), new Point(52.6533272f, 13.4939106f),
new Point(52.6534072f, 13.4940196f), new Point(52.6525143f, 13.4963012f), new Point(52.6524343f, 13.4961943f),
new Point(52.6519154f, 13.4975231f), new Point(52.6515874f, 13.4983859f), new Point(52.6510115f, 13.4998887f),
new Point(52.6510115f, 13.4999987f), new Point(52.6510075f, 13.5002407f), new Point(52.6509505f, 13.5004796f),
new Point(52.6508055f, 13.5008496f), new Point(52.6505576f, 13.5015055f), new Point(52.6502216f, 13.5024354f),
new Point(52.6500615f, 13.5027339f), new Point(52.6499436f, 13.5029563f), new Point(52.6498017f, 13.5034582f),
new Point(52.6496187f, 13.5043101f), new Point(52.6492227f, 13.505315f), new Point(52.6489898f, 13.5060718f),
new Point(52.6483109f, 13.5071627f), new Point(52.6482039f, 13.5073697f), new Point(52.6477689f, 13.5082445f),
new Point(52.6468001f, 13.5100353f), new Point(52.6466891f, 13.5102233f), new Point(52.6465751f, 13.5104202f),
new Point(52.6453082f, 13.5125769f), new Point(52.6460982f, 13.5152545f), new Point(52.6461362f, 13.5153845f),
new Point(52.6463802f, 13.5162474f), new Point(52.6469751f, 13.5190219f), new Point(52.6469371f, 13.5191129f),
new Point(52.6460292f, 13.5196089f), new Point(52.6446904f, 13.5203428f), new Point(52.6447514f, 13.5216026f),
new Point(52.6448124f, 13.5228704f), new Point(52.6441375f, 13.5227454f), new Point(52.6412228f, 13.5222806f),
new Point(52.6405249f, 13.5221356f), new Point(52.639777f, 13.5219806f), new Point(52.638976f, 13.5216237f),
new Point(52.6388231f, 13.5215767f), new Point(52.6386751f, 13.5215307f), new Point(52.6380981f, 13.5213468f),
new Point(52.6352184f, 13.520114f), new Point(52.6316558f, 13.5182774f), new Point(52.62971f, 13.5176266f),
new Point(52.6295841f, 13.5175376f), new Point(52.6290421f, 13.5157019f), new Point(52.6280352f, 13.5120494f),
new Point(52.6276962f, 13.5109466f), new Point(52.6275092f, 13.5103427f), new Point(52.6265703f, 13.5078531f),
new Point(52.6260404f, 13.5065303f), new Point(52.6258874f, 13.5061504f), new Point(52.6256704f, 13.5057475f),
new Point(52.6255254f, 13.5056595f), new Point(52.6245675f, 13.5056325f), new Point(52.6222638f, 13.5054656f),
new Point(52.620543f, 13.5054406f), new Point(52.619964f, 13.5054337f), new Point(52.6197351f, 13.5053937f),
new Point(52.6196121f, 13.5053027f), new Point(52.6195711f, 13.5049917f), new Point(52.6193421f, 13.5043978f),
new Point(52.6191321f, 13.503606f), new Point(52.6190141f, 13.503305f), new Point(52.6171483f, 13.5021002f),
new Point(52.6151097f, 13.5011241f), new Point(52.6138753f, 13.500502f), new Point(52.613385f, 13.5002605f),
new Point(52.6120427f, 13.4993323f), new Point(52.6109234f, 13.4987704f), new Point(52.6106114f, 13.4985662f),
new Point(52.6104641f, 13.4984895f), new Point(52.6066844f, 13.4970763f), new Point(52.6051316f, 13.4967323f),
new Point(52.6049376f, 13.4966894f), new Point(52.6052316f, 13.4975362f), new Point(52.6052846f, 13.498847f),
new Point(52.6036408f, 13.4999989f), new Point(52.6011841f, 13.5017167f), new Point(52.5999972f, 13.5025466f),
new Point(52.5966786f, 13.5048693f), new Point(52.5966176f, 13.5049103f), new Point(52.5965337f, 13.5049693f),
new Point(52.5963906f, 13.5051015f), new Point(52.5961787f, 13.5052903f), new Point(52.5954048f, 13.5058152f),
new Point(52.5921202f, 13.5080489f), new Point(52.5922f, 13.5108f), new Point(52.5922272f, 13.5107985f),
new Point(52.5924362f, 13.5161427f), new Point(52.5925092f, 13.5171535f), new Point(52.5925432f, 13.5176365f),
new Point(52.5926732f, 13.520641f), new Point(52.5927302f, 13.5228167f), new Point(52.5922273f, 13.527236f),
new Point(52.5922043f, 13.527424f), new Point(52.5917614f, 13.5297906f), new Point(52.5906816f, 13.5347149f),
new Point(52.5904456f, 13.5358248f), new Point(52.5901707f, 13.5371226f), new Point(52.5898807f, 13.5384744f),
new Point(52.5891638f, 13.5416769f), new Point(52.5891028f, 13.5419359f), new Point(52.588057f, 13.5463032f),
new Point(52.587855f, 13.5471451f), new Point(52.587577f, 13.5469831f), new Point(52.5875584f, 13.5470487f),
new Point(52.5873401f, 13.547818f), new Point(52.5872681f, 13.548022f), new Point(52.5867602f, 13.5493398f),
new Point(52.5866952f, 13.5495088f), new Point(52.586713f, 13.5498579f), new Point(52.5852654f, 13.5530173f),
new Point(52.5845095f, 13.554673f), new Point(52.5843225f, 13.555083f), new Point(52.5838076f, 13.5560029f),
new Point(52.5827087f, 13.5579716f), new Point(52.5813399f, 13.5604232f), new Point(52.5803769f, 13.5618078f),
new Point(52.5799503f, 13.5623438f), new Point(52.5789672f, 13.5635328f), new Point(52.5787902f, 13.5637804f),
new Point(52.5783112f, 13.5644507f), new Point(52.5761135f, 13.5665194f), new Point(52.5745877f, 13.5675663f),
new Point(52.5744608f, 13.5676539f), new Point(52.5743587f, 13.5677243f), new Point(52.5737908f, 13.5681413f),
new Point(52.5736678f, 13.5682292f), new Point(52.5734008f, 13.5684182f), new Point(52.5731269f, 13.5685302f),
new Point(52.5731339f, 13.5691701f), new Point(52.5733818f, 13.5690621f), new Point(52.5733709f, 13.569627f),
new Point(52.5733629f, 13.569962f), new Point(52.5733359f, 13.5708189f), new Point(52.5733139f, 13.5712038f),
new Point(52.5732949f, 13.5715687f), new Point(52.5732909f, 13.5716577f), new Point(52.5736109f, 13.5733445f),
new Point(52.5738548f, 13.5745903f), new Point(52.5738738f, 13.5747612f), new Point(52.5738778f, 13.5749602f),
new Point(52.5737139f, 13.5753162f), new Point(52.5734739f, 13.5758141f), new Point(52.5733559f, 13.5760421f),
new Point(52.5730809f, 13.57665f), new Point(52.572993f, 13.576804f), new Point(52.572886f, 13.5769319f),
new Point(52.572749f, 13.5770389f), new Point(52.572612f, 13.5771079f), new Point(52.5720971f, 13.5773449f),
new Point(52.5718681f, 13.5774599f), new Point(52.5711582f, 13.5777969f), new Point(52.5710892f, 13.5778328f),
new Point(52.5710362f, 13.5778958f), new Point(52.5710442f, 13.5790017f), new Point(52.5710472f, 13.5802205f),
new Point(52.5710662f, 13.5812173f), new Point(52.5711202f, 13.5812963f), new Point(52.5711392f, 13.5814033f),
new Point(52.5710172f, 13.5815043f), new Point(52.5708682f, 13.5815273f), new Point(52.5703223f, 13.5818683f),
new Point(52.5690065f, 13.5825722f), new Point(52.5684615f, 13.5828931f), new Point(52.5679426f, 13.5831161f),
new Point(52.567746f, 13.5831785f), new Point(52.5676526f, 13.5832081f), new Point(52.5670917f, 13.5832921f),
new Point(52.5667447f, 13.5832621f), new Point(52.5665387f, 13.5831761f), new Point(52.5661958f, 13.5830322f),
new Point(52.5659928f, 13.5829992f), new Point(52.5655199f, 13.5831002f), new Point(52.5651079f, 13.5830522f),
new Point(52.5649519f, 13.5831072f), new Point(52.5648829f, 13.5831302f), new Point(52.5637421f, 13.5838151f),
new Point(52.5632391f, 13.5839161f), new Point(52.5625522f, 13.5839661f), new Point(52.5622162f, 13.5840461f),
new Point(52.5618503f, 13.5841711f), new Point(52.5611334f, 13.5844161f), new Point(52.5599545f, 13.5844941f),
new Point(52.5593976f, 13.5846701f), new Point(52.5587986f, 13.5850521f), new Point(52.5576848f, 13.5863429f),
new Point(52.5573028f, 13.5865349f), new Point(52.555747f, 13.5877247f), new Point(52.5552741f, 13.5878437f),
new Point(52.5541142f, 13.5877878f), new Point(52.5527673f, 13.5877238f), new Point(52.5523934f, 13.5875648f),
new Point(52.5519774f, 13.5873329f), new Point(52.5517294f, 13.5870609f), new Point(52.5515735f, 13.5870089f),
new Point(52.5512145f, 13.5870349f), new Point(52.5508565f, 13.586911f), new Point(52.5502266f, 13.5864991f),
new Point(52.5501236f, 13.5864401f), new Point(52.5499941f, 13.5863412f), new Point(52.5498336f, 13.5862721f),
new Point(52.5496767f, 13.5861483f), new Point(52.549561f, 13.5863541f), new Point(52.5494827f, 13.5864811f),
new Point(52.5494597f, 13.5865831f), new Point(52.5494407f, 13.586757f), new Point(52.5494297f, 13.586853f),
new Point(52.5494107f, 13.586987f), new Point(52.5493987f, 13.587119f), new Point(52.5493797f, 13.587289f),
new Point(52.5493607f, 13.5873999f), new Point(52.5493497f, 13.5875079f), new Point(52.5493307f, 13.5876419f),
new Point(52.5489068f, 13.5901165f), new Point(52.5484799f, 13.5926342f), new Point(52.5484529f, 13.5928081f),
new Point(52.5484419f, 13.5928881f), new Point(52.5484109f, 13.5930601f), new Point(52.5480909f, 13.5949288f),
new Point(52.547553f, 13.5980834f), new Point(52.547511f, 13.5983183f), new Point(52.5474089f, 13.5989573f),
new Point(52.5472671f, 13.5997611f), new Point(52.5472251f, 13.5999991f), new Point(52.5466602f, 13.6033126f),
new Point(52.5466332f, 13.6034666f), new Point(52.5466102f, 13.6036105f), new Point(52.5459963f, 13.607418f),
new Point(52.5456413f, 13.6096406f), new Point(52.5455154f, 13.6104265f), new Point(52.5454514f, 13.6107035f),
new Point(52.5449854f, 13.6136691f), new Point(52.5444015f, 13.6171795f), new Point(52.5443785f, 13.6173705f),
new Point(52.5444325f, 13.6174495f), new Point(52.5443026f, 13.6182594f), new Point(52.5442226f, 13.6187573f),
new Point(52.5441576f, 13.6191562f), new Point(52.5441276f, 13.6193212f), new Point(52.5440586f, 13.6199721f),
new Point(52.5440016f, 13.6211169f), new Point(52.5438527f, 13.6232676f), new Point(52.5437727f, 13.6246724f),
new Point(52.5436807f, 13.6258602f), new Point(52.5435057f, 13.6282589f), new Point(52.5433608f, 13.6299996f),
new Point(52.5433108f, 13.6307475f), new Point(52.5432198f, 13.6319433f), new Point(52.5431198f, 13.6330971f),
new Point(52.5430938f, 13.6333771f), new Point(52.5430588f, 13.6335551f), new Point(52.5429749f, 13.633814f),
new Point(52.5428069f, 13.634352f), new Point(52.5425369f, 13.6351159f), new Point(52.5424719f, 13.6353508f),
new Point(52.5424449f, 13.6354958f), new Point(52.5424299f, 13.6356558f), new Point(52.5424029f, 13.6362787f),
new Point(52.542395f, 13.6370886f), new Point(52.541972f, 13.6372026f), new Point(52.5412091f, 13.6374525f),
new Point(52.5409231f, 13.6375135f), new Point(52.5404342f, 13.6370896f), new Point(52.5396563f, 13.6363107f),
new Point(52.5390043f, 13.6356719f), new Point(52.5389393f, 13.6356249f), new Point(52.5384354f, 13.635089f),
new Point(52.5383704f, 13.635039f), new Point(52.5383784f, 13.634748f), new Point(52.5381327f, 13.6345874f),
new Point(52.5380578f, 13.6345442f), new Point(52.5379854f, 13.6344891f), new Point(52.5380504f, 13.6341971f),
new Point(52.5380177f, 13.6341762f), new Point(52.5377105f, 13.6339801f), new Point(52.5378634f, 13.6335612f),
new Point(52.5379054f, 13.6333952f), new Point(52.5379054f, 13.6332363f), new Point(52.5378324f, 13.6330823f),
new Point(52.5378594f, 13.6329283f), new Point(52.5380844f, 13.6318095f), new Point(52.5380844f, 13.6316955f),
new Point(52.5380584f, 13.6315745f), new Point(52.5379134f, 13.6309926f), new Point(52.5377304f, 13.6307416f),
new Point(52.5376884f, 13.6306417f), new Point(52.5376994f, 13.6305287f), new Point(52.5379364f, 13.6294348f),
new Point(52.5380424f, 13.6289499f), new Point(52.5378589f, 13.6286379f), new Point(52.5376884f, 13.628348f),
new Point(52.5376044f, 13.628103f), new Point(52.5375814f, 13.6279711f), new Point(52.5375774f, 13.6277781f),
new Point(52.5375964f, 13.6275131f), new Point(52.5380233f, 13.6249645f), new Point(52.5377944f, 13.6249985f),
new Point(52.5371954f, 13.6251305f), new Point(52.5370624f, 13.6251625f), new Point(52.5362955f, 13.6253305f),
new Point(52.5355286f, 13.6255065f), new Point(52.5354566f, 13.6255215f), new Point(52.5348387f, 13.6256555f),
new Point(52.5342018f, 13.6257945f), new Point(52.5340908f, 13.6257575f), new Point(52.5336258f, 13.6248756f),
new Point(52.5326979f, 13.6250766f), new Point(52.531954f, 13.6252776f), new Point(52.5312301f, 13.6254736f),
new Point(52.5304932f, 13.6256706f), new Point(52.5301192f, 13.6257576f), new Point(52.5303522f, 13.6260285f),
new Point(52.5301882f, 13.6266175f), new Point(52.5301882f, 13.6267434f), new Point(52.5302072f, 13.6269694f),
new Point(52.5304062f, 13.6289801f), new Point(52.5305542f, 13.6307268f), new Point(52.5305962f, 13.6315337f),
new Point(52.5305892f, 13.6329305f), new Point(52.5305543f, 13.6338763f), new Point(52.5305353f, 13.6366069f),
new Point(52.5304783f, 13.6401424f), new Point(52.5304323f, 13.6406403f), new Point(52.5304243f, 13.6409713f),
new Point(52.5303334f, 13.6416902f), new Point(52.5301274f, 13.642841f), new Point(52.5299744f, 13.6434599f),
new Point(52.5298984f, 13.6439768f), new Point(52.5298144f, 13.6449507f), new Point(52.5297075f, 13.6469544f),
new Point(52.5296977f, 13.6483062f), new Point(52.5297995f, 13.6509048f), new Point(52.5298835f, 13.6569499f),
new Point(52.5290326f, 13.6572591f), new Point(52.5272174f, 13.6578667f), new Point(52.5264539f, 13.6580698f),
new Point(52.526171f, 13.6582348f), new Point(52.525912f, 13.6584747f), new Point(52.5251071f, 13.6571209f),
new Point(52.5250001f, 13.656944f), new Point(52.5241342f, 13.6554882f), new Point(52.5225813f, 13.6518158f),
new Point(52.5213424f, 13.6487263f), new Point(52.5206745f, 13.6470646f), new Point(52.5204645f, 13.6466167f),
new Point(52.5193776f, 13.644307f), new Point(52.5188507f, 13.6431942f), new Point(52.5184807f, 13.6424573f),
new Point(52.5181677f, 13.6419034f), new Point(52.5176188f, 13.6410366f), new Point(52.5163869f, 13.6393039f),
new Point(52.515177f, 13.6372942f), new Point(52.515135f, 13.6372222f), new Point(52.5138421f, 13.6354185f),
new Point(52.5137662f, 13.6353155f), new Point(52.5134992f, 13.6349546f), new Point(52.5134222f, 13.6348686f),
new Point(52.5133542f, 13.6347946f), new Point(52.5128852f, 13.6342707f), new Point(52.5124343f, 13.6338308f),
new Point(52.5118743f, 13.6333429f), new Point(52.5116374f, 13.6331289f), new Point(52.5112364f, 13.632829f),
new Point(52.5108785f, 13.632564f), new Point(52.5098946f, 13.6318092f), new Point(52.5078108f, 13.6303434f),
new Point(52.5069909f, 13.6297576f), new Point(52.5067239f, 13.6295916f), new Point(52.5065789f, 13.6294996f),
new Point(52.5063659f, 13.6293976f), new Point(52.506152f, 13.6292976f), new Point(52.506041f, 13.6292527f),
new Point(52.505969f, 13.6292237f), new Point(52.5049746f, 13.6288216f), new Point(52.5049311f, 13.6288107f),
new Point(52.5034093f, 13.6281977f), new Point(52.5032939f, 13.6281503f), new Point(52.5025309f, 13.6279208f),
new Point(52.4999946f, 13.6271581f), new Point(52.499826f, 13.6270819f), new Point(52.496546f, 13.6254245f),
new Point(52.4958251f, 13.6251275f), new Point(52.4942882f, 13.6240237f), new Point(52.4940363f, 13.6247326f),
new Point(52.4936583f, 13.6257875f), new Point(52.4930714f, 13.6297089f), new Point(52.4929699f, 13.6296392f),
new Point(52.4929374f, 13.6296169f), new Point(52.4916216f, 13.6279552f), new Point(52.4906337f, 13.6267484f),
new Point(52.4894058f, 13.6252467f), new Point(52.4893098f, 13.6251287f), new Point(52.487838f, 13.623331f),
new Point(52.487551f, 13.6229881f), new Point(52.4853432f, 13.6203305f), new Point(52.4836224f, 13.6182579f),
new Point(52.4810316f, 13.6152164f), new Point(52.4807877f, 13.6150014f), new Point(52.4806047f, 13.6148575f),
new Point(52.4794568f, 13.6145575f), new Point(52.47779f, 13.6142216f), new Point(52.4776913f, 13.6142062f),
new Point(52.4762672f, 13.6137178f), new Point(52.4757032f, 13.6135848f), new Point(52.4756612f, 13.6136598f),
new Point(52.4754323f, 13.6148336f), new Point(52.4751613f, 13.6158875f), new Point(52.4749663f, 13.6163994f),
new Point(52.4745394f, 13.6160794f), new Point(52.4732195f, 13.6144347f), new Point(52.4722006f, 13.6131629f),
new Point(52.4713537f, 13.6121011f), new Point(52.4708428f, 13.6114622f), new Point(52.4708048f, 13.6116202f),
new Point(52.4707628f, 13.6117982f), new Point(52.4707541f, 13.611846f), new Point(52.4707478f, 13.6118772f),
new Point(52.4706978f, 13.6120961f), new Point(52.4699999f, 13.6151637f), new Point(52.4700229f, 13.6153837f),
new Point(52.4711138f, 13.6169014f), new Point(52.4711978f, 13.6173853f), new Point(52.4706599f, 13.6206058f),
new Point(52.4705149f, 13.6213507f), new Point(52.4704309f, 13.6213367f), new Point(52.46987f, 13.6212538f),
new Point(52.4685041f, 13.6212898f), new Point(52.4684431f, 13.6219347f), new Point(52.4671883f, 13.6218547f),
new Point(52.4669253f, 13.6216518f), new Point(52.4666123f, 13.6214118f), new Point(52.4665703f, 13.6216548f),
new Point(52.4663994f, 13.6227026f), new Point(52.4665243f, 13.6229056f), new Point(52.4666353f, 13.6230876f),
new Point(52.4667843f, 13.6233365f), new Point(52.4670853f, 13.6230706f), new Point(52.4677342f, 13.6228356f),
new Point(52.4687221f, 13.6228096f), new Point(52.4687371f, 13.6230675f), new Point(52.4687451f, 13.6231835f),
new Point(52.4687641f, 13.6234735f), new Point(52.4687681f, 13.6251862f), new Point(52.4689241f, 13.6250912f),
new Point(52.4690121f, 13.6249232f), new Point(52.4691001f, 13.6245883f), new Point(52.469523f, 13.6246233f),
new Point(52.469973f, 13.6246573f), new Point(52.470179f, 13.6247562f), new Point(52.4703129f, 13.6248182f),
new Point(52.4735596f, 13.6251831f), new Point(52.4737536f, 13.625785f), new Point(52.4737916f, 13.6260979f),
new Point(52.4737686f, 13.6264459f), new Point(52.4735976f, 13.6269858f), new Point(52.4735326f, 13.6275217f),
new Point(52.4735136f, 13.6279457f), new Point(52.4735746f, 13.6283496f), new Point(52.4738486f, 13.6291155f),
new Point(52.4744285f, 13.6301333f), new Point(52.4747035f, 13.6305142f), new Point(52.4750315f, 13.6311331f),
new Point(52.4758744f, 13.6352925f), new Point(52.4760694f, 13.6361004f), new Point(52.4762944f, 13.6370342f),
new Point(52.4767133f, 13.6377951f), new Point(52.4776063f, 13.6398907f), new Point(52.4781972f, 13.6413875f),
new Point(52.4783962f, 13.6418994f), new Point(52.4788081f, 13.6427013f), new Point(52.4792581f, 13.6433882f),
new Point(52.4791251f, 13.6441331f), new Point(52.4790941f, 13.644304f), new Point(52.4789532f, 13.6450909f),
new Point(52.4788162f, 13.6475616f), new Point(52.4787582f, 13.6477205f), new Point(52.4786822f, 13.6479295f),
new Point(52.4783353f, 13.6489004f), new Point(52.4781333f, 13.6494993f), new Point(52.4775034f, 13.651407f),
new Point(52.4771754f, 13.6525368f), new Point(52.4773094f, 13.6527348f), new Point(52.4768475f, 13.6548105f),
new Point(52.4764615f, 13.6558694f), new Point(52.4758636f, 13.6568972f), new Point(52.4750887f, 13.658259f),
new Point(52.4748487f, 13.658781f), new Point(52.4746198f, 13.6596688f), new Point(52.4745508f, 13.6598078f),
new Point(52.4744328f, 13.6600598f), new Point(52.4741698f, 13.6609316f), new Point(52.4740019f, 13.6614586f),
new Point(52.4737989f, 13.6620835f), new Point(52.4736659f, 13.6626954f), new Point(52.4737229f, 13.6638172f),
new Point(52.4737769f, 13.6648111f), new Point(52.4741539f, 13.6670947f), new Point(52.4741769f, 13.6672487f),
new Point(52.4738299f, 13.6674967f), new Point(52.473742f, 13.6677196f), new Point(52.473475f, 13.6687915f),
new Point(52.473307f, 13.6694444f), new Point(52.473143f, 13.6699083f), new Point(52.4728381f, 13.6705792f),
new Point(52.4714343f, 13.6732288f), new Point(52.4707514f, 13.6748636f), new Point(52.4705764f, 13.6752186f),
new Point(52.4699545f, 13.6766334f), new Point(52.4691266f, 13.678899f), new Point(52.4690576f, 13.679104f),
new Point(52.4689356f, 13.679174f), new Point(52.4688216f, 13.679239f), new Point(52.4685546f, 13.679519f),
new Point(52.4679977f, 13.6801769f), new Point(52.4679167f, 13.6800499f), new Point(52.4673408f, 13.6808198f),
new Point(52.4672988f, 13.6811338f), new Point(52.4661849f, 13.6827635f), new Point(52.466082f, 13.6830235f),
new Point(52.4653001f, 13.6859341f), new Point(52.4651781f, 13.686449f), new Point(52.4649451f, 13.6869219f),
new Point(52.4651091f, 13.6871869f), new Point(52.4650221f, 13.6884257f), new Point(52.4650061f, 13.6896225f),
new Point(52.4649871f, 13.6899725f), new Point(52.4649302f, 13.6903614f), new Point(52.4647282f, 13.6914712f),
new Point(52.4642893f, 13.6949807f), new Point(52.4641863f, 13.6951177f), new Point(52.4640723f, 13.6952677f),
new Point(52.4640303f, 13.6956216f), new Point(52.4640143f, 13.6957406f), new Point(52.4637663f, 13.6959316f),
new Point(52.4629274f, 13.6964715f), new Point(52.4621035f, 13.6969975f), new Point(52.4602647f, 13.6973685f),
new Point(52.4602347f, 13.6976484f), new Point(52.4600898f, 13.6977424f), new Point(52.4598648f, 13.6977834f),
new Point(52.458144f, 13.6976815f), new Point(52.4568891f, 13.6985084f), new Point(52.4567282f, 13.6986144f),
new Point(52.4564772f, 13.6986194f), new Point(52.4562212f, 13.6986234f), new Point(52.4552103f, 13.6983334f),
new Point(52.4551113f, 13.6985004f), new Point(52.4550503f, 13.6993283f), new Point(52.4549624f, 13.6999982f),
new Point(52.4548064f, 13.701246f), new Point(52.4547984f, 13.701485f), new Point(52.4547104f, 13.7032307f),
new Point(52.4546764f, 13.7035617f), new Point(52.4546194f, 13.7045915f), new Point(52.4554664f, 13.7051444f),
new Point(52.4570532f, 13.7054953f), new Point(52.4578611f, 13.7057363f), new Point(52.4581551f, 13.7057283f),
new Point(52.4596009f, 13.7053773f), new Point(52.4597919f, 13.7053553f), new Point(52.4600478f, 13.7033256f),
new Point(52.4610887f, 13.7030266f), new Point(52.4630495f, 13.7026146f), new Point(52.4642853f, 13.7024486f),
new Point(52.4643353f, 13.7022746f), new Point(52.4645603f, 13.7020486f), new Point(52.4662311f, 13.7009098f),
new Point(52.4663531f, 13.7008298f), new Point(52.4663221f, 13.7005298f), new Point(52.467085f, 13.6999979f),
new Point(52.4681919f, 13.699227f), new Point(52.4681839f, 13.6999979f), new Point(52.4681769f, 13.7012887f),
new Point(52.4677649f, 13.7015726f), new Point(52.467478f, 13.7019286f), new Point(52.4666771f, 13.7035004f),
new Point(52.4665591f, 13.7037363f), new Point(52.4664291f, 13.7039953f), new Point(52.4657122f, 13.7054351f),
new Point(52.4652163f, 13.706439f), new Point(52.4639044f, 13.7097065f), new Point(52.4633435f, 13.7111733f),
new Point(52.4632595f, 13.7114653f), new Point(52.4632025f, 13.7117092f), new Point(52.4629546f, 13.713004f),
new Point(52.4628706f, 13.7139619f), new Point(52.4625996f, 13.7142248f), new Point(52.4627706f, 13.7149687f),
new Point(52.4626416f, 13.7153737f), new Point(52.4617068f, 13.7163555f), new Point(52.4614058f, 13.7167275f),
new Point(52.4568353f, 13.7203471f), new Point(52.4565034f, 13.720904f), new Point(52.4553815f, 13.7225188f),
new Point(52.4540507f, 13.7244715f), new Point(52.4522999f, 13.7269492f), new Point(52.4508001f, 13.7289679f),
new Point(52.4507241f, 13.7292449f), new Point(52.4506481f, 13.7299078f), new Point(52.4506291f, 13.7303477f),
new Point(52.4503732f, 13.7330193f), new Point(52.4506862f, 13.7343911f), new Point(52.4505602f, 13.7355709f),
new Point(52.4502472f, 13.7356699f), new Point(52.4498733f, 13.7365598f), new Point(52.4497473f, 13.7375536f),
new Point(52.4497023f, 13.7377106f), new Point(52.4496253f, 13.7379796f), new Point(52.4494614f, 13.7397123f),
new Point(52.4492174f, 13.741649f), new Point(52.4489274f, 13.7432168f), new Point(52.4492324f, 13.7447356f),
new Point(52.4490725f, 13.7455674f), new Point(52.4488965f, 13.7469082f), new Point(52.4480766f, 13.7512936f),
new Point(52.4478786f, 13.7520845f), new Point(52.4477407f, 13.7526424f), new Point(52.4474667f, 13.7534983f),
new Point(52.4470888f, 13.7540592f), new Point(52.4467758f, 13.7547491f), new Point(52.4465318f, 13.7549371f),
new Point(52.4463178f, 13.7550171f), new Point(52.4461199f, 13.755298f), new Point(52.4463759f, 13.7562479f),
new Point(52.4461389f, 13.7564009f), new Point(52.4460059f, 13.7563309f), new Point(52.4455969f, 13.7560139f),
new Point(52.445063f, 13.7556f), new Point(52.4436711f, 13.7545822f), new Point(52.4431862f, 13.7541733f),
new Point(52.4431562f, 13.7543393f), new Point(52.4429112f, 13.756302f), new Point(52.4428773f, 13.7565269f),
new Point(52.4428393f, 13.7568619f), new Point(52.4428123f, 13.7570689f), new Point(52.4384557f, 13.7553712f),
new Point(52.4379448f, 13.7607894f), new Point(52.4377929f, 13.7608854f), new Point(52.4375519f, 13.7609084f),
new Point(52.4373419f, 13.7608394f), new Point(52.436849f, 13.7604099f), new Point(52.436766f, 13.7603385f),
new Point(52.436518f, 13.7600876f), new Point(52.436102f, 13.7598396f), new Point(52.43627f, 13.7583828f),
new Point(52.436404f, 13.7568371f), new Point(52.4366559f, 13.7544964f), new Point(52.4415636f, 13.7564501f),
new Point(52.4414354f, 13.7503889f), new Point(52.4392536f, 13.7461786f), new Point(52.4381437f, 13.7440739f),
new Point(52.4379187f, 13.743651f), new Point(52.4359769f, 13.7431981f), new Point(52.434832f, 13.7429292f),
new Point(52.4345991f, 13.7428762f), new Point(52.4344351f, 13.7431082f), new Point(52.4331502f, 13.7428313f),
new Point(52.4329282f, 13.7427823f), new Point(52.4330432f, 13.7404096f), new Point(52.4332952f, 13.7383089f),
new Point(52.4330512f, 13.738195f), new Point(52.4328792f, 13.738115f), new Point(52.4329472f, 13.7375511f),
new Point(52.4335311f, 13.7327528f), new Point(52.433867f, 13.73109f), new Point(52.434065f, 13.7303351f),
new Point(52.4344999f, 13.7288363f), new Point(52.4352598f, 13.7267796f), new Point(52.4363997f, 13.72447f),
new Point(52.4365797f, 13.724105f), new Point(52.4367086f, 13.7235511f), new Point(52.4370566f, 13.7230662f),
new Point(52.4369306f, 13.7230482f), new Point(52.4367206f, 13.7230172f), new Point(52.4366366f, 13.7232181f),
new Point(52.4362707f, 13.724075f), new Point(52.4352978f, 13.7260427f), new Point(52.4351028f, 13.7264887f),
new Point(52.4350758f, 13.7265617f), new Point(52.4348899f, 13.7269886f), new Point(52.4345839f, 13.7278405f),
new Point(52.433924f, 13.7298952f), new Point(52.433642f, 13.731058f), new Point(52.4334051f, 13.7322219f),
new Point(52.4333211f, 13.7328488f), new Point(52.4329482f, 13.7354304f), new Point(52.4326732f, 13.7374991f),
new Point(52.4326042f, 13.738023f), new Point(52.4323333f, 13.7400567f), new Point(52.4319063f, 13.7399587f),
new Point(52.4314104f, 13.7398478f), new Point(52.4298276f, 13.7394848f), new Point(52.4289576f, 13.7389709f),
new Point(52.4283737f, 13.7415946f), new Point(52.4281828f, 13.7415216f), new Point(52.4280838f, 13.7414856f),
new Point(52.4273938f, 13.7412286f), new Point(52.4265389f, 13.7409687f), new Point(52.4264929f, 13.7408607f),
new Point(52.4265579f, 13.7394629f), new Point(52.4267379f, 13.7376562f), new Point(52.4265089f, 13.7374182f),
new Point(52.4228233f, 13.7336599f), new Point(52.4226023f, 13.7334219f), new Point(52.4210225f, 13.7317252f),
new Point(52.4208245f, 13.7315113f), new Point(52.4205995f, 13.7312683f), new Point(52.4203095f, 13.7309574f),
new Point(52.4198866f, 13.7311684f), new Point(52.4197781f, 13.7311814f), new Point(52.4196451f, 13.7311904f),
new Point(52.4192332f, 13.7311954f), new Point(52.4188362f, 13.7310824f), new Point(52.4181153f, 13.7304705f),
new Point(52.4173904f, 13.7300466f), new Point(52.4169174f, 13.7298236f), new Point(52.4167114f, 13.7297307f),
new Point(52.4165015f, 13.7296247f), new Point(52.4161775f, 13.7295967f), new Point(52.4159865f, 13.7296167f),
new Point(52.4158185f, 13.7296577f), new Point(52.4155476f, 13.7298087f), new Point(52.4146667f, 13.7306706f),
new Point(52.4144797f, 13.7309485f), new Point(52.4143237f, 13.7310435f), new Point(52.4137398f, 13.7315695f),
new Point(52.4129959f, 13.7323104f), new Point(52.4126149f, 13.7326903f), new Point(52.412046f, 13.7333072f),
new Point(52.411909f, 13.7335792f), new Point(52.411771f, 13.7337782f), new Point(52.4114891f, 13.7339052f),
new Point(52.4111301f, 13.7340221f), new Point(52.4109631f, 13.7341331f), new Point(52.4108291f, 13.7343561f),
new Point(52.4105432f, 13.735059f), new Point(52.4102992f, 13.7357989f), new Point(52.4101232f, 13.7363268f),
new Point(52.4100473f, 13.7364648f), new Point(52.4099483f, 13.7366498f), new Point(52.4094673f, 13.7371537f),
new Point(52.4090974f, 13.7374547f), new Point(52.4085514f, 13.7376857f), new Point(52.4078915f, 13.7382486f),
new Point(52.4078045f, 13.7381686f), new Point(52.4074621f, 13.7380396f), new Point(52.4073401f, 13.7379836f),
new Point(52.4071371f, 13.7378997f), new Point(52.4070381f, 13.7378807f), new Point(52.4068931f, 13.7378027f),
new Point(52.4067101f, 13.7376627f), new Point(52.4066181f, 13.7373338f), new Point(52.4065231f, 13.7367838f),
new Point(52.4064202f, 13.7363809f), new Point(52.4060652f, 13.7352311f), new Point(52.4047383f, 13.7344872f),
new Point(52.4036624f, 13.7339733f), new Point(52.4031735f, 13.7339454f), new Point(52.4025826f, 13.7340294f),
new Point(52.4022356f, 13.7340004f), new Point(52.4019986f, 13.7338394f), new Point(52.4015797f, 13.7333705f),
new Point(52.4012357f, 13.7327696f), new Point(52.4010527f, 13.7323866f), new Point(52.4006178f, 13.7316988f),
new Point(52.4004768f, 13.7314988f), new Point(52.4002438f, 13.7313928f), new Point(52.4000648f, 13.7311779f),
new Point(52.3999958f, 13.7309769f), new Point(52.3999618f, 13.7308669f), new Point(52.3999238f, 13.7307519f),
new Point(52.3996489f, 13.7298811f), new Point(52.3996948f, 13.7297151f), new Point(52.3998628f, 13.7295821f),
new Point(52.3999968f, 13.7295331f), new Point(52.4000838f, 13.7293411f), new Point(52.3999968f, 13.7291482f),
new Point(52.3998478f, 13.7290332f), new Point(52.3997448f, 13.7287972f), new Point(52.3997368f, 13.7285223f),
new Point(52.3997638f, 13.7282093f), new Point(52.3998738f, 13.7279323f), new Point(52.3999968f, 13.7277574f),
new Point(52.4000838f, 13.7276364f), new Point(52.4000838f, 13.7275424f), new Point(52.3999968f, 13.7274374f),
new Point(52.3998938f, 13.7273084f), new Point(52.3995918f, 13.7266346f), new Point(52.3993819f, 13.7262716f),
new Point(52.3993788f, 13.7259027f), new Point(52.3994658f, 13.7255897f), new Point(52.3994618f, 13.7252408f),
new Point(52.3993818f, 13.7250598f), new Point(52.3990349f, 13.7247549f), new Point(52.3988979f, 13.7244989f),
new Point(52.3988179f, 13.7242059f), new Point(52.3985579f, 13.7234961f), new Point(52.3983409f, 13.7231431f),
new Point(52.3982529f, 13.7228102f), new Point(52.3982759f, 13.7225952f), new Point(52.3984629f, 13.7219283f),
new Point(52.3986959f, 13.7211434f), new Point(52.3989468f, 13.7202765f), new Point(52.3990238f, 13.7198896f),
new Point(52.3989738f, 13.7194137f), new Point(52.3988708f, 13.7190497f), new Point(52.3988328f, 13.7183328f),
new Point(52.3988438f, 13.7181479f), new Point(52.3989738f, 13.7177789f), new Point(52.3991378f, 13.7175549f),
new Point(52.3993558f, 13.71744f), new Point(52.3994778f, 13.71731f), new Point(52.3997759f, 13.7169361f),
new Point(52.3996837f, 13.7163331f), new Point(52.3996037f, 13.7159122f), new Point(52.3993398f, 13.7154413f),
new Point(52.3989438f, 13.7143664f), new Point(52.3987258f, 13.7140765f), new Point(52.3985658f, 13.7139445f),
new Point(52.3982459f, 13.7136965f), new Point(52.3981269f, 13.7136196f), new Point(52.3980549f, 13.7134296f),
new Point(52.3979629f, 13.7130646f), new Point(52.3979369f, 13.7129657f), new Point(52.3979139f, 13.7128887f),
new Point(52.3978409f, 13.7126147f), new Point(52.3977989f, 13.7124677f), new Point(52.3976769f, 13.7120838f),
new Point(52.3975439f, 13.7119138f), new Point(52.3974439f, 13.7117659f), new Point(52.3973569f, 13.7115689f),
new Point(52.3972879f, 13.7113139f), new Point(52.3972f, 13.711099f), new Point(52.397078f, 13.711005f),
new Point(52.396582f, 13.7105641f), new Point(52.396506f, 13.7104201f), new Point(52.396365f, 13.7101601f),
new Point(52.396296f, 13.7099782f), new Point(52.39633f, 13.7096712f), new Point(52.3953092f, 13.7087799f),
new Point(52.3952358f, 13.7085654f), new Point(52.395173f, 13.7083079f), new Point(52.3951206f, 13.707956f),
new Point(52.3950944f, 13.7076985f), new Point(52.3950839f, 13.7073208f), new Point(52.3950839f, 13.7070805f),
new Point(52.3950735f, 13.7069518f), new Point(52.3950003f, 13.7065995f), new Point(52.3948498f, 13.7062455f),
new Point(52.3946403f, 13.7060523f), new Point(52.3940969f, 13.7055159f), new Point(52.393632f, 13.7049258f),
new Point(52.393357f, 13.7045289f), new Point(52.3932916f, 13.704089f), new Point(52.3933212f, 13.703616f),
new Point(52.3933047f, 13.7026835f), new Point(52.393379f, 13.7026732f), new Point(52.3933736f, 13.7025173f),
new Point(52.3932531f, 13.7021826f), new Point(52.392986f, 13.7017363f), new Point(52.3929074f, 13.7015989f),
new Point(52.3928446f, 13.7016762f), new Point(52.3926874f, 13.7015389f), new Point(52.3925565f, 13.7014702f),
new Point(52.3924098f, 13.7014444f), new Point(52.3923051f, 13.7014444f), new Point(52.3921689f, 13.7013929f),
new Point(52.3921327f, 13.7009991f), new Point(52.3899786f, 13.6969713f), new Point(52.3895597f, 13.6964034f),
new Point(52.3893142f, 13.6963976f), new Point(52.3891099f, 13.6959341f), new Point(52.3888584f, 13.6954449f),
new Point(52.3884079f, 13.694887f), new Point(52.3878632f, 13.694269f), new Point(52.3870326f, 13.6931256f),
new Point(52.3866555f, 13.6926064f), new Point(52.3857792f, 13.6913253f), new Point(52.385601f, 13.6910764f),
new Point(52.3854648f, 13.6908533f), new Point(52.385381f, 13.6905614f), new Point(52.3853024f, 13.6902267f),
new Point(52.3852553f, 13.6899435f), new Point(52.3852186f, 13.689686f), new Point(52.3851977f, 13.6894199f),
new Point(52.3852256f, 13.689134f), new Point(52.3853877f, 13.6887698f), new Point(52.3855975f, 13.6884559f),
new Point(52.3859014f, 13.6881469f), new Point(52.3856604f, 13.6879177f), new Point(52.3854823f, 13.6877889f),
new Point(52.3850317f, 13.6875744f), new Point(52.3851679f, 13.6867332f), new Point(52.3842992f, 13.686431f),
new Point(52.3839932f, 13.6861981f), new Point(52.3839402f, 13.686475f), new Point(52.3836732f, 13.686927f),
new Point(52.3833223f, 13.6875199f), new Point(52.3831583f, 13.6879268f), new Point(52.3831163f, 13.6882768f),
new Point(52.3834063f, 13.6895946f), new Point(52.3832303f, 13.6900735f), new Point(52.3826314f, 13.6912783f),
new Point(52.3814186f, 13.693911f), new Point(52.3813576f, 13.6940789f), new Point(52.3811666f, 13.6946129f),
new Point(52.3811366f, 13.6950168f), new Point(52.3812086f, 13.6955957f), new Point(52.3815716f, 13.6983873f),
new Point(52.3815486f, 13.6984663f), new Point(52.3815176f, 13.6985713f), new Point(52.3815406f, 13.6986632f),
new Point(52.3815066f, 13.6987922f), new Point(52.3813536f, 13.6987922f), new Point(52.377596f, 13.6971676f),
new Point(52.377612f, 13.6973495f), new Point(52.3778061f, 13.6992767f), new Point(52.37765f, 13.6995082f),
new Point(52.3775621f, 13.6998602f), new Point(52.3775701f, 13.6999991f), new Point(52.3775851f, 13.7002621f),
new Point(52.3773901f, 13.7005061f), new Point(52.3772071f, 13.7005641f), new Point(52.3758452f, 13.6999992f),
new Point(52.3756053f, 13.6998992f), new Point(52.3748384f, 13.6990713f), new Point(52.3744606f, 13.6988346f),
new Point(52.3743614f, 13.6987724f), new Point(52.3741284f, 13.6985984f), new Point(52.3734115f, 13.6979566f),
new Point(52.3720996f, 13.6967058f), new Point(52.3717637f, 13.6963848f), new Point(52.3714167f, 13.6960539f),
new Point(52.3705778f, 13.695235f), new Point(52.3699599f, 13.6943212f), new Point(52.3696469f, 13.6938583f),
new Point(52.3693719f, 13.6933873f), new Point(52.368979f, 13.6930444f), new Point(52.368823f, 13.6929564f),
new Point(52.368708f, 13.6929754f), new Point(52.368216f, 13.6933144f), new Point(52.3680251f, 13.6933004f),
new Point(52.3679261f, 13.6932274f), new Point(52.3678691f, 13.6929914f), new Point(52.3678151f, 13.6919456f),
new Point(52.3677011f, 13.6915257f), new Point(52.3676211f, 13.6913977f), new Point(52.3673691f, 13.6921926f),
new Point(52.3673041f, 13.6923406f), new Point(52.3671442f, 13.6922866f), new Point(52.3671132f, 13.6922156f),
new Point(52.3671212f, 13.6920126f), new Point(52.3673691f, 13.6907608f), new Point(52.3676321f, 13.6905008f),
new Point(52.3677541f, 13.6903158f), new Point(52.3677581f, 13.6901689f), new Point(52.3677098f, 13.6900665f),
new Point(52.3675261f, 13.689677f), new Point(52.3673731f, 13.689203f), new Point(52.3672431f, 13.6885641f),
new Point(52.3671971f, 13.6878312f), new Point(52.3672471f, 13.6874643f), new Point(52.3674841f, 13.6869284f),
new Point(52.367739f, 13.6865024f), new Point(52.3687809f, 13.6846117f), new Point(52.3688949f, 13.6837998f),
new Point(52.3693418f, 13.68258f), new Point(52.3694028f, 13.682174f), new Point(52.3693678f, 13.6818641f),
new Point(52.3692998f, 13.6802843f), new Point(52.3690898f, 13.6789135f), new Point(52.3689258f, 13.6784566f),
new Point(52.3682279f, 13.6771648f), new Point(52.3677849f, 13.676201f), new Point(52.367427f, 13.6751591f),
new Point(52.367129f, 13.6740103f), new Point(52.366828f, 13.6723456f), new Point(52.366652f, 13.6717407f),
new Point(52.366446f, 13.6714687f), new Point(52.3659421f, 13.6710558f), new Point(52.3655991f, 13.6708069f),
new Point(52.3649502f, 13.6704519f), new Point(52.3648212f, 13.6703249f), new Point(52.3646532f, 13.669961f),
new Point(52.3644092f, 13.6691581f), new Point(52.3641303f, 13.6687222f), new Point(52.3632954f, 13.6678204f),
new Point(52.3628184f, 13.6673884f), new Point(52.3622655f, 13.6669575f), new Point(52.3616015f, 13.6666416f),
new Point(52.3610136f, 13.6664856f), new Point(52.3602887f, 13.6663907f), new Point(52.3598577f, 13.6661957f),
new Point(52.3596138f, 13.6661277f), new Point(52.3592858f, 13.6661707f), new Point(52.3585379f, 13.6664037f),
new Point(52.3582029f, 13.6664477f), new Point(52.3580959f, 13.6663487f), new Point(52.3579579f, 13.6652939f),
new Point(52.3579089f, 13.6651409f), new Point(52.3577519f, 13.664638f), new Point(52.35742f, 13.6640381f),
new Point(52.357195f, 13.6637491f), new Point(52.35689f, 13.6634422f), new Point(52.3565051f, 13.6631382f),
new Point(52.3561771f, 13.6629053f), new Point(52.3555592f, 13.6626433f), new Point(52.3551122f, 13.6626703f),
new Point(52.3548303f, 13.6626364f), new Point(52.3539873f, 13.6619745f), new Point(52.3538464f, 13.6617445f),
new Point(52.3537124f, 13.6615206f), new Point(52.3536444f, 13.6613196f), new Point(52.3533924f, 13.6603887f),
new Point(52.3531514f, 13.6598248f), new Point(52.3529234f, 13.6594979f), new Point(52.3526865f, 13.6593559f),
new Point(52.3523625f, 13.6592519f), new Point(52.3521375f, 13.658999f), new Point(52.3518016f, 13.6577392f),
new Point(52.3516526f, 13.6574482f), new Point(52.3514506f, 13.6572863f), new Point(52.3499018f, 13.6570063f),
new Point(52.3496118f, 13.6570113f), new Point(52.3493408f, 13.6569244f), new Point(52.3483569f, 13.6561885f),
new Point(52.347609f, 13.6561855f), new Point(52.347414f, 13.6560805f), new Point(52.3470791f, 13.6557746f),
new Point(52.3456402f, 13.6538009f), new Point(52.3450643f, 13.653316f), new Point(52.3440154f, 13.6526381f),
new Point(52.3437374f, 13.6524982f), new Point(52.3432185f, 13.6520662f), new Point(52.3426495f, 13.6515093f),
new Point(52.3425735f, 13.6515053f), new Point(52.3425315f, 13.6514374f), new Point(52.3424365f, 13.6513834f),
new Point(52.3419556f, 13.6514114f), new Point(52.3402658f, 13.6517744f), new Point(52.3398728f, 13.6517454f),
new Point(52.3397239f, 13.6516564f), new Point(52.3396589f, 13.6516194f), new Point(52.3393503f, 13.6513658f),
new Point(52.3393119f, 13.6513325f), new Point(52.3388119f, 13.6505536f), new Point(52.338355f, 13.6494628f),
new Point(52.338149f, 13.6487329f), new Point(52.338076f, 13.6482569f), new Point(52.338095f, 13.647816f),
new Point(52.3385299f, 13.6459163f), new Point(52.3386939f, 13.6455653f), new Point(52.3389729f, 13.6452824f),
new Point(52.3396978f, 13.6446645f), new Point(52.3397508f, 13.6445365f), new Point(52.3397428f, 13.6432347f),
new Point(52.3397618f, 13.6428107f), new Point(52.3398268f, 13.6426817f), new Point(52.3398918f, 13.6426208f),
new Point(52.3402167f, 13.6423238f), new Point(52.3408076f, 13.6418728f), new Point(52.3409986f, 13.6416559f),
new Point(52.3411856f, 13.6414439f), new Point(52.3421155f, 13.6398841f), new Point(52.3434243f, 13.6382243f),
new Point(52.3436573f, 13.6380174f), new Point(52.3442602f, 13.6374734f), new Point(52.3452741f, 13.6368675f),
new Point(52.346022f, 13.6364875f), new Point(52.346491f, 13.6363105f), new Point(52.3469529f, 13.6363405f),
new Point(52.3479638f, 13.6365945f), new Point(52.3499246f, 13.6365934f), new Point(52.3514204f, 13.6368213f),
new Point(52.3519803f, 13.6368643f), new Point(52.3533162f, 13.6368763f), new Point(52.3563409f, 13.6371472f),
new Point(52.3580037f, 13.6375371f), new Point(52.3586376f, 13.637819f), new Point(52.3591755f, 13.638101f),
new Point(52.3600415f, 13.6387798f), new Point(52.3601594f, 13.6388718f), new Point(52.3606324f, 13.6393757f),
new Point(52.3610943f, 13.6399366f), new Point(52.3624902f, 13.6416913f), new Point(52.3640541f, 13.6442309f),
new Point(52.364199f, 13.6445399f), new Point(52.364565f, 13.6451028f), new Point(52.3651219f, 13.6460826f),
new Point(52.3654389f, 13.6465355f), new Point(52.3657559f, 13.6468425f), new Point(52.3662898f, 13.6472544f),
new Point(52.3667288f, 13.6474834f), new Point(52.3676177f, 13.6474663f), new Point(52.3681746f, 13.6472913f),
new Point(52.3686436f, 13.6470064f), new Point(52.3694485f, 13.6468664f), new Point(52.3697684f, 13.6467814f),
new Point(52.3700664f, 13.6467224f), new Point(52.3702264f, 13.6439268f), new Point(52.3703023f, 13.6435779f),
new Point(52.3703713f, 13.6432789f), new Point(52.3705572f, 13.6424314f), new Point(52.3718084f, 13.6431449f),
new Point(52.3725324f, 13.6433599f), new Point(52.3732698f, 13.6433087f), new Point(52.3757951f, 13.6431974f),
new Point(52.3772703f, 13.6430744f), new Point(52.3776287f, 13.6423594f), new Point(52.3773021f, 13.6392119f),
new Point(52.3768047f, 13.6356209f), new Point(52.376488f, 13.6332965f), new Point(52.3779524f, 13.6318979f),
new Point(52.3797308f, 13.6302743f), new Point(52.3809909f, 13.6292313f), new Point(52.3814705f, 13.6286891f),
new Point(52.3814244f, 13.6285445f), new Point(52.381438f, 13.6285269f), new Point(52.381255f, 13.627736f),
new Point(52.3812596f, 13.6277314f), new Point(52.3811715f, 13.6277522f), new Point(52.3808599f, 13.6267758f),
new Point(52.3785474f, 13.6201599f), new Point(52.3766327f, 13.6146824f), new Point(52.3758624f, 13.6123679f),
new Point(52.3757075f, 13.6124577f), new Point(52.3756767f, 13.6123672f), new Point(52.375657f, 13.6123181f),
new Point(52.3750254f, 13.6106861f), new Point(52.3746715f, 13.6097777f), new Point(52.3745116f, 13.60915f),
new Point(52.3743109f, 13.6086428f), new Point(52.3738693f, 13.6072351f), new Point(52.3736791f, 13.6063175f),
new Point(52.3735228f, 13.6060395f), new Point(52.3734337f, 13.605891f), new Point(52.3735329f, 13.6057585f),
new Point(52.3748345f, 13.6065833f), new Point(52.3750365f, 13.6066173f), new Point(52.3751205f, 13.6066403f),
new Point(52.3754564f, 13.6067363f), new Point(52.3757384f, 13.6067313f), new Point(52.3763753f, 13.6065563f),
new Point(52.3766773f, 13.6064983f), new Point(52.3775741f, 13.6058279f), new Point(52.3777222f, 13.6057144f),
new Point(52.3781111f, 13.6054094f), new Point(52.3781881f, 13.6054074f), new Point(52.3784621f, 13.6060083f),
new Point(52.3786641f, 13.6062993f), new Point(52.378958f, 13.6063493f), new Point(52.3791546f, 13.6063241f),
new Point(52.379386f, 13.6062883f), new Point(52.3796979f, 13.6060823f), new Point(52.3801219f, 13.6058743f),
new Point(52.3807818f, 13.6052574f), new Point(52.3811368f, 13.6048285f), new Point(52.3815067f, 13.6041985f),
new Point(52.3818847f, 13.6037346f), new Point(52.3822196f, 13.6034536f), new Point(52.3824376f, 13.6033217f),
new Point(52.3829335f, 13.6030207f), new Point(52.3835365f, 13.6020018f), new Point(52.3838334f, 13.6015929f),
new Point(52.3841884f, 13.60076f), new Point(52.3843214f, 13.600666f), new Point(52.3847033f, 13.6002201f),
new Point(52.3848673f, 13.5999991f), new Point(52.3849243f, 13.5999231f), new Point(52.3853712f, 13.5995671f),
new Point(52.3853932f, 13.5992732f), new Point(52.3859242f, 13.5963656f), new Point(52.3861371f, 13.5960307f),
new Point(52.387251f, 13.5949488f), new Point(52.387591f, 13.5949248f), new Point(52.3881289f, 13.5952667f),
new Point(52.3884909f, 13.5953887f), new Point(52.3886938f, 13.5953297f), new Point(52.3888688f, 13.5951817f),
new Point(52.3889488f, 13.5950137f), new Point(52.3889448f, 13.5947568f), new Point(52.3889068f, 13.5945558f),
new Point(52.3890448f, 13.5943328f), new Point(52.3893987f, 13.5943278f), new Point(52.3896047f, 13.5940319f),
new Point(52.3899527f, 13.5937869f), new Point(52.3902846f, 13.5937449f), new Point(52.3920504f, 13.5942498f),
new Point(52.3923864f, 13.5942448f), new Point(52.3925884f, 13.5941318f), new Point(52.3935453f, 13.5929449f),
new Point(52.3937364f, 13.592744f), new Point(52.3935263f, 13.5918711f), new Point(52.3934963f, 13.5917301f),
new Point(52.3930573f, 13.5897544f), new Point(52.3925003f, 13.5880207f), new Point(52.3923363f, 13.5874318f),
new Point(52.3918214f, 13.5851422f), new Point(52.3912264f, 13.5822336f), new Point(52.3909024f, 13.5804909f),
new Point(52.3902465f, 13.5762576f), new Point(52.3901355f, 13.5756157f), new Point(52.3900975f, 13.5753607f),
new Point(52.3899945f, 13.5745328f), new Point(52.3892045f, 13.5707764f), new Point(52.3891666f, 13.5706044f),
new Point(52.3885946f, 13.5675499f), new Point(52.3884076f, 13.5663761f), new Point(52.3882666f, 13.5652363f),
new Point(52.3881666f, 13.5644514f), new Point(52.3881436f, 13.5642494f), new Point(52.3881436f, 13.5641644f),
new Point(52.3881406f, 13.5640545f), new Point(52.3881136f, 13.5637265f), new Point(52.3881176f, 13.5632766f),
new Point(52.3881636f, 13.5616368f), new Point(52.3880826f, 13.5615818f), new Point(52.3880946f, 13.5613439f),
new Point(52.3881446f, 13.5599541f), new Point(52.3881666f, 13.5593382f), new Point(52.3881936f, 13.5588252f),
new Point(52.3881976f, 13.5586783f), new Point(52.3882625f, 13.5570355f), new Point(52.3884765f, 13.5513544f),
new Point(52.3889143f, 13.5354818f), new Point(52.390959f, 13.5347525f), new Point(52.3910696f, 13.534713f),
new Point(52.3931612f, 13.535182f), new Point(52.3949403f, 13.5355456f), new Point(52.395034f, 13.5355883f),
new Point(52.3972971f, 13.5366185f), new Point(52.3977663f, 13.5363643f), new Point(52.3979957f, 13.5373301f),
new Point(52.3986807f, 13.5373537f), new Point(52.3992655f, 13.5378182f), new Point(52.3998818f, 13.5380957f),
new Point(52.400494f, 13.5382888f), new Point(52.4003735f, 13.5380742f), new Point(52.3999158f, 13.5371211f),
new Point(52.399848f, 13.5366663f), new Point(52.399806f, 13.5365353f), new Point(52.3996571f, 13.5360834f),
new Point(52.3992941f, 13.5349816f), new Point(52.3992451f, 13.5348336f), new Point(52.3992181f, 13.5347556f),
new Point(52.3989131f, 13.5338058f), new Point(52.3988791f, 13.5337018f), new Point(52.3985621f, 13.5329089f),
new Point(52.3981382f, 13.5318411f), new Point(52.3978332f, 13.5310942f), new Point(52.3976852f, 13.5307313f),
new Point(52.3974712f, 13.5302104f), new Point(52.3972273f, 13.5296135f), new Point(52.3974592f, 13.5291855f),
new Point(52.3975432f, 13.5290325f), new Point(52.3976542f, 13.5288316f), new Point(52.3978372f, 13.5285006f),
new Point(52.3978872f, 13.5284006f), new Point(52.3980662f, 13.5280607f), new Point(52.3981502f, 13.5279017f),
new Point(52.3982491f, 13.5277107f), new Point(52.3983411f, 13.5275137f), new Point(52.3984092f, 13.5273688f),
new Point(52.3986651f, 13.5268238f), new Point(52.398955f, 13.5260849f), new Point(52.399096f, 13.525443f),
new Point(52.399287f, 13.5246851f), new Point(52.399428f, 13.5242072f), new Point(52.3996379f, 13.5235633f),
new Point(52.3998739f, 13.5228334f), new Point(52.3999469f, 13.5226054f), new Point(52.4002938f, 13.5213466f),
new Point(52.4004238f, 13.5208787f), new Point(52.4005148f, 13.5207677f), new Point(52.4005648f, 13.5207007f),
new Point(52.4006148f, 13.5206267f), new Point(52.4008707f, 13.519845f), new Point(52.4009045f, 13.5197417f),
new Point(52.4009578f, 13.5195789f), new Point(52.4015987f, 13.5175752f), new Point(52.4018996f, 13.5161854f),
new Point(52.4015987f, 13.5156105f), new Point(52.4015257f, 13.5154655f), new Point(52.4011107f, 13.5141597f),
new Point(52.4010877f, 13.5140417f), new Point(52.4010527f, 13.5139327f), new Point(52.4005377f, 13.5107602f),
new Point(52.3999968f, 13.5072218f), new Point(52.3998018f, 13.505934f), new Point(52.3994168f, 13.5023075f),
new Point(52.3993818f, 13.5019976f), new Point(52.3992528f, 13.5007898f), new Point(52.3991188f, 13.4999989f),
new Point(52.3988708f, 13.4985161f), new Point(52.3987988f, 13.4974723f), new Point(52.3987908f, 13.4973553f),
new Point(52.3985548f, 13.4950627f), new Point(52.3980928f, 13.4924611f), new Point(52.3977499f, 13.4905494f),
new Point(52.3977339f, 13.4901124f), new Point(52.3974179f, 13.4866809f), new Point(52.3974249f, 13.486372f),
new Point(52.3969639f, 13.4836194f), new Point(52.3966209f, 13.4823376f), new Point(52.395953f, 13.479867f),
new Point(52.3990426f, 13.479165f), new Point(52.3991536f, 13.479152f), new Point(52.3998745f, 13.479063f),
new Point(52.3999965f, 13.479009f), new Point(52.4004194f, 13.4788251f), new Point(52.4013883f, 13.4782861f),
new Point(52.4014704f, 13.4782521f), new Point(52.4027582f, 13.4777192f), new Point(52.4030901f, 13.4777352f),
new Point(52.4035466f, 13.4775403f), new Point(52.40391f, 13.4768663f), new Point(52.4062828f, 13.4756094f),
new Point(52.4086865f, 13.4740766f), new Point(52.4118941f, 13.4722448f), new Point(52.4119631f, 13.4722058f),
new Point(52.4137939f, 13.4710229f), new Point(52.4168805f, 13.4693931f), new Point(52.4181584f, 13.4688022f),
new Point(52.4190853f, 13.4683472f), new Point(52.4192262f, 13.4682612f), new Point(52.4198672f, 13.4678693f),
new Point(52.4202371f, 13.4663765f), new Point(52.420729f, 13.4643808f), new Point(52.420813f, 13.4640158f),
new Point(52.420836f, 13.4637119f), new Point(52.420897f, 13.4635949f), new Point(52.420859f, 13.4633619f),
new Point(52.420519f, 13.4603484f), new Point(52.4199183f, 13.4573425f), new Point(52.4197761f, 13.456631f),
new Point(52.4193291f, 13.4550352f), new Point(52.4188371f, 13.4533655f), new Point(52.4184553f, 13.4520657f),
new Point(52.4176902f, 13.4495621f), new Point(52.4175403f, 13.4495381f), new Point(52.4173803f, 13.4489802f),
new Point(52.4172503f, 13.4485083f), new Point(52.4171283f, 13.4479343f), new Point(52.4164573f, 13.4458757f),
new Point(52.4163194f, 13.4457677f), new Point(52.4162517f, 13.4455511f), new Point(52.4157857f, 13.4438766f),
new Point(52.4153687f, 13.4425438f), new Point(52.4148545f, 13.4409845f), new Point(52.4144845f, 13.4392587f),
new Point(52.4144425f, 13.4388868f), new Point(52.4144275f, 13.4387398f), new Point(52.4125467f, 13.4320939f),
new Point(52.4122607f, 13.4304461f), new Point(52.4122687f, 13.4302391f), new Point(52.4121467f, 13.4295063f),
new Point(52.4118717f, 13.4278135f), new Point(52.4114977f, 13.4258908f), new Point(52.4110938f, 13.4241271f),
new Point(52.4105288f, 13.4218405f), new Point(52.4102538f, 13.4200437f), new Point(52.4102118f, 13.4197338f),
new Point(52.4101749f, 13.4195922f), new Point(52.4099948f, 13.4187799f), new Point(52.4091819f, 13.418461f),
new Point(52.408732f, 13.418436f), new Point(52.4072061f, 13.418623f), new Point(52.4050894f, 13.419289f),
new Point(52.4042725f, 13.4196209f), new Point(52.4032656f, 13.4200789f), new Point(52.399996f, 13.4215648f),
new Point(52.399752f, 13.4216757f), new Point(52.3950526f, 13.4238125f), new Point(52.3916499f, 13.4253514f),
new Point(52.391558f, 13.4253934f), new Point(52.3885443f, 13.4266603f), new Point(52.3878814f, 13.4269982f),
new Point(52.3863706f, 13.4274282f), new Point(52.3857526f, 13.4274572f), new Point(52.3855727f, 13.4273282f),
new Point(52.3851417f, 13.4270183f), new Point(52.3850427f, 13.4269463f), new Point(52.383983f, 13.4262054f),
new Point(52.3813161f, 13.4243408f), new Point(52.3778715f, 13.4219312f), new Point(52.3763296f, 13.4209624f),
new Point(52.3761269f, 13.4208338f), new Point(52.3762598f, 13.4178753f), new Point(52.3762638f, 13.4177053f),
new Point(52.3764397f, 13.4127421f), new Point(52.3768207f, 13.412842f), new Point(52.3766417f, 13.4105104f),
new Point(52.3765687f, 13.4098385f), new Point(52.3768057f, 13.4076568f), new Point(52.3769046f, 13.406624f),
new Point(52.3769656f, 13.4046723f), new Point(52.3770226f, 13.4040944f), new Point(52.3771986f, 13.4022866f),
new Point(52.3773395f, 13.4008548f), new Point(52.3773625f, 13.4006059f), new Point(52.3774115f, 13.400005f),
new Point(52.3775265f, 13.3983772f), new Point(52.3777444f, 13.3919242f), new Point(52.3777438f, 13.3916463f),
new Point(52.3778431f, 13.3884202f), new Point(52.3786524f, 13.3884508f), new Point(52.3786973f, 13.3882697f),
new Point(52.3792582f, 13.3881027f), new Point(52.3800508f, 13.3881492f), new Point(52.3800861f, 13.3881177f),
new Point(52.380914f, 13.3882657f), new Point(52.3817229f, 13.3881187f), new Point(52.3822069f, 13.3882276f),
new Point(52.3823479f, 13.3882606f), new Point(52.3842826f, 13.3879826f), new Point(52.3861824f, 13.3876726f),
new Point(52.3867124f, 13.3875856f), new Point(52.3885812f, 13.3873016f), new Point(52.3884971f, 13.3856249f),
new Point(52.3883491f, 13.3825713f), new Point(52.3883411f, 13.3824184f), new Point(52.3883341f, 13.3822729f),
new Point(52.3881564f, 13.3786594f), new Point(52.3881439f, 13.3783976f), new Point(52.3881399f, 13.3769078f),
new Point(52.3881559f, 13.3762139f), new Point(52.3881732f, 13.3754891f), new Point(52.3881859f, 13.3749561f),
new Point(52.3884648f, 13.3704488f), new Point(52.3937102f, 13.3721794f), new Point(52.3949911f, 13.3687809f),
new Point(52.3961055f, 13.3658288f), new Point(52.3965858f, 13.3645565f), new Point(52.3970708f, 13.3629437f),
new Point(52.3977497f, 13.3613029f), new Point(52.3978987f, 13.360924f), new Point(52.3984816f, 13.3594172f),
new Point(52.3986576f, 13.3590923f), new Point(52.3989135f, 13.3586313f), new Point(52.3993865f, 13.3576804f),
new Point(52.3999964f, 13.3564536f), new Point(52.4010643f, 13.3543149f), new Point(52.4020141f, 13.3527681f),
new Point(52.4020521f, 13.3526731f), new Point(52.402949f, 13.3507824f), new Point(52.4038949f, 13.3492106f),
new Point(52.4058406f, 13.3460631f), new Point(52.4059016f, 13.3459631f), new Point(52.4076754f, 13.3430865f),
new Point(52.4106851f, 13.3431964f), new Point(52.411673f, 13.3431324f), new Point(52.411559f, 13.3428514f),
new Point(52.4114762f, 13.3426461f), new Point(52.411238f, 13.3420555f), new Point(52.411036f, 13.3418176f),
new Point(52.4087592f, 13.3357286f), new Point(52.4077323f, 13.33297f), new Point(52.4072564f, 13.3316982f),
new Point(52.4057145f, 13.3274129f), new Point(52.4042576f, 13.3233815f), new Point(52.4024268f, 13.3185023f),
new Point(52.400538f, 13.3139011f), new Point(52.399996f, 13.3131612f), new Point(52.3993002f, 13.3120933f),
new Point(52.399996f, 13.3112705f), new Point(52.400096f, 13.3111945f), new Point(52.4016028f, 13.3095787f),
new Point(52.4044025f, 13.3069f), new Point(52.4044824f, 13.306823f), new Point(52.4059593f, 13.3052092f),
new Point(52.4086289f, 13.3022896f), new Point(52.4095868f, 13.3012108f), new Point(52.4100868f, 13.3006618f),
new Point(52.4106967f, 13.2999989f), new Point(52.4118645f, 13.2987271f), new Point(52.4119895f, 13.2985881f),
new Point(52.4144739f, 13.2959749f), new Point(52.4145072f, 13.2960284f), new Point(52.4145492f, 13.2963494f),
new Point(52.4146755f, 13.2966142f), new Point(52.4147403f, 13.2967379f), new Point(52.4150152f, 13.2970133f),
new Point(52.4154651f, 13.2971692f), new Point(52.4157564f, 13.2971321f), new Point(52.4160647f, 13.2969492f),
new Point(52.4162522f, 13.2967701f), new Point(52.4161669f, 13.2965593f), new Point(52.4145572f, 13.2933147f),
new Point(52.4118139f, 13.2884334f), new Point(52.4117115f, 13.2883447f), new Point(52.4110935f, 13.2871939f),
new Point(52.4090597f, 13.2835295f), new Point(52.4080338f, 13.2816778f), new Point(52.4076219f, 13.2808219f),
new Point(52.406302f, 13.2780853f), new Point(52.4052841f, 13.2759747f), new Point(52.4051771f, 13.2757077f),
new Point(52.4051581f, 13.2756157f), new Point(52.4051001f, 13.2753838f), new Point(52.4049751f, 13.2749379f),
new Point(52.4045931f, 13.2731451f), new Point(52.4045931f, 13.2728132f), new Point(52.4045361f, 13.2726122f),
new Point(52.4043992f, 13.2723953f), new Point(52.4043302f, 13.2721753f), new Point(52.4042002f, 13.2705435f),
new Point(52.4042152f, 13.2697337f), new Point(52.4042841f, 13.2692617f), new Point(52.4042841f, 13.2690795f),
new Point(52.4042841f, 13.2688968f), new Point(52.4042801f, 13.2686328f), new Point(52.4042761f, 13.2684839f),
new Point(52.4043031f, 13.2666631f), new Point(52.4043181f, 13.2662432f), new Point(52.404792f, 13.2643635f),
new Point(52.405055f, 13.2634566f), new Point(52.4059399f, 13.2611269f), new Point(52.4061568f, 13.2602071f),
new Point(52.4063098f, 13.2592682f), new Point(52.4063828f, 13.2584033f), new Point(52.4063978f, 13.2570805f),
new Point(52.4063898f, 13.2569615f), new Point(52.4063208f, 13.2556098f), new Point(52.4062568f, 13.2549099f),
new Point(52.4062188f, 13.2545019f), new Point(52.4062028f, 13.2543649f), new Point(52.4060048f, 13.2529702f),
new Point(52.4057648f, 13.2519303f), new Point(52.4055238f, 13.2511424f), new Point(52.4049859f, 13.2496687f),
new Point(52.4051159f, 13.2496287f), new Point(52.4053828f, 13.2495907f), new Point(52.4075171f, 13.249271f),
new Point(52.4078896f, 13.2492347f), new Point(52.4084045f, 13.2488147f), new Point(52.4088544f, 13.2490197f),
new Point(52.4114332f, 13.2490776f), new Point(52.4117151f, 13.2490826f), new Point(52.4140608f, 13.2484708f),
new Point(52.4156637f, 13.2479427f), new Point(52.4158047f, 13.2479877f), new Point(52.4163806f, 13.2478107f),
new Point(52.4173225f, 13.2475237f), new Point(52.4189173f, 13.2470648f), new Point(52.4199932f, 13.2465848f),
new Point(52.4207671f, 13.2461488f), new Point(52.421126f, 13.2459469f), new Point(52.420977f, 13.2440172f),
new Point(52.42084f, 13.2405437f), new Point(52.420733f, 13.2379311f), new Point(52.420737f, 13.2377671f),
new Point(52.420779f, 13.2358144f), new Point(52.4206f, 13.2346226f), new Point(52.420577f, 13.2344836f),
new Point(52.42026f, 13.2331558f), new Point(52.420287f, 13.232147f), new Point(52.420405f, 13.2296984f),
new Point(52.420493f, 13.2287935f), new Point(52.42052f, 13.2285345f), new Point(52.4206649f, 13.2272637f),
new Point(52.42082f, 13.2264661f), new Point(52.4208236f, 13.2253296f), new Point(52.4207851f, 13.2250795f),
new Point(52.4209176f, 13.225031f), new Point(52.4210189f, 13.2249751f), new Point(52.4208823f, 13.2245661f),
new Point(52.4205154f, 13.223363f), new Point(52.4206178f, 13.2232894f), new Point(52.4202339f, 13.2220285f),
new Point(52.4200539f, 13.2212906f), new Point(52.419772f, 13.2201278f), new Point(52.419345f, 13.2185251f),
new Point(52.419276f, 13.2180411f), new Point(52.419127f, 13.2170103f), new Point(52.418887f, 13.2166474f) };
}

View file

@ -0,0 +1,299 @@
package de.schildbach.pte.util;
/*
* Copyright (C) 1997 Roger Whitney <whitney@cs.sdsu.edu>
*
* This file is part of the San Diego State University Java Library.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* This class implements a characater queue. Yes the JKD does contain a general queue. However that queue operates on
* objects. This queue just handles char elements. Use in IO operations where converting chars to objects will be too
* expensive.
*
* @version 1.0 21 August 1997
* @author Roger Whitney (<a href=mailto:whitney@cs.sdsu.edu>whitney@cs.sdsu.edu</a>)
*/
final public class CharQueue
{
/*
* Class invariant, queueRear is the location the next queue item should be placed If the queue is not empty,
* queueFront is the location of the first item in the queue
*/
private char[] queueElements;
private int queueFront;
private int queueRear;
private int elementCount; // number of elements in the queue
public static final int DEFAULT_QUEUE_SIZE = 256;
public CharQueue(int Size)
{
queueElements = new char[Size];
queueFront = 0;
queueRear = 0;
elementCount = 0;
}
public CharQueue()
{
this(DEFAULT_QUEUE_SIZE);
}
/**
* Returns the current number of locations for chars in queue
*/
public int capacity()
{
return queueElements.length;
}
/**
* Returns true if the queue is empty
*/
public boolean isEmpty()
{
if (elementCount == 0)
return true;
else
return false;
}
/**
* Returns true if the queue is full
*/
public boolean isFull()
{
if (elementCount >= capacity())
return true;
else
return false;
}
/**
* Returns the number of chars in the queue
*/
public int size()
{
return elementCount;
}
/**
* Returns string representation of the queue
*/
@Override
public String toString()
{
StringBuffer queueString = new StringBuffer(elementCount);
if (queueFront < queueRear)
{
queueString.append(queueElements, queueFront, elementCount);
}
else
{
int elementsFromFrontToEnd = capacity() - queueFront;
queueString.append(queueElements, queueFront, elementsFromFrontToEnd);
queueString.append(queueElements, 0, queueRear);
}
return queueString.toString();
}
/**
* Returns the current number of unused locations in the queue
*/
public int unusedCapacity()
{
return capacity() - size();
}
/**
* Removes front char from the queue and returns the char
*/
public char dequeue()
{
char itemRemoved = queueElements[queueFront];
queueFront = (queueFront + 1) % capacity();
elementCount--;
return itemRemoved;
}
/**
* Fills charsRemoved with chars removed from the queue. If charsRemoved is larger than queue then charsRemoved is
* not completely filled
*
* @return actual number of chars put in charsRemoved
*/
public int dequeue(char[] charsRemoved)
{
return dequeue(charsRemoved, 0, charsRemoved.length);
}
/**
* Places chars from queue in charsRemoved starting at charsRemoved[offset]. Will place numCharsRequested into
* charsRemoved if queue has enougth chars.
*
* @return actual number of chars put in charsRemoved
*/
public int dequeue(char[] charsRemoved, int offset, int numCharsRequested)
{
// Don't return more chars than are in the queue
int numCharsToReturn = Math.min(numCharsRequested, elementCount);
int numCharsAtEnd = capacity() - queueFront;
// Are there enough characters after front pointer?
if (numCharsAtEnd >= numCharsToReturn)
{
// arraycopy is about 20 times faster than coping element by element
System.arraycopy(queueElements, queueFront, charsRemoved, offset, numCharsToReturn);
}
else
{
// Handle wrap around
System.arraycopy(queueElements, queueFront, charsRemoved, offset, numCharsAtEnd);
System.arraycopy(queueElements, 0, charsRemoved, offset + numCharsAtEnd, numCharsToReturn - numCharsAtEnd);
}
queueFront = (queueFront + numCharsToReturn) % capacity();
elementCount = elementCount - numCharsToReturn;
return numCharsToReturn;
}
/**
* Returns an array containing all chars in the queue. Afterwards queue is empty.
*/
public char[] dequeueAll()
{
char[] contents = new char[elementCount];
dequeue(contents);
return contents;
}
/**
* Returns the front char from the queue without removing it
*/
public char peek()
{
return queueElements[queueFront];
}
/**
* Adds charToAdd to the end of the queue
*/
public void enqueue(char charToAdd)
{
if (isFull())
grow();
queueElements[queueRear] = charToAdd;
queueRear = (queueRear + 1) % capacity();
elementCount++;
}
/**
* Adds charsToAdd to the end of the queue
*/
public void enqueue(String charsToAdd)
{
enqueue(charsToAdd.toCharArray());
}
/**
* Adds all elements of charsToAdd to the end of the queue
*/
public void enqueue(char[] charsToAdd)
{
enqueue(charsToAdd, 0, charsToAdd.length);
}
/**
* Adds numCharsToAdd elements of charsToAdd, starting with charsToAdd[offset] to the end of the queue
*/
public void enqueue(char[] charsToAdd, int offset, int numCharsToAdd)
{
if (numCharsToAdd > unusedCapacity())
grow(Math.max(numCharsToAdd + 32, capacity() * 2));
// 32 to insure some spare capacity after growing
int numSpacesAtEnd = capacity() - queueRear;
// Are there enough spaces after rear pointer?
if (numSpacesAtEnd >= numCharsToAdd)
{
System.arraycopy(charsToAdd, offset, queueElements, queueRear, numCharsToAdd);
}
else
// Handle wrap around
{
System.arraycopy(charsToAdd, offset, queueElements, queueRear, numSpacesAtEnd);
System.arraycopy(charsToAdd, offset + numSpacesAtEnd, queueElements, 0, numCharsToAdd - numSpacesAtEnd);
}
queueRear = (queueRear + numCharsToAdd) % capacity();
elementCount = elementCount + numCharsToAdd;
}
/**
* Clears the queue so it has no more elements in it
*/
public void clear()
{
queueFront = 0;
queueRear = 0;
elementCount = 0;
}
/**
* Grows the queue. Growth policy insures amortized cost per insert is O(1)
*/
private void grow()
{
// Doubling queue insures that amortized cost per insert is O(1)
if (capacity() <= 16)
grow(32);
else if (capacity() <= 1024)
grow(capacity() * 2);
else
grow((int) (capacity() * 1.5));
}
/**
* Grows the queue to the given new size
*/
private void grow(int newSize)
{
char[] newQueue = new char[newSize];
if (queueFront < queueRear)
{
System.arraycopy(queueElements, queueFront, newQueue, 0, elementCount);
}
else
{
int elementsFromFrontToEnd = capacity() - queueFront;
System.arraycopy(queueElements, queueFront, newQueue, 0, elementsFromFrontToEnd);
System.arraycopy(queueElements, 0, newQueue, elementsFromFrontToEnd, queueRear);
}
queueElements = newQueue;
queueFront = 0;
queueRear = elementCount;
}
}

View file

@ -0,0 +1,466 @@
/*
* Copyright 2010, 2011 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.schildbach.pte.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import de.schildbach.pte.exception.UnexpectedRedirectException;
/**
* @author Andreas Schildbach
*/
public final class ParserUtils
{
private static final String SCRAPE_USER_AGENT = "Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0";
private static final String SCRAPE_ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
private static final int SCRAPE_INITIAL_CAPACITY = 4096;
private static final int SCRAPE_CONNECT_TIMEOUT = 5000;
private static final int SCRAPE_READ_TIMEOUT = 15000;
private static final String SCRAPE_DEFAULT_ENCODING = "ISO-8859-1";
private static final int SCRAPE_PAGE_EMPTY_THRESHOLD = 2;
private static String stateCookie;
public static void resetState()
{
stateCookie = null;
}
public static final CharSequence scrape(final String url) throws IOException
{
return scrape(url, false, null, null, null);
}
public static final CharSequence scrape(final String url, final boolean isPost, final String request, String encoding,
final String sessionCookieName) throws IOException
{
return scrape(url, isPost, request, encoding, sessionCookieName, 3);
}
public static final CharSequence scrape(final String urlStr, final boolean isPost, final String request, String encoding,
final String sessionCookieName, int tries) throws IOException
{
if (encoding == null)
encoding = SCRAPE_DEFAULT_ENCODING;
while (true)
{
try
{
final StringBuilder buffer = new StringBuilder(SCRAPE_INITIAL_CAPACITY);
final URL url = new URL(urlStr);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(request != null);
connection.setConnectTimeout(SCRAPE_CONNECT_TIMEOUT);
connection.setReadTimeout(SCRAPE_READ_TIMEOUT);
connection.addRequestProperty("User-Agent", SCRAPE_USER_AGENT);
connection.addRequestProperty("Accept", SCRAPE_ACCEPT);
// workaround to disable Vodafone compression
connection.addRequestProperty("Cache-Control", "no-cache");
if (sessionCookieName != null && stateCookie != null)
connection.addRequestProperty("Cookie", stateCookie);
if (request != null)
{
if (isPost)
{
connection.setRequestMethod("POST");
connection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.addRequestProperty("Content-Length", Integer.toString(request.length()));
}
final Writer writer = new OutputStreamWriter(connection.getOutputStream(), encoding);
writer.write(request);
writer.close();
}
final Reader pageReader = new InputStreamReader(connection.getInputStream(), encoding);
if (!url.equals(connection.getURL()))
throw new UnexpectedRedirectException(url, connection.getURL());
copy(pageReader, buffer);
pageReader.close();
if (buffer.length() > SCRAPE_PAGE_EMPTY_THRESHOLD)
{
if (sessionCookieName != null)
{
for (final Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet())
{
if ("set-cookie".equalsIgnoreCase(entry.getKey()))
{
for (final String value : entry.getValue())
{
if (value.startsWith(sessionCookieName))
{
stateCookie = value.split(";", 2)[0];
}
}
}
}
}
return buffer;
}
else
{
final String message = "got empty page (length: " + buffer.length() + ")";
if (tries-- > 0)
System.out.println(message + ", retrying...");
else
throw new IOException(message + ": " + url);
}
}
catch (final SocketTimeoutException x)
{
if (tries-- > 0)
System.out.println("socket timed out, retrying...");
else
throw x;
}
}
}
private static final long copy(final Reader reader, final StringBuilder builder) throws IOException
{
final char[] buffer = new char[SCRAPE_INITIAL_CAPACITY];
long count = 0;
int n = 0;
while (-1 != (n = reader.read(buffer)))
{
builder.append(buffer, 0, n);
count += n;
}
return count;
}
public static final InputStream scrapeInputStream(final String url) throws IOException
{
return scrapeInputStream(url, null, null, 3);
}
public static final InputStream scrapeInputStream(final String urlStr, final String postRequest, final String sessionCookieName, int tries)
throws IOException
{
while (true)
{
final URL url = new URL(urlStr);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(postRequest != null);
connection.setConnectTimeout(SCRAPE_CONNECT_TIMEOUT);
connection.setReadTimeout(SCRAPE_READ_TIMEOUT);
connection.addRequestProperty("User-Agent", SCRAPE_USER_AGENT);
connection.addRequestProperty("Accept-Encoding", "gzip");
// workaround to disable Vodafone compression
connection.addRequestProperty("Cache-Control", "no-cache");
if (sessionCookieName != null && stateCookie != null)
connection.addRequestProperty("Cookie", stateCookie);
if (postRequest != null)
{
connection.setRequestMethod("POST");
connection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.addRequestProperty("Content-Length", Integer.toString(postRequest.length()));
final Writer writer = new OutputStreamWriter(connection.getOutputStream(), SCRAPE_DEFAULT_ENCODING);
writer.write(postRequest);
writer.close();
}
final int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK)
{
final String contentEncoding = connection.getContentEncoding();
final InputStream is = connection.getInputStream();
if (!url.equals(connection.getURL()))
throw new UnexpectedRedirectException(url, connection.getURL());
if (sessionCookieName != null)
{
for (final Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet())
{
if ("set-cookie".equalsIgnoreCase(entry.getKey()))
{
for (final String value : entry.getValue())
{
if (value.startsWith(sessionCookieName))
{
stateCookie = value.split(";", 2)[0];
}
}
}
}
}
if ("gzip".equalsIgnoreCase(contentEncoding))
return new GZIPInputStream(is);
return is;
}
else
{
final String message = "got response: " + responseCode + " " + connection.getResponseMessage();
if (tries-- > 0)
System.out.println(message + ", retrying...");
else
throw new IOException(message + ": " + url);
}
}
}
private static final Pattern P_ENTITY = Pattern.compile("&(?:#(x[\\da-f]+|\\d+)|(amp|quot|apos|szlig|nbsp));");
public static String resolveEntities(final CharSequence str)
{
if (str == null)
return null;
final Matcher matcher = P_ENTITY.matcher(str);
final StringBuilder builder = new StringBuilder(str.length());
int pos = 0;
while (matcher.find())
{
final char c;
final String code = matcher.group(1);
if (code != null)
{
if (code.charAt(0) == 'x')
c = (char) Integer.valueOf(code.substring(1), 16).intValue();
else
c = (char) Integer.parseInt(code);
}
else
{
final String namedEntity = matcher.group(2);
if (namedEntity.equals("amp"))
c = '&';
else if (namedEntity.equals("quot"))
c = '"';
else if (namedEntity.equals("apos"))
c = '\'';
else if (namedEntity.equals("szlig"))
c = 'ß';
else if (namedEntity.equals("nbsp"))
c = ' ';
else
throw new IllegalStateException("unknown entity: " + namedEntity);
}
builder.append(str.subSequence(pos, matcher.start()));
builder.append(c);
pos = matcher.end();
}
builder.append(str.subSequence(pos, str.length()));
return builder.toString();
}
private static final Pattern P_ISO_DATE = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
public static final void parseIsoDate(final Calendar calendar, final CharSequence str)
{
final Matcher m = P_ISO_DATE.matcher(str);
if (!m.matches())
throw new RuntimeException("cannot parse: '" + str + "'");
calendar.set(Calendar.YEAR, Integer.parseInt(m.group(1)));
calendar.set(Calendar.MONTH, Integer.parseInt(m.group(2)) - 1);
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(3)));
}
private static final Pattern P_GERMAN_DATE = Pattern.compile("(\\d{2})[\\./-](\\d{2})[\\./-](\\d{2,4})");
public static final void parseGermanDate(final Calendar calendar, final CharSequence str)
{
final Matcher m = P_GERMAN_DATE.matcher(str);
if (!m.matches())
throw new RuntimeException("cannot parse: '" + str + "'");
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(1)));
calendar.set(Calendar.MONTH, Integer.parseInt(m.group(2)) - 1);
final int year = Integer.parseInt(m.group(3));
calendar.set(Calendar.YEAR, year >= 100 ? year : year + 2000);
}
private static final Pattern P_AMERICAN_DATE = Pattern.compile("(\\d{2})/(\\d{2})/(\\d{2,4})");
public static final void parseAmericanDate(final Calendar calendar, final CharSequence str)
{
final Matcher m = P_AMERICAN_DATE.matcher(str);
if (!m.matches())
throw new RuntimeException("cannot parse: '" + str + "'");
calendar.set(Calendar.MONTH, Integer.parseInt(m.group(1)) - 1);
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(2)));
final int year = Integer.parseInt(m.group(3));
calendar.set(Calendar.YEAR, year >= 100 ? year : year + 2000);
}
private static final Pattern P_EUROPEAN_TIME = Pattern.compile("(\\d{1,2}):(\\d{2})(?::(\\d{2}))?");
public static final void parseEuropeanTime(final Calendar calendar, final CharSequence str)
{
final Matcher m = P_EUROPEAN_TIME.matcher(str);
if (!m.matches())
throw new RuntimeException("cannot parse: '" + str + "'");
calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(1)));
calendar.set(Calendar.MINUTE, Integer.parseInt(m.group(2)));
calendar.set(Calendar.SECOND, m.group(3) != null ? Integer.parseInt(m.group(3)) : 0);
}
private static final Pattern P_AMERICAN_TIME = Pattern.compile("(\\d{1,2}):(\\d{2})(?::(\\d{2}))? (AM|PM)");
public static final void parseAmericanTime(final Calendar calendar, final CharSequence str)
{
final Matcher m = P_AMERICAN_TIME.matcher(str);
if (!m.matches())
throw new RuntimeException("cannot parse: '" + str + "'");
calendar.set(Calendar.HOUR, Integer.parseInt(m.group(1)));
calendar.set(Calendar.MINUTE, Integer.parseInt(m.group(2)));
calendar.set(Calendar.SECOND, m.group(3) != null ? Integer.parseInt(m.group(3)) : 0);
calendar.set(Calendar.AM_PM, m.group(4).equals("AM") ? Calendar.AM : Calendar.PM);
}
public static long timeDiff(final Date d1, final Date d2)
{
final long t1 = d1.getTime();
final long t2 = d2.getTime();
return t1 - t2;
}
public static Date addDays(final Date time, final int days)
{
final Calendar c = new GregorianCalendar();
c.setTime(time);
c.add(Calendar.DAY_OF_YEAR, days);
return c.getTime();
}
public static void printGroups(final Matcher m)
{
final int groupCount = m.groupCount();
for (int i = 1; i <= groupCount; i++)
System.out.println("group " + i + ":" + (m.group(i) != null ? "'" + m.group(i) + "'" : "null"));
}
public static void printXml(final CharSequence xml)
{
final Matcher m = Pattern.compile("(<.{80}.*?>)\\s*").matcher(xml);
while (m.find())
System.out.println(m.group(1));
}
public static void printPlain(final CharSequence plain)
{
final Matcher m = Pattern.compile("(.{1,80})").matcher(plain);
while (m.find())
System.out.println(m.group(1));
}
public static void printFromReader(final Reader reader) throws IOException
{
while (true)
{
final int c = reader.read();
if (c == -1)
return;
System.out.print((char) c);
}
}
public static String urlEncode(final String str)
{
try
{
return URLEncoder.encode(str, "utf-8");
}
catch (final UnsupportedEncodingException x)
{
throw new RuntimeException(x);
}
}
public static String urlEncode(final String str, final String enc)
{
try
{
return URLEncoder.encode(str, enc);
}
catch (final UnsupportedEncodingException x)
{
throw new RuntimeException(x);
}
}
public static String urlDecode(final String str, final String enc)
{
try
{
return URLDecoder.decode(str, enc);
}
catch (final UnsupportedEncodingException x)
{
throw new RuntimeException(x);
}
}
public static <T> T selectNotNull(final T... groups)
{
T selected = null;
for (final T group : groups)
{
if (group != null)
{
if (selected == null)
selected = group;
else
throw new IllegalStateException("ambiguous");
}
}
return selected;
}
public static final String P_PLATFORM = "[\\wÄÖÜäöüßáàâéèêíìîóòôúùû\\. -/&#;]+?";
}

View file

@ -0,0 +1,367 @@
package de.schildbach.pte.util;
/*
* Copyright (C) 1997 Roger Whitney <whitney@cs.sdsu.edu>
*
* This file is part of the San Diego State University Java Library.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.io.BufferedReader;
import java.io.FilterReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
/**
* Given a string <b>pattern</b>, a string <b>replacementPattern</b> and an input stream, this class will replace all
* occurances of <b>pattern</b> with <b>replacementPattern</b> in the inputstream. You can give multiple
* pattern-replacementPattern pairs. Multiple pairs are done in order they are given. If first pair is "cat"-"dog" and
* second pair is "dog"-"house", then the result will be all occurences of "cat" or "dog" will be replaced with "house".
*
* @version 0.6 21 August 1997
* @since version 0.5, Fixed error that occured when input was shorter than the pattern
* @author Roger Whitney (<a href=mailto:whitney@cs.sdsu.edu>whitney@cs.sdsu.edu</a>)
*/
public class StringReplaceReader extends FilterReader implements Cloneable
{
protected CharQueue outputBuffer; // holds filtered data
protected char[] inputBuffer;
protected int[] shiftTable; // quick search shift table
protected int inputBufferCharCount; // number of chars in inputBuffer
protected char[] patternToFind = null;
protected char[] replacementPattern = null;
protected boolean reachedEOF = false;
protected static int EOFIndicator = -1;
protected static int DEFAULT_BUFFER_SIZE = 1024;
/**
* Create an StringReplaceReader object that will replace all occurrences ofpattern with replacementPattern in the
* Reader in.
*/
public StringReplaceReader(Reader in, String pattern, String replacementPattern)
{
super(in);
patternToFind = pattern.toCharArray();
this.replacementPattern = replacementPattern.toCharArray();
allocateBuffers();
}
/**
* Create an StringReplaceReader object that will replace all occurrences of pattern with replacementPattern in the
* inputstream in.
*/
public StringReplaceReader(InputStream in, String pattern, String replacementPattern)
{
this(new BufferedReader(new InputStreamReader(in)), pattern, replacementPattern);
}
/**
* Create an StringReplaceReader object that will replace all occurrences of pattern with replacementPattern in the
* string input.
*/
public StringReplaceReader(String input, String pattern, String replacementPattern)
{
this(new StringReader(input), pattern, replacementPattern);
}
/**
* Returns the entire contents of the input stream.
*/
public String contents() throws IOException
{
StringBuffer contents = new StringBuffer(1024);
int readSize = 512;
char[] filteredChars = new char[readSize];
int charsRead = read(filteredChars, 0, readSize);
while (charsRead != EOFIndicator)
{
contents.append(filteredChars, 0, charsRead);
charsRead = read(filteredChars, 0, readSize);
}
return contents.toString();
}
/**
* Adds another pattern-replacementPattern pair. All occurrences of pattern will be replaced with
* replacementPattern.
*
* @exception OutOfMemoryError
* if there is not enough memory to add new pattern-replacementPattern pair
*/
public void replace(String pattern, String replacementPattern) throws OutOfMemoryError
{
// Chain StringReplaceReader objects. Clone current object
// add clone to input stream to insure it filters before this
// object, which gets the new pattern-replacement pair
if (patternToFind != null)
{
// Replace this with clone
try
{
StringReplaceReader currentReplace = (StringReplaceReader) this.clone();
in = currentReplace;
}
catch (CloneNotSupportedException x)
{
}
}
patternToFind = pattern.toCharArray();
this.replacementPattern = replacementPattern.toCharArray();
allocateBuffers();
reachedEOF = false;
}
/**
* Read characters into a portion of an array. This method will block until some input is available, an I/O error
* occurs, or the end of the stream is reached.
*
* @parm buffer Destination buffer
* @parm offset location in buffer to start storing characters
* @parm charsToRead maximum characters to read
* @return number of characters actually read, -1 if reah EOF on reading first character
* @exception IOException
* if an I/O error occurs
*/
@Override
public int read(char[] buffer, int offset, int charsToRead) throws IOException
{
int charsRead = 0;
while ((charsRead < charsToRead) && (!eof()))
{
if (outputBuffer.isEmpty())
{
fillInputWindow();
filterInput();
}
charsRead += outputBuffer.dequeue(buffer, offset + charsRead, charsToRead - charsRead);
}
if (charsRead > 0)
return charsRead;
else if (outputBuffer.size() > 0)
{
charsRead = outputBuffer.dequeue(buffer, offset, charsToRead);
return charsRead;
}
else if ((eof()) && (inputBufferCharCount > 0) && (inputBufferCharCount < patternToFind.length))
{
// remaining input is less than length of pattern
transferRemainingInputToOutputBuffer();
System.out.println(">> End << " + outputBuffer);
charsRead = outputBuffer.dequeue(buffer, offset, charsToRead);
return charsRead;
}
else if (eof())
return EOFIndicator;
else
// this should never happen
throw new IOException("Read attempted. Did not reach EOF and " + " no chars were read");
}
/**
* Call when remaining input is less than the pattern size, so pattern can not exist in remaining input. Just shift
* all input to output. Assumes that have reached EOF and inputBufferCharCount < patternToFind.length
*/
private void transferRemainingInputToOutputBuffer()
{
outputBuffer.enqueue(inputBuffer, 0, inputBufferCharCount);
inputBufferCharCount = 0;
}
/**
* Returns the next character in the inputstream with string replacement done.
*
* @exception IOException
* if error occurs reading io stream
*/
@Override
public int read() throws IOException
{
char[] output = new char[1];
int charsRead = read(output, 0, 1);
if (charsRead == EOFIndicator)
return EOFIndicator;
else if (charsRead == 1)
return output[0];
else
throw new IOException("Single Read attempted. Did not reach EOF and " + " no chars were read");
}
/**
* Determines if a previous ASCII I/O operation caught End Of File.
*
* @return <i>true</i> if end of file was reached.
*/
public boolean eof()
{
return reachedEOF;
}
/**
* Read inpout to see if we have found the pattern. <B>Requires:</B> When this is called we have already have read
* first character in pattern.<BR>
* <B>Side Effects: </B> After attempt to find pattern, output buffer contains either the replacement pattern or all
* characters we konw are not part of pattern.
*/
protected void filterInput() throws IOException
{
// Use quick-search to find pattern. Fill inputBuffer with text.
// Process all text in inputBuffer. Place processed text in
// outputBuffer.
int searchStart = 0;
int windowStart = 0;
int patternLength = patternToFind.length;
// Search until pattern extends past end of inputBuffer
while (searchStart < inputBufferCharCount - patternLength + 1)
{
boolean foundPattern = true;
// The search
for (int index = 0; index < patternLength; index++)
if (patternToFind[index] != inputBuffer[index + searchStart])
{
foundPattern = false;
break; // for loop
}
if (foundPattern)
{
// move text before pattern
outputBuffer.enqueue(inputBuffer, windowStart, searchStart - windowStart);
replacementPatternToBuffer();
windowStart = searchStart + patternLength;
searchStart = windowStart;
}
else
{
// look farther along in inputBuffer
int charLocationAfterPattern = searchStart + patternLength;
if (charLocationAfterPattern >= inputBufferCharCount)
searchStart += 1;
else
searchStart += getShift(inputBuffer[charLocationAfterPattern]);
}
}
if (searchStart > inputBufferCharCount)
searchStart = inputBufferCharCount;
// move chars already searched
if (reachedEOF)
{
outputBuffer.enqueue(inputBuffer, windowStart, inputBufferCharCount - windowStart);
inputBufferCharCount = 0;
}
else
{
outputBuffer.enqueue(inputBuffer, windowStart, searchStart - windowStart);
System.arraycopy(inputBuffer, searchStart, inputBuffer, 0, inputBufferCharCount - searchStart);
inputBufferCharCount = inputBufferCharCount - searchStart;
}
}
/**
* Fill sliding input window with chars from input Read until window is full or reach EOF
*/
final protected void fillInputWindow() throws IOException
{
int charsToRead = inputBuffer.length - inputBufferCharCount;
int firstEmptySlotInWindow = inputBufferCharCount;
int charsRead = in.read(inputBuffer, firstEmptySlotInWindow, charsToRead);
if (charsRead == charsToRead) // full read
{
inputBufferCharCount = inputBufferCharCount + charsRead;
charsToRead = 0;
}
else if (charsRead > 0) // parial read
{
inputBufferCharCount = inputBufferCharCount + charsRead;
charsToRead = charsToRead - charsRead;
}
else if (charsRead == EOFIndicator)
{
reachedEOF = true;
}
else
throw new IOException("Read attempted. Did not reach EOF and " + " no chars were read");
}
/**
* Return the number of positions we can shift pattern when findMyShift is character in inputBuffer after the
* pattern
*/
protected int getShift(char findMyShift)
{
if (findMyShift >= shiftTable.length)
return 1;
else
return shiftTable[findMyShift];
}
/**
* Put replacement pattern in output buffer. Subclass overrides for more complex replacement
*/
protected void replacementPatternToBuffer()
{
outputBuffer.enqueue(replacementPattern);
}
private void allocateBuffers()
{
outputBuffer = new CharQueue(DEFAULT_BUFFER_SIZE);
inputBuffer = new char[Math.max(patternToFind.length + 1, DEFAULT_BUFFER_SIZE)];
inputBufferCharCount = 0;
// allocate for most ascii characters
shiftTable = new int[126];
// build shiftTable for quick search
// Entry for character X contains how far to shift
// pattern when pattern does not match text and
// character X is the character in text after end of
// pattern
// Default for characters not in pattern
for (int k = 0; k < shiftTable.length; k++)
shiftTable[k] = patternToFind.length + 1;
for (int k = 0; k < patternToFind.length; k++)
if (patternToFind[k] < shiftTable.length)
shiftTable[patternToFind[k]] = patternToFind.length - k;
}
}

View file

@ -0,0 +1,527 @@
/*
* For license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/).
* According to www.xmlpull.org, this code is in the public domain.
*/
package de.schildbach.pte.util;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
/**
* Handy functions that combines XmlPull API into higher level functionality.
*
* @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
* @author Naresh Bhatia
*/
public final class XmlPullUtil
{
public static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
/**
* directly jumps forward to start tag, ignoring any structure
*/
public static void jump(final XmlPullParser pp, final String tagName) throws XmlPullParserException, IOException
{
if (!jumpToStartTag(pp, null, tagName))
throw new IllegalStateException("cannot find <" + tagName + " />");
}
public static void require(final XmlPullParser pp, final String tagName) throws XmlPullParserException, IOException
{
pp.require(XmlPullParser.START_TAG, null, tagName);
}
/**
* enters current tag
*
* @throws IOException
*/
public static void enter(final XmlPullParser pp) throws XmlPullParserException, IOException
{
if (pp.getEventType() != XmlPullParser.START_TAG)
throw new IllegalStateException("expecting start tag to enter");
if (pp.isEmptyElementTag())
throw new IllegalStateException("cannot enter empty tag");
pp.next();
}
public static void enter(final XmlPullParser pp, final String tagName) throws XmlPullParserException, IOException
{
pp.require(XmlPullParser.START_TAG, null, tagName);
enter(pp);
}
public static void exit(final XmlPullParser pp) throws XmlPullParserException, IOException
{
exitSkipToEnd(pp);
if (pp.getEventType() != XmlPullParser.END_TAG)
throw new IllegalStateException("expecting end tag to exit");
pp.next();
}
public static void exit(final XmlPullParser pp, final String tagName) throws XmlPullParserException, IOException
{
exitSkipToEnd(pp);
pp.require(XmlPullParser.END_TAG, null, tagName);
pp.next();
}
private static void exitSkipToEnd(final XmlPullParser pp) throws XmlPullParserException, IOException
{
while (pp.getEventType() != XmlPullParser.END_TAG)
{
if (pp.getEventType() == XmlPullParser.START_TAG)
next(pp);
else if (pp.getEventType() == XmlPullParser.TEXT)
pp.next();
else
throw new IllegalStateException();
}
}
public static boolean test(final XmlPullParser pp, final String tagName) throws XmlPullParserException
{
return pp.getEventType() == XmlPullParser.START_TAG && pp.getName().equals(tagName);
}
public static void next(final XmlPullParser pp) throws XmlPullParserException, IOException
{
skipSubTree(pp);
pp.next();
}
public static String attr(final XmlPullParser pp, final String attrName)
{
return pp.getAttributeValue(null, attrName).trim();
}
public static int intAttr(final XmlPullParser pp, final String attrName)
{
return Integer.parseInt(pp.getAttributeValue(null, attrName).trim());
}
public static float floatAttr(final XmlPullParser pp, final String attrName)
{
return Float.parseFloat(pp.getAttributeValue(null, attrName).trim());
}
public static void requireAttr(final XmlPullParser pp, final String attrName, final String requiredValue)
{
if (!requiredValue.equals(attr(pp, attrName)))
throw new IllegalStateException("cannot find " + attrName + "=\"" + requiredValue + "\" />");
}
public static String text(final XmlPullParser pp) throws XmlPullParserException, IOException
{
if (pp.getEventType() != XmlPullParser.START_TAG || pp.isEmptyElementTag())
throw new IllegalStateException("expecting start tag to get text from");
enter(pp);
String text = "";
if (pp.getEventType() == XmlPullParser.TEXT)
text = pp.getText();
exit(pp);
return text;
}
/**
* Return value of attribute with given name and no namespace.
*/
public static String getAttributeValue(final XmlPullParser pp, final String name)
{
return pp.getAttributeValue(XmlPullParser.NO_NAMESPACE, name);
}
/**
* Return PITarget from Processing Instruction (PI) as defined in XML 1.0 Section 2.6 Processing Instructions <code>[16] PI ::= '&lt;?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'</code>
*/
public static String getPITarget(final XmlPullParser pp) throws IllegalStateException
{
int eventType;
try
{
eventType = pp.getEventType();
}
catch (final XmlPullParserException x)
{
// should never happen ...
throw new IllegalStateException("could not determine parser state: " + x + pp.getPositionDescription());
}
if (eventType != XmlPullParser.PROCESSING_INSTRUCTION)
throw new IllegalStateException("parser must be on processing instruction and not " + XmlPullParser.TYPES[eventType]
+ pp.getPositionDescription());
final String PI = pp.getText();
for (int i = 0; i < PI.length(); i++)
{
if (isS(PI.charAt(i)))
{
// assert i > 0
return PI.substring(0, i);
}
}
return PI;
}
/**
* Return everything past PITarget and S from Processing Instruction (PI) as defined in XML 1.0 Section 2.6
* Processing Instructions <code>[16] PI ::= '&lt;?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'</code>
*
* <p>
* <b>NOTE:</b> if there is no PI data it returns empty string.
*/
public static String getPIData(final XmlPullParser pp) throws IllegalStateException
{
int eventType;
try
{
eventType = pp.getEventType();
}
catch (final XmlPullParserException x)
{
// should never happen ...
throw new IllegalStateException("could not determine parser state: " + x + pp.getPositionDescription());
}
if (eventType != XmlPullParser.PROCESSING_INSTRUCTION)
throw new IllegalStateException("parser must be on processing instruction and not " + XmlPullParser.TYPES[eventType]
+ pp.getPositionDescription());
final String PI = pp.getText();
int pos = -1;
for (int i = 0; i < PI.length(); i++)
{
if (isS(PI.charAt(i)))
{
pos = i;
}
else if (pos > 0)
{
return PI.substring(i);
}
}
return "";
}
/**
* Return true if chacters is S as defined in XML 1.0 <code>S ::= (#x20 | #x9 | #xD | #xA)+</code>
*/
private static boolean isS(final char ch)
{
return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
}
/**
* Skip sub tree that is currently porser positioned on. <br>
* NOTE: parser must be on START_TAG and when funtion returns parser will be positioned on corresponding END_TAG
*/
public static void skipSubTree(final XmlPullParser pp) throws XmlPullParserException, IOException
{
pp.require(XmlPullParser.START_TAG, null, null);
int level = 1;
while (level > 0)
{
final int eventType = pp.next();
if (eventType == XmlPullParser.END_TAG)
--level;
else if (eventType == XmlPullParser.START_TAG)
++level;
}
}
/**
* call parser nextTag() and check that it is START_TAG, throw exception if not.
*/
public static void nextStartTag(final XmlPullParser pp) throws XmlPullParserException, IOException
{
if (pp.nextTag() != XmlPullParser.START_TAG)
throw new XmlPullParserException("expected START_TAG and not " + pp.getPositionDescription());
}
/**
* combine nextTag(); pp.require(XmlPullParser.START_TAG, null, name);
*/
public static void nextStartTag(final XmlPullParser pp, final String name) throws XmlPullParserException, IOException
{
pp.nextTag();
pp.require(XmlPullParser.START_TAG, null, name);
}
/**
* combine nextTag(); pp.require(XmlPullParser.START_TAG, namespace, name);
*/
public static void nextStartTag(final XmlPullParser pp, final String namespace, final String name) throws XmlPullParserException, IOException
{
pp.nextTag();
pp.require(XmlPullParser.START_TAG, namespace, name);
}
/**
* combine nextTag(); pp.require(XmlPullParser.END_TAG, namespace, name);
*/
public static void nextEndTag(final XmlPullParser pp, final String namespace, final String name) throws XmlPullParserException, IOException
{
pp.nextTag();
pp.require(XmlPullParser.END_TAG, namespace, name);
}
/**
* Read text content of element ith given namespace and name (use null namespace do indicate that nemspace should
* not be checked)
*/
public static String nextText(final XmlPullParser pp, final String namespace, final String name) throws IOException, XmlPullParserException
{
if (name == null)
throw new XmlPullParserException("name for element can not be null");
pp.require(XmlPullParser.START_TAG, namespace, name);
return pp.nextText();
}
/**
* Read attribute value and return it or throw exception if current element does not have such attribute.
*/
public static String getRequiredAttributeValue(final XmlPullParser pp, final String namespace, final String name) throws IOException,
XmlPullParserException
{
final String value = pp.getAttributeValue(namespace, name);
if (value == null)
throw new XmlPullParserException("required attribute " + name + " is not present");
else
return value;
}
/**
* Call parser nextTag() and check that it is END_TAG, throw exception if not.
*/
public static void nextEndTag(final XmlPullParser pp) throws XmlPullParserException, IOException
{
if (pp.nextTag() != XmlPullParser.END_TAG)
throw new XmlPullParserException("expected END_TAG and not" + pp.getPositionDescription());
}
/**
* Tests if the current event is of the given type and if the namespace and name match. null will match any
* namespace and any name. If the test passes a true is returned otherwise a false is returned.
*/
public static boolean matches(final XmlPullParser pp, final int type, final String namespace, final String name) throws XmlPullParserException
{
boolean matches = type == pp.getEventType() && (namespace == null || namespace.equals(pp.getNamespace()))
&& (name == null || name.equals(pp.getName()));
return matches;
}
/**
* Writes a simple element such as <username>johndoe</username>. The namespace and elementText are allowed to be
* null. If elementText is null, an xsi:nil="true" will be added as an attribute.
*/
public static void writeSimpleElement(final XmlSerializer serializer, final String namespace, final String elementName, final String elementText)
throws IOException, XmlPullParserException
{
if (elementName == null)
throw new XmlPullParserException("name for element can not be null");
serializer.startTag(namespace, elementName);
if (elementText == null)
serializer.attribute(XSI_NS, "nil", "true");
else
serializer.text(elementText);
serializer.endTag(namespace, elementName);
}
/**
* This method bypasses all child subtrees until it reached END_TAG for current tree. Parser must be on START_TAG of
* one of child subtrees.
*/
public static void jumpToEndOfTree(final XmlPullParser pp) throws XmlPullParserException, IOException
{
pp.require(XmlPullParser.START_TAG, null, null);
while (true)
{
final int eventType = pp.next();
if (eventType == XmlPullParser.START_TAG)
{
skipSubTree(pp);
pp.require(XmlPullParser.END_TAG, null, null);
pp.next(); // skip end tag
}
else if (eventType == XmlPullParser.END_TAG)
{
break;
}
}
}
/**
* This method bypasses all child subtrees until it finds a child subtree with start tag that matches the tag name
* (if not null) and namespsce (if not null) passed in. Parser must be positioned on START_TAG.
* <p>
* If succesfulpositions parser on such START_TAG and return true otherwise this method returns false and parser is
* positioned on END_TAG signaling last element in curren subtree.
*/
public static boolean jumpToSubTree(final XmlPullParser pp, final String tagNamespace, final String tagName) throws XmlPullParserException,
IOException
{
if (tagNamespace == null && tagName == null)
throw new IllegalArgumentException("namespace and name argument can not be both null:" + pp.getPositionDescription());
pp.require(XmlPullParser.START_TAG, null, null);
while (true)
{
final int eventType = pp.next();
if (eventType == XmlPullParser.START_TAG)
{
final String name = pp.getName();
final String namespace = pp.getNamespace();
boolean matches = (tagNamespace != null && tagNamespace.equals(namespace)) || (tagName != null && tagName.equals(name));
if (matches)
return true;
skipSubTree(pp);
pp.require(XmlPullParser.END_TAG, name, namespace);
pp.next(); // skip end tag
}
else if (eventType == XmlPullParser.END_TAG)
{
return false;
}
}
}
public static boolean nextStartTagInsideTree(final XmlPullParser pp, final String tagNamespace, final String tagName)
throws XmlPullParserException, IOException
{
if (tagNamespace == null && tagName == null)
throw new IllegalArgumentException("namespace and name argument can not be both null:" + pp.getPositionDescription());
if (pp.getEventType() != XmlPullParser.START_TAG && pp.getEventType() != XmlPullParser.END_TAG)
throw new IllegalStateException("expected START_TAG of parent or END_TAG of child:" + pp.getPositionDescription());
while (true)
{
final int eventType = pp.next();
if (eventType == XmlPullParser.START_TAG)
{
final String name = pp.getName();
final String namespace = pp.getNamespace();
boolean matches = (tagNamespace != null && tagNamespace.equals(namespace)) || (tagName != null && tagName.equals(name));
if (matches)
return true;
skipSubTree(pp);
pp.require(XmlPullParser.END_TAG, namespace, name);
}
else if (eventType == XmlPullParser.END_TAG)
{
return false;
}
}
}
public static void skipRestOfTree(final XmlPullParser pp) throws XmlPullParserException, IOException
{
if (pp.getEventType() != XmlPullParser.START_TAG && pp.getEventType() != XmlPullParser.END_TAG)
throw new IllegalStateException("expected START_TAG of parent or END_TAG of child:" + pp.getPositionDescription());
while (true)
{
final int eventType = pp.next();
if (eventType == XmlPullParser.START_TAG)
{
skipSubTree(pp);
pp.require(XmlPullParser.END_TAG, null, null);
}
else if (eventType == XmlPullParser.END_TAG)
{
return;
}
}
}
/**
* This method bypasses all events until it finds a start tag that has passed in namespace (if not null) and
* namespace (if not null).
*
* @return true if such START_TAG was found or false otherwise (and parser is on END_DOCUMENT).
*/
public static boolean jumpToStartTag(final XmlPullParser pp, final String tagNamespace, final String tagName) throws XmlPullParserException,
IOException
{
if (tagNamespace == null && tagName == null)
throw new IllegalArgumentException("namespace and name argument can not be both null:" + pp.getPositionDescription());
while (true)
{
final int eventType = pp.next();
if (eventType == XmlPullParser.START_TAG)
{
final String name = pp.getName();
final String namespace = pp.getNamespace();
boolean matches = (tagNamespace != null && tagNamespace.equals(namespace)) || (tagName != null && tagName.equals(name));
if (matches)
return true;
}
else if (eventType == XmlPullParser.END_DOCUMENT)
{
return false;
}
}
}
/**
* This method bypasses all events until it finds an end tag that has passed in namespace (if not null) and
* namespace (if not null).
*
* @return true if such END_TAG was found or false otherwise (and parser is on END_DOCUMENT).
*/
public static boolean jumpToEndTag(final XmlPullParser pp, final String tagNamespace, final String tagName) throws XmlPullParserException,
IOException
{
if (tagNamespace == null && tagName == null)
throw new IllegalArgumentException("namespace and name argument can not be both null:" + pp.getPositionDescription());
while (true)
{
final int eventType = pp.next();
if (eventType == XmlPullParser.END_TAG)
{
final String name = pp.getName();
final String namespace = pp.getNamespace();
boolean matches = (tagNamespace != null && tagNamespace.equals(namespace)) || (tagName != null && tagName.equals(name));
if (matches)
return true;
}
else if (eventType == XmlPullParser.END_DOCUMENT)
{
return false;
}
}
}
}