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

621
enabler/COPYING Normal file
View file

@ -0,0 +1,621 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS

67
enabler/pom.xml Normal file
View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.schildbach.pte</groupId>
<artifactId>public-transport-enabler</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20090211</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.sf.kxml</groupId>
<artifactId>kxml2</artifactId>
<version>2.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<testResources>
<testResource>
<directory>test</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

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;
}
}
}
}

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;
import static junit.framework.Assert.assertTrue;
import java.util.regex.Matcher;
import org.junit.Test;
/**
* @author Andreas Schildbach
*/
public class BahnProviderTest
{
@Test
public void connectionUebergang()
{
assertFineConnectionDetails("" //
+ "<span class=\"bold\">Berlin Hbf</span><br />\n" //
+ "&#220;bergang\n" //
+ "<br />\n" //
+ "<span class=\"bold\">Berlin-Lichtenberg</span><br />\n");
}
private void assertFineConnectionDetails(final String s)
{
Matcher m = BahnProvider.P_CONNECTION_DETAILS_FINE.matcher(s);
assertTrue(m.matches());
// ParserUtils.printGroups(m);
}
}

Some files were not shown because too many files have changed in this diff Show more