messageboard-2020-08-31-1014.py
01234567890123456789012345678901234567890123456789012345678901234567890123456789









341342343344345346347348349350351352353354355356357358359360 361362363 364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 397398399400 401402403404405406407408409410411412413414415416417418419420 421422423424425426427428429430431432433434435436437438439440








674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714








24872488248924902491249224932494249524962497249824992500250125022503250425052506   25072508 25092510251125122513251425152516251725182519252025212522252325242525252625272528











                            <----SKIPPED LINES---->




DAYS_OF_WEEK = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']

# AIRCRAFT_LENGTH[''] =
AIRCRAFT_LENGTH = {} # in meters
AIRCRAFT_LENGTH['Airbus A220-100 (twin-jet)'] = 35
AIRCRAFT_LENGTH['Airbus A300F4-600 (twin-jet)'] = 54.08
AIRCRAFT_LENGTH['Airbus A319 (twin-jet)'] = 33.84
AIRCRAFT_LENGTH['Airbus A320 (twin-jet)'] = 37.57
AIRCRAFT_LENGTH['Airbus A320neo (twin-jet)'] = 37.57
AIRCRAFT_LENGTH['Airbus A321 (twin-jet)'] = 44.51
AIRCRAFT_LENGTH['Airbus A321neo (twin-jet)'] = 44.51
AIRCRAFT_LENGTH['Airbus A330-200 (twin-jet)'] = 58.82
AIRCRAFT_LENGTH['Airbus A330-300 (twin-jet)'] = 63.67
AIRCRAFT_LENGTH['Airbus A340-300 (quad-jet)'] = 63.69
AIRCRAFT_LENGTH['Airbus A350-1000 (twin-jet)'] = 73.79
AIRCRAFT_LENGTH['Airbus A350-900 (twin-jet)'] = 66.8
AIRCRAFT_LENGTH['Airbus A380-800 (quad-jet)'] = 72.72
AIRCRAFT_LENGTH['Antonov An-124 Ruslan (quad-jet)'] = 69.1
AIRCRAFT_LENGTH['Beechcraft Beechjet (twin-jet)'] = 14.76
AIRCRAFT_LENGTH['Beechcraft Bonanza (33) (piston-single)'] = 7.65

AIRCRAFT_LENGTH['Beechcraft Super King Air 200 (twin-turboprop)'] = 13.31
AIRCRAFT_LENGTH['Beechcraft Super King Air 350 (twin-turboprop)'] = 14.22
AIRCRAFT_LENGTH['Beechcraft King Air 90 (twin-turboprop)'] = 10.82

