Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Flightstats API: Пишем свое табло прилетов с Боингами и Аэробусами

Anna | 15.06.2014 | нет комментариев
Каждому читающим данный пост — здравствуйте.
Авиация — мое хобби, я об этом теснее писал. Я готов часами стоять и фотографировать самолеты, глядеть видео о них, читать блоги авиаторов, следить за трафиком на fr24.com. А еще мне нравится то, что в авиации кругом одни сокращения: ECAM, CDA, ACESS, APU и так дальше. Вообщем, магия. А вот примерно все люди из моего окружения к авиации безразличны: «Ну самолет, как самолет. Огромный, да. Что? Boeing 777-300ER? Ну ясно, ясно…». Но ничего не сделаешь, на вкус и цвет все фломастеры различные.
Как ко мне пришла идея поста? Так получилось, что я живу в 20 минутах езды от аэродрома Шереметьево. Как-то у меня выдался вольный час и приехал немножко пофотографировать. За то время, пока я там был, мимо меня пролетело около 10 самолетов. Примерно все — Аэрофлот. Я не спорю, у Аэрофлота есть увлекательные борты. Скажем, Добролет либо Хохлома. Но в тот день мне не повезло, ничего сходственного я не увидел. И тогда я подумал, что было бы дюже пригодно планировать сходственные выезды. Вот так вот и родилась идея поста. Мне хотелось иметь дальнейший функционал: таблица вылетов — прилетов для выбранного аэродрома, выделение цветом как увлекательных, так и не дюже ботов, экспорт в pdf.

Начинаем!

Выходит, первым делом нужно зайти на https://developer.flightstats.com, зарегистрироваться, перейти в Dashboard и нажать на кнопку «Create a new application». Это нужно для приобретения связки AppId AppKey, без которой доступ к API немыслим. Вообще, оно платное, но присутствует и безвозмездный тарифный план — “Evaluation Plan“, его вероятностей для наших нужд хватит полностью. Позже этого отважно идем “Get Started” -> “Flex API Reference” -> “Flight Status & Track API” -> “Flight Status & Track by Airport“. В нижней части страницы есть раздел “Interactive Documentation“, выбираем “Airport status (departures)“. В данном запросе есть 7 непременных полей, которые нужно заполнить дальнейшим образом:

appId appKey airport year month day hourOfDay
Ваш appId Ваш appKey SVO 2013 12 7 10

Через пару секунд появится результат.

Иными словами мы попросили выдать нам информацию о рейсах, которые вылетят 7 декабря 2014 года позже 10 часов из аэродрома Шереметьево. Да, SVO — Шереметьево. А еще UUEE — тоже Шереметьево. Помните, чуть выше я говорил о сокращениях? Вот, мы наткнулись на первое.

Коды аэропортов. IATA vs. ICAO

IATA — Интернациональная ассоциация воздушного транспорта, ИАТА (англ. International Air Transport Association) интернациональная неправительственная организация. Ассоциация выступает координатором и поверенным интересов авиатранспортной ветви в таких областях как обеспечение безопасности полетов, производство полетов, тарифная политика, техобслуживание, авиационная безопасность, разработка интернациональных эталонов коллективно с ИКАО и т. д.

ICAO — Интернациональная организация штатской авиации (International Civil Aviation Organization) — специализированное учреждение ООН, устанавливающее интернациональные нормы штатской авиации и координирующее её становление с целью возрастания безопасности и результативности.

И у ИАТА и у ИКАО есть свои коды аэропортов. Они разны, от того что коды ИАТА выбираются созвучными с наименованием аэродрома, а код ИКАО основан на том, где находится аэродром. Именно следственно у Шереметево код ИАТА SVO, а ИКАО — UUEE, для Пулково, скажем, LED и ULLI соответственно.Исключение составляют лишь аэропорты США (добавляется «K» к коду ИАТА: Лос-Анджелес — LAX — KLAX) и Канады (добавляется «С»: Торонто — YYZ — CYYZ).

Результат flightstats

При данном запросе результат имеет следующую конструкцию:

{
  посланный запрос
}
"appendix":
{
  "airlines": {...}
  "airports": {...}
  "equipments": {...}
  "flightStatuses": {...}
}

