messageboard-2021-06-10-1151.py
01234567890123456789012345678901234567890123456789012345678901234567890123456789









373374375376377378379380381382383384385386387388389390391392 393394395396397398399400401402403404405406407408409410411412








24652466246724682469247024712472247324742475247624772478247924802481248224832484                                              24852486248724882489249024912492249324942495249624972498249925002501250225032504








284128422843284428452846284728482849285028512852285328542855285628572858285928602861 28622863286428652866286728682869287028712872287328742875287628772878287928802881








638563866387638863896390639163926393639463956396639763986399640064016402640364046405             640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441











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




AIRCRAFT_LENGTH['Boeing 737 MAX 9 (twin-jet)'] = 42.1
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 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-200ER (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['BOEING 777-200LR (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['Boeing 777-200LR/F (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['Boeing 777-300 (twin-jet)'] = 33.4
AIRCRAFT_LENGTH['BOEING 777-300ER (twin-jet)'] = 73.86
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['BOEING 787-10 Dreamliner (twin-jet)'] = 68.28
AIRCRAFT_LENGTH['BOEING BBJ (747-8) (quad-jet)'] = 76.25
AIRCRAFT_LENGTH['BOEING BBJ (777-200LR) (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['BOEING BBJ (777-300ER) (twin-jet)'] = 73.86
AIRCRAFT_LENGTH['BOEING BBJ3 (twin-jet)'] = 42.11
AIRCRAFT_LENGTH['Boeing Dreamliner (Srs.8) (twin-jet)'] = 56.72
AIRCRAFT_LENGTH['BOEING Dreamliner (Srs.9) (twin-jet)'] = 62.81
AIRCRAFT_LENGTH['Boeing MD-11 (tri-jet)'] = (61.2 + 61.6) / 2
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['Bombardier Learjet 75 (twin-jet)'] = 17.7
AIRCRAFT_LENGTH['Canadair Challenger (twin-jet)'] = 20.9
AIRCRAFT_LENGTH['Canadair Challenger 350 (twin-jet)'] = 20.9
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['Cessna Caravan (single-turboprop)'] = 11.46
AIRCRAFT_LENGTH['Cessna Citation CJ1 (twin-jet)'] = 12.98
AIRCRAFT_LENGTH['Cessna Citation CJ2+ (twin-jet)'] = 14.53




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




                DisplayFlightNumber(flight), minute_of_day,
                configuration['setting_on_time']))
    elif minute_of_day > configuration['setting_off_time'] + 1:
      flight_meets_criteria = False
      if log:
        Log(
            '%s not displayed because it occurs too late - minute_of_day: '
            '%d; setting_off_time: %d' % (
                DisplayFlightNumber(flight), minute_of_day,
                configuration['setting_off_time']))
    elif configuration.get('setting_screen_enabled', 'off') == 'off':
      flight_meets_criteria = False
      if log:
        Log(
            '%s not displayed because screen disabled' %
            DisplayFlightNumber(flight))

  return flight_meets_criteria
















































def IdentifyFlightDisplayed(flights, configuration, display_all_hours=False):
  """Finds the most recent flight in flights that meet the display criteria.

  Args:
    flights: list of flight dictionaries.
    configuration: dictionary of settings.
    display_all_hours: boolean indicating whether we should ignore the time
    constraints (i.e.: whether the screen is enabled, and its turn-on or
    turn-off times) in identifying the most recent flight. That is, if False,
    then this will only return flights that would have been displayed in the
    ordinarily usage, vs. if True, a flight irrespective of the time it would
    be displayed.

  Returns:
    A flight dictionary if one can be found; None otherwise.
  """
  for n in range(len(flights)-1, -1, -1):  # traverse the flights in reverse
    if FlightMeetsDisplayCriteria(
        flights[n], configuration, display_all_hours=display_all_hours):
      return n




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




              1 + percent_size_difference)):
      last_aircraft_bigger = True
      comparative_text = 'smaller'

    last_flight_time_string = DisplayTime(last_flight, '%b %-d')
    if this_aircraft and last_aircraft:
      if this_aircraft_bigger or last_aircraft_bigger:
        message = ('%s used a %s plane today compared with last, on %s '
                   '(%s @ %dft vs. %s @ %dft)' % (
                       this_flight_number, comparative_text,
                       last_flight_time_string,
                       RemoveParentheticals(this_aircraft),
                       this_aircraft_length*FEET_IN_METER,
                       RemoveParentheticals(last_aircraft),
                       last_aircraft_length*FEET_IN_METER))
      elif last_aircraft and this_aircraft and last_aircraft != this_aircraft:
        message = (
            '%s used a different aircraft today compared'
            ' with last, on %s (%s vs. %s)' % (
                this_flight_number, last_flight_time_string,
                this_aircraft, last_aircraft))


  return message