AIRCRAFT_LENGTH['Boeing 737-400 (twin-jet)'] = 36.4
AIRCRAFT_LENGTH['Boeing 737-700 (twin-jet)'] = 33.63
AIRCRAFT_LENGTH['Boeing 737-800 (twin-jet)'] = 39.47
AIRCRAFT_LENGTH['Boeing 737-900 (twin-jet)'] = 42.11
AIRCRAFT_LENGTH['Boeing 747-100 (quad-jet)'] = 70.66
AIRCRAFT_LENGTH['Boeing 747-400 (quad-jet)'] = 70.66
AIRCRAFT_LENGTH['Boeing 747-8 (quad-jet)'] = 76.25
AIRCRAFT_LENGTH['Boeing 757-200 (twin-jet)'] = 47.3
AIRCRAFT_LENGTH['Boeing 757-300 (twin-jet)'] = 54.4
AIRCRAFT_LENGTH['Boeing 767-200 (twin-jet)'] = 48.51
AIRCRAFT_LENGTH['Boeing 767-300 (twin-jet)'] = 54.94
AIRCRAFT_LENGTH['Boeing 777 (twin-jet)'] = (63.73 + 73.86) / 2
AIRCRAFT_LENGTH['Boeing 777-200 (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['Boeing 777-200LR/F (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['Boeing 777-300ER (twin-jet)'] = 73.86
AIRCRAFT_LENGTH['Boeing 787-10 (twin-jet)'] = 68.28
AIRCRAFT_LENGTH['Boeing 787-8 (twin-jet)'] = 56.72
AIRCRAFT_LENGTH['Boeing 787-9 (twin-jet)'] = 62.81
AIRCRAFT_LENGTH['Bombardier Challenger 300 (twin-jet)'] = 20.92
AIRCRAFT_LENGTH['Bombardier Global 5000 (twin-jet)'] = 29.5
AIRCRAFT_LENGTH['Bombardier Global Express (twin-jet)'] = (29.5 + 30.3) / 2
AIRCRAFT_LENGTH['Canadair Regional Jet CRJ-200 (twin-jet)'] = 26.77
AIRCRAFT_LENGTH['Canadair Regional Jet CRJ-700 (twin-jet)'] = 32.3
AIRCRAFT_LENGTH['Canadair Regional Jet CRJ-900 (twin-jet)'] = 36.2
AIRCRAFT_LENGTH['Canadair Challenger (twin-jet)'] = 20.9
AIRCRAFT_LENGTH['Canadair Challenger 350 (twin-jet)'] = 20.9
AIRCRAFT_LENGTH['Cessna Caravan (single-turboprop)'] = 11.46
AIRCRAFT_LENGTH['Cessna Citation CJ1 (twin-jet)'] = 12.98
AIRCRAFT_LENGTH['Cessna Citation CJ2+ (twin-jet)'] = 14.53
AIRCRAFT_LENGTH['Cessna Citation CJ3 (twin-jet)'] = 15.59
AIRCRAFT_LENGTH['Cessna Citation Excel/XLS (twin-jet)'] = 16.0
AIRCRAFT_LENGTH['Cessna Citation II (twin-jet)'] = 14.54
AIRCRAFT_LENGTH['Cessna Citation Latitude (twin-jet)'] = 18.97

AIRCRAFT_LENGTH['Cessna Citation Sovereign (twin-jet)'] = 19.35
AIRCRAFT_LENGTH['Cessna Citation V (twin-jet)'] = 14.91
AIRCRAFT_LENGTH['Cessna Citation X (twin-jet)'] = 22.04
AIRCRAFT_LENGTH['Cessna Citation Mustang (twin-jet)'] = 12.37

AIRCRAFT_LENGTH['Cessna Skyhawk (piston-single)'] = 8.28
AIRCRAFT_LENGTH['Cessna Skylane (piston-single)'] = 8.84
AIRCRAFT_LENGTH['Cessna T206 Turbo Stationair (piston-single)'] = 8.61
AIRCRAFT_LENGTH['Cirrus SR-22 (piston-single)'] = 7.92
AIRCRAFT_LENGTH['Dassault Falcon 900 (tri-jet)'] = 20.21
AIRCRAFT_LENGTH['Dassault Falcon 2000 (twin-jet)'] = 20.23
AIRCRAFT_LENGTH['Embraer 170/175 (twin-jet)'] = (29.90 + 31.68) / 2
AIRCRAFT_LENGTH['Embraer Phenom 300 (twin-jet)'] = 15.9
AIRCRAFT_LENGTH['Embraer ERJ-135 (twin-jet)'] = 26.33
AIRCRAFT_LENGTH['Embraer ERJ-145 (twin-jet)'] = 29.87
AIRCRAFT_LENGTH['Embraer Legacy 450 (twin-jet)'] = 19.69
AIRCRAFT_LENGTH['EMBRAER 175 (long wing) (twin-jet)'] = 31.68
AIRCRAFT_LENGTH['Eurocopter EC-635 (twin-turboshaft)'] = 10.21
AIRCRAFT_LENGTH['IAI Gulfstream G280 (twin-jet)'] = 20.3
AIRCRAFT_LENGTH['Gulfstream Aerospace Gulfstream G550 (twin-jet)'] = 29.39
AIRCRAFT_LENGTH['Gulfstream Aerospace Gulfstream IV (twin-jet)'] = 26.92
AIRCRAFT_LENGTH['Learjet 35 (twin-jet)'] = 14.83
AIRCRAFT_LENGTH['Learjet 45 (twin-jet)'] = 17.68
AIRCRAFT_LENGTH['McDonnell Douglas MD-11 (tri-jet)'] = 61.6
AIRCRAFT_LENGTH['Pilatus PC-12 (single-turboprop)'] = 14.4



def Log(message, file=None, rolling=None):
  """Write a message to a logfile along with a timestamp.

  Args:
    message: string message to write
    file: string representing file name and, if needed, path to the
      file to write to
    rolling: name of file that will keep only the last n files of file
  """
  # can't define as a default parameter because LOGFILE name is potentially
  # modified based on SIMULATION flag
  if not file:
    file = LOGFILE

  # special case: for the main logfile, we always keep a rolling log
  if not rolling and file == LOGFILE:
    rolling = ROLLING_LOGFILE





                            <----SKIPPED LINES---->




  haversines, relating the sides and angles of spherical triangles.

  Reference: https://en.wikipedia.org/wiki/Haversine_formula

  Args:
    pos1: a 2-tuple defining (lat, lon) in decimal degrees
    pos2: a 2-tuple defining (lat, lon) in decimal degrees

  Returns:
    Distance between two points in meters.
  """
  is_numeric = [isinstance(x, numbers.Number) for x in (*pos1, *pos2)]
  if False in is_numeric:
    return None

  lat1, lon1, lat2, lon2 = [math.radians(x) for x in (*pos1, *pos2)]
  hav = (math.sin((lat2 - lat1) / 2.0)**2
         + math.cos(lat1) * math.cos(lat2) * math.sin((lon2 - lon1) / 2.0)**2)
  distance = 2 * RADIUS * math.asin(math.sqrt(hav))

  # Note: though pyproj has this, having trouble installing on rpi
  #az12, az21, distance = g.inv(lon1, lat1, lon2, lat2)

  return distance


def SpeedInMeters(speed_in_knots):
  """Converts speed in knots to speed in meters per second."""
  return speed_in_knots * METERS_PER_SECOND_IN_KNOTS


def MetersTraveled(speed_in_knots, seconds):
  """Converts speed in knots to distance in meters given elapsed sec."""
  return SpeedInMeters(speed_in_knots) * seconds


def ClosestKnownLocation(flight, seconds):
  """Returns the most recent location observation from a flight.

  Flights in the flight dictionary have their path maintained over all the time
  that the radio continues to observe the flight. This function identifies the




                            <----SKIPPED LINES---->




  is an easier-to-read and more faithful representation of how the message will
  be displayed. The transformations are to add blank lines to the message to
  make it consistent number of lines, and to add border to the sides & top /
  bottom of the message.

  Args:
    lines: list of strings that comprise the message
    splitflap: boolean, True if directed for splitflap display; false if
    directed to screen

  Returns:
    String - which includes embedded new line characters, borders, etc. as
    described above, that can be printed to screen as the message.
  """
  divider = '+' + '-'*SPLITFLAP_CHARS_PER_LINE + '+'
  border_character = '|'
  append_character = '\n'

  if splitflap:
    border_character = ''



    append_character = ''


  for unused_n in range(SPLITFLAP_LINE_COUNT-len(lines)):
    lines.append('')

  # convert escaped character codes potentially embedded in personal
  # message to something that can be displayed well on screen, albeit
  # the colors for {63}..{69} aren't captured in plain text
  # see https://docs.vestaboard.com/characters
  escaped_characters = (
      ('{62}', u'\u00b0'),
      ('{63}', u'\u2588'),  # red
      ('{64}', u'\u2588'),  # orange
      ('{65}', u'\u2588'),  # yellow
      ('{66}', u'\u2588'),  # green
      ('{67}', u'\u2588'),  # blue
      ('{68}', u'\u2588'),  # violet
      ('{69}', u'\u2588'))  # red

  lines = [
      border_character +
      line.ljust(SPLITFLAP_CHARS_PER_LINE).upper() +




                            <----SKIPPED LINES---->





01234567890123456789012345678901234567890123456789012345678901234567890123456789









341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445








679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719








2492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537











                            <----SKIPPED LINES---->




DAYS_OF_WEEK = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']

# AIRCRAFT_LENGTH[''] =
AIRCRAFT_LENGTH = {} # in meters
AIRCRAFT_LENGTH['Airbus A220-100 (twin-jet)'] = 35
AIRCRAFT_LENGTH['Airbus A300F4-600 (twin-jet)'] = 54.08
AIRCRAFT_LENGTH['Airbus A319 (twin-jet)'] = 33.84
AIRCRAFT_LENGTH['Airbus A320 (twin-jet)'] = 37.57
AIRCRAFT_LENGTH['Airbus A320neo (twin-jet)'] = 37.57
AIRCRAFT_LENGTH['Airbus A321 (twin-jet)'] = 44.51
AIRCRAFT_LENGTH['Airbus A321neo (twin-jet)'] = 44.51
AIRCRAFT_LENGTH['Airbus A330-200 (twin-jet)'] = 58.82
AIRCRAFT_LENGTH['Airbus A330-300 (twin-jet)'] = 63.67
AIRCRAFT_LENGTH['Airbus A340-300 (quad-jet)'] = 63.69
AIRCRAFT_LENGTH['Airbus A350-1000 (twin-jet)'] = 73.79
AIRCRAFT_LENGTH['Airbus A350-900 (twin-jet)'] = 66.8
AIRCRAFT_LENGTH['Airbus A380-800 (quad-jet)'] = 72.72
AIRCRAFT_LENGTH['Antonov An-124 Ruslan (quad-jet)'] = 69.1
AIRCRAFT_LENGTH['Beechcraft Beechjet (twin-jet)'] = 14.76
AIRCRAFT_LENGTH['Beechcraft Bonanza (33) (piston-single)'] = 7.65
AIRCRAFT_LENGTH['Beechcraft Premier 1 (twin-jet)'] = 14.02
AIRCRAFT_LENGTH['Beechcraft Super King Air 200 (twin-turboprop)'] = 13.31
AIRCRAFT_LENGTH['Beechcraft Super King Air 350 (twin-turboprop)'] = 14.22
AIRCRAFT_LENGTH['Beechcraft King Air 90 (twin-turboprop)'] = 10.82
AIRCRAFT_LENGTH['Boeing 777-300 (twin-jet)'] = 33.4
AIRCRAFT_LENGTH['Boeing 737-400 (twin-jet)'] = 36.4
AIRCRAFT_LENGTH['Boeing 737-700 (twin-jet)'] = 33.63
AIRCRAFT_LENGTH['Boeing 737-800 (twin-jet)'] = 39.47
AIRCRAFT_LENGTH['Boeing 737-900 (twin-jet)'] = 42.11
AIRCRAFT_LENGTH['Boeing 747-100 (quad-jet)'] = 70.66
AIRCRAFT_LENGTH['Boeing 747-400 (quad-jet)'] = 70.66
AIRCRAFT_LENGTH['Boeing 747-8 (quad-jet)'] = 76.25
AIRCRAFT_LENGTH['Boeing 757-200 (twin-jet)'] = 47.3
AIRCRAFT_LENGTH['Boeing 757-300 (twin-jet)'] = 54.4
AIRCRAFT_LENGTH['Boeing 767-200 (twin-jet)'] = 48.51
AIRCRAFT_LENGTH['Boeing 767-300 (twin-jet)'] = 54.94
AIRCRAFT_LENGTH['Boeing 777 (twin-jet)'] = (63.73 + 73.86) / 2
AIRCRAFT_LENGTH['Boeing 777-200 (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['Boeing 777-200LR/F (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['Boeing 777-300ER (twin-jet)'] = 73.86
AIRCRAFT_LENGTH['Boeing 787-10 (twin-jet)'] = 68.28
AIRCRAFT_LENGTH['Boeing 787-8 (twin-jet)'] = 56.72
AIRCRAFT_LENGTH['Boeing 787-9 (twin-jet)'] = 62.81
AIRCRAFT_LENGTH['Bombardier Challenger 300 (twin-jet)'] = 20.92
AIRCRAFT_LENGTH['Bombardier Global 5000 (twin-jet)'] = 29.5
AIRCRAFT_LENGTH['Bombardier Global Express (twin-jet)'] = (29.5 + 30.3) / 2
AIRCRAFT_LENGTH['Canadair Regional Jet CRJ-200 (twin-jet)'] = 26.77
AIRCRAFT_LENGTH['Canadair Regional Jet CRJ-700 (twin-jet)'] = 32.3
AIRCRAFT_LENGTH['Canadair Regional Jet CRJ-900 (twin-jet)'] = 36.2
AIRCRAFT_LENGTH['Canadair Challenger (twin-jet)'] = 20.9
AIRCRAFT_LENGTH['Canadair Challenger 350 (twin-jet)'] = 20.9
AIRCRAFT_LENGTH['Cessna Caravan (single-turboprop)'] = 11.46
AIRCRAFT_LENGTH['Cessna Citation CJ1 (twin-jet)'] = 12.98
AIRCRAFT_LENGTH['Cessna Citation CJ2+ (twin-jet)'] = 14.53
AIRCRAFT_LENGTH['Cessna Citation CJ3 (twin-jet)'] = 15.59
AIRCRAFT_LENGTH['Cessna Citation Excel/XLS (twin-jet)'] = 16.0
AIRCRAFT_LENGTH['Cessna Citation II (twin-jet)'] = 14.54
AIRCRAFT_LENGTH['Cessna Citation Latitude (twin-jet)'] = 18.97
AIRCRAFT_LENGTH['Cessna Citation Longitude (twin-jet)'] = 22.3
AIRCRAFT_LENGTH['Cessna Citation Sovereign (twin-jet)'] = 19.35
AIRCRAFT_LENGTH['Cessna Citation V (twin-jet)'] = 14.91
AIRCRAFT_LENGTH['Cessna Citation X (twin-jet)'] = 22.04
AIRCRAFT_LENGTH['Cessna Citation Mustang (twin-jet)'] = 12.37
AIRCRAFT_LENGTH['Cessna Conquest 2 (twin-turboprop)'] = 11.89
AIRCRAFT_LENGTH['Cessna Skyhawk (piston-single)'] = 8.28
AIRCRAFT_LENGTH['Cessna Skylane (piston-single)'] = 8.84
AIRCRAFT_LENGTH['Cessna T206 Turbo Stationair (piston-single)'] = 8.61
AIRCRAFT_LENGTH['Cirrus SR-22 (piston-single)'] = 7.92
AIRCRAFT_LENGTH['Dassault Falcon 900 (tri-jet)'] = 20.21
AIRCRAFT_LENGTH['Dassault Falcon 2000 (twin-jet)'] = 20.23
AIRCRAFT_LENGTH['Embraer 170/175 (twin-jet)'] = (29.90 + 31.68) / 2
AIRCRAFT_LENGTH['Embraer Phenom 300 (twin-jet)'] = 15.9
AIRCRAFT_LENGTH['Embraer ERJ-135 (twin-jet)'] = 26.33
AIRCRAFT_LENGTH['Embraer ERJ-145 (twin-jet)'] = 29.87
AIRCRAFT_LENGTH['Embraer Legacy 450 (twin-jet)'] = 19.69
AIRCRAFT_LENGTH['EMBRAER 175 (long wing) (twin-jet)'] = 31.68
AIRCRAFT_LENGTH['Eurocopter EC-635 (twin-turboshaft)'] = 10.21
AIRCRAFT_LENGTH['IAI Gulfstream G280 (twin-jet)'] = 20.3
AIRCRAFT_LENGTH['Gulfstream Aerospace Gulfstream G550 (twin-jet)'] = 29.39
AIRCRAFT_LENGTH['Gulfstream Aerospace Gulfstream IV (twin-jet)'] = 26.92
AIRCRAFT_LENGTH['Learjet 35 (twin-jet)'] = 14.83
AIRCRAFT_LENGTH['Learjet 45 (twin-jet)'] = 17.68
AIRCRAFT_LENGTH['McDonnell Douglas MD-11 (tri-jet)'] = 61.6
AIRCRAFT_LENGTH['Pilatus PC-12 (single-turboprop)'] = 14.4
AIRCRAFT_LENGTH['Rockwell Turbo Commander 690 (twin-turboprop)'] = 11.22


def Log(message, file=None, rolling=None):
  """Write a message to a logfile along with a timestamp.

  Args:
    message: string message to write
    file: string representing file name and, if needed, path to the
      file to write to
    rolling: name of file that will keep only the last n files of file
  """
  # can't define as a default parameter because LOGFILE name is potentially
  # modified based on SIMULATION flag
  if not file:
    file = LOGFILE

  # special case: for the main logfile, we always keep a rolling log
  if not rolling and file == LOGFILE:
    rolling = ROLLING_LOGFILE





                            <----SKIPPED LINES---->




  haversines, relating the sides and angles of spherical triangles.

  Reference: https://en.wikipedia.org/wiki/Haversine_formula

  Args:
    pos1: a 2-tuple defining (lat, lon) in decimal degrees
    pos2: a 2-tuple defining (lat, lon) in decimal degrees

  Returns:
    Distance between two points in meters.
  """
  is_numeric = [isinstance(x, numbers.Number) for x in (*pos1, *pos2)]
  if False in is_numeric:
    return None

  lat1, lon1, lat2, lon2 = [math.radians(x) for x in (*pos1, *pos2)]
  hav = (math.sin((lat2 - lat1) / 2.0)**2
         + math.cos(lat1) * math.cos(lat2) * math.sin((lon2 - lon1) / 2.0)**2)
  distance = 2 * RADIUS * math.asin(math.sqrt(hav))

  # Though pyproj has HaversineDistance, having trouble installing on rpi
  #az12, az21, distance = g.inv(lon1, lat1, lon2, lat2)

  return distance


def SpeedInMeters(speed_in_knots):
  """Converts speed in knots to speed in meters per second."""
  return speed_in_knots * METERS_PER_SECOND_IN_KNOTS


def MetersTraveled(speed_in_knots, seconds):
  """Converts speed in knots to distance in meters given elapsed sec."""
  return SpeedInMeters(speed_in_knots) * seconds


def ClosestKnownLocation(flight, seconds):
  """Returns the most recent location observation from a flight.

  Flights in the flight dictionary have their path maintained over all the time
  that the radio continues to observe the flight. This function identifies the




                            <----SKIPPED LINES---->




  is an easier-to-read and more faithful representation of how the message will
  be displayed. The transformations are to add blank lines to the message to
  make it consistent number of lines, and to add border to the sides & top /
  bottom of the message.

  Args:
    lines: list of strings that comprise the message
    splitflap: boolean, True if directed for splitflap display; false if
    directed to screen

  Returns:
    String - which includes embedded new line characters, borders, etc. as
    described above, that can be printed to screen as the message.
  """
  divider = '+' + '-'*SPLITFLAP_CHARS_PER_LINE + '+'
  border_character = '|'
  append_character = '\n'

  if splitflap:
    border_character = ''
    # vestaboard tries to line wrap so adding a space ensures that it does not
    # interpret a pair of lines that end and begin with characters as one
    # contiguous string
    append_character = ' '

  # Create blank lines up to the required number of lines
  for unused_n in range(SPLITFLAP_LINE_COUNT-len(lines)):
    lines.append('')

  # convert escaped character codes potentially embedded in personal
  # message to something that can be displayed well on screen, albeit
  # the colors for {63}..{69} aren't captured in plain text
  # see https://docs.vestaboard.com/characters
  escaped_characters = (
      ('{62}', u'\u00b0'),
      ('{63}', u'\u2588'),  # red
      ('{64}', u'\u2588'),  # orange
      ('{65}', u'\u2588'),  # yellow
      ('{66}', u'\u2588'),  # green
      ('{67}', u'\u2588'),  # blue
      ('{68}', u'\u2588'),  # violet
      ('{69}', u'\u2588'))  # red

  lines = [
      border_character +
      line.ljust(SPLITFLAP_CHARS_PER_LINE).upper() +




                            <----SKIPPED LINES---->