Merge pull request #52 from Meisterschueler/feature/relationships

Feature/relationships
pull/55/head
Meisterschueler 2016-06-16 12:30:31 +02:00 zatwierdzone przez GitHub
commit 0529013f87
28 zmienionych plików z 57845 dodań i 1160 usunięć

Wyświetl plik

@ -1,6 +1,15 @@
# CHANGELOG # CHANGELOG
## Unreleased ## Unreleased
- Moved to PostGIS, PostgreSQL is now mandantory
- Changed database schema (added airport, added relations, added aircraft_type, removed unused fields)
- Added Airport manager with command line option `db.import_airports`,
default is WELT2000
- Logbook: instead of lat, lon and name of the airport just pass the name
- Logbook: optional utc offset, optional single day selection
- Logbook: remark if different airport is used for takeoff or landing
- Logbook: several accuracy and speed improvements
- DDB: consider aircraft_type
- Moved exceptions from `ogn.exceptions` to `ogn.parser.exceptions` - Moved exceptions from `ogn.exceptions` to `ogn.parser.exceptions`
- Moved parsing from `ogn.model.*` to `ogn.parser` - Moved parsing from `ogn.model.*` to `ogn.parser`

Wyświetl plik

@ -10,8 +10,7 @@
A database backend for the [Open Glider Network](http://wiki.glidernet.org/). A database backend for the [Open Glider Network](http://wiki.glidernet.org/).
The ogn-python module saves all received beacons into a database with [SQLAlchemy](http://www.sqlalchemy.org/). The ogn-python module saves all received beacons into a database with [SQLAlchemy](http://www.sqlalchemy.org/).
It connects to the OGN aprs servers with [python-ogn-client](https://github.com/glidernet/python-ogn-client). It connects to the OGN aprs servers with [python-ogn-client](https://github.com/glidernet/python-ogn-client).
For simple tests a [sqlite](https://www.sqlite.org/)-backend is sufficient, It requires [PostgreSQL](http://www.postgresql.org/) and [PostGIS](http://www.postgis.net/).
but some tasks (e.g. logbook generation) require a proper database backend like [postgresql](http://www.postgresql.org/).
[Examples](https://github.com/glidernet/ogn-python/wiki/Examples) [Examples](https://github.com/glidernet/ogn-python/wiki/Examples)
@ -28,14 +27,17 @@ but some tasks (e.g. logbook generation) require a proper database backend like
``` ```
pip install -r requirements.txt pip install -r requirements.txt
``` ```
3. Install [PostgreSQL](http://www.postgresql.org/) with [PostGIS](http://www.postgis.net/) Extension.
Create a database (use "ogn" as default, otherwise you have to modify the configuration, see below)
3. Install redis for asynchronous tasks (like takeoff/landing-detection)
4. Optional: Install redis for asynchronous tasks (like takeoff/landing-detection)
``` ```
apt-get install redis-server apt-get install redis-server
``` ```
4. Create database 5. Create database
``` ```
./manage.py db.init ./manage.py db.init
@ -103,6 +105,9 @@ available commands:
compute Compute takeoffs and landings. compute Compute takeoffs and landings.
show Show a logbook for <airport_name>. show Show a logbook for <airport_name>.
[show.airport]
list_all Show a list of all airports.
[show.devices] [show.devices]
stats Show some stats on registered devices. stats Show some stats on registered devices.
@ -119,9 +124,8 @@ Only the command `logbook.compute` requires a running task server (celery) at th
- `ogn.collect.database.import_ddb` - Import registered devices from the ddb - `ogn.collect.database.import_ddb` - Import registered devices from the ddb
- `ogn.collect.database.import_file` - Import registered devices from a local file - `ogn.collect.database.import_file` - Import registered devices from a local file
- `ogn.collect.heatmap.update_beacon_receiver_distance_all` - Calculate the distance between aircraft and receiver for the last aircraft beacons - `ogn.collect.receiver.update_receivers` - Populate/update receiver table
- `ogn.collect.receiver.update_receivers` - Populate/update receiver table (requires postgresql-backend) - `ogn.collect.logbook.compute_takeoff_and_landing` - Generate TakeoffLanding table
- `ogn.collect.logbook.compute_takeoff_and_landing` - Generate TakeoffLanding table (requires postgresql-backend)
If the task server is up and running, tasks could be started manually. If the task server is up and running, tasks could be started manually.

Wyświetl plik

@ -0,0 +1,26 @@
"""remove unused fields from takeoff_landing
Revision ID: 163f6213d3f
Revises: 258a3f6bbdc
Create Date: 2016-06-03 20:05:20.749369
"""
# revision identifiers, used by Alembic.
revision = '163f6213d3f'
down_revision = '258a3f6bbdc'
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
def upgrade():
op.drop_column('takeoff_landing', 'altitude')
op.drop_column('takeoff_landing', 'ground_speed')
def downgrade():
op.add_column('takeoff_landing', sa.Column('altitude', sa.Integer))
op.add_column('takeoff_landing', sa.Column('ground_speed', sa.Float))

Wyświetl plik

@ -0,0 +1,28 @@
"""add aircraft_type to device
Revision ID: 258a3f6bbdc
Revises: 7585491482
Create Date: 2016-05-25 20:16:57.990249
"""
# revision identifiers, used by Alembic.
revision = '258a3f6bbdc'
down_revision = '7585491482'
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('device', sa.Column('aircraft_type', sa.Integer))
op.create_index('ix_device_aircraft_type', 'device', ['aircraft_type'])
op.create_index('ix_aircraft_beacon_aircraft_type', 'aircraft_beacon', ['aircraft_type'])
def downgrade():
op.drop_index('ix_aircraft_beacon_aircraft_type', 'aircraft_beacon')
op.drop_index('ix_device_aircraft_type', 'device')
op.drop_column('device', 'aircraft_type')

Wyświetl plik

@ -0,0 +1,83 @@
"""Create relations
Revision ID: 46d818bc09b
Revises: 2004ce1566c
Create Date: 2016-05-18 21:00:24.832298
"""
# revision identifiers, used by Alembic.
revision = '46d818bc09b'
down_revision = '2004ce1566c'
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
import geoalchemy2 as ga
def upgrade():
op.add_column('aircraft_beacon', sa.Column('device_id', sa.Integer))
op.create_foreign_key("aircraft_beacon_device_id_fkey", "aircraft_beacon", "device", ["device_id"], ["id"], ondelete="SET NULL")
op.create_index('ix_aircraft_beacon_device_id', 'aircraft_beacon', ['device_id'])
op.add_column('aircraft_beacon', sa.Column('receiver_id', sa.Integer))
op.create_foreign_key("aircraft_beacon_receiver_id_fkey", "aircraft_beacon", "receiver", ["receiver_id"], ["id"], ondelete="SET NULL")
op.create_index('ix_aircraft_beacon_receiver_id', 'aircraft_beacon', ['receiver_id'])
op.drop_index('ix_aircraft_beacon_address', 'aircraft_beacon')
op.add_column('receiver_beacon', sa.Column('receiver_id', sa.Integer))
op.create_foreign_key("receiver_beacon_receiver_id_fkey", "receiver_beacon", "receiver", ["receiver_id"], ["id"], ondelete="SET NULL")
op.create_index('ix_receiver_beacon_receiver_id', 'receiver_beacon', ['receiver_id'])
op.add_column('takeoff_landing', sa.Column('airport_id', sa.Integer))
op.create_foreign_key("takeoff_landing_airport_id_fkey", "takeoff_landing", "airport", ["airport_id"], ["id"], ondelete="SET NULL")
op.create_index('ix_takeoff_landing_airport_id', 'takeoff_landing', ['airport_id'])
op.add_column('takeoff_landing', sa.Column('device_id', sa.Integer))
op.create_foreign_key('takeoff_landing_device_id_fkey', 'takeoff_landing', 'device', ['device_id'], ['id'], ondelete="SET NULL")
op.create_index('ix_takeoff_landing_device_id', 'takeoff_landing', ['device_id'])
op.drop_index('ix_takeoff_landing_address', 'takeoff_landing')
op.drop_index('idx_takeoff_landing_location', 'takeoff_landing')
op.drop_column('takeoff_landing', 'address')
op.drop_column('takeoff_landing', 'name')
op.drop_column('takeoff_landing', 'receiver_name')
op.drop_column('takeoff_landing', 'location')
def downgrade():
op.drop_index('ix_aircraft_beacon_device_id', 'aircraft_beacon')
op.drop_foreign_key("aircraft_beacon_device_id_fkey", "aircraft_beacon")
op.drop_column('aircraft_beacon', 'device_id')
op.drop_index('ix_aircraft_beacon_receiver_id', 'aircraft_beacon')
op.drop_foreign_key("aircraft_beacon_receiver_id_fkey", "aircraft_beacon")
op.drop_column('aircraft_beacon', 'receiver_id')
op.create_index('ix_aircraft_beacon_address', sa.Column('address', sa.String))
op.drop_index('ix_receiver_beacon_receiver_id', 'receiver_beacon')
op.drop_foreign_key("ix_receiver_beacon_receiver_id", "receiver_beacon")
op.drop_column('receiver_beacon', 'receiver_id')
op.drop_index('ix_takeoff_landing_airport_id', 'takeoff_landing')
op.drop_foreign_key("takeoff_landing_airport_id_fkey", "takeoff_landing")
op.drop_column('takeoff_landing', 'airport_id')
op.drop_index('ix_takeoff_landing_device_id', 'takeoff_landing')
op.drop_foreign_key("takeoff_landing_device_id_fkey", "takeoff_landing")
op.drop_column('takeoff_landing', 'device_id')
op.add_column('takeoff_landing', sa.Column('name', sa.String))
op.add_column('takeoff_landing', sa.Column('receiver_name', sa.String(9)))
op.add_column('takeoff_landing', sa.Column('address', sa.String(6)))
op.add_column('takeoff_landing', sa.Column('location', ga.Geometry('POINT', srid=4326)))
op.create_index('ix_takeoff_landing_address', 'takeoff_landing', ['address'])
op.create_index('idx_takeoff_landing_location', 'takeoff_landing', ['location'])

Wyświetl plik

@ -0,0 +1,24 @@
"""correct airport scheme
Revision ID: 7585491482
Revises: 46d818bc09b
Create Date: 2016-05-21 20:19:24.865915
"""
# revision identifiers, used by Alembic.
revision = '7585491482'
down_revision = '46d818bc09b'
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
def upgrade():
op.execute('ALTER TABLE airport ALTER COLUMN code TYPE varchar(6)')
def downgrade():
op.execute('ALTER TABLE airport ALTER COLUMN code TYPE varchar(5)')

Wyświetl plik

@ -1,4 +1,4 @@
SQLALCHEMY_DATABASE_URI = 'sqlite:///beacons.db' SQLALCHEMY_DATABASE_URI = 'postgresql://postgres@localhost:5432/ogn'
BROKER_URL = 'redis://localhost:6379/0' BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'

Wyświetl plik

@ -1,3 +1,5 @@
from sqlalchemy.sql import null
from celery.utils.log import get_task_logger from celery.utils.log import get_task_logger
from ogn.model import Device, AddressOrigin from ogn.model import Device, AddressOrigin
@ -8,13 +10,42 @@ from ogn.collect.celery import app
logger = get_task_logger(__name__) logger = get_task_logger(__name__)
temp_address_origin = 7
def add_devices(session, origin):
before_sq = session.query(Device.address) \
.filter(Device.address_origin == origin) \
.subquery()
add_query = session.query(Device) \
.filter(Device.address_origin == temp_address_origin) \
.filter(~Device.address.in_(before_sq))
result = add_query.update({Device.address_origin: origin},
synchronize_session='fetch')
return result
def update_devices(session, origin, devices): def update_devices(session, origin, devices):
session.query(Device) \ session.query(Device) \
.filter(Device.address_origin == origin) \ .filter(Device.address_origin == temp_address_origin) \
.delete() .delete()
session.bulk_save_objects(devices) session.bulk_save_objects(devices)
# mark temporary added devices
session.query(Device) \
.filter(Device.address_origin == null()) \
.update({Device.address_origin: temp_address_origin})
logger.info('Added {} devices'.format(add_devices(session, origin)))
# delete temporary added devices
session.query(Device) \
.filter(Device.address_origin == temp_address_origin) \
.delete()
session.commit() session.commit()
return len(devices) return len(devices)

Wyświetl plik

@ -4,10 +4,10 @@ from celery.utils.log import get_task_logger
from ogn.collect.celery import app from ogn.collect.celery import app
from sqlalchemy.sql import func from sqlalchemy.sql import func
from sqlalchemy import and_, or_, insert from sqlalchemy import and_, or_, insert, between
from sqlalchemy.sql.expression import case from sqlalchemy.sql.expression import case
from ogn.model import AircraftBeacon, TakeoffLanding from ogn.model import AircraftBeacon, TakeoffLanding, Airport
logger = get_task_logger(__name__) logger = get_task_logger(__name__)
@ -22,7 +22,11 @@ def compute_takeoff_and_landing():
duration = 100 # the points must not exceed this duration duration = 100 # the points must not exceed this duration
radius = 0.05 # the points must not exceed this radius (degree!) around the 2nd point radius = 0.05 # the points must not exceed this radius (degree!) around the 2nd point
# calculate the time where the computation starts # takeoff / landing has to be near an airport
airport_radius = 0.025 # takeoff / landing must not exceed this radius (degree!) around the airport
airport_delta = 100 # takeoff / landing must not exceed this altitude offset above/below the airport
# calculate the start (and stop) timestamp for the computatio
last_takeoff_landing_query = app.session.query(func.max(TakeoffLanding.timestamp)) last_takeoff_landing_query = app.session.query(func.max(TakeoffLanding.timestamp))
begin_computation = last_takeoff_landing_query.one()[0] begin_computation = last_takeoff_landing_query.one()[0]
if begin_computation is None: if begin_computation is None:
@ -37,55 +41,48 @@ def compute_takeoff_and_landing():
app.session.query(TakeoffLanding) \ app.session.query(TakeoffLanding) \
.filter(TakeoffLanding.timestamp >= begin_computation) \ .filter(TakeoffLanding.timestamp >= begin_computation) \
.delete() .delete()
end_computation = begin_computation + timedelta(days=30) end_computation = begin_computation + timedelta(days=5)
logger.debug("Calculate takeoffs and landings between {} and {}" logger.debug("Calculate takeoffs and landings between {} and {}"
.format(begin_computation, end_computation)) .format(begin_computation, end_computation))
# make a query with current, previous and next position # make a query with current, previous and next position
sq = app.session.query( sq = app.session.query(
AircraftBeacon.address,
func.lag(AircraftBeacon.address).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('address_prev'),
func.lead(AircraftBeacon.address).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('address_next'),
AircraftBeacon.timestamp, AircraftBeacon.timestamp,
func.lag(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('timestamp_prev'), func.lag(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('timestamp_prev'),
func.lead(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('timestamp_next'), func.lead(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('timestamp_next'),
AircraftBeacon.name,
func.lag(AircraftBeacon.name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('name_prev'),
func.lead(AircraftBeacon.name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('name_next'),
AircraftBeacon.receiver_name,
func.lag(AircraftBeacon.receiver_name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('receiver_name_prev'),
func.lead(AircraftBeacon.receiver_name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('receiver_name_next'),
AircraftBeacon.location_wkt, AircraftBeacon.location_wkt,
func.lag(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('location_wkt_prev'), func.lag(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('location_wkt_prev'),
func.lead(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('location_wkt_next'), func.lead(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('location_wkt_next'),
AircraftBeacon.track, AircraftBeacon.track,
func.lag(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('track_prev'), func.lag(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('track_prev'),
func.lead(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('track_next'), func.lead(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('track_next'),
AircraftBeacon.ground_speed, AircraftBeacon.ground_speed,
func.lag(AircraftBeacon.ground_speed).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('ground_speed_prev'), func.lag(AircraftBeacon.ground_speed).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('ground_speed_prev'),
func.lead(AircraftBeacon.ground_speed).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('ground_speed_next'), func.lead(AircraftBeacon.ground_speed).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('ground_speed_next'),
AircraftBeacon.altitude, AircraftBeacon.altitude,
func.lag(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('altitude_prev'), func.lag(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('altitude_prev'),
func.lead(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('altitude_next')) \ func.lead(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('altitude_next'),
AircraftBeacon.device_id,
func.lag(AircraftBeacon.device_id).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('device_id_prev'),
func.lead(AircraftBeacon.device_id).over(order_by=and_(AircraftBeacon.device_id, AircraftBeacon.timestamp)).label('device_id_next')) \
.filter(AircraftBeacon.timestamp >= begin_computation) \ .filter(AircraftBeacon.timestamp >= begin_computation) \
.filter(AircraftBeacon.timestamp <= end_computation) \ .filter(AircraftBeacon.timestamp <= end_computation) \
.order_by(func.date(AircraftBeacon.timestamp), AircraftBeacon.address, AircraftBeacon.timestamp) \
.subquery() .subquery()
# find takeoffs and landings # find possible takeoffs and landings
takeoff_landing_query = app.session.query( sq2 = app.session.query(
sq.c.address,
sq.c.name,
sq.c.receiver_name,
sq.c.timestamp, sq.c.timestamp,
sq.c.location, case([(sq.c.ground_speed > takeoff_speed, sq.c.location_wkt_prev), # on takeoff we take the location from the previous fix because it is nearer to the airport
sq.c.track, (sq.c.ground_speed < landing_speed, sq.c.location)]).label('location'),
case([(sq.c.ground_speed > takeoff_speed, sq.c.track),
(sq.c.ground_speed < landing_speed, sq.c.track_prev)]).label('track'), # on landing we take the track from the previous fix because gliders tend to leave the runway quickly
sq.c.ground_speed, sq.c.ground_speed,
sq.c.altitude, sq.c.altitude,
case([(sq.c.ground_speed > takeoff_speed, True), case([(sq.c.ground_speed > takeoff_speed, True),
(sq.c.ground_speed < landing_speed, False)]).label('is_takeoff')) \ (sq.c.ground_speed < landing_speed, False)]).label('is_takeoff'),
.filter(sq.c.address_prev == sq.c.address == sq.c.address_next) \ sq.c.device_id) \
.filter(sq.c.device_id_prev == sq.c.device_id == sq.c.device_id_next) \
.filter(or_(and_(sq.c.ground_speed_prev < takeoff_speed, # takeoff .filter(or_(and_(sq.c.ground_speed_prev < takeoff_speed, # takeoff
sq.c.ground_speed > takeoff_speed, sq.c.ground_speed > takeoff_speed,
sq.c.ground_speed_next > takeoff_speed), sq.c.ground_speed_next > takeoff_speed),
@ -95,10 +92,26 @@ def compute_takeoff_and_landing():
.filter(sq.c.timestamp_next - sq.c.timestamp_prev < timedelta(seconds=duration)) \ .filter(sq.c.timestamp_next - sq.c.timestamp_prev < timedelta(seconds=duration)) \
.filter(and_(func.ST_DFullyWithin(sq.c.location, sq.c.location_wkt_prev, radius), .filter(and_(func.ST_DFullyWithin(sq.c.location, sq.c.location_wkt_prev, radius),
func.ST_DFullyWithin(sq.c.location, sq.c.location_wkt_next, radius))) \ func.ST_DFullyWithin(sq.c.location, sq.c.location_wkt_next, radius))) \
.order_by(func.date(sq.c.timestamp), sq.c.timestamp) .subquery()
# consider them if they are near a airport
takeoff_landing_query = app.session.query(
sq2.c.timestamp,
sq2.c.track,
sq2.c.is_takeoff,
sq2.c.device_id,
Airport.id) \
.filter(and_(func.ST_DFullyWithin(sq2.c.location, Airport.location_wkt, airport_radius),
between(sq2.c.altitude, Airport.altitude - airport_delta, Airport.altitude + airport_delta))) \
.filter(between(Airport.style, 2, 5))
# ... and save them # ... and save them
ins = insert(TakeoffLanding).from_select((TakeoffLanding.address, TakeoffLanding.name, TakeoffLanding.receiver_name, TakeoffLanding.timestamp, TakeoffLanding.location_wkt, TakeoffLanding.track, TakeoffLanding.ground_speed, TakeoffLanding.altitude, TakeoffLanding.is_takeoff), takeoff_landing_query) ins = insert(TakeoffLanding).from_select((TakeoffLanding.timestamp,
TakeoffLanding.track,
TakeoffLanding.is_takeoff,
TakeoffLanding.device_id,
TakeoffLanding.airport_id),
takeoff_landing_query)
result = app.session.execute(ins) result = app.session.execute(ins)
counter = result.rowcount counter = result.rowcount
app.session.commit() app.session.commit()

Wyświetl plik

@ -1,6 +1,6 @@
from sqlalchemy.sql import func, null from sqlalchemy.sql import func, null
from sqlalchemy.sql.functions import coalesce from sqlalchemy.sql.functions import coalesce
from sqlalchemy import and_, not_ from sqlalchemy import and_, not_, or_
from celery.utils.log import get_task_logger from celery.utils.log import get_task_logger
@ -25,6 +25,7 @@ def update_receivers():
.group_by(ReceiverBeacon.name) \ .group_by(ReceiverBeacon.name) \
.subquery() .subquery()
# update receivers
receivers_to_update = app.session.query(ReceiverBeacon.name, receivers_to_update = app.session.query(ReceiverBeacon.name,
ReceiverBeacon.location_wkt, ReceiverBeacon.location_wkt,
ReceiverBeacon.altitude, ReceiverBeacon.altitude,
@ -35,25 +36,23 @@ def update_receivers():
ReceiverBeacon.timestamp == last_receiver_beacon_sq.columns.lastseen)) \ ReceiverBeacon.timestamp == last_receiver_beacon_sq.columns.lastseen)) \
.subquery() .subquery()
# set country code to None if lat or lon changed # ... set country code to None if lat or lon changed
count = app.session.query(Receiver) \ changed_count = app.session.query(Receiver) \
.filter(and_(Receiver.name == receivers_to_update.columns.name, .filter(Receiver.name == receivers_to_update.columns.name) \
not_(func.ST_Equals(Receiver.location_wkt, receivers_to_update.columns.location)))) \ .filter(or_(not_(func.ST_Equals(Receiver.location_wkt, receivers_to_update.columns.location)),
and_(Receiver.location_wkt == null(),
receivers_to_update.columns.location != null()))) \
.update({"location_wkt": receivers_to_update.columns.location, .update({"location_wkt": receivers_to_update.columns.location,
"country_code": null()}, "country_code": null()},
synchronize_session=False) synchronize_session=False)
logger.info("Count of receivers who changed lat or lon: {}".format(count)) # ... and update altitude, lastseen, version and platform
update_count = app.session.query(Receiver) \
# update lastseen of known receivers .filter(Receiver.name == receivers_to_update.columns.name) \
count = app.session.query(Receiver) \ .update({"altitude": receivers_to_update.columns.altitude,
.filter(Receiver.name == receivers_to_update.columns.name) \ "lastseen": receivers_to_update.columns.lastseen,
.update({"altitude": receivers_to_update.columns.altitude, "version": receivers_to_update.columns.version,
"lastseen": receivers_to_update.columns.lastseen, "platform": receivers_to_update.columns.platform})
"version": receivers_to_update.columns.version,
"platform": receivers_to_update.columns.platform})
logger.info("Count of receivers who where updated: {}".format(count))
# add new receivers # add new receivers
empty_sq = app.session.query(ReceiverBeacon.name, empty_sq = app.session.query(ReceiverBeacon.name,
@ -88,20 +87,25 @@ def update_receivers():
.group_by(Receiver.name) \ .group_by(Receiver.name) \
.subquery() .subquery()
count = app.session.query(Receiver) \ added_count = app.session.query(Receiver) \
.filter(Receiver.name == firstseen_null_query.columns.name) \ .filter(Receiver.name == firstseen_null_query.columns.name) \
.update({'firstseen': firstseen_null_query.columns.firstseen}) .update({'firstseen': firstseen_null_query.columns.firstseen})
logger.info("Total: {} receivers added".format(count))
# update country code if None # update country code if None
unknown_country_query = app.session.query(Receiver) \ unknown_country_query = app.session.query(Receiver) \
.filter(Receiver.country_code == null()) \ .filter(Receiver.country_code == null()) \
.filter(Receiver.location_wkt != null()) \
.order_by(Receiver.name) .order_by(Receiver.name)
for receiver in unknown_country_query.all(): for receiver in unknown_country_query.all():
location = receiver.location location = receiver.location
receiver.country_code = get_country_code(location.latitude, location.longitude) country_code = get_country_code(location.latitude, location.longitude)
if receiver.country_code is not None: if country_code is not None:
receiver.country_code = country_code
logger.info("Updated country_code for {} to {}".format(receiver.name, receiver.country_code)) logger.info("Updated country_code for {} to {}".format(receiver.name, receiver.country_code))
logger.info("Added: {}, location changed: {}".format(added_count, changed_count))
app.session.commit() app.session.commit()
return update_count

Wyświetl plik

@ -1,4 +1,5 @@
from .database import manager as database_manager from .database import manager as database_manager
from .showairport import manager as show_airport_manager
from .showreceiver import manager as show_receiver_manager from .showreceiver import manager as show_receiver_manager
from .showdevices import manager as show_devices_manager from .showdevices import manager as show_devices_manager
from .logbook import manager as logbook_manager from .logbook import manager as logbook_manager
@ -8,6 +9,7 @@ from manager import Manager
manager = Manager() manager = Manager()
manager.merge(database_manager, namespace='db') manager.merge(database_manager, namespace='db')
manager.merge(show_airport_manager, namespace='show.airport')
manager.merge(show_receiver_manager, namespace='show.receiver') manager.merge(show_receiver_manager, namespace='show.receiver')
manager.merge(show_devices_manager, namespace='show.devices') manager.merge(show_devices_manager, namespace='show.devices')
manager.merge(logbook_manager, namespace='logbook') manager.merge(logbook_manager, namespace='logbook')

Wyświetl plik

@ -16,6 +16,8 @@ def init():
from alembic.config import Config from alembic.config import Config
from alembic import command from alembic import command
session.execute('CREATE EXTENSION IF NOT EXISTS postgis;')
session.commit()
Base.metadata.create_all(engine) Base.metadata.create_all(engine)
alembic_cfg = Config(ALEMBIC_CONFIG_FILE) alembic_cfg = Config(ALEMBIC_CONFIG_FILE)
command.stamp(alembic_cfg, "head") command.stamp(alembic_cfg, "head")
@ -64,7 +66,7 @@ def import_file(path='tests/custom_ddb.txt'):
@manager.command @manager.command
def import_airports(path='tests/Germany.cup'): def import_airports(path='tests/SeeYou.cup'):
"""Import airports from a ".cup" file""" """Import airports from a ".cup" file"""
print("Import airports from '{}'...".format(path)) print("Import airports from '{}'...".format(path))

Wyświetl plik

@ -1,10 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from datetime import timedelta from datetime import timedelta, datetime
from sqlalchemy.sql import func, null from sqlalchemy.sql import func, null
from sqlalchemy import and_, or_ from sqlalchemy import and_, or_
from sqlalchemy.sql.expression import true, false, label from sqlalchemy.sql.expression import true, false, label
from sqlalchemy.orm import aliased
from ogn.model import Device, TakeoffLanding, Airport from ogn.model import Device, TakeoffLanding, Airport
@ -24,8 +25,10 @@ def compute():
print("New/recalculated takeoffs/landings: {}".format(counter)) print("New/recalculated takeoffs/landings: {}".format(counter))
@manager.arg('date', help='date (format: yyyy-mm-dd')
@manager.arg('utc_delta_hours', help='delta hours to utc (for local time logs)')
@manager.command @manager.command
def show(airport_name): def show(airport_name, utc_delta_hours=0, date=None):
"""Show a logbook for <airport_name>.""" """Show a logbook for <airport_name>."""
airport = session.query(Airport) \ airport = session.query(Airport) \
.filter(Airport.name == airport_name) \ .filter(Airport.name == airport_name) \
@ -35,110 +38,152 @@ def show(airport_name):
print('Airport "{}" not found.'.format(airport_name)) print('Airport "{}" not found.'.format(airport_name))
return return
delta_altitude = 200 utc_timedelta = timedelta(hours=utc_delta_hours)
delta_radius = 0.01 # degree! or_args = []
if date is not None:
date = datetime.strptime(date, "%Y-%m-%d")
or_args = [and_(TakeoffLanding.timestamp >= date + utc_timedelta,
TakeoffLanding.timestamp < date + timedelta(hours=24) + utc_timedelta)]
# make a query with current, previous and next "takeoff_landing" event, so we can find complete flights # make a query with current, previous and next "takeoff_landing" event, so we can find complete flights
sq = session.query( sq = session.query(
TakeoffLanding.address, TakeoffLanding.device_id,
func.lag(TakeoffLanding.address) func.lag(TakeoffLanding.device_id)
.over( .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
order_by=and_(func.date(TakeoffLanding.timestamp), TakeoffLanding.device_id,
TakeoffLanding.address, TakeoffLanding.timestamp + utc_timedelta))
TakeoffLanding.timestamp)) .label('device_id_prev'),
.label('address_prev'), func.lead(TakeoffLanding.device_id)
func.lead(TakeoffLanding.address) .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
.over(order_by=and_(func.date(TakeoffLanding.timestamp), TakeoffLanding.device_id,
TakeoffLanding.address, TakeoffLanding.timestamp + utc_timedelta))
TakeoffLanding.timestamp)) .label('device_id_next'),
.label('address_next'), (TakeoffLanding.timestamp + utc_timedelta).label('timestamp'),
TakeoffLanding.timestamp,
func.lag(TakeoffLanding.timestamp) func.lag(TakeoffLanding.timestamp)
.over(order_by=and_(func.date(TakeoffLanding.timestamp), .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
TakeoffLanding.address, TakeoffLanding.device_id,
TakeoffLanding.timestamp)) TakeoffLanding.timestamp + utc_timedelta))
.label('timestamp_prev'), .label('timestamp_prev'),
func.lead(TakeoffLanding.timestamp) func.lead(TakeoffLanding.timestamp + utc_timedelta)
.over(order_by=and_(func.date(TakeoffLanding.timestamp), .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
TakeoffLanding.address, TakeoffLanding.device_id,
TakeoffLanding.timestamp)) TakeoffLanding.timestamp + utc_timedelta))
.label('timestamp_next'), .label('timestamp_next'),
TakeoffLanding.track, TakeoffLanding.track,
func.lag(TakeoffLanding.track) func.lag(TakeoffLanding.track)
.over(order_by=and_(func.date(TakeoffLanding.timestamp), .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
TakeoffLanding.address, TakeoffLanding.device_id,
TakeoffLanding.timestamp)) TakeoffLanding.timestamp + utc_timedelta))
.label('track_prev'), .label('track_prev'),
func.lead(TakeoffLanding.track) func.lead(TakeoffLanding.track)
.over(order_by=and_(func.date(TakeoffLanding.timestamp), .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
TakeoffLanding.address, TakeoffLanding.device_id,
TakeoffLanding.timestamp)) TakeoffLanding.timestamp + utc_timedelta))
.label('track_next'), .label('track_next'),
TakeoffLanding.is_takeoff, TakeoffLanding.is_takeoff,
func.lag(TakeoffLanding.is_takeoff) func.lag(TakeoffLanding.is_takeoff)
.over(order_by=and_(func.date(TakeoffLanding.timestamp), .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
TakeoffLanding.address, TakeoffLanding.device_id,
TakeoffLanding.timestamp)) TakeoffLanding.timestamp + utc_timedelta))
.label('is_takeoff_prev'), .label('is_takeoff_prev'),
func.lead(TakeoffLanding.is_takeoff) func.lead(TakeoffLanding.is_takeoff)
.over(order_by=and_(func.date(TakeoffLanding.timestamp), .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
TakeoffLanding.address, TakeoffLanding.device_id,
TakeoffLanding.timestamp)) TakeoffLanding.timestamp + utc_timedelta))
.label('is_takeoff_next')) \ .label('is_takeoff_next'),
.filter(func.ST_DFullyWithin(TakeoffLanding.location_wkt, Airport.location_wkt, delta_radius)) \ TakeoffLanding.airport_id,
.filter(TakeoffLanding.altitude < Airport.altitude + delta_altitude) \ func.lag(TakeoffLanding.airport_id)
.filter(Airport.name == airport.name) \ .over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
TakeoffLanding.device_id,
TakeoffLanding.timestamp + utc_timedelta))
.label('airport_id_prev'),
func.lead(TakeoffLanding.airport_id)
.over(order_by=and_(func.date(TakeoffLanding.timestamp + utc_timedelta),
TakeoffLanding.device_id,
TakeoffLanding.timestamp + utc_timedelta))
.label('airport_id_next')) \
.filter(*or_args) \
.subquery() .subquery()
# find complete flights (with takeoff and landing) with duration < 1 day # find complete flights (with takeoff and landing on the same day)
complete_flight_query = session.query(sq.c.timestamp.label('reftime'), sq.c.address.label('address'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), sq.c.timestamp_next.label('landing'), sq.c.track_next.label('landing_track'), label('duration', sq.c.timestamp_next - sq.c.timestamp)) \ complete_flight_query = session.query(sq.c.timestamp.label('reftime'),
sq.c.device_id.label('device_id'),
sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), sq.c.airport_id.label('takeoff_airport_id'),
sq.c.timestamp_next.label('landing'), sq.c.track_next.label('landing_track'), sq.c.airport_id_next.label('landing_airport_id'),
label('duration', sq.c.timestamp_next - sq.c.timestamp)) \
.filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \ .filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \
.filter(sq.c.address == sq.c.address_next) \ .filter(sq.c.device_id == sq.c.device_id_next) \
.filter(sq.c.timestamp_next - sq.c.timestamp < timedelta(days=1)) .filter(func.date(sq.c.timestamp_next) == func.date(sq.c.timestamp)) \
.filter(or_(sq.c.airport_id == airport.id,
sq.c.airport_id_next == airport.id))
# split complete flights (with takeoff and landing) with duration > 1 day into one takeoff and one landing # split complete flights (with takeoff and landing on different days) into one takeoff and one landing
split_start_query = session.query(sq.c.timestamp.label('reftime'), sq.c.address.label('address'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), null().label('landing'), null().label('landing_track'), null().label('duration')) \ split_start_query = session.query(sq.c.timestamp.label('reftime'),
sq.c.device_id.label('device_id'),
sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), sq.c.airport_id.label('takeoff_airport_id'),
null().label('landing'), null().label('landing_track'), null().label('landing_airport_id'),
null().label('duration')) \
.filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \ .filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \
.filter(sq.c.address == sq.c.address_next) \ .filter(sq.c.device_id == sq.c.device_id_next) \
.filter(sq.c.timestamp_next - sq.c.timestamp >= timedelta(days=1)) .filter(func.date(sq.c.timestamp_next) != func.date(sq.c.timestamp)) \
.filter(and_(sq.c.airport_id == airport.id,
sq.c.airport_id_next == airport.id))
split_landing_query = session.query(sq.c.timestamp_next.label('reftime'), sq.c.address.label('address'), null().label('takeoff'), null().label('takeoff_track'), sq.c.timestamp_next.label('landing'), sq.c.track_next.label('landing_track'), null().label('duration')) \ split_landing_query = session.query(sq.c.timestamp_next.label('reftime'),
sq.c.device_id.label('device_id'),
null().label('takeoff'), null().label('takeoff_track'), null().label('takeoff_airport_id'),
sq.c.timestamp_next.label('landing'), sq.c.track_next.label('landing_track'), sq.c.airport_id_next.label('landing_airport_id'),
null().label('duration')) \
.filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \ .filter(and_(sq.c.is_takeoff == true(), sq.c.is_takeoff_next == false())) \
.filter(sq.c.address == sq.c.address_next) \ .filter(sq.c.device_id == sq.c.device_id_next) \
.filter(sq.c.timestamp_next - sq.c.timestamp >= timedelta(days=1)) .filter(func.date(sq.c.timestamp_next) != func.date(sq.c.timestamp)) \
.filter(and_(sq.c.airport_id == airport.id,
sq.c.airport_id_next == airport.id))
# find landings without start # find landings without start
only_landings_query = session.query(sq.c.timestamp.label('reftime'), sq.c.address.label('address'), null().label('takeoff'), null().label('takeoff_track'), sq.c.timestamp.label('landing'), sq.c.track_next.label('landing_track'), null().label('duration')) \ only_landings_query = session.query(sq.c.timestamp.label('reftime'),
sq.c.device_id.label('device_id'),
null().label('takeoff'), null().label('takeoff_track'), null().label('takeoff_airport_id'),
sq.c.timestamp.label('landing'), sq.c.track_next.label('landing_track'), sq.c.airport_id_next.label('landing_airport_id'),
null().label('duration')) \
.filter(sq.c.is_takeoff == false()) \ .filter(sq.c.is_takeoff == false()) \
.filter(or_(sq.c.address != sq.c.address_prev, .filter(or_(sq.c.device_id != sq.c.device_id_prev,
sq.c.is_takeoff_prev == false())) sq.c.is_takeoff_prev == false())) \
.filter(sq.c.airport_id_next == airport.id)
# find starts without landing # find starts without landing
only_starts_query = session.query(sq.c.timestamp.label('reftime'), sq.c.address.label('address'), sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), null().label('landing'), null().label('landing_track'), null().label('duration')) \ only_starts_query = session.query(sq.c.timestamp.label('reftime'),
sq.c.device_id.label('device_id'),
sq.c.timestamp.label('takeoff'), sq.c.track.label('takeoff_track'), sq.c.airport_id.label('takeoff_airport_id'),
null().label('landing'), null().label('landing_track'), null().label('landing_airport_id'),
null().label('duration')) \
.filter(sq.c.is_takeoff == true()) \ .filter(sq.c.is_takeoff == true()) \
.filter(or_(sq.c.address != sq.c.address_next, .filter(or_(sq.c.device_id != sq.c.device_id_next,
sq.c.is_takeoff_next == true())) sq.c.is_takeoff_next == true())) \
.filter(sq.c.airport_id == airport.id)
# unite all # unite all
union_query = complete_flight_query.union( union_query = complete_flight_query.union(split_start_query,
split_start_query, split_landing_query,
split_landing_query, only_landings_query,
only_landings_query, only_starts_query) \
only_starts_query) \
.subquery() .subquery()
# get aircraft informations and sort all entries by the reference time # get aircraft and airport informations and sort all entries by the reference time
logbook_query = session.query( takeoff_airport = aliased(Airport, name='takeoff_airport')
union_query.c.reftime, landing_airport = aliased(Airport, name='landing_airport')
union_query.c.address, logbook_query = session.query(union_query.c.reftime,
union_query.c.takeoff, union_query.c.takeoff,
union_query.c.takeoff_track, union_query.c.takeoff_track,
union_query.c.landing, takeoff_airport,
union_query.c.landing_track, union_query.c.landing,
union_query.c.duration, union_query.c.landing_track,
Device.registration, landing_airport,
Device.aircraft) \ union_query.c.duration,
.outerjoin(Device, union_query.c.address == Device.address) \ Device) \
.outerjoin(Device, union_query.c.device_id == Device.id) \
.outerjoin(takeoff_airport, union_query.c.takeoff_airport_id == takeoff_airport.id) \
.outerjoin(landing_airport, union_query.c.landing_airport_id == landing_airport.id) \
.order_by(union_query.c.reftime) .order_by(union_query.c.reftime)
print('--- Logbook ({}) ---'.format(airport_name)) print('--- Logbook ({}) ---'.format(airport_name))
@ -152,19 +197,28 @@ def show(airport_name):
def none_timedelta_replacer(timedelta_object): def none_timedelta_replacer(timedelta_object):
return '--:--:--' if timedelta_object is None else timedelta_object return '--:--:--' if timedelta_object is None else timedelta_object
def none_registration_replacer(registration_object, address): def none_registration_replacer(device_object):
return '[' + address + ']' if registration_object is None else registration_object return '[' + device_object.address + ']' if device_object.registration is None else device_object.registration
def none_aircraft_replacer(aircraft_object): def none_aircraft_replacer(device_object):
return '(unknown)' if aircraft_object is None else aircraft_object return '(unknown)' if device_object.aircraft is None else device_object.aircraft
for [reftime, address, takeoff, takeoff_track, landing, landing_track, duration, registration, aircraft] in logbook_query.all(): def airport_marker(takeoff_airport_object, landing_airport_object):
print('%10s %8s (%2s) %8s (%2s) %8s %8s %s' % ( if takeoff_airport_object is not None and takeoff_airport_object.name is not airport.name:
return ('FROM: {}'.format(takeoff_airport_object.name))
elif landing_airport_object is not None and landing_airport_object.name is not airport.name:
return ('TO: {}'.format(landing_airport_object.name))
else:
return ('')
for [reftime, takeoff, takeoff_track, takeoff_airport, landing, landing_track, landing_airport, duration, device] in logbook_query.all():
print('%10s %8s (%2s) %8s (%2s) %8s %8s %17s %20s' % (
reftime.date(), reftime.date(),
none_datetime_replacer(takeoff), none_datetime_replacer(takeoff),
none_track_replacer(takeoff_track), none_track_replacer(takeoff_track),
none_datetime_replacer(landing), none_datetime_replacer(landing),
none_track_replacer(landing_track), none_track_replacer(landing_track),
none_timedelta_replacer(duration), none_timedelta_replacer(duration),
none_registration_replacer(registration, address), none_registration_replacer(device),
none_aircraft_replacer(aircraft))) none_aircraft_replacer(device),
airport_marker(takeoff_airport, landing_airport)))

Wyświetl plik

@ -0,0 +1,16 @@
from ogn.model import Airport
from ogn.commands.dbutils import session
from manager import Manager
manager = Manager()
@manager.command
def list_all():
"""Show a list of all airports."""
query = session.query(Airport) \
.order_by(Airport.name)
print('--- Airports ---')
for airport in query.all():
print(airport.name)

Wyświetl plik

@ -1,7 +1,8 @@
import logging import logging
from ogn.commands.dbutils import session from ogn.commands.dbutils import session
from ogn.model import AircraftBeacon, ReceiverBeacon, Location from ogn.model import AircraftBeacon, ReceiverBeacon, Device, Receiver, Location
from ogn.parser import parse_aprs, parse_ogn_receiver_beacon, parse_ogn_aircraft_beacon, ParseError from ogn.parser import parse_aprs, parse_ogn_receiver_beacon, parse_ogn_aircraft_beacon, ParseError
from ogn.model.address_origin import AddressOrigin
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -32,13 +33,48 @@ def process_beacon(raw_message):
# /z: ? # /z: ?
# /o: ? # /o: ?
if message['symboltable'] == "I" and message['symbolcode'] == '&': if message['symboltable'] == "I" and message['symbolcode'] == '&':
# ... we have a receiver_beacon
message.update(parse_ogn_receiver_beacon(message['comment'])) message.update(parse_ogn_receiver_beacon(message['comment']))
message = replace_lonlat_with_wkt(message) message = replace_lonlat_with_wkt(message)
beacon = ReceiverBeacon(**message) beacon = ReceiverBeacon(**message)
# connect beacon with receiver
receiver = session.query(Receiver.id) \
.filter(Receiver.name == beacon.name) \
.first()
if receiver is None:
receiver = Receiver()
receiver.name = beacon.name
session.add(receiver)
beacon.receiver_id = receiver.id
else: else:
# ... we have a aircraft_beacon
message.update(parse_ogn_aircraft_beacon(message['comment'])) message.update(parse_ogn_aircraft_beacon(message['comment']))
message = replace_lonlat_with_wkt(message) message = replace_lonlat_with_wkt(message)
beacon = AircraftBeacon(**message) beacon = AircraftBeacon(**message)
# connect beacon with device
device = session.query(Device.id) \
.filter(Device.address == beacon.address) \
.order_by(Device.address_origin) \
.first()
if device is None:
device = Device()
device.address = beacon.address
device.address_origin = AddressOrigin.seen
session.add(device)
beacon.device_id = device.id
# connect beacon with receiver
receiver = session.query(Receiver.id) \
.filter(Receiver.name == beacon.receiver_name) \
.first()
if receiver is None:
receiver = Receiver()
receiver.name = beacon.receiver_name
session.add(receiver)
beacon.receiver_id = receiver.id
session.add(beacon) session.add(beacon)
session.commit() session.commit()
logger.debug('Received message: {}'.format(raw_message)) logger.debug('Received message: {}'.format(raw_message))

Wyświetl plik

@ -2,9 +2,10 @@ class AddressOrigin:
ogn_ddb = 1 ogn_ddb = 1
flarmnet = 2 flarmnet = 2
user_defined = 3 user_defined = 3
seen = 4
def __init__(self, origin): def __init__(self, origin):
if origin in [1, 2, 3]: if origin in [1, 2, 3, 4]:
self.origin = origin self.origin = origin
else: else:
raise ValueError('no address origin with id {} known'.format(origin)) raise ValueError('no address origin with id {} known'.format(origin))
@ -16,4 +17,6 @@ class AddressOrigin:
return 'FlarmNet' return 'FlarmNet'
elif self.origin == self.user_defined: elif self.origin == self.user_defined:
return 'user-defined' return 'user-defined'
elif self.origin == self.seen:
return 'seen'
return '' return ''

Wyświetl plik

@ -1,4 +1,5 @@
from sqlalchemy import Column, String, Integer, Float, Boolean, SmallInteger from sqlalchemy import Column, String, Integer, Float, Boolean, SmallInteger, ForeignKey
from sqlalchemy.orm import relationship
from .beacon import Beacon from .beacon import Beacon
@ -8,9 +9,9 @@ class AircraftBeacon(Beacon):
# Flarm specific data # Flarm specific data
address_type = Column(SmallInteger) address_type = Column(SmallInteger)
aircraft_type = Column(SmallInteger) aircraft_type = Column(SmallInteger, index=True)
stealth = Column(Boolean) stealth = Column(Boolean)
address = Column(String(6), index=True) address = Column(String(6))
climb_rate = Column(Float) climb_rate = Column(Float)
turn_rate = Column(Float) turn_rate = Column(Float)
signal_strength = Column(Float) signal_strength = Column(Float)
@ -24,6 +25,13 @@ class AircraftBeacon(Beacon):
flightlevel = Column(Float) flightlevel = Column(Float)
# Relations
receiver_id = Column(Integer, ForeignKey('receiver.id', ondelete='SET NULL'), index=True)
receiver = relationship('Receiver', foreign_keys=[receiver_id])
device_id = Column(Integer, ForeignKey('device.id', ondelete='SET NULL'), index=True)
device = relationship('Device', foreign_keys=[device_id])
def __repr__(self): def __repr__(self):
return "<AircraftBeacon %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s>" % ( return "<AircraftBeacon %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s>" % (
self.name, self.name,

Wyświetl plik

@ -1,4 +1,5 @@
from sqlalchemy import Column, String, Integer, Float, SmallInteger from sqlalchemy import Column, String, Integer, Float, SmallInteger
from sqlalchemy.orm import relationship
from geoalchemy2.types import Geometry from geoalchemy2.types import Geometry
from .base import Base from .base import Base
@ -13,7 +14,7 @@ class Airport(Base):
altitude = Column(Integer) altitude = Column(Integer)
name = Column(String, index=True) name = Column(String, index=True)
code = Column(String(5)) code = Column(String(6))
country_code = Column(String(2)) country_code = Column(String(2))
style = Column(SmallInteger) style = Column(SmallInteger)
description = Column(String) description = Column(String)
@ -21,6 +22,9 @@ class Airport(Base):
runway_length = Column(Integer) runway_length = Column(Integer)
frequency = Column(Float) frequency = Column(Float)
# Relations
takeoff_landings = relationship('TakeoffLanding')
def __repr__(self): def __repr__(self):
return "<Airport %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,% s>" % ( return "<Airport %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,% s>" % (
self.name, self.name,

Wyświetl plik

@ -1,4 +1,5 @@
from sqlalchemy import Column, Integer, String, Unicode, Boolean, SmallInteger from sqlalchemy import Column, Integer, String, Unicode, Boolean, SmallInteger
from sqlalchemy.orm import relationship
from .base import Base from .base import Base
@ -17,9 +18,13 @@ class Device(Base):
frequency = Column(String) frequency = Column(String)
tracked = Column(Boolean) tracked = Column(Boolean)
identified = Column(Boolean) identified = Column(Boolean)
aircraft_type = Column(SmallInteger, index=True)
address_origin = Column(SmallInteger) address_origin = Column(SmallInteger)
# Relations
aircraft_beacons = relationship('AircraftBeacon')
def __repr__(self): def __repr__(self):
return "<Device: %s,%s,%s,%s,%s,%s,%s,%s,%s,%s>" % ( return "<Device: %s,%s,%s,%s,%s,%s,%s,%s,%s,%s>" % (
self.address_type, self.address_type,

Wyświetl plik

@ -1,4 +1,5 @@
from sqlalchemy import Column, String, Integer, DateTime from sqlalchemy import Column, String, Integer, DateTime
from sqlalchemy.orm import relationship
from geoalchemy2.types import Geometry from geoalchemy2.types import Geometry
from geoalchemy2.shape import to_shape from geoalchemy2.shape import to_shape
@ -21,6 +22,10 @@ class Receiver(Base):
version = Column(String) version = Column(String)
platform = Column(String) platform = Column(String)
# Relations
aircraft_beacons = relationship('AircraftBeacon')
receiver_beacons = relationship('ReceiverBeacon')
@property @property
def location(self): def location(self):
if self.location_wkt is None: if self.location_wkt is None:

Wyświetl plik

@ -1,4 +1,5 @@
from sqlalchemy import Column, Float, String from sqlalchemy import Column, Float, String, Integer, ForeignKey
from sqlalchemy.orm import relationship
from .beacon import Beacon from .beacon import Beacon
@ -20,5 +21,9 @@ class ReceiverBeacon(Beacon):
rec_crystal_correction_fine = 0 # obsolete since 0.2.0 rec_crystal_correction_fine = 0 # obsolete since 0.2.0
rec_input_noise = Column(Float) rec_input_noise = Column(Float)
# Relations
receiver_id = Column(Integer, ForeignKey('receiver.id', ondelete='SET NULL'), index=True)
receiver = relationship('Receiver', foreign_keys=[receiver_id])
def __repr__(self): def __repr__(self):
return "<ReceiverBeacon %s: %s>" % (self.name, self.version) return "<ReceiverBeacon %s: %s>" % (self.name, self.version)

Wyświetl plik

@ -1,10 +1,21 @@
from sqlalchemy import Column, String, Boolean from sqlalchemy import Boolean, Column, Integer, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from .beacon import Beacon from .base import Base
class TakeoffLanding(Beacon): class TakeoffLanding(Base):
__tablename__ = 'takeoff_landing' __tablename__ = 'takeoff_landing'
address = Column(String(6), index=True) id = Column(Integer, primary_key=True)
timestamp = Column(DateTime, index=True)
track = Column(Integer)
is_takeoff = Column(Boolean) is_takeoff = Column(Boolean)
# Relations
airport_id = Column(Integer, ForeignKey('airport.id', ondelete='SET NULL'), index=True)
airport = relationship('Airport', foreign_keys=[airport_id])
device_id = Column(Integer, ForeignKey('device.id', ondelete='SET NULL'), index=True)
device = relationship('Device', foreign_keys=[device_id])

Wyświetl plik

@ -2,7 +2,7 @@ import requests
import csv import csv
from io import StringIO from io import StringIO
from .model import Device, AddressOrigin, Airport, Location from .model import Device, Airport, Location
from geopy.geocoders import Nominatim from geopy.geocoders import Nominatim
from geopy.exc import GeopyError from geopy.exc import GeopyError
@ -10,7 +10,7 @@ from geopy.exc import GeopyError
from aerofiles.seeyou import Reader from aerofiles.seeyou import Reader
from ogn.parser.utils import feet2m from ogn.parser.utils import feet2m
DDB_URL = "http://ddb.glidernet.org/download" DDB_URL = "http://ddb.glidernet.org/download/?t=1"
address_prefixes = {'F': 'FLR', address_prefixes = {'F': 'FLR',
@ -25,28 +25,25 @@ def get_ddb(csvfile=None):
if csvfile is None: if csvfile is None:
r = requests.get(DDB_URL) r = requests.get(DDB_URL)
rows = '\n'.join(i for i in r.text.splitlines() if i[0] != '#') rows = '\n'.join(i for i in r.text.splitlines() if i[0] != '#')
address_origin = AddressOrigin.ogn_ddb
else: else:
r = open(csvfile, 'r') r = open(csvfile, 'r')
rows = ''.join(i for i in r.readlines() if i[0] != '#') rows = ''.join(i for i in r.readlines() if i[0] != '#')
address_origin = AddressOrigin.user_defined
data = csv.reader(StringIO(rows), quotechar="'", quoting=csv.QUOTE_ALL) data = csv.reader(StringIO(rows), quotechar="'", quoting=csv.QUOTE_ALL)
devices = list() devices = list()
for row in data: for row in data:
flarm = Device() device = Device()
flarm.address_type = row[0] device.address_type = row[0]
flarm.address = row[1] device.address = row[1]
flarm.aircraft = row[2] device.aircraft = row[2]
flarm.registration = row[3] device.registration = row[3]
flarm.competition = row[4] device.competition = row[4]
flarm.tracked = row[5] == 'Y' device.tracked = row[5] == 'Y'
flarm.identified = row[6] == 'Y' device.identified = row[6] == 'Y'
device.aircraft_type = int(row[7])
flarm.address_origin = address_origin devices.append(device)
devices.append(flarm)
return devices return devices
@ -77,6 +74,9 @@ def get_airports(cupfile):
for line in f: for line in f:
try: try:
for waypoint in Reader([line]): for waypoint in Reader([line]):
if waypoint['style'] > 5: # reject unlandable places
continue
airport = Airport() airport = Airport()
airport.name = waypoint['name'] airport.name = waypoint['name']
airport.code = waypoint['code'] airport.code = waypoint['code']

Wyświetl plik

@ -40,16 +40,14 @@ setup(
'aerofiles==0.3', 'aerofiles==0.3',
'geoalchemy2==0.3.0', 'geoalchemy2==0.3.0',
'shapely==1.5.15', 'shapely==1.5.15',
'ogn-client==0.3.0' 'ogn-client==0.3.0',
'psycopg2==2.6.1'
], ],
extras_require={ extras_require={
'dev': [ 'dev': [
'nose==1.3.7', 'nose==1.3.7',
'coveralls==0.4.4', 'coveralls==0.4.4',
'flake8==2.5.0' 'flake8==2.5.0'
],
'postgresql': [
'psycopg2==2.6.1'
] ]
}, },
zip_safe=False zip_safe=False

Wyświetl plik

@ -1,966 +0,0 @@
"Aachen Merzbruck",,DE,5049.383N,00611.183E,189.0m,5,080,520.0m,122.875,"Flugplatz"
"Aalen Heidenheim",,DE,4846.667N,01015.883E,585.0m,5,090,1000.0m,121.400,"Flugplatz"
"Achmer",,DE,5222.633N,00754.800E,53.0m,2,070,940.0m,123.050,"Flugplatz"
"Achterstedt Prv",,DE,5323.850N,00819.783E,1.0m,2,080,460.0m,123.425,"Flugplatz"
"Agathazeller Moo",,DE,4733.300N,01016.367E,727.0m,5,180,450.0m,123.350,"Flugplatz"
"Ahlen Nord Heli",,DE,5147.083N,00754.750E,88.0m,2,070,1060.0m,130.075,"Flugplatz"
"Ahlhorn",,DE,5253.333N,00813.950E,47.0m,5,090,2100.0m,122.100,"Flugplatz"
"Ahrenlohe",,DE,5342.000N,00944.483E,7.0m,5,050,600.0m,122.600,"Flugplatz"
"Aichach",,DE,4828.400N,01108.133E,439.0m,4,020,430.0m,122.300,"Flugplatz"
"Aichelberg X",,DE,4839.967N,00831.183E,798.0m,3,310,250.0m,,"Landefeld"
"Aichhalden",,DE,4838.667N,00832.717E,755.0m,3,020,300.0m,,"Landefeld"
"Ailertchen",,DE,5035.550N,00756.667E,469.0m,2,040,550.0m,123.050,"Flugplatz"
"Albstadt Deger",,DE,4814.983N,00903.833E,891.0m,2,090,960.0m,125.100,"Flugplatz"
"Allendorf",,DE,5102.100N,00840.850E,354.0m,5,110,1240.0m,118.175,"Flugplatz"
"Allstedt",,DE,5122.833N,01126.800E,284.0m,5,070,1200.0m,122.000,"Flugplatz"
"Alsfeld",,DE,5045.033N,00914.917E,292.0m,4,060,650.0m,123.500,"Flugplatz"
"Altenbachtal",,DE,4955.367N,00909.483E,130.0m,4,070,600.0m,126.500,"Segelflug"
"Altdorf Hagenhau",,DE,4923.217N,01125.267E,538.0m,4,050,500.0m,129.975,"Flugplatz"
"Altdorf Wallburg",,DE,4816.200N,00750.533E,194.0m,2,070,840.0m,127.150,"Flugplatz"
"Alte Ems Herbrum",,DE,5301.850N,00718.333E,1.0m,4,100,720.0m,123.150,"Segelflug"
"Altena Hegensche",,DE,5118.783N,00742.217E,473.0m,2,060,600.0m,122.200,"Flugplatz"
"Leipzig-Altenbur",,DE,5058.917N,01230.383E,195.0m,5,040,2230.0m,123.575,"Flugplatz"
"Altenstadt Mil",,DE,4750.133N,01052.267E,741.0m,2,090,680.0m,122.100,"Flugplatz"
"Altfeld",,DE,4949.917N,00932.233E,354.0m,5,100,560.0m,130.125,"Flugplatz"
"Altomuenster Ul",,DE,4822.900N,01116.383E,496.0m,3,020,200.0m,123.425,"Landefeld"
"Altoetting",,DE,4812.967N,01238.900E,398.0m,4,090,540.0m,123.500,"Flugplatz"
"Amberg 29 Rwy",,DE,4926.383N,01148.750E,391.0m,3,290,280.0m,123.350,"Landefeld"
"Amberg Rammerts",,DE,4926.350N,01148.383E,388.0m,4,080,710.0m,123.350,"Flugplatz"
"Am Deister Lauen",,DE,5217.650N,00922.667E,116.0m,3,090,350.0m,123.425,"Landefeld"
"Amoeneburg",,DE,5047.433N,00854.483E,230.0m,4,050,620.0m,122.475,"Flugplatz"
"Ampfing Waldkra",,DE,4815.800N,01224.733E,415.0m,2,090,890.0m,123.600,"Flugplatz"
"Am Salzgittersee",,DE,5210.217N,01018.950E,81.0m,4,050,720.0m,130.125,"Flugplatz"
"Am Stauffenberg",,DE,5121.717N,00937.767E,369.0m,4,090,330.0m,123.500,"Flugplatz"
"Anklam",,DE,5349.967N,01340.133E,6.0m,5,090,1000.0m,122.650,"Flugplatz"
"Ansbach Petersdo",,DE,4921.650N,01040.100E,418.0m,2,090,780.0m,123.650,"Flugplatz"
"Ansbach Mil Heli",,DE,4918.483N,01038.317E,466.0m,5,080,370.0m,122.100,"Flugplatz"
"An Den 7 Bergen",,DE,5203.450N,00948.633E,135.0m,4,080,570.0m,123.500,"Flugplatz"
"Anspach Taunus",,DE,5017.333N,00832.117E,335.0m,2,060,580.0m,121.025,"Flugplatz"
"Antdorf",,DE,4745.600N,01118.267E,615.0m,3,080,480.0m,,"Landefeld"
"Antersberg",,DE,4757.767N,01159.767E,498.0m,4,130,980.0m,123.350,"Flugplatz"
"Argenbuehl Eisen",,DE,4741.483N,00957.783E,684.0m,3,080,400.0m,123.425,"Landefeld"
"Arnbruck",,DE,4907.533N,01259.117E,524.0m,5,160,610.0m,118.550,"Flugplatz"
"Arnsberg Ruhrwie",,DE,5123.250N,00803.633E,185.0m,4,170,850.0m,123.400,"Flugplatz"
"Arnsberg-Menden",,DE,5129.017N,00753.883E,241.0m,5,050,920.0m,123.025,"Flugplatz"
"Arnschwang Ul",,DE,4916.300N,01246.700E,414.0m,3,050,400.0m,123.425,"Landefeld"
"Arnstadt Alkersl",,DE,5050.517N,01104.200E,351.0m,5,090,870.0m,123.000,"Flugplatz"
"Aschaffenburg",,DE,4956.333N,00903.750E,125.0m,5,080,840.0m,132.425,"Flugplatz"
"Aschersleben",,DE,5146.017N,01129.933E,162.0m,2,110,1050.0m,123.375,"Flugplatz"
"Asslarer Huette",,DE,5035.983N,00826.633E,232.0m,4,170,590.0m,129.975,"Flugplatz"
"Attendorn Finnen",,DE,5108.750N,00756.183E,317.0m,2,030,560.0m,121.400,"Flugplatz"
"Aue Bei Hattorf",,DE,5138.000N,01015.283E,190.0m,4,100,1050.0m,122.200,"Flugplatz"
"Auerbach",,DE,5029.833N,01222.683E,573.0m,5,010,800.0m,122.700,"Flugplatz"
"Augsburg",,DE,4825.517N,01055.900E,463.0m,5,070,1590.0m,124.975,"Flugplatz"
"Aukrug",,DE,5403.883N,00947.900E,17.0m,4,110,1000.0m,123.350,"Flugplatz"
"Aurach",,DE,4742.000N,01155.450E,808.0m,3,180,310.0m,,"Landefeld"
"Aventoft",,DE,5453.767N,00849.233E,2.0m,4,090,970.0m,122.400,"Flugplatz"
"Babenhausen",,DE,4957.167N,00858.150E,133.0m,5,060,670.0m,123.200,"Flugplatz"
"Bad Bibra Ul",,DE,5112.133N,01129.867E,298.0m,3,090,600.0m,123.425,"Landefeld"
"Bad Berka",,DE,5054.233N,01115.517E,305.0m,2,070,700.0m,123.650,"Flugplatz"
"Bad Buchau Feder",,DE,4803.300N,00938.383E,579.0m,4,080,500.0m,123.150,"Flugplatz"
"Backnang Heinin",,DE,4855.200N,00927.300E,297.0m,2,110,500.0m,126.500,"Flugplatz"
"Bad Brueckenau",,DE,5016.317N,00949.417E,402.0m,4,130,550.0m,123.500,"Flugplatz"
"Bad Ditzenbach",,DE,4833.767N,00943.733E,730.0m,2,160,600.0m,122.350,"Flugplatz"
"Bad Duerkheim",,DE,4928.383N,00811.783E,107.0m,5,080,600.0m,122.400,"Flugplatz"
"Bad Endorf Jolli",,DE,4755.617N,01217.233E,514.0m,2,170,770.0m,122.500,"Flugplatz"
"Baden Oos",,DE,4847.450N,00811.050E,125.0m,2,030,790.0m,121.000,"Flugplatz"
"Bad Frankenhause",,DE,5122.367N,01108.583E,241.0m,2,080,650.0m,122.600,"Flugplatz"
"Bad Gandersheim",,DE,5151.150N,01001.567E,239.0m,2,170,720.0m,123.000,"Flugplatz"
"Bad Hersfeld",,DE,5050.667N,00942.433E,239.0m,5,010,670.0m,124.000,"Flugplatz"
"Bad Kissingen",,DE,5012.633N,01004.167E,198.0m,2,170,800.0m,122.000,"Flugplatz"
"Bad Koenigshofen",,DE,5017.250N,01025.317E,313.0m,4,070,700.0m,130.125,"Flugplatz"
"Bad Langensalza",,DE,5107.750N,01037.300E,199.0m,2,090,800.0m,130.125,"Flugplatz"
"Bad Marienberg",,DE,5039.650N,00801.717E,544.0m,4,110,860.0m,129.975,"Flugplatz"
"Bad Neuenahr Ahr",,DE,5033.467N,00708.233E,204.0m,5,100,500.0m,122.350,"Flugplatz"
"Bad Neustadt/Saa",,DE,5018.367N,01013.633E,303.0m,5,130,600.0m,123.650,"Flugplatz"
"Bad Rotenfels",,DE,4849.450N,00817.433E,129.0m,3,140,260.0m,,"Landefeld"
"Bad Sobernheim",,DE,4947.483N,00740.000E,244.0m,2,040,680.0m,118.925,"Flugplatz"
"Bad Waldsee Reu",,DE,4754.900N,00942.600E,577.0m,2,150,660.0m,123.000,"Flugplatz"
"Bad Windsheim",,DE,4930.617N,01021.967E,370.0m,2,080,690.0m,118.275,"Flugplatz"
"Bad Worishofen-N",,DE,4800.983N,01036.900E,619.0m,2,080,800.0m,122.600,"Flugplatz"
"Bad Zwischenahn",,DE,5312.617N,00759.317E,9.0m,4,090,900.0m,123.500,"Flugplatz"
"Baerental",,DE,4752.700N,00806.717E,906.0m,3,050,250.0m,,"Landefeld"
"Baiersbron Cls",,DE,4832.283N,00823.900E,507.0m,3,170,230.0m,,"Landefeld"
"Baiersbronn",,DE,4830.933N,00822.400E,574.0m,3,050,220.0m,,"Landefeld"
"Ballenstedt",,DE,5144.750N,01113.750E,153.0m,5,090,680.0m,122.700,"Flugplatz"
"Baltrum",,DE,5343.517N,00722.333E,3.0m,5,100,360.0m,123.050,"Flugplatz"
"Bamberg",,DE,4955.233N,01054.850E,250.0m,5,040,1140.0m,120.175,"Flugplatz"
"Barssel",,DE,5309.867N,00747.650E,3.0m,2,120,770.0m,122.000,"Flugplatz"
"Bartholoma Amali",,DE,4844.800N,01000.300E,637.0m,2,160,900.0m,122.200,"Flugplatz"
"Barth",,DE,5420.300N,01242.617E,6.0m,5,090,1200.0m,118.075,"Flugplatz"
"Bad Salzungen Ul",,DE,5049.017N,01013.083E,236.0m,3,090,500.0m,123.425,"Landefeld"
"Basepohl Mil Cls",,DE,5344.717N,01257.133E,50.0m,3,110,500.0m,122.100,"Landefeld"
"Baumerlenbach",,DE,4913.833N,00925.150E,236.0m,5,080,420.0m,123.150,"Flugplatz"
"Baumholder Mil",,DE,4939.100N,00718.433E,442.0m,5,070,550.0m,122.100,"Flugplatz"
"Bautzen",,DE,5111.617N,01431.183E,174.0m,5,070,2200.0m,120.600,"Flugplatz"
"Bad Wildungen",,DE,5105.633N,00908.900E,332.0m,4,010,980.0m,123.350,"Flugplatz"
"Bayreuth",,DE,4959.117N,01138.467E,482.0m,5,060,1080.0m,127.525,"Flugplatz"
"Bayrischzll",,DE,4740.083N,01201.100E,797.0m,3,170,300.0m,,"Landefeld"
"Becherbach Ul",,DE,4938.567N,00741.033E,421.0m,3,060,400.0m,123.425,"Landefeld"
"Beelen",,DE,5155.900N,00804.900E,59.0m,2,090,450.0m,123.500,"Flugplatz"
"Beilngries",,DE,4901.267N,01129.083E,365.0m,2,100,600.0m,118.350,"Flugplatz"
"Bell Hundheim",,DE,5001.650N,00725.317E,445.0m,3,040,360.0m,120.975,"Landefeld"
"Benediktbeuren",,DE,4742.950N,01123.433E,609.0m,4,090,750.0m,123.500,"Flugplatz"
"Bensheimer Stadt",,DE,4941.517N,00834.967E,93.0m,4,140,620.0m,123.375,"Flugplatz"
"Berg Ravensburg",,DE,4749.967N,00932.500E,594.0m,3,030,270.0m,120.975,"Landefeld"
"Berching",,DE,4907.900N,01126.617E,390.0m,2,020,850.0m,123.350,"Flugplatz"
"Bergheim",,DE,5058.617N,00636.500E,70.0m,4,140,1100.0m,130.125,"Flugplatz"
"Bergneustadt",,DE,5103.117N,00742.433E,481.0m,2,040,600.0m,123.650,"Flugplatz"
"Berliner Heide",,DE,5240.183N,01022.233E,69.0m,4,030,1070.0m,123.500,"Flugplatz"
"Berlin Tegel",,DE,5233.583N,01317.267E,37.0m,5,080,3020.0m,124.525,"Flugplatz"
"Berneck",,DE,4834.383N,00943.783E,746.0m,4,160,840.0m,123.475,"Flugplatz"
"Berlin Schonfeld",,DE,5222.717N,01331.233E,49.0m,5,070,3600.0m,119.575,"Flugplatz"
"Bernau",,DE,4748.283N,00801.783E,921.0m,3,100,250.0m,,"Landefeld"
"Besenbfeldn",,DE,4835.950N,00824.767E,818.0m,3,320,450.0m,,"Landefeld"
"Besenbfelds",,DE,4835.267N,00825.300E,790.0m,3,040,350.0m,,"Landefeld"
"Betzdorf Kirchen",,DE,5049.017N,00749.817E,351.0m,2,080,500.0m,122.750,"Flugplatz"
"Biberach Riss",,DE,4806.700N,00945.800E,580.0m,5,040,980.0m,122.750,"Flugplatz"
"Bielefeld",,DE,5157.883N,00832.683E,137.0m,5,110,1250.0m,118.350,"Flugplatz"
"Bienenfarm",,DE,5239.733N,01244.717E,27.0m,2,120,850.0m,122.850,"Flugplatz"
"Binningen",,DE,4747.967N,00843.217E,489.0m,2,060,860.0m,130.600,"Flugplatz"
"Bischofsberg",,DE,5025.933N,01017.000E,342.0m,4,080,900.0m,122.200,"Flugplatz"
"Bisperode West",,DE,5204.733N,00928.567E,194.0m,4,060,1130.0m,123.150,"Flugplatz"
"Bitburg",,DE,4956.717N,00633.900E,372.0m,5,050,3050.0m,118.700,"Flugplatz"
"Blaubeuren",,DE,4825.183N,00947.850E,677.0m,2,100,870.0m,130.600,"Flugplatz"
"BleXEn",,DE,5332.350N,00832.367E,3.0m,2,090,1000.0m,120.600,"Flugplatz"
"Blomberg Borkhau",,DE,5155.033N,00906.667E,182.0m,2,060,590.0m,118.925,"Flugplatz"
"Blumberg",,DE,4750.667N,00833.917E,701.0m,2,070,780.0m,123.050,"Flugplatz"
"Boberg",,DE,5330.883N,01008.650E,2.0m,4,120,1240.0m,133.500,"Flugplatz"
"Bobzin Scharbow",,DE,5329.167N,01110.100E,49.0m,5,100,600.0m,123.425,"Flugplatz"
"Boehlen",,DE,5112.967N,01222.100E,131.0m,2,060,950.0m,123.000,"Flugplatz"
"Boesingen Ul",,DE,4813.667N,00832.083E,694.0m,3,090,410.0m,123.425,"Landefeld"
"Bohlenberger Fel",,DE,5325.100N,00754.250E,6.0m,4,060,950.0m,129.500,"Flugplatz"
"Bohlhof",,DE,4739.050N,00823.200E,558.0m,4,040,800.0m,129.975,"Flugplatz"
"Bohmte Bad Essen",,DE,5221.067N,00819.683E,45.0m,2,100,580.0m,122.500,"Flugplatz"
"Bohlsbach",,DE,4830.117N,00756.933E,151.0m,3,100,330.0m,,"Landefeld"
"Bonn Hangelar",,DE,5046.133N,00709.767E,61.0m,5,110,800.0m,135.150,"Flugplatz"
"Bopfingen",,DE,4850.900N,01020.050E,619.0m,5,070,930.0m,122.850,"Flugplatz"
"Borghorst Fuecht",,DE,5209.017N,00727.117E,47.0m,4,060,460.0m,123.350,"Flugplatz"
"Borkheide",,DE,5214.033N,01250.833E,62.0m,3,170,820.0m,,"Landefeld"
"Borkenberge",,DE,5146.800N,00717.283E,49.0m,5,080,670.0m,135.000,"Flugplatz"
"Borken HoXFeld",,DE,5151.183N,00648.917E,49.0m,2,120,740.0m,122.925,"Flugplatz"
"Borkum",,DE,5335.650N,00642.967E,1.0m,5,130,1000.0m,123.000,"Flugplatz"
"Boschhof",,DE,4749.000N,01125.000E,597.0m,3,020,400.0m,,"Landefeld"
"Bottenhorn",,DE,5047.683N,00827.650E,516.0m,2,110,520.0m,123.800,"Flugplatz"
"Brannenburg",,DE,4744.333N,01206.967E,467.0m,4,170,400.0m,122.500,"Flugplatz"
"Brandis Wald Cls",,DE,5119.683N,01239.350E,165.0m,3,080,1380.0m,129.250,"Landefeld"
"Brakel Ul 25M",,DE,5144.333N,00912.150E,164.0m,3,080,300.0m,123.425,"Landefeld"
"Brandenburg Mue",,DE,5226.217N,01235.583E,28.0m,2,100,730.0m,118.625,"Flugplatz"
"Braunfels",,DE,5031.533N,00823.583E,240.0m,4,070,430.0m,123.150,"Flugplatz"
"Braunschweig",,DE,5219.150N,01033.267E,92.0m,5,080,2300.0m,120.050,"Flugplatz"
"Bredstedt",,DE,5438.000N,00859.133E,7.0m,3,010,420.0m,122.800,"Landefeld"
"Breitscheid",,DE,5040.617N,00810.183E,562.0m,5,070,780.0m,122.600,"Flugplatz"
"Bremen",,DE,5302.850N,00847.217E,3.0m,5,090,2040.0m,120.325,"Flugplatz"
"Bremgarten",,DE,4754.200N,00737.050E,213.0m,5,050,1660.0m,122.000,"Flugplatz"
"Bremerhaven",,DE,5330.417N,00834.383E,3.0m,5,160,1200.0m,129.050,"Flugplatz"
"Briesen Brand",,DE,5203.183N,01345.950E,70.0m,3,100,1000.0m,,"Landefeld"
"Brilon",,DE,5124.150N,00838.517E,460.0m,5,070,750.0m,129.375,"Flugplatz"
"Brauna Kamenz",,DE,5117.000N,01403.517E,190.0m,3,080,380.0m,122.475,"Landefeld"
"Brockzetel",,DE,5328.883N,00739.100E,9.0m,4,110,1060.0m,123.500,"Flugplatz"
"Brodau Delitzsch",,DE,5129.883N,01219.783E,101.0m,3,010,270.0m,120.975,"Landefeld"
"Bronkow",,DE,5140.317N,01357.817E,128.0m,2,120,900.0m,130.325,"Flugplatz"
"Bruchsal",,DE,4908.117N,00833.817E,113.0m,2,120,500.0m,128.375,"Flugplatz"
"Buechig Ostheim",,DE,5026.900N,01015.150E,388.0m,4,100,550.0m,123.375,"Flugplatz"
"Buechel Mil",,DE,5010.433N,00703.800E,479.0m,5,030,2510.0m,122.100,"Flugplatz"
"Bueckeburg Wein",,DE,5215.050N,00901.067E,77.0m,4,110,1130.0m,129.975,"Flugplatz"
"Bueckeburg Mil",,DE,5216.700N,00904.933E,70.0m,5,080,1840.0m,122.100,"Flugplatz"
"Bueckeburg Nord",,DE,5215.217N,00900.850E,74.0m,4,110,1130.0m,129.975,"Flugplatz"
"Bueren Schwalnbr",,DE,5132.567N,00834.833E,265.0m,4,070,710.0m,123.350,"Flugplatz"
"Buhlbach X Wiese",,DE,4831.500N,00815.600E,649.0m,3,240,200.0m,,"Landefeld"
"Bundenthal Rumbc",,DE,4905.633N,00747.633E,308.0m,4,180,570.0m,123.350,"Flugplatz"
"Burg",,DE,5214.500N,01151.367E,52.0m,2,090,850.0m,122.050,"Flugplatz"
"Burg Feuerstein",,DE,4947.650N,01108.033E,501.0m,5,080,970.0m,130.775,"Flugplatz"
"Burgstaedt Ul ?",,DE,5054.733N,01249.350E,335.0m,3,060,180.0m,123.600,"Landefeld"
"Burgheim",,DE,4841.517N,01102.017E,406.0m,2,140,660.0m,123.350,"Flugplatz"
"Burgebrach Ul",,DE,4950.300N,01046.733E,282.0m,3,100,280.0m,123.425,"Landefeld"
"Butzbach Pfingst",,DE,5026.150N,00837.167E,340.0m,5,100,510.0m,133.500,"Flugplatz"
"Celle Arloh",,DE,5241.267N,01006.733E,64.0m,2,040,900.0m,123.650,"Flugplatz"
"Celle Mil",,DE,5235.467N,01001.333E,40.0m,5,080,1840.0m,122.100,"Flugplatz"
"Cham Janahof",,DE,4912.700N,01239.400E,364.0m,5,100,560.0m,130.125,"Flugplatz"
"Chemnitz Jahns",,DE,5044.850N,01250.233E,370.0m,5,070,900.0m,122.500,"Flugplatz"
"Coburg Brandstn",,DE,5015.750N,01059.750E,449.0m,5,120,630.0m,128.675,"Flugplatz"
"Coburg Steinrue",,DE,5013.833N,01059.717E,356.0m,2,070,700.0m,129.800,"Flugplatz"
"Coleman Mil",,DE,4933.817N,00827.800E,95.0m,5,050,920.0m,122.100,"Flugplatz"
"Cottbus Mil Cls",,DE,5146.083N,01417.517E,70.0m,3,080,2360.0m,,"Landefeld"
"Cottbus Drewitz",,DE,5153.367N,01431.917E,82.0m,5,070,2480.0m,118.125,"Flugplatz"
"Crawinkel Ul",,DE,5046.700N,01049.000E,473.0m,3,050,510.0m,123.425,"Landefeld"
"Crussow Ul",,DE,5300.883N,01404.133E,53.0m,3,140,300.0m,123.425,"Landefeld"
"Dachau Groebenr",,DE,4813.717N,01125.367E,489.0m,2,100,620.0m,118.425,"Flugplatz"
"Dahlemer Binz",,DE,5024.333N,00631.733E,579.0m,5,060,1070.0m,122.375,"Flugplatz"
"Damgarten Cls",,DE,5415.850N,01226.667E,5.0m,3,070,2000.0m,121.500,"Landefeld"
"Damme",,DE,5229.250N,00811.100E,46.0m,5,100,700.0m,133.300,"Flugplatz"
"Dankern Haren Ul",,DE,5248.150N,00709.617E,11.0m,3,100,360.0m,120.975,"Landefeld"
"Dauborn",,DE,5019.300N,00811.633E,164.0m,2,120,330.0m,123.500,"Flugplatz"
"Daun Senheld",,DE,5010.550N,00651.467E,526.0m,5,080,420.0m,123.150,"Flugplatz"
"Deckenpfronn Ege",,DE,4838.300N,00849.050E,578.0m,4,070,800.0m,130.125,"Flugplatz"
"Deggendorf",,DE,4849.817N,01252.783E,314.0m,5,090,550.0m,122.025,"Flugplatz"
"Degmarn",,DE,4915.467N,00916.467E,169.0m,4,080,700.0m,123.500,"Flugplatz"
"Dehausen Diemels",,DE,5127.800N,00902.967E,305.0m,4,160,650.0m,123.150,"Flugplatz"
"Der Dingel Huemm",,DE,5132.167N,00922.783E,220.0m,4,050,870.0m,123.500,"Flugplatz"
"Der Ring Schwalm",,DE,5054.183N,00914.433E,212.0m,4,030,660.0m,123.375,"Flugplatz"
"Dessau",,DE,5149.900N,01211.067E,56.0m,5,090,1000.0m,118.175,"Flugplatz"
"Dettingen 09 Rwy",,DE,4836.567N,00928.267E,374.0m,3,090,220.0m,122.175,"Landefeld"
"Detmold",,DE,5156.450N,00854.250E,189.0m,5,090,510.0m,122.750,"Flugplatz"
"Dettingen Teck",,DE,4836.500N,00928.533E,386.0m,4,130,490.0m,122.175,"Flugplatz"
"Diepholz Mil",,DE,5235.133N,00820.467E,40.0m,5,080,1280.0m,122.100,"Flugplatz"
"Dierdorf Wienau",,DE,5033.950N,00739.150E,291.0m,5,070,580.0m,128.925,"Flugplatz"
"Dillingen",,DE,4923.167N,00644.917E,239.0m,4,060,680.0m,130.125,"Flugplatz"
"Dingelstedt Ul",,DE,5159.183N,01058.033E,122.0m,3,100,330.0m,123.425,"Landefeld"
"Dingolfing",,DE,4839.400N,01229.933E,352.0m,2,080,660.0m,123.600,"Flugplatz"
"Dinkelsbuehl",,DE,4903.900N,01024.150E,488.0m,2,090,700.0m,118.425,"Flugplatz"
"Dinslaken Schwa",,DE,5136.967N,00651.933E,65.0m,5,080,1500.0m,122.700,"Flugplatz"
"Dobenreuth",,DE,4941.817N,01108.600E,338.0m,4,100,470.0m,123.350,"Flugplatz"
"Doebbersen",,DE,5333.567N,01103.050E,42.0m,3,160,250.0m,,"Landefeld"
"Doernberg Rwy21",,DE,5122.017N,00920.200E,439.0m,3,210,320.0m,122.300,"Landefeld"
"Doerzbach Hoheba",,DE,4921.050N,00942.883E,404.0m,3,150,270.0m,123.425,"Landefeld"
"Dolmar Kuendorf",,DE,5036.733N,01028.350E,515.0m,3,040,400.0m,123.425,"Landefeld"
"Donaueschingen",,DE,4758.417N,00831.333E,680.0m,5,180,1290.0m,124.250,"Flugplatz"
"Donauwoerth",,DE,4842.183N,01051.133E,399.0m,5,090,700.0m,134.125,"Flugplatz"
"Donstorf Ul",,DE,5239.300N,00833.417E,33.0m,3,170,310.0m,123.425,"Landefeld"
"Donzdorf Messe",,DE,4840.717N,00950.750E,690.0m,5,090,600.0m,122.600,"Flugplatz"
"Dorsten Kanal",,DE,5139.733N,00659.100E,32.0m,4,090,600.0m,123.350,"Flugplatz"
"Dortmund Wickede",,DE,5131.150N,00736.867E,128.0m,5,060,2000.0m,134.175,"Flugplatz"
"Drensteinfurt",,DE,5146.050N,00744.817E,69.0m,3,030,310.0m,123.425,"Landefeld"
"Dresden",,DE,5108.067N,01346.083E,229.0m,5,040,2850.0m,122.925,"Flugplatz"
"Drosa Bobbe Ul",,DE,5149.517N,01153.800E,72.0m,3,100,660.0m,123.425,"Landefeld"
"Duerabuch Cls",,DE,4815.733N,01112.583E,537.0m,4,080,850.0m,123.500,"Flugplatz"
"Duernbach",,DE,4745.933N,01143.933E,751.0m,3,160,500.0m,,"Landefeld"
"Dueren Huertgen",,DE,5041.633N,00625.100E,360.0m,4,060,770.0m,123.150,"Flugplatz"
"Duesseldorf",,DE,5117.267N,00646.150E,37.0m,5,050,3000.0m,118.300,"Flugplatz"
"Duesseld Wolfsaa",,DE,5115.883N,00651.217E,113.0m,4,070,800.0m,123.150,"Flugplatz"
"Durrweiler Hesel",,DE,4831.500N,00832.433E,650.0m,3,150,350.0m,123.425,"Landefeld"
"Ebern Sendelbach",,DE,5002.383N,01049.367E,253.0m,2,140,520.0m,122.500,"Flugplatz"
"Eberswalde Finow",,DE,5249.633N,01341.617E,37.0m,5,100,1480.0m,119.050,"Flugplatz"
"Edling",,DE,4804.300N,01208.150E,493.0m,3,110,340.0m,,"Landefeld"
"Egelsbach",,DE,4957.650N,00838.483E,119.0m,5,090,1400.0m,118.400,"Flugplatz"
"Eggenfelden",,DE,4823.767N,01243.283E,407.0m,5,080,1160.0m,120.300,"Flugplatz"
"Eggersdorf",,DE,5228.967N,01405.450E,67.0m,2,060,1200.0m,123.000,"Flugplatz"
"Ehlershausen Gr",,DE,5232.150N,01001.183E,45.0m,4,100,1010.0m,122.200,"Flugplatz"
"Eichstaett",,DE,4852.617N,01110.900E,524.0m,2,110,710.0m,123.000,"Flugplatz"
"Eisenhuettenstad",,DE,5211.833N,01435.133E,46.0m,5,110,1170.0m,122.000,"Flugplatz"
"Eisenach Kindel",,DE,5059.533N,01028.567E,335.0m,5,100,1720.0m,119.750,"Flugplatz"
"Ellwangen",,DE,4857.683N,01014.083E,503.0m,2,120,780.0m,122.000,"Flugplatz"
"Elsenthal Grafen",,DE,4849.350N,01322.050E,485.0m,2,160,460.0m,122.500,"Flugplatz"
"Elz",,DE,5025.600N,00800.600E,213.0m,2,070,750.0m,123.600,"Flugplatz"
"Emden",,DE,5323.467N,00713.533E,1.0m,5,070,1300.0m,118.600,"Flugplatz"
"Emmerich",,DE,5149.333N,00616.467E,13.0m,4,130,990.0m,123.350,"Flugplatz"
"Engelbrand",,DE,4849.900N,00838.150E,571.0m,3,060,450.0m,,"Landefeld"
"Enzloesterle",,DE,4839.800N,00827.967E,599.0m,3,040,260.0m,,"Landefeld"
"Epfenbach Ul",,DE,4919.250N,00855.017E,219.0m,3,070,220.0m,123.425,"Landefeld"
"Erbach",,DE,4820.517N,00955.000E,476.0m,2,030,650.0m,118.275,"Flugplatz"
"Erbendorf Schwei",,DE,4950.633N,01204.017E,494.0m,5,120,630.0m,123.350,"Flugplatz"
"Erding Mil",,DE,4819.333N,01156.917E,463.0m,5,080,2510.0m,120.200,"Flugplatz"
"Erfurt",,DE,5058.783N,01057.483E,317.0m,5,100,2600.0m,121.150,"Flugplatz"
"Erkelenz Kueckho",,DE,5103.900N,00621.583E,85.0m,3,160,450.0m,120.975,"Landefeld"
"Ernzen Ul",,DE,4949.733N,00626.133E,345.0m,3,050,450.0m,123.425,"Landefeld"
"Erpetshof Ul ?",,DE,4939.433N,01217.783E,497.0m,3,100,300.0m,123.425,"Landefeld"
"Eschelbach Ul",,DE,4834.183N,01136.533E,459.0m,3,110,380.0m,123.450,"Landefeld"
"Essen Muelheim",,DE,5124.133N,00656.233E,128.0m,5,070,1530.0m,119.750,"Flugplatz"
"Esslingen Jaege",,DE,4845.733N,00920.033E,496.0m,4,120,730.0m,122.475,"Flugplatz"
"Essweiler",,DE,4933.733N,00734.800E,409.0m,4,050,820.0m,129.975,"Flugplatz"
"Etting Adelmanns",,DE,4848.617N,01125.267E,382.0m,4,100,720.0m,123.500,"Flugplatz"
"Eudenbach",,DE,5040.333N,00721.917E,300.0m,4,090,800.0m,118.425,"Flugplatz"
"Eutingen",,DE,4829.133N,00846.700E,497.0m,4,060,710.0m,129.975,"Flugplatz"
"Falkenberg Loen",,DE,5132.867N,01313.683E,85.0m,5,080,1200.0m,130.125,"Flugplatz"
"Fall Sylvenstein",,DE,4734.167N,01132.983E,780.0m,3,160,470.0m,,"Landefeld"
"Farchant N",,DE,4732.417N,01106.483E,665.0m,3,030,350.0m,,"Landefeld"
"Farchant S",,DE,4731.417N,01106.483E,679.0m,3,020,300.0m,,"Landefeld"
"Farrenberg",,DE,4823.133N,00904.600E,794.0m,4,100,750.0m,123.475,"Flugplatz"
"Fassberg Mil",,DE,5255.150N,01011.033E,70.0m,5,090,2170.0m,122.100,"Flugplatz"
"Faulenfuerst1",,DE,4748.450N,00813.033E,1032.0m,3,130,250.0m,,"Landefeld"
"Faulenfuers3",,DE,4748.317N,00813.183E,1025.0m,3,130,280.0m,,"Landefeld"
"Fichtelbrunn",,DE,4929.883N,01139.567E,498.0m,4,090,360.0m,122.300,"Flugplatz"
"Finsterw Heinric",,DE,5138.067N,01340.317E,127.0m,2,080,1000.0m,123.500,"Flugplatz"
"Finsterw Schacks",,DE,5136.450N,01344.283E,122.0m,5,090,1200.0m,123.050,"Flugplatz"
"Fischbek",,DE,5327.350N,00949.783E,64.0m,4,120,910.0m,129.975,"Flugplatz"
"Fischbachau",,DE,4743.350N,01155.983E,754.0m,3,090,300.0m,,"Landefeld"
"Fischhausen",,DE,4742.550N,01152.117E,801.0m,3,140,400.0m,,"Landefeld"
"Flensburg",,DE,5446.400N,00922.733E,40.0m,5,110,1220.0m,122.850,"Flugplatz"
"Flintsbach",,DE,4743.350N,01206.850E,489.0m,4,090,430.0m,122.500,"Flugplatz"
"Frankfurt Hahn",,DE,4956.917N,00715.833E,503.0m,5,030,3800.0m,119.650,"Flugplatz"
"Frankfurt Main",,DE,5002.000N,00834.233E,110.0m,5,070,4000.0m,119.900,"Flugplatz"
"Freiburg",,DE,4801.367N,00749.967E,242.0m,5,160,1400.0m,118.250,"Flugplatz"
"Friedersdorf",,DE,5216.917N,01348.133E,33.0m,2,110,950.0m,122.200,"Flugplatz"
"Friedrichshafen",,DE,4740.283N,00930.683E,418.0m,5,060,2350.0m,120.075,"Flugplatz"
"Fritzlar Mil",,DE,5106.883N,00917.150E,174.0m,5,120,1040.0m,122.100,"Flugplatz"
"Friesoythe Ul",,DE,5301.767N,00748.000E,6.0m,3,080,340.0m,124.000,"Landefeld"
"Friesener Warte",,DE,4950.183N,01102.800E,517.0m,4,010,640.0m,122.200,"Flugplatz"
"Fuenftbronn",,DE,4836.667N,00829.417E,740.0m,3,050,350.0m,,"Landefeld"
"Furstenfeldb Cls",,DE,4812.333N,01116.033E,518.0m,5,090,2750.0m,123.700,"Flugplatz"
"Furth Seckendorf",,DE,4928.883N,01051.517E,334.0m,4,090,620.0m,123.475,"Flugplatz"
"Fuerstenzell",,DE,4831.083N,01320.767E,412.0m,5,150,480.0m,122.000,"Flugplatz"
"Fuessen",,DE,4735.000N,01041.450E,787.0m,4,080,1030.0m,123.350,"Flugplatz"
"Fulda Jossa",,DE,5028.517N,00926.533E,471.0m,2,080,580.0m,122.400,"Flugplatz"
"Further Drachenh",,DE,4917.817N,01252.200E,412.0m,3,120,230.0m,,"Landefeld"
"Gaggenau",,DE,4847.850N,00819.083E,165.0m,3,190,300.0m,,"Landefeld"
"Gammelsdorf",,DE,4834.067N,01155.950E,495.0m,4,180,770.0m,129.975,"Flugplatz"
"Ganderkesee",,DE,5302.167N,00830.317E,31.0m,5,080,830.0m,118.625,"Flugplatz"
"Garbenheimer Wie",,DE,5034.500N,00831.917E,151.0m,4,080,800.0m,122.300,"Flugplatz"
"Gardelegen",,DE,5231.833N,01121.217E,73.0m,2,080,550.0m,122.850,"Flugplatz"
"Garmisch O",,DE,4729.000N,01105.933E,731.0m,3,180,300.0m,,"Landefeld"
"Garmisch W",,DE,4728.300N,01103.283E,743.0m,3,040,250.0m,,"Landefeld"
"Gedern",,DE,5025.950N,00911.667E,371.0m,4,040,700.0m,123.475,"Flugplatz"
"Geesthacht Wiese",,DE,5326.933N,01020.350E,4.0m,3,120,410.0m,133.500,"Landefeld"
"Geilenkirche Mil",,DE,5057.650N,00602.550E,92.0m,5,090,3060.0m,120.050,"Flugplatz"
"Geitau",,DE,4740.767N,01157.733E,818.0m,4,160,550.0m,123.400,"Flugplatz"
"Gelnhausen",,DE,5011.783N,00910.067E,126.0m,2,070,840.0m,123.050,"Flugplatz"
"Gera Leumnitz",,DE,5052.883N,01208.133E,307.0m,5,060,750.0m,118.075,"Flugplatz"
"Geratshof",,DE,4759.583N,01050.617E,634.0m,4,080,250.0m,123.500,"Flugplatz"
"Gernsbach X",,DE,4846.417N,00820.283E,160.0m,3,030,220.0m,,"Landefeld"
"Gerstetten",,DE,4837.233N,01003.667E,599.0m,2,080,530.0m,123.000,"Flugplatz"
"Giebelstadt",,DE,4938.900N,00957.983E,299.0m,5,080,1980.0m,122.500,"Flugplatz"
"Giengen Brenz",,DE,4838.033N,01013.000E,518.0m,5,170,560.0m,122.350,"Flugplatz"
"Giessen Reiskir",,DE,5034.000N,00852.183E,213.0m,2,040,430.0m,123.650,"Flugplatz"
"Giessen Lutzell",,DE,5032.667N,00835.450E,232.0m,5,070,710.0m,122.500,"Flugplatz"
"Giessen Wieseck",,DE,5036.250N,00843.717E,165.0m,4,080,920.0m,122.000,"Flugplatz"
"Glasewitz Eh Fpl",,DE,5350.050N,01218.583E,47.0m,3,070,1100.0m,,"Landefeld"
"Goch Asperden",,DE,5141.450N,00606.233E,16.0m,2,100,750.0m,118.450,"Flugplatz"
"Goeppingen Betzg",,DE,4839.517N,00937.450E,374.0m,2,140,320.0m,,"Flugplatz"
"Goepfersdorf",,DE,5054.817N,01236.700E,291.0m,4,070,700.0m,123.475,"Flugplatz"
"Goerlitz",,DE,5109.533N,01457.017E,238.0m,2,060,740.0m,122.000,"Flugplatz"
"Goettingen Heili",,DE,5124.450N,01008.683E,363.0m,2,060,700.0m,122.200,"Flugplatz"
"Goettelfingen",,DE,4834.350N,00827.933E,776.0m,3,160,510.0m,,"Landefeld"
"Goeppingen Cls",,DE,4842.450N,00941.383E,371.0m,3,070,600.0m,122.100,"Landefeld"
"Goslar Bollrich",,DE,5154.283N,01027.550E,295.0m,4,060,540.0m,123.475,"Flugplatz"
"Gotha Ost",,DE,5058.217N,01043.750E,305.0m,2,080,550.0m,122.500,"Flugplatz"
"Grafenhausen1",,DE,4747.383N,00814.933E,962.0m,3,130,300.0m,,"Landefeld"
"Grafenhause3",,DE,4747.067N,00814.967E,959.0m,3,180,250.0m,,"Landefeld"
"Grabenstetten",,DE,4832.167N,00926.233E,710.0m,2,120,1110.0m,130.125,"Flugplatz"
"Grafenwoehr Mil",,DE,4941.917N,01156.417E,415.0m,5,140,1010.0m,122.100,"Flugplatz"
"Grambeker Heide",,DE,5335.000N,01041.917E,48.0m,4,090,860.0m,123.150,"Flugplatz"
"Gransee",,DE,5300.400N,01312.117E,51.0m,2,110,880.0m,126.725,"Flugplatz"
"Grabenstaett",,DE,4751.167N,01233.067E,537.0m,2,080,480.0m,129.975,"Flugplatz"
"Greding",,DE,4903.733N,01117.517E,525.0m,4,110,650.0m,122.500,"Flugplatz"
"Grefrath Niersho",,DE,5120.050N,00621.583E,31.0m,2,070,670.0m,123.625,"Flugplatz"
"Greiling B Toelz",,DE,4745.917N,01135.717E,713.0m,5,030,1250.0m,123.350,"Flugplatz"
"Greiz Obergroch",,DE,5038.650N,01210.500E,387.0m,2,050,740.0m,122.000,"Flugplatz"
"Griesau",,DE,4857.250N,01225.283E,321.0m,2,150,410.0m,122.600,"Flugplatz"
"Grifte Edermuend",,DE,5113.267N,00926.867E,202.0m,4,050,780.0m,123.500,"Flugplatz"
"Gross Garz Cls",,DE,5257.050N,01135.550E,18.0m,3,020,300.0m,123.425,"Landefeld"
"Grosse Hoehe",,DE,5259.183N,00834.333E,20.0m,4,040,920.0m,123.375,"Flugplatz"
"Gronenfelde Ul",,DE,5221.833N,01429.717E,63.0m,3,120,490.0m,120.975,"Landefeld"
"Grossrueckerswa",,DE,5038.650N,01307.717E,671.0m,2,110,1000.0m,123.000,"Flugplatz"
"Grossenhain",,DE,5118.483N,01333.333E,128.0m,5,110,2400.0m,122.700,"Flugplatz"
"Grosse Wiese",,DE,5208.233N,01034.250E,78.0m,4,070,760.0m,123.350,"Flugplatz"
"Grube",,DE,5414.667N,01101.433E,3.0m,2,090,500.0m,122.600,"Flugplatz"
"Gruenstadt Quirn",,DE,4935.133N,00808.367E,316.0m,4,180,900.0m,122.300,"Flugplatz"
"Gruibingen Norte",,DE,4837.267N,00939.317E,706.0m,4,080,520.0m,129.975,"Flugplatz"
"Guenching Ul",,DE,4916.067N,01134.383E,557.0m,3,060,440.0m,123.500,"Landefeld"
"Gunzburg Donau",,DE,4829.183N,01016.950E,445.0m,2,060,580.0m,118.125,"Flugplatz"
"Guestrow",,DE,5348.333N,01213.800E,14.0m,2,090,700.0m,122.000,"Flugplatz"
"Guetersloh Mil",,DE,5155.383N,00818.383E,73.0m,5,090,2240.0m,130.500,"Flugplatz"
"Gundelfingen",,DE,4834.167N,01021.517E,440.0m,2,100,580.0m,122.500,"Flugplatz"
"Gundelsheim Ul",,DE,4917.450N,00910.367E,273.0m,3,090,350.0m,123.425,"Landefeld"
"Gunzenhausen Re",,DE,4906.733N,01046.917E,485.0m,5,060,720.0m,118.550,"Flugplatz"
"Gustorfer Hoehe",,DE,5104.617N,00632.867E,89.0m,4,090,1030.0m,122.050,"Flugplatz"
"Hagen Hof",,DE,5118.433N,00725.617E,394.0m,4,100,410.0m,129.975,"Flugplatz"
"Hahnweide",,DE,4837.917N,00925.750E,352.0m,2,130,640.0m,123.250,"Flugplatz"
"Hain Modell 40M",,DE,5126.333N,01046.083E,266.0m,3,110,400.0m,123.425,"Landefeld"
"Hain Ul",,DE,5126.250N,01046.467E,268.0m,3,110,540.0m,123.425,"Landefeld"
"Haiterbach Nagol",,DE,4831.917N,00840.667E,596.0m,4,070,470.0m,123.350,"Flugplatz"
"Halbmeil X",,DE,4817.767N,00815.417E,291.0m,3,140,160.0m,,"Landefeld"
"Halle Oppin",,DE,5133.133N,01203.233E,107.0m,5,110,1120.0m,135.150,"Flugplatz"
"Hallertau",,DE,4838.967N,01135.783E,386.0m,4,030,770.0m,123.350,"Flugplatz"
"Hamburg Finkenw",,DE,5332.117N,00950.133E,6.0m,5,050,3180.0m,123.250,"Flugplatz"
"Hamburg Fuhlsbu",,DE,5337.833N,00959.300E,15.0m,5,150,3660.0m,121.275,"Flugplatz"
"Hameln Pyrmont",,DE,5157.967N,00917.450E,360.0m,5,040,600.0m,121.175,"Flugplatz"
"Hamm Lippewiesen",,DE,5141.417N,00749.067E,58.0m,5,060,900.0m,134.050,"Flugplatz"
"Hangensteinerhof",,DE,4855.967N,00848.917E,299.0m,4,070,550.0m,123.150,"Flugplatz"
"Hannover",,DE,5227.617N,00941.017E,55.0m,5,090,3800.0m,120.175,"Flugplatz"
"Harle",,DE,5342.400N,00749.217E,3.0m,5,090,510.0m,122.400,"Flugplatz"
"Hartenholm",,DE,5354.867N,01002.100E,37.0m,5,050,760.0m,118.125,"Flugplatz"
"Hartenstein Thie",,DE,5040.550N,01240.733E,408.0m,3,090,370.0m,120.975,"Landefeld"
"Haslach",,DE,4817.267N,00804.167E,207.0m,3,140,500.0m,,"Landefeld"
"Hassloch Pfalz",,DE,4921.317N,00817.417E,108.0m,4,080,920.0m,123.500,"Flugplatz"
"Hassfurt",,DE,5001.083N,01031.767E,220.0m,5,110,1100.0m,119.800,"Flugplatz"
"Hausach",,DE,4817.083N,00809.767E,235.0m,3,090,440.0m,,"Landefeld"
"Hausen",,DE,4740.433N,00750.483E,393.0m,3,020,400.0m,,"Landefeld"
"Hausham",,DE,4744.800N,01151.150E,781.0m,3,100,300.0m,,"Landefeld"
"Hayingen",,DE,4817.083N,00927.933E,703.0m,4,140,810.0m,123.500,"Flugplatz"
"Heilbronn Boecki",,DE,4907.300N,00910.767E,159.0m,4,070,760.0m,123.500,"Flugplatz"
"Heide Buesum",,DE,5409.200N,00854.100E,3.0m,5,110,720.0m,122.600,"Flugplatz"
"Heiligenberg",,DE,4750.000N,00918.067E,759.0m,4,180,500.0m,123.500,"Flugplatz"
"Heinsberg Aphov",,DE,5103.033N,00603.250E,65.0m,3,140,260.0m,123.425,"Landefeld"
"Heldburg",,DE,5016.200N,01044.067E,286.0m,3,160,600.0m,123.425,"Landefeld"
"Helgoland Duene",,DE,5411.117N,00754.950E,3.0m,5,150,480.0m,122.450,"Flugplatz"
"Hellenhagen",,DE,5201.517N,00933.883E,181.0m,4,100,260.0m,123.150,"Flugplatz"
"Helmstedt Rote",,DE,5214.033N,01058.700E,111.0m,4,080,940.0m,122.475,"Flugplatz"
"Hellingst",,DE,5322.500N,00851.000E,20.0m,4,130,1000.0m,123.500,"Flugplatz"
"Helm Unterthal",,DE,5009.367N,00952.683E,272.0m,3,170,330.0m,,"Landefeld"
"Hengsen Opherdic",,DE,5128.400N,00738.700E,132.0m,4,080,540.0m,123.450,"Flugplatz"
"Heppenheim",,DE,4937.283N,00837.500E,98.0m,2,150,1110.0m,122.475,"Flugplatz"
"Heringsdorf",,DE,5352.717N,01409.133E,28.0m,5,100,2300.0m,132.825,"Flugplatz"
"Hermuthausen",,DE,4918.867N,00944.717E,410.0m,4,080,990.0m,123.500,"Flugplatz"
"Herrenteich",,DE,4920.750N,00829.300E,91.0m,2,040,630.0m,132.050,"Flugplatz"
"Herrischried",,DE,4740.517N,00800.450E,904.0m,3,120,250.0m,,"Landefeld"
"Hersbruck",,DE,4930.450N,01126.617E,335.0m,4,090,470.0m,122.050,"Flugplatz"
"Herten Rheinfld",,DE,4733.600N,00744.900E,284.0m,2,060,730.0m,123.250,"Flugplatz"
"Herzogenaurach",,DE,4934.967N,01052.700E,324.0m,5,080,700.0m,122.850,"Flugplatz"
"Hessisch Lichten",,DE,5111.333N,00944.567E,411.0m,4,090,800.0m,123.500,"Flugplatz"
"Hettstadt",,DE,4947.917N,00950.217E,320.0m,2,090,550.0m,122.425,"Flugplatz"
"Hetzleser Berg",,DE,4938.533N,01109.750E,528.0m,5,080,600.0m,123.600,"Flugplatz"
"Heubach",,DE,4848.183N,00955.667E,433.0m,5,070,750.0m,123.025,"Flugplatz"
"Hienheim",,DE,4852.683N,01145.633E,397.0m,4,110,540.0m,123.500,"Flugplatz"
"Hildesheim",,DE,5210.783N,00956.733E,88.0m,5,070,1220.0m,118.300,"Flugplatz"
"Hilzingen",,DE,4745.633N,00846.050E,459.0m,4,090,820.0m,123.375,"Flugplatz"
"Hinterweiler",,DE,5014.700N,00645.317E,598.0m,3,060,270.0m,123.425,"Landefeld"
"Hirzenhain",,DE,5047.267N,00823.550E,528.0m,2,110,650.0m,118.325,"Flugplatz"
"Hirzenhain Nw-Ha",,DE,5048.100N,00822.667E,544.0m,4,310,150.0m,118.325,"Flugplatz"
"Hockenheim",,DE,4919.483N,00831.667E,93.0m,2,140,840.0m,123.650,"Flugplatz"
"Hodenhagen",,DE,5245.750N,00936.733E,22.0m,2,030,900.0m,119.000,"Flugplatz"
"Hoechenschwand1",,DE,4743.633N,00810.717E,969.0m,3,110,300.0m,,"Landefeld"
"Hoechenschw3",,DE,4744.000N,00809.617E,1016.0m,3,180,250.0m,,"Landefeld"
"Hoelleberg",,DE,5136.650N,00923.917E,257.0m,2,080,520.0m,122.000,"Flugplatz"
"Hoepen",,DE,5308.833N,00947.800E,85.0m,4,100,920.0m,122.475,"Flugplatz"
"Hoerbach",,DE,5040.100N,00815.633E,330.0m,4,050,310.0m,130.125,"Flugplatz"
"HoeXTer Holzmin",,DE,5148.383N,00922.700E,284.0m,5,140,810.0m,123.625,"Flugplatz"
"Hof-Plauen",,DE,5017.317N,01151.200E,598.0m,5,090,1480.0m,124.350,"Flugplatz"
"Hohenfels Mil",,DE,4913.000N,01150.150E,445.0m,5,090,670.0m,122.100,"Flugplatz"
"Hoherodskopf",,DE,5030.100N,00913.350E,674.0m,4,070,860.0m,123.500,"Flugplatz"
"Hohn Mil",,DE,5418.733N,00932.300E,12.0m,5,080,2450.0m,122.100,"Flugplatz"
"Hohentann Lands",,DE,4839.767N,01203.533E,471.0m,3,070,320.0m,123.425,"Landefeld"
"Holtorfsloh",,DE,5319.333N,01004.467E,55.0m,4,150,690.0m,123.350,"Flugplatz"
"Holzdorf Mil",,DE,5146.083N,01310.050E,82.0m,5,090,2420.0m,122.100,"Flugplatz"
"Homberg Ohm",,DE,5044.833N,00901.183E,349.0m,4,040,700.0m,123.500,"Flugplatz"
"Hoppensen Einbec",,DE,5147.183N,00945.317E,180.0m,3,070,380.0m,123.425,"Landefeld"
"Hoppstaedten We",,DE,4936.650N,00711.200E,332.0m,5,060,670.0m,130.650,"Flugplatz"
"Hornberg",,DE,4844.683N,00951.750E,682.0m,4,170,650.0m,122.025,"Flugplatz"
"Hoya",,DE,5248.717N,00909.833E,15.0m,4,120,680.0m,122.475,"Flugplatz"
"Hoym Ul",,DE,5146.683N,01117.117E,144.0m,3,100,350.0m,123.425,"Landefeld"
"Huelben",,DE,4831.750N,00923.867E,718.0m,4,090,660.0m,133.500,"Flugplatz"
"Huensborn",,DE,5055.717N,00753.950E,421.0m,2,090,950.0m,130.125,"Flugplatz"
"Hutten Hotzenwal",,DE,4737.983N,00756.483E,873.0m,4,110,710.0m,130.125,"Flugplatz"
"Huettenbusch",,DE,5317.200N,00856.900E,3.0m,2,090,450.0m,122.850,"Flugplatz"
"Huhnrain As",,DE,5029.400N,00950.833E,434.0m,5,080,500.0m,133.425,"Flugplatz"
"Husum",,DE,5430.600N,00908.300E,18.0m,5,030,1450.0m,122.050,"Flugplatz"
"Ibach",,DE,4743.617N,00803.867E,926.0m,3,170,250.0m,,"Landefeld"
"Ibach X",,DE,4826.700N,00810.100E,326.0m,3,160,250.0m,,"Landefeld"
"Idar Oberstein",,DE,4943.933N,00720.167E,475.0m,2,060,650.0m,122.850,"Flugplatz"
"Igelsloch",,DE,4844.867N,00839.233E,680.0m,3,110,250.0m,,"Landefeld"
"Igelsberg",,DE,4832.250N,00826.133E,749.0m,3,060,300.0m,,"Landefeld"
"Illertissen",,DE,4814.117N,01008.267E,512.0m,2,070,540.0m,118.525,"Flugplatz"
"Illeshe Mil Heli",,DE,4928.433N,01023.283E,329.0m,2,060,1500.0m,122.100,"Flugplatz"
"Imsweiler Donne",,DE,4936.367N,00747.617E,289.0m,3,060,280.0m,123.425,"Landefeld"
"Ingelfingen Bueh",,DE,4919.300N,00939.817E,421.0m,5,070,480.0m,130.600,"Flugplatz"
"Ingolstadt Manch",,DE,4842.933N,01132.033E,366.0m,5,070,2940.0m,122.100,"Flugplatz"
"Ippesheim Ul",,DE,4936.583N,01013.533E,297.0m,3,100,350.0m,120.975,"Landefeld"
"Irsingen",,DE,4902.300N,01030.183E,466.0m,4,260,560.0m,122.475,"Flugplatz"
"Iserlohn Rheiner",,DE,5125.817N,00738.650E,191.0m,4,070,800.0m,123.500,"Flugplatz"
"Iserlohn Suemmer",,DE,5126.250N,00742.100E,157.0m,4,040,440.0m,122.425,"Flugplatz"
"Isny Rotmoos",,DE,4742.017N,01001.233E,689.0m,4,080,450.0m,123.500,"Flugplatz"
"Ithwiesen",,DE,5157.067N,00939.767E,375.0m,2,320,850.0m,122.375,"Flugplatz"
"Itzehoe",,DE,5359.667N,00934.717E,24.0m,5,030,1040.0m,123.375,"Flugplatz"
"Jachenau Hoefen?",,DE,4736.483N,01129.500E,734.0m,3,070,300.0m,,"Landefeld"
"Jena Schongleina",,DE,5054.933N,01142.850E,375.0m,5,020,1170.0m,122.050,"Flugplatz"
"Jesenwang",,DE,4810.467N,01107.517E,565.0m,5,070,410.0m,120.050,"Flugplatz"
"Jever Mil",,DE,5332.017N,00753.317E,6.0m,5,100,2480.0m,118.725,"Flugplatz"
"Johannisau",,DE,5032.217N,00939.750E,265.0m,4,060,300.0m,122.300,"Flugplatz"
"Jueterbog Altes",,DE,5159.800N,01258.017E,94.0m,3,100,480.0m,123.425,"Landefeld"
"Juist",,DE,5340.883N,00703.400E,3.0m,5,080,700.0m,120.500,"Flugplatz"
"Kaelberbronn",,DE,4831.917N,00829.750E,706.0m,3,230,210.0m,,"Landefeld"
"Kalkhorst Agrar",,DE,5358.500N,01101.350E,22.0m,3,060,320.0m,,"Landefeld"
"Kamen Heeren",,DE,5135.417N,00742.600E,63.0m,4,110,970.0m,129.975,"Flugplatz"
"Kamenz",,DE,5117.817N,01407.650E,153.0m,5,030,1100.0m,122.050,"Flugplatz"
"Kammermark",,DE,5311.717N,01209.850E,84.0m,4,080,1040.0m,123.500,"Flugplatz"
"Kamp-Lintfort",,DE,5131.767N,00632.217E,21.0m,2,070,790.0m,123.000,"Flugplatz"
"Karbach",,DE,4952.400N,00940.083E,256.0m,3,090,180.0m,,"Landefeld"
"Karlsruhe Baden",,DE,4846.750N,00804.833E,125.0m,5,030,3000.0m,134.100,"Flugplatz"
"Karlshoefen",,DE,5319.967N,00901.717E,6.0m,5,120,700.0m,118.925,"Flugplatz"
"Karlstadt Saupur",,DE,4958.283N,00947.483E,248.0m,4,090,540.0m,123.475,"Flugplatz"
"Kassel Calden",,DE,5125.250N,00923.533E,250.0m,5,090,2500.0m,118.100,"Flugplatz"
"Kaufbeuren",,DE,4751.683N,01036.850E,726.0m,5,020,1830.0m,122.200,"Flugplatz"
"Kehl Sundheim",,DE,4833.683N,00750.633E,137.0m,2,030,680.0m,122.750,"Flugplatz"
"Kell",,DE,4937.300N,00650.417E,559.0m,4,050,820.0m,123.150,"Flugplatz"
"Kemmen Ul 30M",,DE,5247.733N,01306.283E,35.0m,3,140,360.0m,123.425,"Landefeld"
"Kempten Durach",,DE,4741.467N,01020.283E,710.0m,2,170,900.0m,122.000,"Flugplatz"
"Kerken",,DE,5126.317N,00626.733E,32.0m,3,020,250.0m,123.425,"Landefeld"
"Kiel Holtenau",,DE,5422.767N,01008.717E,31.0m,5,080,1260.0m,119.975,"Flugplatz"
"Kirchzarten",,DE,4757.050N,00757.350E,415.0m,4,180,1170.0m,122.475,"Flugplatz"
"Kirchdorf Inn",,DE,4814.300N,01258.617E,340.0m,2,040,670.0m,118.625,"Flugplatz"
"Kirn",,DE,4946.433N,00731.300E,429.0m,4,140,590.0m,123.375,"Flugplatz"
"Kitzingen",,DE,4944.517N,01012.117E,202.0m,5,070,800.0m,123.150,"Flugplatz"
"Kleinkoschen Ul",,DE,5130.600N,01404.983E,106.0m,3,150,410.0m,122.300,"Landefeld"
"Klein Muehlingen",,DE,5156.850N,01146.183E,53.0m,2,090,470.0m,122.000,"Flugplatz"
"Kleve Wisseler D",,DE,5146.167N,00617.950E,18.0m,4,070,510.0m,123.150,"Flugplatz"
"Kleinhartpenning",,DE,4751.100N,01139.967E,720.0m,3,070,300.0m,,"Landefeld"
"Klietz Scharlibb",,DE,5242.600N,01204.383E,26.0m,2,170,710.0m,122.375,"Flugplatz"
"Klippeneck Feld",,DE,4806.333N,00843.167E,685.0m,3,070,300.0m,,"Landefeld"
"Klippeneck",,DE,4806.467N,00845.750E,962.0m,4,050,1040.0m,122.175,"Flugplatz"
"KliX",,DE,5116.433N,01430.417E,145.0m,2,100,900.0m,118.600,"Flugplatz"
"Kniebis",,DE,4828.350N,00817.650E,920.0m,3,060,250.0m,,"Landefeld"
"Koblenz Winninge",,DE,5019.517N,00731.683E,195.0m,5,060,1170.0m,122.650,"Flugplatz"
"Kochel",,DE,4740.250N,01121.167E,599.0m,3,130,400.0m,,"Landefeld"
"Koln-Bonn",,DE,5051.950N,00708.567E,92.0m,5,140,3810.0m,124.975,"Flugplatz"
"Koenigsdorf",,DE,4749.717N,01127.967E,600.0m,5,100,740.0m,118.275,"Flugplatz"
"Kothen",,DE,5143.417N,01156.883E,93.0m,5,070,800.0m,123.650,"Flugplatz"
"Kohlenbissen Mil",,DE,5259.450N,01009.417E,80.0m,3,070,450.0m,121.500,"Landefeld"
"Konstanz",,DE,4740.900N,00908.283E,396.0m,2,120,760.0m,124.350,"Flugplatz"
"Konz Koenen",,DE,4940.533N,00632.567E,217.0m,4,020,780.0m,123.350,"Flugplatz"
"Korbach",,DE,5115.150N,00852.400E,390.0m,2,030,600.0m,119.975,"Flugplatz"
"Krefeld Egelsber",,DE,5123.083N,00635.267E,43.0m,2,060,640.0m,120.675,"Flugplatz"
"Kronach",,DE,5014.617N,01121.533E,466.0m,4,120,650.0m,123.350,"Flugplatz"
"Kruen",,DE,4730.600N,01116.000E,889.0m,3,070,500.0m,,"Landefeld"
"Kuehrstedt Beder",,DE,5334.083N,00847.367E,9.0m,2,120,580.0m,135.000,"Flugplatz"
"Kulmbach",,DE,5008.100N,01127.550E,506.0m,5,090,710.0m,118.525,"Flugplatz"
"Kunrau Ul 30M",,DE,5234.050N,01059.667E,65.0m,3,080,350.0m,123.425,"Landefeld"
"Kusel Langenbach",,DE,4928.683N,00718.533E,457.0m,4,100,520.0m,123.350,"Flugplatz"
"Kyritz",,DE,5255.133N,01225.517E,40.0m,5,140,1000.0m,122.725,"Flugplatz"
"Laage Mil",,DE,5355.083N,01216.700E,43.0m,5,100,2520.0m,118.425,"Flugplatz"
"Lachen Speyerdo",,DE,4919.800N,00812.767E,118.0m,2,110,1000.0m,118.175,"Flugplatz"
"Lager Hammelbur",,DE,5005.917N,00953.033E,342.0m,2,100,550.0m,118.425,"Flugplatz"
"Lahr",,DE,4822.150N,00749.667E,156.0m,5,030,3000.0m,125.175,"Flugplatz"
"Laichingen",,DE,4829.817N,00938.417E,746.0m,5,070,730.0m,127.700,"Flugplatz"
"Langenberg 36",,DE,5047.617N,00933.683E,360.0m,3,360,250.0m,123.500,"Landefeld"
"Landau Ebenberg",,DE,4910.583N,00808.167E,162.0m,4,100,590.0m,123.375,"Flugplatz"
"Landshut",,DE,4830.700N,01202.000E,399.0m,5,070,900.0m,129.800,"Flugplatz"
"Landsberg Mil",,DE,4804.233N,01054.367E,622.0m,5,070,2050.0m,122.100,"Flugplatz"
"Langenberg Hatte",,DE,5047.850N,00933.800E,350.0m,4,200,880.0m,123.500,"Flugplatz"
"Langeoog",,DE,5344.567N,00729.917E,3.0m,5,050,600.0m,122.025,"Flugplatz"
"Langhennersdorf",,DE,5056.917N,01315.717E,390.0m,2,050,900.0m,122.300,"Flugplatz"
"Langenlonsheim",,DE,4954.500N,00754.467E,92.0m,2,010,450.0m,122.875,"Flugplatz"
"Langenselbold",,DE,5010.617N,00904.000E,118.0m,4,070,400.0m,129.975,"Flugplatz"
"Langenfeld Wiesc",,DE,5108.450N,00659.117E,86.0m,4,070,620.0m,122.475,"Flugplatz"
"Langenbrand",,DE,4848.383N,00837.517E,702.0m,3,330,400.0m,,"Landefeld"
"Laucha",,DE,5114.767N,01141.617E,226.0m,2,090,720.0m,122.475,"Flugplatz"
"Lauda Landefeld",,DE,4934.483N,00942.583E,185.0m,3,160,370.0m,,"Landefeld"
"Lauenbrueck",,DE,5312.467N,00934.400E,29.0m,2,110,600.0m,123.650,"Flugplatz"
"Laufenselden",,DE,5013.300N,00759.917E,400.0m,4,050,510.0m,122.475,"Flugplatz"
"Lauf Lillinghof",,DE,4936.317N,01117.017E,544.0m,5,070,450.0m,133.500,"Flugplatz"
"Laupheim Mil",,DE,4813.200N,00954.617E,540.0m,5,090,1660.0m,122.100,"Flugplatz"
"Lauterbach",,DE,5041.017N,00924.683E,364.0m,2,060,600.0m,122.175,"Flugplatz"
"Leibertingen",,DE,4802.683N,00901.833E,833.0m,4,100,940.0m,129.975,"Flugplatz"
"Lechfeld Mil",,DE,4811.133N,01051.667E,555.0m,5,030,2660.0m,122.100,"Flugplatz"
"Leck",,DE,5447.400N,00857.683E,6.0m,2,120,820.0m,122.600,"Flugplatz"
"Leer Papenburg",,DE,5316.317N,00726.517E,1.0m,5,080,1200.0m,130.775,"Flugplatz"
"Leipheim",,DE,4826.450N,01014.283E,473.0m,5,060,610.0m,122.500,"Flugplatz"
"Leipzig",,DE,5125.433N,01214.183E,143.0m,5,080,3600.0m,121.100,"Flugplatz"
"Lengries1",,DE,4740.850N,01133.600E,698.0m,3,260,400.0m,,"Landefeld"
"Lengries3",,DE,4740.000N,01134.000E,716.0m,3,090,400.0m,,"Landefeld"
"Lenzkirch",,DE,4752.100N,00811.367E,834.0m,3,090,300.0m,,"Landefeld"
"Leutkirch Unterz",,DE,4751.533N,01000.867E,640.0m,5,060,1020.0m,122.875,"Flugplatz"
"Leuzendorf",,DE,4921.100N,01004.467E,463.0m,4,080,400.0m,123.500,"Flugplatz"
"Leverkusen",,DE,5100.917N,00700.367E,49.0m,2,150,920.0m,122.425,"Flugplatz"
"Lichtenfels",,DE,5008.867N,01102.817E,259.0m,2,040,700.0m,123.000,"Flugplatz"
"Lindlar",,DE,5059.817N,00722.600E,327.0m,4,050,900.0m,129.975,"Flugplatz"
"Linkenheim",,DE,4908.500N,00823.667E,97.0m,2,050,740.0m,122.600,"Flugplatz"
"Linnich Ul",,DE,5057.767N,00620.283E,103.0m,3,070,280.0m,123.425,"Landefeld"
"Lombach",,DE,4825.617N,00827.867E,657.0m,3,100,280.0m,,"Landefeld"
"Locktow Ul",,DE,5207.000N,01242.567E,65.0m,3,110,420.0m,126.500,"Landefeld"
"Loechgau",,DE,4900.067N,00904.917E,272.0m,4,110,600.0m,123.475,"Flugplatz"
"Ludwigshafen Dan",,DE,4924.717N,00820.983E,96.0m,4,050,1000.0m,130.125,"Flugplatz"
"Lubeck",,DE,5348.317N,01043.150E,15.0m,5,070,2100.0m,128.700,"Flugplatz"
"Luchow Rehbeck",,DE,5301.033N,01108.683E,10.0m,5,150,650.0m,122.500,"Flugplatz"
"Lunen Lippeweide",,DE,5137.017N,00730.083E,50.0m,4,090,1030.0m,123.500,"Flugplatz"
"Lueneburg",,DE,5314.900N,01027.483E,49.0m,2,070,980.0m,122.175,"Flugplatz"
"Luesse",,DE,5208.600N,01240.217E,64.0m,2,060,1020.0m,129.975,"Flugplatz"
"Magdeburg Cochst",,DE,5151.367N,01125.083E,183.0m,5,080,2500.0m,131.125,"Flugplatz"
"Magdeburg-City",,DE,5204.417N,01137.617E,82.0m,5,090,1000.0m,119.300,"Flugplatz"
"Mainbullau",,DE,4941.700N,00910.950E,455.0m,5,050,700.0m,122.375,"Flugplatz"
"Mainz Finthen",,DE,4958.150N,00808.867E,232.0m,5,080,1000.0m,122.925,"Flugplatz"
"Malmsheim",,DE,4847.083N,00855.050E,451.0m,4,080,710.0m,122.200,"Flugplatz"
"Malsch",,DE,4914.250N,00840.700E,133.0m,4,070,920.0m,129.975,"Flugplatz"
"Mannheim City",,DE,4928.367N,00830.783E,95.0m,5,090,1060.0m,129.775,"Flugplatz"
"Marburg Schoen",,DE,5052.450N,00848.900E,251.0m,2,040,750.0m,123.000,"Flugplatz"
"Markdorf",,DE,4742.567N,00923.350E,431.0m,4,130,600.0m,123.350,"Flugplatz"
"Marl Loemuehle",,DE,5138.817N,00709.817E,73.0m,5,070,830.0m,122.000,"Flugplatz"
"Marpingen",,DE,4927.167N,00702.367E,351.0m,4,100,780.0m,123.475,"Flugplatz"
"Meiersberg",,DE,5117.983N,00657.383E,164.0m,4,130,800.0m,130.125,"Flugplatz"
"Meinerzhagen",,DE,5106.000N,00735.967E,472.0m,5,070,1170.0m,130.600,"Flugplatz"
"Meistern",,DE,4841.583N,00832.700E,772.0m,3,260,260.0m,,"Landefeld"
"Melle Groenegau",,DE,5212.050N,00822.833E,73.0m,5,090,760.0m,122.400,"Flugplatz"
"Mellenthin Ul",,DE,5355.050N,01401.950E,19.0m,3,120,600.0m,123.425,"Landefeld"
"Memmingen",,DE,4759.333N,01014.367E,628.0m,5,060,2400.0m,126.850,"Flugplatz"
"Menden Barge",,DE,5127.583N,00750.167E,207.0m,4,240,920.0m,123.500,"Flugplatz"
"Mendig",,DE,5021.950N,00718.917E,174.0m,5,080,1610.0m,123.475,"Flugplatz"
"Mengen Hohenteng",,DE,4803.233N,00922.367E,555.0m,5,080,1560.0m,135.175,"Flugplatz"
"Mengeringhausen",,DE,5122.583N,00858.867E,363.0m,2,120,540.0m,121.025,"Flugplatz"
"Meppen Mil",,DE,5243.400N,00719.583E,21.0m,2,060,590.0m,122.100,"Flugplatz"
"Merseburg",,DE,5121.750N,01156.467E,104.0m,5,080,1140.0m,122.900,"Flugplatz"
"Meschede Schuren",,DE,5118.167N,00814.367E,439.0m,5,040,900.0m,122.050,"Flugplatz"
"Michelbach Am As",,DE,5013.900N,00804.617E,301.0m,4,070,600.0m,123.375,"Flugplatz"
"Michelstadt",,DE,4940.717N,00858.300E,349.0m,5,080,600.0m,123.650,"Flugplatz"
"Mindelheim Matts",,DE,4806.467N,01031.483E,567.0m,5,150,1140.0m,122.975,"Flugplatz"
"Mitteltal",,DE,4831.350N,00819.617E,589.0m,3,040,160.0m,,"Landefeld"
"Mittelfischach",,DE,4902.133N,00952.233E,385.0m,3,150,500.0m,123.425,"Landefeld"
"Mittenwald",,DE,4725.100N,01115.533E,934.0m,3,010,300.0m,,"Landefeld"
"Moeckmuehl Korb",,DE,4920.650N,00924.017E,354.0m,4,080,670.0m,129.975,"Flugplatz"
"Moeckern Tryppeh",,DE,5210.667N,01155.700E,71.0m,3,170,760.0m,120.975,"Landefeld"
"Moenchengladbach",,DE,5113.817N,00630.267E,40.0m,5,130,1200.0m,120.450,"Flugplatz"
"Moenchsheide",,DE,5030.483N,00715.333E,213.0m,4,100,690.0m,122.000,"Flugplatz"
"Mohorn",,DE,5059.883N,01326.783E,356.0m,3,040,340.0m,123.425,"Landefeld"
"Mohrdorf",,DE,5422.983N,01254.733E,3.0m,5,130,2300.0m,118.625,"Flugplatz"
"Montabaur",,DE,5025.433N,00749.800E,265.0m,4,050,580.0m,123.350,"Flugplatz"
"Moosburg Auf Kip",,DE,4827.400N,01156.500E,421.0m,2,040,650.0m,123.650,"Flugplatz"
"Morbach Ul",,DE,4902.017N,00935.467E,495.0m,3,090,430.0m,123.425,"Landefeld"
"Morschenich",,DE,5052.400N,00633.150E,104.0m,3,070,350.0m,123.425,"Landefeld"
"Mortitz Cls",,DE,5030.450N,01240.900E,100.0m,3,070,640.0m,,"Landefeld"
"Mosbach Lohrbach",,DE,4923.967N,00907.417E,332.0m,5,150,610.0m,122.850,"Flugplatz"
"Mosenberg",,DE,5103.767N,00925.317E,402.0m,2,070,510.0m,123.050,"Flugplatz"
"Muelben",,DE,4927.300N,00906.283E,519.0m,4,340,750.0m,130.125,"Flugplatz"
"Muehldorf",,DE,4816.783N,01230.017E,406.0m,5,080,850.0m,119.775,"Flugplatz"
"Muehlhausen",,DE,5112.783N,01032.967E,247.0m,2,080,900.0m,122.850,"Flugplatz"
"Muellheim",,DE,4749.450N,00738.383E,292.0m,4,160,700.0m,129.975,"Flugplatz"
"Munchen",,DE,4821.233N,01147.167E,454.0m,5,080,4000.0m,118.700,"Flugplatz"
"Munsingen Eisber",,DE,4824.550N,00926.550E,725.0m,4,080,450.0m,123.500,"Flugplatz"
"Munster Osnabruc",,DE,5208.083N,00741.083E,49.0m,5,070,2170.0m,129.800,"Flugplatz"
"Muenster Telgte",,DE,5156.667N,00746.417E,55.0m,5,100,850.0m,122.850,"Flugplatz"
"Mueritz Airpark",,DE,5318.383N,01245.150E,63.0m,5,070,2380.0m,129.975,"Flugplatz"
"Musbach",,DE,4830.167N,00828.717E,697.0m,4,170,1000.0m,130.125,"Flugplatz"
"Nabern Teck",,DE,4836.750N,00928.633E,372.0m,2,140,570.0m,118.325,"Flugplatz"
"Nannhausen",,DE,4958.217N,00728.733E,381.0m,2,060,560.0m,130.600,"Flugplatz"
"Nardt",,DE,5127.100N,01412.150E,117.0m,2,080,950.0m,123.000,"Flugplatz"
"Nastaetten",,DE,5011.883N,00753.333E,363.0m,4,080,1020.0m,126.500,"Flugplatz"
"Nauen Cls",,DE,5237.600N,01254.833E,28.0m,3,100,850.0m,,"Landefeld"
"Naunheim Maifeld",,DE,5015.500N,00719.933E,195.0m,3,060,180.0m,123.425,"Landefeld"
"Neresheim",,DE,4844.500N,01019.667E,538.0m,4,080,750.0m,130.125,"Flugplatz"
"Neuweiler Wiese",,DE,4839.300N,00836.500E,654.0m,3,080,250.0m,,"Landefeld"
"Neubiberg Cls",,DE,4804.383N,01138.283E,576.0m,3,070,2140.0m,,"Landefeld"
"Neubrandenbu Mil",,DE,5336.133N,01318.367E,70.0m,5,090,2290.0m,119.175,"Flugplatz"
"Neuburg Egweil",,DE,4846.917N,01112.917E,412.0m,2,080,640.0m,123.475,"Flugplatz"
"Neuburg Mil",,DE,4842.667N,01112.700E,381.0m,5,090,2450.0m,122.100,"Flugplatz"
"Neuhausen Ob Eck",,DE,4758.600N,00854.250E,806.0m,5,090,1240.0m,119.600,"Flugplatz"
"Neuenstadt A Koc",,DE,4914.567N,00919.033E,168.0m,3,100,250.0m,123.425,"Landefeld"
"Neu Guelze",,DE,5322.867N,01048.250E,12.0m,4,070,800.0m,123.500,"Flugplatz"
"Neuhardenberg",,DE,5236.783N,01414.567E,12.0m,5,080,2400.0m,119.125,"Flugplatz"
"Neuhausen",,DE,5141.083N,01425.383E,85.0m,2,110,1080.0m,122.725,"Flugplatz"
"Neuhaus Sumte",,DE,5317.383N,01054.267E,8.0m,3,130,300.0m,,"Landefeld"
"Neujellingsdorf",,DE,5427.350N,01106.567E,7.0m,2,110,590.0m,122.050,"Flugplatz"
"Neumagen Dhron",,DE,4950.567N,00654.967E,268.0m,2,090,750.0m,118.175,"Flugplatz"
"Neumarkt Oberpfa",,DE,4917.133N,01126.617E,424.0m,5,090,710.0m,119.975,"Flugplatz"
"Neumuenster",,DE,5404.767N,00956.517E,21.0m,5,080,600.0m,123.000,"Flugplatz"
"Neunkirchen BeXB",,DE,4920.400N,00715.200E,272.0m,2,060,450.0m,123.050,"Flugplatz"
"Neuruppin",,DE,5256.567N,01246.767E,43.0m,4,100,1260.0m,123.350,"Flugplatz"
"Neustadt Aisch",,DE,4935.250N,01034.667E,363.0m,5,090,600.0m,118.925,"Flugplatz"
"Neustadt Glewe",,DE,5321.717N,01136.867E,37.0m,2,090,1200.0m,123.375,"Flugplatz"
"Nidda A D Helm",,DE,5024.317N,00859.267E,176.0m,4,040,770.0m,123.375,"Flugplatz"
"Niederrhein",,DE,5136.150N,00608.533E,34.0m,5,090,2440.0m,129.400,"Flugplatz"
"Niederstetten",,DE,4923.517N,00957.500E,469.0m,5,070,1310.0m,122.100,"Flugplatz"
"Nienburg Holzbal",,DE,5242.583N,00909.733E,24.0m,2,080,850.0m,122.000,"Flugplatz"
"Niederwillingen",,DE,5046.817N,01103.117E,395.0m,3,060,350.0m,120.975,"Landefeld"
"Nittenau Bruck",,DE,4913.333N,01217.800E,357.0m,5,010,550.0m,118.925,"Flugplatz"
"Noerdlingen",,DE,4852.217N,01030.283E,421.0m,5,040,750.0m,133.075,"Flugplatz"
"Noervenich Mil",,DE,5049.867N,00639.483E,119.0m,5,070,2450.0m,122.100,"Flugplatz"
"Nordenbeck",,DE,5114.100N,00849.017E,452.0m,2,080,600.0m,122.500,"Flugplatz"
"Norddoellen Vis",,DE,5248.317N,00819.483E,49.0m,3,070,200.0m,123.425,"Landefeld"
"Norderney",,DE,5342.400N,00713.800E,3.0m,5,080,1000.0m,122.600,"Flugplatz"
"Nordhausen",,DE,5129.567N,01050.267E,210.0m,2,100,890.0m,118.625,"Flugplatz"
"Nordhorn Lingen",,DE,5227.467N,00710.950E,28.0m,5,060,900.0m,122.650,"Flugplatz"
"Nordholz Mil",,DE,5346.050N,00839.500E,21.0m,5,080,2430.0m,131.250,"Flugplatz"
"Norden Nordeich",,DE,5337.983N,00711.400E,1.0m,5,160,720.0m,121.400,"Flugplatz"
"Nordholz Spieka",,DE,5346.017N,00838.617E,21.0m,2,080,870.0m,121.025,"Flugplatz"
"Northeim",,DE,5142.383N,01002.383E,122.0m,2,110,680.0m,118.700,"Flugplatz"
"Nuernberg",,DE,4929.933N,01104.633E,314.0m,5,100,2700.0m,118.300,"Flugplatz"
"Nussbach",,DE,4832.300N,00802.283E,173.0m,3,120,200.0m,,"Landefeld"
"Oberems",,DE,5014.500N,00823.933E,403.0m,4,130,710.0m,123.350,"Flugplatz"
"Oberhinkofen",,DE,4857.100N,01208.800E,396.0m,4,050,540.0m,122.300,"Flugplatz"
"Ober Moerlen",,DE,5021.717N,00842.683E,247.0m,2,050,800.0m,122.850,"Flugplatz"
"Oberpfaffenhofen",,DE,4804.883N,01116.983E,594.0m,5,040,2280.0m,119.550,"Flugplatz"
"Oberrissdorf",,DE,5132.600N,01135.683E,224.0m,2,140,500.0m,122.200,"Flugplatz"
"Oberrot Glashofe",,DE,4900.600N,00938.333E,488.0m,3,100,250.0m,123.425,"Landefeld"
"Oberschleissheim",,DE,4814.350N,01133.550E,485.0m,5,080,800.0m,129.400,"Flugplatz"
"Obersoellbach",,DE,4911.000N,00933.550E,287.0m,3,150,260.0m,123.425,"Landefeld"
"Oberhamersbach",,DE,4821.967N,00807.033E,290.0m,3,050,250.0m,,"Landefeld"
"Oberkirch",,DE,4832.000N,00803.783E,180.0m,3,130,300.0m,,"Landefeld"
"Oberkollwangen",,DE,4840.850N,00836.917E,683.0m,3,340,260.0m,,"Landefeld"
"Obermehler Schlo",,DE,5116.067N,01038.083E,277.0m,5,110,1450.0m,122.900,"Flugplatz"
"Ochsenfurt",,DE,4940.417N,01004.267E,248.0m,2,100,510.0m,123.000,"Flugplatz"
"Ochsenhausen",,DE,4803.200N,00954.950E,650.0m,4,080,320.0m,123.500,"Flugplatz"
"Oedheim Heli Mil",,DE,4914.483N,00914.067E,156.0m,3,180,420.0m,122.000,"Landefeld"
"Oehna",,DE,5153.983N,01303.183E,85.0m,5,080,850.0m,122.500,"Flugplatz"
"Oelde Bergeler",,DE,5149.833N,00810.483E,82.0m,2,060,550.0m,122.800,"Flugplatz"
"Oerlinghausen",,DE,5155.950N,00839.717E,171.0m,5,040,800.0m,122.175,"Flugplatz"
"Oeventrop Ruhrwi",,DE,5123.767N,00808.667E,241.0m,4,120,440.0m,123.350,"Flugplatz"
"Offenbuettel Ul",,DE,5410.550N,00922.683E,3.0m,3,140,310.0m,123.425,"Landefeld"
"Offenburg",,DE,4826.883N,00755.417E,153.0m,5,020,910.0m,119.750,"Flugplatz"
"Ohlstadt",,DE,4739.467N,01114.033E,655.0m,5,040,880.0m,130.125,"Flugplatz"
"Oldenburg Hatten",,DE,5304.117N,00818.750E,9.0m,2,060,770.0m,118.175,"Flugplatz"
"Oldenburg Cls",,DE,5310.800N,00809.667E,8.0m,3,100,2110.0m,122.100,"Landefeld"
"Oppenheim",,DE,4950.467N,00822.550E,86.0m,2,020,800.0m,122.000,"Flugplatz"
"Oppershausen",,DE,5235.733N,01013.383E,43.0m,4,100,1090.0m,122.475,"Flugplatz"
"Oppingen Au",,DE,4833.400N,00949.333E,681.0m,4,100,690.0m,123.150,"Flugplatz"
"Ortenberg",,DE,4826.533N,00757.667E,159.0m,3,150,400.0m,,"Landefeld"
"Oschatz",,DE,5117.817N,01304.783E,156.0m,2,080,830.0m,122.200,"Flugplatz"
"Oschersleben",,DE,5202.283N,01112.333E,104.0m,2,110,600.0m,129.400,"Flugplatz"
"Osnabruck Atterh",,DE,5217.200N,00758.183E,83.0m,5,090,800.0m,118.675,"Flugplatz"
"Osterholz Scharm",,DE,5312.817N,00848.617E,2.0m,4,130,820.0m,130.125,"Flugplatz"
"Ottengruner Heid",,DE,5013.550N,01143.883E,575.0m,2,100,650.0m,123.000,"Flugplatz"
"Ottenberg Pilsac",,DE,4919.717N,01128.783E,552.0m,4,160,750.0m,122.200,"Flugplatz"
"Paderborn Lippst",,DE,5136.833N,00836.950E,213.0m,5,060,2180.0m,133.375,"Flugplatz"
"Paderborn HaXTer",,DE,5141.317N,00846.550E,241.0m,5,060,1190.0m,125.275,"Flugplatz"
"Paradiek Ul",,DE,5240.083N,00819.283E,39.0m,3,090,620.0m,120.975,"Landefeld"
"Parchim Kl Platz",,DE,5325.117N,01148.100E,44.0m,4,070,750.0m,123.500,"Flugplatz"
"Pasewalk",,DE,5330.317N,01356.900E,23.0m,5,090,900.0m,123.650,"Flugplatz"
"Paterzell",,DE,4750.750N,01103.667E,595.0m,5,180,480.0m,123.500,"Flugplatz"
"Pattonville",,DE,4851.850N,00913.483E,278.0m,5,100,670.0m,123.650,"Flugplatz"
"Peenemuende",,DE,5409.533N,01346.383E,3.0m,5,130,2400.0m,122.475,"Flugplatz"
"Pegnitz Zipser",,DE,4945.733N,01134.467E,543.0m,2,080,880.0m,132.025,"Flugplatz"
"Peine Glindbruch",,DE,5219.417N,01010.900E,68.0m,4,090,640.0m,123.350,"Flugplatz"
"Peissenberg Cls",,DE,4749.967N,01104.000E,606.0m,3,010,850.0m,123.500,"Landefeld"
"Peiting",,DE,4745.500N,01054.500E,745.0m,3,060,300.0m,,"Landefeld"
"Pellworm",,DE,5432.200N,00840.800E,1.0m,2,110,680.0m,123.000,"Flugplatz"
"Pennewitz",,DE,5040.167N,01103.050E,457.0m,2,060,900.0m,123.050,"Flugplatz"
"Perleberg",,DE,5304.233N,01149.083E,31.0m,4,110,1110.0m,122.300,"Flugplatz"
"Pfarrkirchen",,DE,4825.217N,01251.883E,387.0m,2,070,700.0m,119.975,"Flugplatz"
"Pfullendorf",,DE,4754.567N,00915.050E,699.0m,2,010,600.0m,123.250,"Flugplatz"
"Pieverstorf 25M",,DE,5349.100N,01108.683E,27.0m,3,080,320.0m,,"Landefeld"
"Pinnow",,DE,5336.950N,01133.767E,43.0m,2,010,800.0m,122.500,"Flugplatz"
"Pirmasens",,DE,4915.867N,00729.300E,381.0m,5,050,800.0m,122.350,"Flugplatz"
"Pirna Pratzschwi",,DE,5058.783N,01354.517E,122.0m,2,120,900.0m,118.625,"Flugplatz"
"Plaetzer Huenfel",,DE,5042.567N,00944.350E,350.0m,4,160,540.0m,122.200,"Flugplatz"
"Pleidelsheim",,DE,4857.400N,00911.517E,190.0m,4,020,480.0m,123.500,"Flugplatz"
"Plettenberg",,DE,5111.533N,00747.383E,307.0m,2,100,430.0m,122.925,"Flugplatz"
"Ploetzin Ul",,DE,5221.333N,01249.500E,50.0m,3,080,330.0m,123.425,"Landefeld"
"Poel Agrar",,DE,5400.200N,01127.750E,14.0m,3,070,300.0m,,"Landefeld"
"Pohlheim Viehhei",,DE,5031.933N,00844.033E,237.0m,4,080,870.0m,122.150,"Flugplatz"
"Poltringen",,DE,4832.817N,00856.750E,404.0m,5,170,400.0m,123.050,"Flugplatz"
"Porta Westfalica",,DE,5213.267N,00851.583E,44.0m,5,050,860.0m,122.375,"Flugplatz"
"Porta W Gras Gld",,DE,5213.333N,00851.567E,45.0m,3,060,1000.0m,122.500,"Landefeld"
"Pretzschendorf",,DE,5053.033N,01331.850E,490.0m,3,060,780.0m,123.425,"Landefeld"
"Pritzwalk Sommer",,DE,5310.800N,01211.067E,88.0m,2,080,830.0m,122.600,"Flugplatz"
"Preschen Cls",,DE,5139.817N,01438.050E,101.0m,3,060,2400.0m,,"Landefeld"
"Purkshof",,DE,5409.717N,01214.867E,21.0m,2,040,1100.0m,122.400,"Flugplatz"
"Quakenbrueck",,DE,5239.783N,00755.583E,24.0m,4,100,540.0m,122.300,"Flugplatz"
"Radevormwald Ley",,DE,5112.983N,00722.933E,390.0m,4,090,350.0m,123.475,"Flugplatz"
"Radolfzell-Stahr",,DE,4748.167N,00858.767E,421.0m,2,010,710.0m,130.125,"Flugplatz"
"Ramstein Mil",,DE,4926.217N,00736.017E,238.0m,5,080,3200.0m,133.200,"Flugplatz"
"Rastatt Baldenau",,DE,4852.467N,00812.783E,113.0m,4,050,900.0m,122.475,"Flugplatz"
"Regensburg",,DE,4908.517N,01204.917E,396.0m,5,100,640.0m,120.425,"Flugplatz"
"Reichelsheim",,DE,5020.317N,00852.717E,121.0m,5,180,1300.0m,120.425,"Flugplatz"
"Reinheim",,DE,4950.367N,00851.033E,155.0m,4,010,720.0m,124.000,"Flugplatz"
"Reinsdorf",,DE,5154.050N,01311.767E,102.0m,2,100,1280.0m,122.850,"Flugplatz"
"Reiselfingen",,DE,4751.100N,00822.283E,746.0m,4,070,610.0m,123.000,"Flugplatz"
"Reit I Winkel",,DE,4740.417N,01228.700E,689.0m,3,010,250.0m,,"Landefeld"
"Rendsburg Schach",,DE,5413.267N,00936.050E,6.0m,5,030,990.0m,123.650,"Flugplatz"
"Renneritz",,DE,5135.683N,01214.250E,91.0m,2,070,1100.0m,123.475,"Flugplatz"
"Rerik Zweedorf",,DE,5404.917N,01138.933E,9.0m,2,080,640.0m,126.500,"Flugplatz"
"Rheine Bentl Mil",,DE,5217.467N,00723.233E,40.0m,5,090,500.0m,122.100,"Flugplatz"
"Rheine Eschendor",,DE,5216.600N,00729.533E,41.0m,2,110,920.0m,122.050,"Flugplatz"
"Rheinstetten",,DE,4858.667N,00820.550E,116.0m,4,020,1030.0m,123.350,"Flugplatz"
"Riedelbach",,DE,5018.133N,00823.083E,508.0m,4,060,710.0m,130.125,"Flugplatz"
"Riedlingen",,DE,4808.667N,00928.000E,529.0m,4,040,520.0m,129.975,"Flugplatz"
"Riesa Goehlis",,DE,5117.583N,01321.433E,98.0m,5,120,1000.0m,122.600,"Flugplatz"
"Riesa Canitz",,DE,5118.183N,01313.667E,123.0m,4,090,1050.0m,123.500,"Flugplatz"
"Rinteln",,DE,5210.517N,00903.200E,55.0m,5,110,600.0m,122.925,"Flugplatz"
"Roggenhagen Ul",,DE,5340.250N,01323.983E,47.0m,3,110,550.0m,123.425,"Landefeld"
"Roitzschjora",,DE,5134.617N,01229.650E,88.0m,2,100,1200.0m,122.000,"Flugplatz"
"Rosenthal Field",,DE,4951.800N,01147.283E,457.0m,5,090,750.0m,127.450,"Flugplatz"
"Rossfeld",,DE,4830.817N,00920.067E,803.0m,4,070,420.0m,122.475,"Flugplatz"
"Rotenburg Wumme",,DE,5307.700N,00920.917E,27.0m,5,080,800.0m,122.050,"Flugplatz"
"Rothenberg",,DE,4929.150N,00856.167E,479.0m,4,090,640.0m,123.500,"Flugplatz"
"Rothenburg O D T",,DE,4923.300N,01013.100E,399.0m,5,030,950.0m,118.175,"Flugplatz"
"Roth Mil",,DE,4913.050N,01106.000E,387.0m,5,090,530.0m,122.100,"Flugplatz"
"Rothenburg Goerl",,DE,5121.833N,01457.067E,159.0m,5,180,2500.0m,123.250,"Flugplatz"
"Rottach",,DE,4740.950N,01148.150E,761.0m,3,110,260.0m,,"Landefeld"
"Rottweil Zepfenh",,DE,4811.200N,00843.383E,738.0m,5,080,800.0m,129.500,"Flugplatz"
"Rudolstadt Gros",,DE,5043.967N,01114.167E,470.0m,2,070,800.0m,118.325,"Flugplatz"
"Rudesheim",,DE,5001.017N,00753.567E,405.0m,4,360,420.0m,123.500,"Flugplatz"
"Rugen",,DE,5423.000N,01319.533E,21.0m,5,090,900.0m,123.000,"Flugplatz"
"Ruppiner Land",,DE,5247.600N,01245.650E,43.0m,5,110,900.0m,122.500,"Flugplatz"
"Saal Kreuzberg",,DE,5018.533N,01022.400E,266.0m,4,120,590.0m,122.475,"Flugplatz"
"Saarbrucken",,DE,4912.883N,00706.567E,323.0m,5,090,1990.0m,118.350,"Flugplatz"
"Saarlouis Dueren",,DE,4918.750N,00640.450E,341.0m,5,070,800.0m,122.600,"Flugplatz"
"Salzwedel",,DE,5249.683N,01118.983E,33.0m,4,090,810.0m,122.200,"Flugplatz"
"Salzgitter Drutt",,DE,5209.267N,01025.583E,98.0m,5,070,630.0m,122.850,"Flugplatz"
"Salzgitter Schaf",,DE,5201.833N,01021.783E,203.0m,2,110,950.0m,122.500,"Flugplatz"
"Saarmund",,DE,5218.500N,01306.033E,52.0m,2,090,1000.0m,123.650,"Flugplatz"
"Sauldorf Boll",,DE,4757.383N,00902.000E,650.0m,3,020,300.0m,120.975,"Landefeld"
"Saulgau",,DE,4801.767N,00930.433E,582.0m,5,120,450.0m,123.600,"Flugplatz"
"Schoenau3",,DE,4747.150N,00753.983E,536.0m,3,040,400.0m,,"Landefeld"
"Schaefhalde Stei",,DE,4841.550N,01006.017E,628.0m,4,040,770.0m,123.500,"Flugplatz"
"Schameder",,DE,5100.017N,00818.550E,550.0m,2,100,750.0m,122.025,"Flugplatz"
"Scharling",,DE,4740.150N,01144.767E,778.0m,3,090,300.0m,,"Landefeld"
"Schwann Connweil",,DE,4850.300N,00832.583E,480.0m,4,070,330.0m,122.300,"Flugplatz"
"Scheuen Celle",,DE,5240.167N,01005.333E,55.0m,4,080,1120.0m,122.200,"Flugplatz"
"Schlechtenfeld",,DE,4817.083N,00940.400E,562.0m,4,330,300.0m,123.350,"Flugplatz"
"Schleswig Kropp",,DE,5425.533N,00932.517E,15.0m,2,090,820.0m,118.675,"Flugplatz"
"Schlierstadt Sel",,DE,4926.567N,00921.750E,344.0m,2,180,580.0m,122.050,"Flugplatz"
"Schleswig Mil",,DE,5427.567N,00930.983E,21.0m,5,050,2450.0m,122.100,"Flugplatz"
"Schmallenberg",,DE,5109.700N,00815.700E,467.0m,2,090,900.0m,122.425,"Flugplatz"
"Schmidgaden",,DE,4925.767N,01205.883E,380.0m,2,120,520.0m,123.000,"Flugplatz"
"Schmoldow",,DE,5358.367N,01320.583E,24.0m,2,150,900.0m,122.850,"Flugplatz"
"Schnuckenhei Rep",,DE,5242.967N,01032.000E,106.0m,4,110,980.0m,123.475,"Flugplatz"
"Schoenhagen",,DE,5212.217N,01309.500E,40.0m,5,070,1510.0m,131.150,"Flugplatz"
"Schoenberg",,DE,4802.867N,01230.033E,543.0m,2,080,450.0m,118.550,"Flugplatz"
"Schonebeck Zackm",,DE,5159.783N,01147.383E,52.0m,2,070,800.0m,123.000,"Flugplatz"
"Schreckhof Mosba",,DE,4921.050N,00907.267E,270.0m,4,160,300.0m,123.500,"Flugplatz"
"Schwedenstebelul",,DE,5249.350N,01002.400E,71.0m,3,110,290.0m,120.975,"Landefeld"
"Schotten",,DE,5032.083N,00908.733E,500.0m,4,050,380.0m,123.500,"Flugplatz"
"Schwarzenbach So",,DE,4935.517N,00701.900E,493.0m,3,050,380.0m,123.425,"Landefeld"
"Schwarzheide",,DE,5129.383N,01352.733E,101.0m,2,080,850.0m,129.975,"Flugplatz"
"Schwaigern Stet",,DE,4908.500N,00859.250E,237.0m,3,080,350.0m,123.425,"Landefeld"
"Schwandorf",,DE,4920.433N,01211.083E,387.0m,2,110,840.0m,121.200,"Flugplatz"
"Schwerin Parchim",,DE,5325.617N,01147.000E,52.0m,5,060,3000.0m,128.900,"Flugplatz"
"Schwaebisch Hall",,DE,4907.100N,00947.033E,399.0m,5,100,1540.0m,129.225,"Flugplatz"
"Schwabmuenchen",,DE,4810.750N,01042.183E,550.0m,2,080,850.0m,122.500,"Flugplatz"
"Schwenningen A N",,DE,4803.933N,00834.267E,667.0m,5,040,800.0m,122.850,"Flugplatz"
"Schweinfurt-Sud",,DE,5000.633N,01015.083E,210.0m,2,100,980.0m,119.975,"Flugplatz"
"Schwein Mil Heli",,DE,5002.933N,01010.200E,241.0m,5,090,680.0m,122.100,"Flugplatz"
"Schwabisch-H Wec",,DE,4907.450N,00946.867E,399.0m,2,080,550.0m,129.225,"Flugplatz"
"Schoemberg",,DE,4823.550N,00824.783E,723.0m,3,130,400.0m,,"Landefeld"
"Schiltach X",,DE,4817.917N,00821.350E,336.0m,3,040,210.0m,,"Landefeld"
"Schwabach Buchen",,DE,4916.117N,01100.600E,359.0m,5,100,530.0m,135.425,"Flugplatz"
"Schwarzenbrg X",,DE,4836.167N,00822.833E,563.0m,3,060,190.0m,,"Landefeld"
"Schweighofen",,DE,4901.900N,00759.400E,149.0m,2,080,620.0m,123.000,"Flugplatz"
"Schernbach",,DE,4833.800N,00829.617E,675.0m,3,040,430.0m,,"Landefeld"
"Seedorf",,DE,5320.117N,00915.583E,17.0m,2,060,450.0m,119.650,"Flugplatz"
"Segeletz",,DE,5249.600N,01232.550E,39.0m,2,100,920.0m,123.500,"Flugplatz"
"Seissen",,DE,4824.783N,00945.983E,692.0m,4,110,540.0m,123.425,"Flugplatz"
"Sengenthal Ul",,DE,4912.917N,01124.050E,437.0m,3,120,250.0m,123.425,"Landefeld"
"Seussling Prv Ul",,DE,4947.483N,01058.233E,336.0m,3,060,260.0m,123.425,"Landefeld"
"Siegen Eisernhar",,DE,5050.250N,00800.850E,390.0m,4,090,720.0m,123.375,"Flugplatz"
"Siegerland",,DE,5042.467N,00804.983E,601.0m,5,130,1620.0m,120.375,"Flugplatz"
"Sierksdorf Hof A",,DE,5404.033N,01044.567E,28.0m,2,030,500.0m,122.000,"Flugplatz"
"Siewisch Ul",,DE,5141.250N,01412.517E,89.0m,2,080,510.0m,123.425,"Flugplatz"
"Singhofen",,DE,5016.217N,00751.217E,302.0m,4,040,800.0m,123.150,"Flugplatz"
"Sinsheim",,DE,4914.833N,00853.633E,159.0m,2,120,1020.0m,122.475,"Flugplatz"
"Sommerda",,DE,5111.917N,01111.467E,137.0m,2,070,920.0m,124.000,"Flugplatz"
"Soest Bad Sassen",,DE,5134.683N,00812.850E,120.0m,2,070,820.0m,122.600,"Flugplatz"
"Sonnen",,DE,4840.950N,01341.683E,824.0m,5,020,650.0m,122.050,"Flugplatz"
"Sontra Dornberg",,DE,5105.250N,00954.933E,403.0m,4,120,500.0m,123.500,"Flugplatz"
"Spangdahlem Mil",,DE,4958.567N,00641.867E,362.0m,5,050,3180.0m,122.200,"Flugplatz"
"Sperenberg Cls",,DE,5208.233N,01318.100E,46.0m,3,090,1240.0m,,"Landefeld"
"Speyer",,DE,4918.283N,00827.100E,95.0m,5,160,1670.0m,118.075,"Flugplatz"
"Spitzingsee",,DE,4739.150N,01153.400E,1051.0m,3,130,300.0m,,"Landefeld"
"Spremberg Welzow",,DE,5134.617N,01408.217E,116.0m,5,030,2000.0m,134.850,"Flugplatz"
"Sprossen",,DE,5102.600N,01213.983E,206.0m,2,090,740.0m,120.975,"Flugplatz"
"Steinberg 0725",,DE,5257.333N,00733.717E,28.0m,3,070,250.0m,123.500,"Landefeld"
"Stade",,DE,5333.667N,00929.917E,19.0m,5,110,650.0m,123.000,"Flugplatz"
"Stadtlohn Vreden",,DE,5159.750N,00650.433E,49.0m,5,110,1240.0m,119.200,"Flugplatz"
"Stauffenbuehl",,DE,5109.550N,01002.833E,277.0m,4,020,820.0m,123.500,"Flugplatz"
"St Blasien",,DE,4746.517N,00806.733E,801.0m,3,140,250.0m,,"Landefeld"
"Stechow Ferchesa",,DE,5239.050N,01229.283E,42.0m,2,040,610.0m,122.200,"Flugplatz"
"Steinberg Wessel",,DE,5205.017N,01001.100E,180.0m,4,090,720.0m,123.500,"Flugplatz"
"Stendal Borstel",,DE,5237.733N,01149.200E,55.0m,5,080,1990.0m,122.400,"Flugplatz"
"Steinberg Surwol",,DE,5257.383N,00733.417E,29.0m,4,090,860.0m,123.500,"Flugplatz"
"Stillberghof",,DE,4843.850N,01050.117E,510.0m,4,090,710.0m,123.475,"Flugplatz"
"St Michaelisdon",,DE,5358.700N,00908.733E,37.0m,5,070,700.0m,122.500,"Flugplatz"
"Stoelln Rhinow",,DE,5244.450N,01223.467E,40.0m,2,080,840.0m,122.000,"Flugplatz"
"Stolberg Diepenl",,DE,5046.233N,00616.917E,259.0m,4,030,770.0m,123.500,"Flugplatz"
"St Peter Ording",,DE,5418.533N,00841.200E,3.0m,5,070,670.0m,129.775,"Flugplatz"
"Stralsund",,DE,5420.150N,01302.617E,15.0m,2,050,900.0m,118.625,"Flugplatz"
"Strausberg",,DE,5234.800N,01354.933E,78.0m,5,050,1200.0m,123.050,"Flugplatz"
"Straubing",,DE,4854.050N,01231.033E,320.0m,5,090,1350.0m,127.150,"Flugplatz"
"Strassham Ul",,DE,4810.800N,01155.633E,514.0m,3,030,400.0m,123.425,"Landefeld"
"Stude Bernsteins",,DE,5233.817N,01041.050E,73.0m,4,110,920.0m,123.150,"Flugplatz"
"Stuttgart",,DE,4841.400N,00913.317E,390.0m,5,070,3340.0m,119.050,"Flugplatz"
"Suhl Goldlauter",,DE,5037.933N,01043.550E,588.0m,2,100,570.0m,124.550,"Flugplatz"
"Sultmer Berg",,DE,5143.767N,00959.533E,222.0m,4,180,550.0m,123.150,"Flugplatz"
"Sulz Ul",,DE,4820.700N,00838.200E,536.0m,3,040,310.0m,123.425,"Landefeld"
"Sylt",,DE,5454.700N,00820.550E,15.0m,5,140,2120.0m,119.750,"Flugplatz"
"Tannheim",,DE,4800.600N,01005.950E,561.0m,2,090,1020.0m,122.825,"Flugplatz"
"Tarmstedt",,DE,5315.083N,00906.517E,41.0m,4,060,700.0m,123.150,"Flugplatz"
"Tauberbischofshe",,DE,4938.867N,00937.967E,285.0m,4,120,740.0m,122.200,"Flugplatz"
"Tauberbisch Wies",,DE,4939.000N,00938.683E,171.0m,3,150,360.0m,,"Landefeld"
"Taucha",,DE,5123.717N,01232.283E,149.0m,2,070,600.0m,122.400,"Flugplatz"
"Teisendorf Pank",,DE,4749.583N,01250.700E,578.0m,4,150,250.0m,123.500,"Flugplatz"
"Teldau Ul",,DE,5319.700N,01049.983E,5.0m,3,040,320.0m,123.425,"Landefeld"
"Thalmaessing Wai",,DE,4903.850N,01112.567E,577.0m,2,170,410.0m,123.650,"Flugplatz"
"Thannhausen",,DE,4817.400N,01026.517E,491.0m,2,080,500.0m,118.175,"Flugplatz"
"Tirschenreuth",,DE,4952.417N,01219.450E,499.0m,4,080,520.0m,123.500,"Flugplatz"
"Titschendor2 Rwy",,DE,5023.550N,01131.317E,638.0m,3,180,600.0m,122.300,"Landefeld"
"Titisee",,DE,4754.017N,00809.717E,857.0m,3,060,200.0m,,"Landefeld"
"Titschendorf",,DE,5023.833N,01131.367E,650.0m,4,010,480.0m,122.300,"Flugplatz"
"Torgau Beilrode",,DE,5134.267N,01303.133E,82.0m,2,080,800.0m,122.300,"Flugplatz"
"Traben Trarbach",,DE,4958.067N,00706.700E,275.0m,2,180,750.0m,123.000,"Flugplatz"
"Treuchtlingen Bu",,DE,4859.750N,01053.100E,412.0m,2,150,640.0m,122.600,"Flugplatz"
"Trier Foehren",,DE,4951.850N,00647.267E,204.0m,5,040,1200.0m,122.050,"Flugplatz"
"Troestau",,DE,5001.200N,01155.867E,561.0m,4,130,400.0m,123.150,"Flugplatz"
"Trollenberg",,DE,4821.617N,00827.000E,653.0m,3,110,400.0m,,"Landefeld"
"Tutow",,DE,5355.317N,01313.133E,6.0m,5,170,1200.0m,130.125,"Flugplatz"
"Uebersberg",,DE,4827.483N,00917.800E,784.0m,4,080,950.0m,123.150,"Flugplatz"
"Uehrde Ul",,DE,5206.417N,01045.333E,153.0m,3,130,500.0m,123.425,"Landefeld"
"Uelzen",,DE,5259.017N,01027.933E,75.0m,5,080,800.0m,130.900,"Flugplatz"
"Uetersen Heist",,DE,5338.800N,00942.233E,5.0m,2,090,1100.0m,122.700,"Flugplatz"
"Uetersen Segelfl",,DE,5338.967N,00942.350E,5.0m,4,090,1140.0m,123.475,"Flugplatz"
"Ummern",,DE,5237.200N,01024.617E,71.0m,4,130,560.0m,123.500,"Flugplatz"
"Unterbuchen",,DE,4747.017N,01129.133E,635.0m,3,040,300.0m,,"Landefeld"
"Unterwoessen",,DE,4743.783N,01226.283E,565.0m,5,060,800.0m,122.300,"Flugplatz"
"Unterschuepf",,DE,4930.950N,00940.150E,346.0m,2,080,670.0m,122.600,"Flugplatz"
"Unterschwaningen",,DE,4905.167N,01038.083E,476.0m,3,080,300.0m,120.975,"Landefeld"
"Urspring",,DE,4833.233N,00954.167E,642.0m,4,150,610.0m,123.500,"Flugplatz"
"Uslar",,DE,5139.733N,00936.317E,260.0m,4,070,550.0m,129.975,"Flugplatz"
"Utscheid",,DE,4959.867N,00620.583E,421.0m,4,060,720.0m,123.350,"Flugplatz"
"Vaihingen",,DE,4856.183N,00858.817E,312.0m,4,090,1000.0m,129.400,"Flugplatz"
"Varrelbusch",,DE,5254.500N,00802.600E,37.0m,2,090,850.0m,123.000,"Flugplatz"
"Verden Scharnh",,DE,5257.917N,00916.967E,42.0m,2,130,510.0m,122.400,"Flugplatz"
"Vettweiss Soller",,DE,5044.850N,00634.033E,159.0m,3,150,380.0m,120.975,"Landefeld"
"Vielbrunn",,DE,4943.183N,00904.933E,459.0m,4,170,680.0m,123.150,"Flugplatz"
"Vilsbiburg",,DE,4825.583N,01220.733E,442.0m,2,030,450.0m,123.000,"Flugplatz"
"Vilseck Mil",,DE,4938.017N,01146.033E,412.0m,5,100,1080.0m,122.100,"Flugplatz"
"Vilshofen",,DE,4838.083N,01311.800E,302.0m,5,120,1130.0m,119.175,"Flugplatz"
"Vinsebeck Frankn",,DE,5150.683N,00900.817E,247.0m,4,180,510.0m,122.200,"Flugplatz"
"Volkleshofen",,DE,4900.567N,00921.267E,396.0m,4,080,680.0m,130.125,"Flugplatz"
"Vogelsberg Wiese",,DE,4823.750N,00826.950E,680.0m,3,290,250.0m,,"Landefeld"
"Vogtareuth",,DE,4756.767N,01212.283E,471.0m,5,060,590.0m,121.025,"Flugplatz"
"Vorderriss",,DE,4733.550N,01126.267E,810.0m,3,170,300.0m,,"Landefeld"
"Wackersberg",,DE,4744.100N,01133.100E,731.0m,3,100,400.0m,,"Landefeld"
"Wachtersberg Hub",,DE,4836.900N,00845.333E,591.0m,4,070,600.0m,123.475,"Flugplatz"
"Wahlstedt",,DE,5358.167N,01013.300E,40.0m,2,110,800.0m,121.025,"Flugplatz"
"Wasserkuppe",,DE,5029.933N,00957.217E,898.0m,5,060,670.0m,118.650,"Flugplatz"
"Waldeck",,DE,5113.550N,00903.317E,405.0m,4,010,560.0m,123.475,"Flugplatz"
"Walldorf",,DE,4918.283N,00839.550E,103.0m,2,180,500.0m,118.275,"Flugplatz"
"Wallduern",,DE,4934.900N,00924.133E,402.0m,5,060,820.0m,122.750,"Flugplatz"
"Walldorf Ul",,DE,5036.867N,01021.933E,361.0m,3,040,700.0m,123.425,"Landefeld"
"Walsrode Luisenh",,DE,5253.300N,00936.050E,57.0m,4,080,640.0m,123.500,"Flugplatz"
"Waltrop Ul",,DE,5138.400N,00725.567E,50.0m,3,120,370.0m,123.425,"Landefeld"
"WalXHeim Untersc",,DE,4857.217N,01019.517E,509.0m,3,090,300.0m,120.975,"Landefeld"
"Wangerooge",,DE,5346.867N,00755.233E,3.0m,5,100,850.0m,122.400,"Flugplatz"
"Wangen Kissleg",,DE,4745.400N,00951.367E,640.0m,4,120,770.0m,123.500,"Flugplatz"
"Wanlo Niersquell",,DE,5106.067N,00623.617E,74.0m,4,080,540.0m,121.175,"Flugplatz"
"Warburg Heinber",,DE,5129.833N,00905.250E,172.0m,4,130,900.0m,123.500,"Flugplatz"
"Waren Vielist",,DE,5334.067N,01239.117E,85.0m,2,040,800.0m,130.325,"Flugplatz"
"Warbelow Cls",,DE,5359.717N,01242.633E,20.0m,3,070,700.0m,122.100,"Landefeld"
"Warngau Tannried",,DE,4749.467N,01142.250E,723.0m,5,020,550.0m,123.050,"Flugplatz"
"Wasentegernbach",,DE,4816.400N,01213.117E,463.0m,3,060,260.0m,120.975,"Landefeld"
"Wegscheid",,DE,4739.833N,01134.233E,711.0m,3,080,300.0m,,"Landefeld"
"Wehr",,DE,4738.633N,00754.550E,392.0m,3,020,250.0m,,"Landefeld"
"Weidberg Kaltenw",,DE,5036.550N,01005.283E,619.0m,3,140,400.0m,123.425,"Landefeld"
"Weiden Opf",,DE,4940.733N,01207.000E,405.0m,5,140,570.0m,120.250,"Flugplatz"
"Weimar Umpferst",,DE,5057.900N,01124.000E,299.0m,2,100,670.0m,122.400,"Flugplatz"
"Weinheim Bergst",,DE,4934.017N,00836.650E,96.0m,2,170,770.0m,123.600,"Flugplatz"
"Weipertshofen",,DE,4905.183N,01007.483E,440.0m,4,110,470.0m,123.350,"Flugplatz"
"Weissenhorn",,DE,4817.367N,01008.417E,500.0m,2,080,650.0m,119.425,"Flugplatz"
"Weissenburg Wuel",,DE,4901.550N,01101.117E,615.0m,5,050,590.0m,123.050,"Flugplatz"
"Weilerswist",,DE,5043.200N,00651.033E,137.0m,3,040,320.0m,123.425,"Landefeld"
"Welzheim",,DE,4852.583N,00939.217E,518.0m,4,080,520.0m,123.150,"Flugplatz"
"Wenzendorf",,DE,5320.183N,00946.700E,66.0m,4,040,390.0m,123.500,"Flugplatz"
"Weper",,DE,5142.750N,00948.167E,360.0m,4,350,450.0m,123.500,"Flugplatz"
"Werdohl Kuentrop",,DE,5117.817N,00749.050E,307.0m,2,070,810.0m,118.000,"Flugplatz"
"Werneuchen",,DE,5237.917N,01346.467E,79.0m,5,080,1490.0m,122.600,"Flugplatz"
"Werneck Ul",,DE,4959.300N,01000.583E,281.0m,3,070,210.0m,120.975,"Landefeld"
"Wershofen Eifel",,DE,5027.100N,00647.067E,476.0m,2,070,630.0m,122.400,"Flugplatz"
"Wertheim Ul",,DE,4943.550N,00930.367E,304.0m,3,070,260.0m,120.975,"Landefeld"
"Wesel Romerwardt",,DE,5139.767N,00635.750E,21.0m,2,090,720.0m,122.025,"Flugplatz"
"Weser Wuemme",,DE,5303.233N,00912.517E,18.0m,2,180,850.0m,122.600,"Flugplatz"
"Westhausen",,DE,5018.250N,01040.817E,301.0m,3,140,300.0m,,"Landefeld"
"Westerstede Feld",,DE,5317.317N,00755.850E,8.0m,5,060,570.0m,123.650,"Flugplatz"
"Wiefelstede Conn",,DE,5319.283N,00804.400E,7.0m,2,120,600.0m,126.500,"Flugplatz"
"Wiesbaden Mil",,DE,5002.983N,00819.517E,140.0m,5,070,2140.0m,122.100,"Flugplatz"
"Wildberg Bodense",,DE,4736.017N,00944.517E,520.0m,4,030,490.0m,118.550,"Flugplatz"
"Wilhelmshavn Ma",,DE,5330.133N,00803.133E,6.0m,5,020,1450.0m,129.250,"Flugplatz"
"Wildbergkengel",,DE,4838.200N,00843.833E,509.0m,4,080,600.0m,123.000,"Flugplatz"
"Wilsche",,DE,5231.483N,01027.683E,60.0m,2,090,500.0m,129.975,"Flugplatz"
"Winzeln Schrambe",,DE,4816.750N,00825.700E,670.0m,5,140,700.0m,123.650,"Flugplatz"
"Wipperfurth Neye",,DE,5107.483N,00722.333E,265.0m,2,100,600.0m,122.400,"Flugplatz"
"Wismar",,DE,5354.883N,01130.083E,12.0m,2,080,640.0m,123.050,"Flugplatz"
"Wittstock Berlin",,DE,5313.550N,01234.067E,79.0m,4,050,700.0m,122.200,"Flugplatz"
"Wittstock Cls",,DE,5312.150N,01231.367E,71.0m,3,080,2400.0m,,"Landefeld"
"Wittmundhafe Mil",,DE,5332.867N,00740.050E,9.0m,5,080,2450.0m,118.725,"Flugplatz"
"Witzenhausen",,DE,5121.000N,00949.483E,204.0m,4,350,400.0m,123.500,"Flugplatz"
"Woermlitz Ul",,DE,5210.200N,01149.667E,72.0m,3,080,580.0m,123.425,"Landefeld"
"Worishofen",,DE,4801.617N,01036.133E,616.0m,4,080,630.0m,123.350,"Flugplatz"
"Wolfhagen Graner",,DE,5118.433N,00910.517E,314.0m,2,150,500.0m,127.450,"Flugplatz"
"Worms",,DE,4936.383N,00822.100E,91.0m,5,060,800.0m,124.600,"Flugplatz"
"Wurzburg",,DE,4949.067N,00953.850E,297.0m,5,110,670.0m,122.175,"Flugplatz"
"Wuerzbach",,DE,4843.117N,00838.283E,684.0m,3,050,400.0m,,"Landefeld"
"Wunstorf Mil",,DE,5227.433N,00925.633E,58.0m,5,080,1870.0m,122.100,"Flugplatz"
"Wustweiler Cls",,DE,4924.633N,00703.300E,368.0m,3,070,360.0m,122.475,"Landefeld"
"Wyk Auf Foehr",,DE,5441.117N,00831.917E,9.0m,2,020,660.0m,118.250,"Flugplatz"
"Zellhausen",,DE,5001.233N,00859.017E,113.0m,4,170,860.0m,122.300,"Flugplatz"
"Zell Haidberg",,DE,5008.217N,01147.667E,583.0m,2,060,800.0m,123.375,"Flugplatz"
"Zerbst",,DE,5200.133N,01209.167E,80.0m,5,070,750.0m,123.050,"Flugplatz"
"Zierenberg Dornb",,DE,5121.750N,00920.383E,423.0m,4,170,380.0m,122.300,"Flugplatz"
"Zschorna",,DE,5123.783N,01249.400E,132.0m,3,160,280.0m,123.425,"Landefeld"
"Zweibruecken",,DE,4912.567N,00724.033E,345.0m,5,030,2670.0m,123.825,"Flugplatz"
"Zwickau",,DE,5042.067N,01227.167E,316.0m,2,060,800.0m,122.900,"Flugplatz"

57281
tests/SeeYou.cup 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -1,7 +1,7 @@
#DEVICE_TYPE,DEVICE_ID,AIRCRAFT_MODEL,REGISTRATION,CN,TRACKED,IDENTIFIED #DEVICE_TYPE,DEVICE_ID,AIRCRAFT_MODEL,REGISTRATION,CN,TRACKED,IDENTIFIED,AIRCRAFT_TYPE
'F','DD4711','HK36 TTC','D-EULE','CU','Y','Y' 'F','DD4711','HK36 TTC','D-EULE','CU','Y','Y','1'
'F','DD0815','Ventus 2cxM','D-1234','','Y','N' 'F','DD0815','Ventus 2cxM','D-1234','','Y','N','1'
'F','DD1234','LS 8 18m','D-8654','12','N','Y' 'F','DD1234','LS 8 18m','D-8654','12','N','Y','1'
'F','DD3141','Arcus T','OE-4321','','N','N' 'F','DD3141','Arcus T','OE-4321','','N','N','1'
'O','DEADBE','Baloon','OE-ABC','','Y','Y' 'O','DEADBE','Baloon','OE-ABC','','Y','Y','11'
'I','999999','A380','G-XXXL','XXL','Y','Y' 'I','999999','A380','G-XXXL','XXL','Y','Y','9'

Wyświetl plik

@ -2,7 +2,7 @@ import unittest
import unittest.mock as mock import unittest.mock as mock
from ogn.utils import get_ddb, get_trackable, get_country_code from ogn.utils import get_ddb, get_trackable, get_country_code
from ogn.model import AddressOrigin from ogn.model import AircraftType
class TestStringMethods(unittest.TestCase): class TestStringMethods(unittest.TestCase):
@ -21,8 +21,7 @@ class TestStringMethods(unittest.TestCase):
self.assertEqual(device.competition, 'CU') self.assertEqual(device.competition, 'CU')
self.assertTrue(device.tracked) self.assertTrue(device.tracked)
self.assertTrue(device.identified) self.assertTrue(device.identified)
self.assertEqual(device.aircraft_type, AircraftType.glider_or_motor_glider)
self.assertEqual(device.address_origin, AddressOrigin.user_defined)
def test_get_trackable(self): def test_get_trackable(self):
devices = get_ddb('tests/custom_ddb.txt') devices = get_ddb('tests/custom_ddb.txt')