def FlightInsightNthFlight(flights, hours=1, min_multiple_flights=2):
  """Generates string about seeing frequent flights to the same dest.

  Generates text of the following form for the "focus" flight in the data.
  - ASA1337 was the 4th flight to PHX in the last 53 minutes, served by Alaska
    Airlines, American Airlines, Southwest and United
  - SWA3102 was the 2nd flight to SAN in the last 25 minutes, both with
    Southwest

  Args:
    flights: the list of the raw data from which the insights will be generated,
      where the flights are listed in order of observation - i.e.: flights[0]
      was the earliest seen, and flights[-1] is the most recent flight for
      which we are attempting to generate an insight.
    hours: the time horizon over which to look for flights with the same
      destination.




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




    message_queue: FIFO list of message tuples of (message type,
      message string).
    next_message_time: epoch at which next message should be displayed
    configuration: dictionary of configuration attributes.
    screens: List of past screens displayed to splitflap screen.

  Returns:
    Next_message_time, potentially updated if a message has been displayed,
    or unchanged if no message was displayed.
  """
  if message_queue and (time.time() >= next_message_time or SIMULATION):

    if SIMULATION:  # drain the queue because the messages come so fast
      messages_to_display = list(message_queue)
      # passed by reference, so clear it out since we drained it to the display
      del message_queue[:]
    else:  # display only one message, being mindful of the display timing
      messages_to_display = [message_queue.pop(0)]

    for message in messages_to_display:
      message_text = message[1]













      if isinstance(message_text, str):
        message_text = textwrap.wrap(
            message_text,
            width=SPLITFLAP_CHARS_PER_LINE)
      display_message = Screenify(message_text, False)
      Log(display_message, file=ALL_MESSAGE_FILE)

      # Saving this to disk allows us to identify
      # persistently whats currently on the screen
      PickleObjectToFile(message, PICKLE_SCREENS, True)
      screens.append(message)

      MaintainRollingWebLog(display_message, 25)
      if not SIMULATION:
        splitflap_message = Screenify(message_text, True)
        PublishMessage(splitflap_message)

    next_message_time = time.time() + configuration['setting_delay']
  return next_message_time


def DeleteMessageTypes(q, types_to_delete):
  """Delete messages from the queue if type is in the iterable types."""
  if VERBOSE:
    messages_to_delete = [m for m in q if m[0] in types_to_delete]
    if messages_to_delete:
      Log('Deleting messages from queue due to new-found plane: %s'
          % messages_to_delete)
  updated_q = [m for m in q if m[0] not in types_to_delete]
  return updated_q


def BootstrapInsightList(full_path=PICKLE_FLIGHTS):
  """(Re)populate flight pickle files with flight insight distributions.

  The set of insights generated for each flight is created at the time




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





01234567890123456789012345678901234567890123456789012345678901234567890123456789









373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413








24662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551








288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929








6433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502











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




AIRCRAFT_LENGTH['Boeing 737 MAX 9 (twin-jet)'] = 42.1
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 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-200ER (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['BOEING 777-200LR (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['Boeing 777-200LR/F (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['Boeing 777-300 (twin-jet)'] = 33.4
AIRCRAFT_LENGTH['BOEING 777-300ER (twin-jet)'] = 73.86
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['Boeing 787-9 Dreamliner (twin-jet)'] = 62.81
AIRCRAFT_LENGTH['BOEING 787-10 Dreamliner (twin-jet)'] = 68.28
AIRCRAFT_LENGTH['BOEING BBJ (747-8) (quad-jet)'] = 76.25
AIRCRAFT_LENGTH['BOEING BBJ (777-200LR) (twin-jet)'] = 63.73
AIRCRAFT_LENGTH['BOEING BBJ (777-300ER) (twin-jet)'] = 73.86
AIRCRAFT_LENGTH['BOEING BBJ3 (twin-jet)'] = 42.11
AIRCRAFT_LENGTH['Boeing Dreamliner (Srs.8) (twin-jet)'] = 56.72
AIRCRAFT_LENGTH['BOEING Dreamliner (Srs.9) (twin-jet)'] = 62.81
AIRCRAFT_LENGTH['Boeing MD-11 (tri-jet)'] = (61.2 + 61.6) / 2
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['Bombardier Learjet 75 (twin-jet)'] = 17.7
AIRCRAFT_LENGTH['Canadair Challenger (twin-jet)'] = 20.9
AIRCRAFT_LENGTH['Canadair Challenger 350 (twin-jet)'] = 20.9
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['Cessna Caravan (single-turboprop)'] = 11.46
AIRCRAFT_LENGTH['Cessna Citation CJ1 (twin-jet)'] = 12.98
AIRCRAFT_LENGTH['Cessna Citation CJ2+ (twin-jet)'] = 14.53




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




                DisplayFlightNumber(flight), minute_of_day,
                configuration['setting_on_time']))
    elif minute_of_day > configuration['setting_off_time'] + 1:
      flight_meets_criteria = False
      if log:
        Log(
            '%s not displayed because it occurs too late - minute_of_day: '
            '%d; setting_off_time: %d' % (
                DisplayFlightNumber(flight), minute_of_day,
                configuration['setting_off_time']))
    elif configuration.get('setting_screen_enabled', 'off') == 'off':
      flight_meets_criteria = False
      if log:
        Log(
            '%s not displayed because screen disabled' %
            DisplayFlightNumber(flight))

  return flight_meets_criteria


def MessageMeetsDisplayCriteria(configuration, log=False):
  """Returns boolean indicating whether is active.

  Based on the configuration file, determines whether the flight data should be
  displayed. Specifically, the configuration:
  - may include 'enabled' indicating whether screen should be driven at all
  - should include 'on' & 'off' parameters indicating minute (from midnight) of
    operation
  Note that this differs from FlightMeetsDisplayCriteria in that this function
  does not use any attribute about the flight (elevation or distance), only
  whether the screen is still active.

  Args:
    configuration: dictionary of configuration attributes.
    log: optional boolean indicating whether a flight that fails the criteria
      should be logged with the reason

  Returns:
    Boolean as described.
  """
  message_meets_criteria = True

  now = time.time()
  minute_of_day = MinuteOfDay(now)
  if minute_of_day < configuration['setting_on_time']:
    message_meets_criteria = False
    if log:
      Log(
          'Message purged because it occurs too early - minute_of_day: '
          '%d; setting_on_time: %d' % (
              minute_of_day, configuration['setting_on_time']))
  elif minute_of_day > configuration['setting_off_time'] + 1:
    message_meets_criteria = False
    if log:
      Log(
          'Message purged because it occurs too late - minute_of_day: '
          '%d; setting_off_time: %d' % (
              minute_of_day, configuration['setting_off_time']))
  elif configuration.get('setting_screen_enabled', 'off') == 'off':
    message_meets_criteria = False
    if log:
      Log('Message purged because screen disabled')

  return message_meets_criteria


def IdentifyFlightDisplayed(flights, configuration, display_all_hours=False):
  """Finds the most recent flight in flights that meet the display criteria.

  Args:
    flights: list of flight dictionaries.
    configuration: dictionary of settings.
    display_all_hours: boolean indicating whether we should ignore the time
    constraints (i.e.: whether the screen is enabled, and its turn-on or
    turn-off times) in identifying the most recent flight. That is, if False,
    then this will only return flights that would have been displayed in the
    ordinarily usage, vs. if True, a flight irrespective of the time it would
    be displayed.

  Returns:
    A flight dictionary if one can be found; None otherwise.
  """
  for n in range(len(flights)-1, -1, -1):  # traverse the flights in reverse
    if FlightMeetsDisplayCriteria(
        flights[n], configuration, display_all_hours=display_all_hours):
      return n




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




              1 + percent_size_difference)):
      last_aircraft_bigger = True
      comparative_text = 'smaller'

    last_flight_time_string = DisplayTime(last_flight, '%b %-d')
    if this_aircraft and last_aircraft:
      if this_aircraft_bigger or last_aircraft_bigger:
        message = ('%s used a %s plane today compared with last, on %s '
                   '(%s @ %dft vs. %s @ %dft)' % (
                       this_flight_number, comparative_text,
                       last_flight_time_string,
                       RemoveParentheticals(this_aircraft),
                       this_aircraft_length*FEET_IN_METER,
                       RemoveParentheticals(last_aircraft),
                       last_aircraft_length*FEET_IN_METER))
      elif last_aircraft and this_aircraft and last_aircraft != this_aircraft:
        message = (
            '%s used a different aircraft today compared'
            ' with last, on %s (%s vs. %s)' % (
                this_flight_number, last_flight_time_string,
                RemoveParentheticals(this_aircraft),
                RemoveParentheticals(last_aircraft)))

  return message


def FlightInsightNthFlight(flights, hours=1, min_multiple_flights=2):
  """Generates string about seeing frequent flights to the same dest.

  Generates text of the following form for the "focus" flight in the data.
  - ASA1337 was the 4th flight to PHX in the last 53 minutes, served by Alaska
    Airlines, American Airlines, Southwest and United
  - SWA3102 was the 2nd flight to SAN in the last 25 minutes, both with
    Southwest

  Args:
    flights: the list of the raw data from which the insights will be generated,
      where the flights are listed in order of observation - i.e.: flights[0]
      was the earliest seen, and flights[-1] is the most recent flight for
      which we are attempting to generate an insight.
    hours: the time horizon over which to look for flights with the same
      destination.




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




    message_queue: FIFO list of message tuples of (message type,
      message string).
    next_message_time: epoch at which next message should be displayed
    configuration: dictionary of configuration attributes.
    screens: List of past screens displayed to splitflap screen.

  Returns:
    Next_message_time, potentially updated if a message has been displayed,
    or unchanged if no message was displayed.
  """
  if message_queue and (time.time() >= next_message_time or SIMULATION):

    if SIMULATION:  # drain the queue because the messages come so fast
      messages_to_display = list(message_queue)
      # passed by reference, so clear it out since we drained it to the display
      del message_queue[:]
    else:  # display only one message, being mindful of the display timing
      messages_to_display = [message_queue.pop(0)]

    for message in messages_to_display:
      message_type, message_text = message

      # There may be one or several insight messages that were added to the
      # message queue along with the flight at a time when the screen was
      # enabled, but by the time it comes to display them, the screen is now
      # disabled.  These should not be displayed.  Note that this check only
      # needs to be done for insight messages because other message types
      # are user initiated and so presumably should be displayed irrespective
      # of when the user triggered it to be displayed.
      if message_type == FLAG_MSG_INSIGHT and not MessageMeetsDisplayCriteria(
          configuration):
        Log('Message %s purged')

      else:
        if isinstance(message_text, str):
          message_text = textwrap.wrap(
              message_text,
              width=SPLITFLAP_CHARS_PER_LINE)
        display_message = Screenify(message_text, False)
        Log(display_message, file=ALL_MESSAGE_FILE)

        # Saving this to disk allows us to identify
        # persistently whats currently on the screen
        PickleObjectToFile(message, PICKLE_SCREENS, True)
        screens.append(message)

        MaintainRollingWebLog(display_message, 25)
        if not SIMULATION:
          splitflap_message = Screenify(message_text, True)
          PublishMessage(splitflap_message)

    next_message_time = time.time() + configuration['setting_delay']
  return next_message_time


def DeleteMessageTypes(q, types_to_delete):
  """Delete messages from the queue if type is in the iterable types."""
  if VERBOSE:
    messages_to_delete = [m for m in q if m[0] in types_to_delete]
    if messages_to_delete:
      Log('Deleting messages from queue due to new-found plane: %s'
          % messages_to_delete)
  updated_q = [m for m in q if m[0] not in types_to_delete]
  return updated_q


def BootstrapInsightList(full_path=PICKLE_FLIGHTS):
  """(Re)populate flight pickle files with flight insight distributions.

  The set of insights generated for each flight is created at the time




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