Сегменты airlinesairports и equipments содержат в себе изложение авиакомпаний, аэропортов и типов самолетов, которые присутствуют в сегменты flightStatuses.
Сегмент «airlines» предельно примитивна:

"airlines": [
   {
    "fs": "SU",
    "iata": "SU",
    "icao": "AFL",
    "name": "Aeroflot",
    "active": true
   },
...

Поле «fs» содержит в себе код авиакомпании в базе flightStats. Примерно неизменно он совпадает с кодом IATA.

Сегмент «airports» потруднее:

"airports": [
   {
    "fs": "BUD",
    "iata": "BUD",
    "icao": "LHBP",
    "name": "Liszt Ferenc International Airport",
    "city": "Budapest",
    "cityCode": "BUD",
    "countryCode": "HU",
    "countryName": "Hungary",
    "regionName": "Europe",
    "timeZoneRegionName": "Europe/Budapest",
    "localTime": "2013-12-06T20:51:56.974",
    "utcOffsetHours": 1,
    "latitude": 47.433037,
    "longitude": 19.261621,
    "elevationFeet": 495,
    "classification": 2,
    "active": true,
    "delayIndexUrl": "https://api.flightstats.com/flex/delayindex/rest/v1/json/airports/BUD?codeType=fs",
    "weatherUrl": "https://api.flightstats.com/flex/weather/rest/v1/json/all/BUD?codeType=fs"
   }, 
...

Тут содержится каждая нужная информация, помимо погоды и показателя задержки, которые нужно запрашивать отдельно.

Сегмент «equipments».

"equipments": [
   {
    "iata": "319",
    "name": "Airbus Industrie A319",
    "turboProp": false,
    "jet": true,
    "widebody": false,
    "regional": false
   },
...

Описывает базовые колляции самолета.

Отвлечемся опять от API.

Учимся различать типы самолетов

Это вовсе не трудно. Я подготовил небольшую схему (кликабельна), которая поможет легко сориентироваться в мире летающих машин.

И сейчас подтвержение моих слов:
Airbus A380 vs. Boeing 747
 

Ил-96 vs. Airbus A340

Boeing 737 vs. Airbus A320
 

Boeing 757 vs. Boeing 767
 

Airbus A330 vs. Boeing 777
 

Як-42 vs. Ту-154 vs. McDonnel Douglas MD-11

Разбираем flightStatus

Срдержимое flightStatus. Длинное, следственно спрятано

{
   "flightId": 317846653,
   "carrierFsCode": "SU",
   "flightNumber": "2030",
   "departureAirportFsCode": "SVO",
   "arrivalAirportFsCode": "BUD",
   "departureDate": {
    "dateLocal": "2013-12-07T10:50:00.000",
    "dateUtc": "2013-12-07T06:50:00.000Z"
   },
   "arrivalDate": {
    "dateLocal": "2013-12-07T10:35:00.000",
    "dateUtc": "2013-12-07T09:35:00.000Z"
   },
   "status": "L",
   "schedule": {
    "flightType": "J",
    "serviceClasses": "RJY",
    "restrictions": ""
   },
   "operationalTimes": {
    "publishedDeparture": {
     "dateLocal": "2013-12-07T10:50:00.000",
     "dateUtc": "2013-12-07T06:50:00.000Z"
    },
    "publishedArrival": {
     "dateLocal": "2013-12-07T10:35:00.000",
     "dateUtc": "2013-12-07T09:35:00.000Z"
    },
    "scheduledGateDeparture": {
     "dateLocal": "2013-12-07T10:50:00.000",
     "dateUtc": "2013-12-07T06:50:00.000Z"
    },
    "estimatedGateDeparture": {
     "dateLocal": "2013-12-07T10:50:00.000",
     "dateUtc": "2013-12-07T06:50:00.000Z"
    },
    "actualGateDeparture": {
     "dateLocal": "2013-12-07T11:27:00.000",
     "dateUtc": "2013-12-07T07:27:00.000Z"
    },
    "scheduledGateArrival": {
     "dateLocal": "2013-12-07T10:35:00.000",
     "dateUtc": "2013-12-07T09:35:00.000Z"
    },
    "estimatedGateArrival": {
     "dateLocal": "2013-12-07T11:12:00.000",
     "dateUtc": "2013-12-07T10:12:00.000Z"
    },
    "actualGateArrival": {
     "dateLocal": "2013-12-07T10:43:00.000",
     "dateUtc": "2013-12-07T09:43:00.000Z"
    }
   },
   "delays": {
    "departureGateDelayMinutes": 37,
    "arrivalGateDelayMinutes": 8
   },
   "flightDurations": {
    "scheduledBlockMinutes": 165,
    "blockMinutes": 136
   },
   "airportResources": {
    "departureTerminal": "D",
    "departureGate": "28",
    "arrivalTerminal": "2"
   },
   "flightEquipment": {
    "scheduledEquipmentIataCode": "320",
    "actualEquipmentIataCode": "A320",
    "tailNumber": "VP-BWI"
   }
  },
...

Предназначение полей в большинстве случаев видимо. Я детально расскажу лишь о тех, содержимое которых не вовсе видимо. А отчего? Верно, потому что сокращения.
Вот эта часть результата:

"status": "L",
   "schedule": {
    "flightType": "J",
    "serviceClasses": "RJY",
    "restrictions": ""
   },
Поле Изложение
status Нынешний ранг рейса
A — Active
C — Canceled
D — Diverted — Была произведена смена пункта назначения (скажем, по метео-условиям)
DN — Data source needed — Неоткуда получить информацию о ранге
L — Landed
NO — Not Operational
R — Redirected
S — Scheduled
U — Unknown
flightType Тип рейса. Каждого их существует 23 штуки. Скажем,
J — Scheduled Passanger — Пассажириский по расписанию
M — Scheduled Cargo/Mail(MailOnly) — Грузовой, но только с письмами.
W — Military — Армейский
serviceClasses Варианты обслуживания, предусмотренные на рейсе по систематизации IATA. Подробнее здесь — http://en.wikipedia.org/wiki/IATA_class_codes
restrictions Ограничения по систематизации IATA. Подробнее —http://www.flyerguide.com/wiki/index.php/Traffic_Restriction_Codes_(AA)

Программирование

На данный момент я использую python 2.7, urllib2 и simplejson.

Первое, что необходимо сделать — подключить нужные библиотеки и проинициализировать переменные.

import urllib2
import simplejson

appId = "Ваш appId здесь"
appKey = "Ваш appKey здесь"

# Наименование аэродрома. Может быть запрошен как по внутреннему коду flightstats, так и по кодам ICAO либо IATA
requestedAirport = "SVO"

# Какие рейсы нам необходимы. arr - прибывающие, dep - отбывающие
flightsType = "arr"

# Дата 
requestedDate = "2013/12/7"

# Время, с которого мы хотим получить список рейсов
requestedHour = "15"

# число часов, за которые будет составлен список
requestedNumHours = "6"

Дальнейший шаг — упаковываем эти переменные в url, отправляем запрос и ожидаем результата.

# Заготовка для запроса
url = "https://api.flightstats.com/flex/flightstatus/rest/v2/json/" \
       "airport/status/%s/%s/%s/%s?appId=%s&appKey=%s&utc=false&numHours=%s" 

# Подставляем надобные значения в запрос        
url = url %(requestedAirport, flightsType, requestedDate, requestedHour, appId, appKey, requestedNumHours)

# Шлем запрос и получаем JSON-результат            
req = urllib2.Request(url, None)
opener = urllib2.build_opener()
f = opener.open(req)         
response = simplejson.load(f)

После этого парсим вспомогательные поля. Они нам необходимы для того, Дабы подставлять развернутые наименования самолетов и аэропотов в список.

# Сберегаем ветку с аэропортами
airports = response["appendix"]["airports"]

# Данные по аэропортам будут храниться в словаре (dictionary)
airportsDict = dict()

# Для всякого аэродрома записываем пару [код flightstats]:[название]
for airport in airports:
    airportsDict[airport["fs"]] = airport["name"]

# Подобно поступаем для типов бортов...
equipments = response["appendix"]["equipments"]
equipmentsDict = dict()
for equipment in equipments:
    equipmentsDict[equipment["iata"]] = equipment["name"], equipment["iata"] 

#... и для авиакомпаний
airlines = response["appendix"]["airlines"]
airlinesDict = dict()
for airline in airlines:
    airlinesDict[airline["fs"]] = airline["name"]

Итогом работы нашего кода должна быть вот такая таблица:

Flight Carrier Equipment Registration From STD ATD To STA STD
XQ114 SunExpress Boeing 737-800 Passenger D-ASXA Antalya 15:00:00.000 CGN 17:55:00.000

Выводить данные будем в HTML.

# Заготовка для страницы
webPage = "<html><body><table border=\"1\">    \
           <tr><th>Flight</th><th>Carrier</th><th>Equipment</th><th>Registration</th><th>From</th><th>STD</th>   \
           <th>ATD</th><th>To</th><th>STA</th><th>ETA</th></tr>"

# Заготовка для строки таблицы
templateRow = "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td> \
               <td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>"

f = open("./list.html", "w")

Дальше нужно написать вспомогательную функцию.
Надобные нам значения лежат на различной глубине. Скажем, carrierFsCode, код аэродрома, на нулевой глубине. А Дабы достать время фактическое время вылета, необходимо опуститься на вторую глубину:operationalTimes --> actualGateDeparture --> dateLocal". Для этого необходима первая вспомогательная функция.

def getProperty(status, propertyNames):
  # Пытаемся обнаружить необходимый ключ
  try:
      # Перебираем всякий ключ из propertyNames
      for propertyName in propertyNames:
          # Отсекаем непотребное  
          status = status[propertyName]

      # Необходимый ключ обнаружен!
      return status
   except
      # А если нет, то возвращаем заглушку
      return "---"

Сейчас самое увлекательное: нужно предпочесть то, что вас особенно волнует в трафике. Это содержится в 3 массивах:

interestingCarriers = ["RU", # AirBridgeCargo
                       "CU", # Cubana de Aviacion
                       "ME", # China Eastern Airlines
                       "KE", # Korean Air Lines
                       ]
interestingEquipments = ["SU9"] # Sukhoi Superjet 100

interestingTailNumbers = ["VP-BGB"] # Номер первого Boeing 777-300ER для Аэрофлота

А сейчас, собственно, парсер:

for flightStatus in flightStatuses:
    newRow = templateRow %(getProperty(flightStatus, ["carrierFsCode"])   getProperty(flightStatus, ["flightNumber"]),
                   airlinesDict[getProperty(flightStatus, ["carrierFsCode"])],
                   getProperty(flightStatus, ["flightEquipment", "scheduledEquipmentIataCode"]),
                   getProperty(flightStatus, ["flightEquipment", "tailNumber"]),
                   str(airportsDict[getProperty(flightStatus, ["departureAirportFsCode"])]).replace("Airport", ""),
                   str(getProperty(flightStatus, ["departureDate", "dateLocal"])).split("T")[-1],
                   str(getProperty(flightStatus, ["operationalTimes", "actualGateDeparture", "dateLocal"])).split("T")[-1],
                   str(airportsDict[getProperty(flightStatus, ["arrivalAirportFsCode"])]).replace("Airport", "")
                   str(getProperty(flightStatus, ["arrivalDate", "dateLocal"])).split("T")[-1],
                   str(getProperty(flightStatus, ["operationalTimes", "estimatedGateArrival", "dateLocal"])).split("T")[-1])

    # Подсвечиваем нужную строку
    if (getProperty(flightStatus, ["carrierFsCode"]) in interestingCarriers) or \
        (getProperty(flightStatus, ["flightEquipment", "scheduledEquipmentIataCode"]) in interestingEquipments) or \
        (getProperty(flightStatus, ["flightEquipment", "tailNumber"]) in interestingTailNumbers):
        newRow = newRow.replace("<tr>", "<tr bgcolor=\"#FF0000\">")

    #  Добавляем ее к странице
    webPage  = newRow

Завершающий штрих — дописываем теги в конец страницы и закрываем файл.

webPage = webPage   "</table></body></html>"
f.write(webPage)
f.close()
Итог работы

Flight Carrier Equipment Registration From STD ATD To STA ETA
SU155 Aeroflot 332 VQ-BBE Cancun International 12:30:00.000 13:17:00.000 Sheremetyevo International 10:30:00.000 11:03:00.000
DL466 Delta Air Lines 76W John F. Kennedy International 16:15:00.000 16:14:00.000 Sheremetyevo International 10:50:00.000 10:12:00.000
SU111 Aeroflot 332 VP-BLX Miami International 17:35:00.000 18:35:00.000 Sheremetyevo International 13:45:00.000 13:46:00.000
SU103 Aeroflot 333 VP-BDE John F. Kennedy International 19:05:00.000 Sheremetyevo International 13:25:00.000 13:34:00.000
UN576 Transaero Airlines 744 EI-XLJ Punta Cana International 19:55:00.000 21:18:00.000 Sheremetyevo International 14:50:00.000 15:35:00.000
RU566 AirBridgeCargo 74Y Frankfurt am Main 04:45:00.000 Sheremetyevo International 11:00:00.000
RU498 AirBridgeCargo 74N Shanghai Pudong International 05:00:00.000 Sheremetyevo International 10:45:00.000
SU233 Aeroflot 332 Indira Gandhi International 05:05:00.000 05:26:00.000 Sheremetyevo International 10:10:00.000 10:13:00.000
RU506 AirBridgeCargo 74N Milano Malpensa 05:30:00.000 Sheremetyevo International 12:00:00.000
SU1827 Aeroflot 320 VQ-BAZ Simferopol 06:00:00.000 06:25:00.000 Sheremetyevo International 10:15:00.000 10:40:00.000
SU2437 Aeroflot 320 VP-BLH Dusseldorf International 06:05:00.000 06:27:00.000 Sheremetyevo International 12:25:00.000 12:24:00.000
RU440 AirBridgeCargo 74N VP-BIM Hong Kong International 06:15:00.000 06:15:00.000 Sheremetyevo International 12:25:00.000
KE529 Korean Air Lines 74Y HL7466 Incheon International 06:25:00.000 07:07:00.000 Sheremetyevo International 10:40:00.000
JU650 Jat Airways 733 Belgrad Nikola Tesla 06:45:00.000 06:45:00.000 Sheremetyevo International 12:35:00.000 12:39:00.000
PS561 UIA 73N UR-GAP Kiev/Kyiv — Borispol 07:00:00.000 07:00:00.000 Sheremetyevo International 10:35:00.000 10:35:00.000
SU1009 Aeroflot 321 VQ-BED Kaliningrad 07:10:00.000 07:36:00.000 Sheremetyevo International 10:00:00.000 10:26:00.000
AF1644 Air France 319 F-GRHL Charles de Gaulle 07:15:00.000 07:13:00.000 Sheremetyevo International 13:55:00.000 13:52:00.000
SU1867 Aeroflot 320 VP-BQP Zvartnots International 08:10:00.000 08:21:00.000 Sheremetyevo International 11:00:00.000 11:11:00.000
5N502 Nordavia Regional Airlines 735 Syktyvkar 08:20:00.000 08:27:00.000 Sheremetyevo International 10:15:00.000 10:11:00.000
KC893 Air Astana 320 P4-KBC Astana 08:40:00.000 08:36:00.000 Sheremetyevo International 10:20:00.000 10:49:00.000
SU3 Aeroflot 321 VP-BWO Pulkovo 08:55:00.000 09:04:00.000 Sheremetyevo International 10:20:00.000 10:29:00.000
SU1513 Aeroflot 319 VP-BWA Surgut 09:00:00.000 08:59:00.000 Sheremetyevo International 10:35:00.000 10:34:00.000
SU1293 Aeroflot 320 VQ-BIV Kazan 09:00:00.000 09:27:00.000 Sheremetyevo International 10:30:00.000 10:50:00.000
SU1229 Aeroflot 320 VP-BDK Nizhniy Novgorod 09:05:00.000 09:21:00.000 Sheremetyevo International 10:25:00.000 10:41:00.000
SU1309 Aeroflot 319 VP-BDO Samara 09:15:00.000 09:20:00.000 Sheremetyevo International 10:55:00.000 11:00:00.000
AY153 Finnair 319 OH-LVI Helsinki-Vantaa 09:25:00.000 09:29:00.000 Sheremetyevo International 13:05:00.000 12:57:00.000
OK892 CSA 319 Vaclav Havel Prague 09:30:00.000 09:31:00.000 Sheremetyevo International 15:10:00.000 15:05:00.000
SU2005 Aeroflot 320 VP-BWI J. Paul II International Krakow-Balice 09:35:00.000 09:56:00.000 Sheremetyevo International 14:40:00.000 14:49:00.000
SU1121 Aeroflot 320 VP-BTI Adler/Sochi 09:50:00.000 09:55:00.000 Sheremetyevo International 12:20:00.000 12:25:00.000
SU2685 Aeroflot 320 VQ-BCM Schoenefeld 09:50:00.000 10:44:00.000 Sheremetyevo International 15:25:00.000 16:15:00.000
SU5 Aeroflot 320 VQ-BAX Pulkovo 09:55:00.000 10:20:00.000 Sheremetyevo International 11:15:00.000 11:40:00.000
SU1839 Aeroflot SU9 RA-89010 Kharkov 09:55:00.000 10:10:00.000 Sheremetyevo International 13:30:00.000 13:20:00.000
SU2321 Aeroflot 320 VQ-BHL Franz Josef Strauss 10:00:00.000 10:16:00.000 Sheremetyevo International 16:00:00.000 16:16:00.000
SU1001 Aeroflot 320 VP-BLL Kaliningrad 10:05:00.000 10:25:00.000 Sheremetyevo International 12:55:00.000 13:15:00.000
R25807 Orenair 738 Barnaul 10:10:00.000 10:15:00.000 Sheremetyevo International 11:30:00.000 11:35:00.000
SU1307 Aeroflot 320 VP-BKX Tolmachevo 10:15:00.000 10:19:00.000 Sheremetyevo International 11:25:00.000 11:29:00.000
SU1701 Aeroflot 333 VQ-BNS Vladivostok International 10:20:00.000 10:24:00.000 Sheremetyevo International 12:25:00.000 12:29:00.000
SU1805 Aeroflot 321 VP-BOE Kiev/Kyiv — Borispol 10:20:00.000 11:00:00.000 Sheremetyevo International 13:50:00.000 14:30:00.000
SU2137 Aeroflot 321 VQ-BHK Istanbul Ataturk 10:20:00.000 11:03:00.000 Sheremetyevo International 15:15:00.000 15:26:00.000
SK734 SAS 320 OY-KAP Copenhagen 10:20:00.000 10:46:00.000 Sheremetyevo International 15:45:00.000 16:02:00.000
SU7 Aeroflot 320 Pulkovo 10:25:00.000 10:43:00.000 Sheremetyevo International 11:45:00.000 12:03:00.000
SU1813 Aeroflot 320 VP-BRX Donetsk 10:30:00.000 10:31:00.000 Sheremetyevo International 14:25:00.000 14:26:00.000
SU1831 Aeroflot 320 Minsk International 2 10:50:00.000 11:40:00.000 Sheremetyevo International 13:15:00.000 14:05:00.000
SU2107 Aeroflot 320 VP-BZS Tallinn 10:50:00.000 10:54:00.000 Sheremetyevo International 14:30:00.000 14:18:00.000
SU1479 Aeroflot 319 VP-BDM Abakan 10:55:00.000 10:55:00.000 Sheremetyevo International 11:55:00.000 11:55:00.000
SU1483 Aeroflot 77W VP-BGB Krasnojarsk 11:00:00.000 11:13:00.000 Sheremetyevo International 11:35:00.000 11:48:00.000
SU2683 Aeroflot 319 VQ-BCO Riga 11:00:00.000 11:24:00.000 Sheremetyevo International 14:35:00.000 14:44:00.000
D95399 Donavia 319 VP-BNN Stavropol 11:15:00.000 11:17:00.000 Sheremetyevo International 13:30:00.000 13:32:00.000
SU2035 Aeroflot SU9 RA-89008 Otopeni International 11:15:00.000 11:28:00.000 Sheremetyevo International 15:35:00.000 15:33:00.000
SU11 Aeroflot 320 Pulkovo 11:30:00.000 11:49:00.000 Sheremetyevo International 12:45:00.000 13:04:00.000
SU1139 Aeroflot 321 VQ-BKU Adler/Sochi 11:35:00.000 11:55:00.000 Sheremetyevo International 14:00:00.000 14:20:00.000
SU1211 Aeroflot 320 VQ-BIT Samara 11:40:00.000 12:13:00.000 Sheremetyevo International 13:25:00.000 13:42:00.000
SU1759 Aeroflot SU9 VP-BZQ Volgograd 11:45:00.000 11:53:00.000 Sheremetyevo International 13:35:00.000 13:43:00.000
SU1255 Aeroflot 319 VP-BDN Begishevo 11:50:00.000 12:03:00.000 Sheremetyevo International 13:40:00.000 13:53:00.000
SU1643 Aeroflot 320 VQ-BIW Astrakhan 11:50:00.000 11:55:00.000 Sheremetyevo International 14:10:00.000 14:15:00.000
SU1305 Aeroflot 320 VP-BLP Mineralnye Vody 11:50:00.000 12:08:00.000 Sheremetyevo International 14:15:00.000 14:33:00.000
SU1761 Aeroflot 738 VP-BRH Chita 11:55:00.000 12:10:00.000 Sheremetyevo International 12:45:00.000 13:00:00.000
SU1221 Aeroflot 320 VP-BMF Nizhniy Novgorod 12:05:00.000 12:12:00.000 Sheremetyevo International 13:10:00.000 13:17:00.000
SU1743 Aeroflot 333 VQ-BQX Yuzhno-Sakhalinsk 12:10:00.000 12:20:00.000 Sheremetyevo International 14:05:00.000 14:15:00.000
D95301 Donavia 734 VQ-BCS Rostov 12:15:00.000 12:28:00.000 Sheremetyevo International 14:15:00.000 14:28:00.000
SU13 Aeroflot 319 Pulkovo 12:20:00.000 12:50:00.000 Sheremetyevo International 13:35:00.000 14:05:00.000
5N117 Nordavia Regional Airlines 735 Arkhangelsk 12:20:00.000 12:25:00.000 Sheremetyevo International 14:05:00.000 14:10:00.000
SU1191 Aeroflot 320 VQ-BEA Kazan 12:25:00.000 13:04:00.000 Sheremetyevo International 13:55:00.000 14:34:00.000
SU1751 Aeroflot 738 VP-BRF Yakutsk 12:30:00.000 12:58:00.000 Sheremetyevo International 13:15:00.000 13:43:00.000
SU1547 Aeroflot SU9 Anapa 12:30:00.000 12:50:00.000 Sheremetyevo International 14:45:00.000 15:05:00.000
D95377 Donavia 319 Mineralnye Vody 12:45:00.000 13:03:00.000 Sheremetyevo International 15:10:00.000 15:28:00.000
D95363 Donavia 319 VP-BQK Rostov 13:05:00.000 13:20:00.000 Sheremetyevo International 15:05:00.000 15:20:00.000
SU1411 Aeroflot 321 VQ-BOI Koltsovo International 13:15:00.000 13:43:00.000 Sheremetyevo International 13:40:00.000 14:08:00.000
SU1731 Aeroflot 333 VQ-BCQ Petropavlovsk-Kamchatsky 13:30:00.000 13:44:00.000 Sheremetyevo International 14:30:00.000 14:44:00.000
SU15 Aeroflot 320 Pulkovo 13:30:00.000 13:39:00.000 Sheremetyevo International 14:45:00.000 14:52:00.000
SU1231 Aeroflot 320 VP-BLR Ufa 13:55:00.000 14:19:00.000 Sheremetyevo International 14:00:00.000 14:24:00.000
SU1421 Aeroflot 320 VP-BNL Chelyabinsk 13:55:00.000 13:56:00.000 Sheremetyevo International 14:20:00.000 14:21:00.000
R25803 Orenair 738 Irkutsk 14:05:00.000 14:30:00.000 Sheremetyevo International 14:50:00.000 15:15:00.000
SU1201 Aeroflot SU9 Perm 14:10:00.000 Sheremetyevo International 14:25:00.000 14:25:00.000
5N9134 Nordavia Regional Airlines Kazan 14:10:00.000 15:07:00.000 Sheremetyevo International 15:30:00.000
SU17 Aeroflot 320 Pulkovo 14:25:00.000 14:56:00.000 Sheremetyevo International 15:40:00.000 16:11:00.000

Future work

  • Хочу сделать больше прекрасный вид таблицы итогами
  • Типичный итог в PDF, а не как печать web-страницы
  • Приложение для Android

 

 Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB