messageboard-2022-09-01-1912.py
01234567890123456789012345678901234567890123456789012345678901234567890123456789
1234567891011121314151617181920 21222324252627282930313233343536373839404142434445464748    4950515253545556575859606162636465666768








63806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402 64036404640564066407640864096410641164126413641464156416641764186419642064216422








6750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792








69046905690669076908690969106911691269136914691569166917691869196920692169226923                    69246925692669276928692969306931693269336934693569366937693869396940694169426943








698969906991699269936994699569966997699869997000700170027003700470057006700770087009 70107011701270137014701570167017701870197020702170227023702470257026702770287029








70737074707570767077707870797080708170827083708470857086708770887089709070917092  709370947095709670977098709971007101710271037104710571067107710871097110711171127113








71157116711771187119712071217122712371247125712671277128712971307131713271337134           71357136713771387139714071417142714371447145714671477148714971507151715271537154








72197220722172227223722472257226722772287229723072317232723372347235723672377238 7239724072417242724372447245724672477248724972507251725272537254725572567257725872597260








#!/usr/bin/python3

import datetime
import gc
import io
import json
import math
import multiprocessing
import numbers
import os
import pickle
import queue
import re
import shutil
import signal
import statistics
import sys
import textwrap
import time
import tracemalloc


import bs4
import dateutils
import numpy
import matplotlib
import matplotlib.pyplot
import psutil
import pycurl
import pytz
import requests
import tzlocal
import unidecode

# pylint: disable=line-too-long
from constants import RASPBERRY_PI, MESSAGEBOARD_PATH, WEBSERVER_PATH, KEY, SECRET, SUBSCRIPTION_ID
# pylint: enable=line-too-long

import arduino

if RASPBERRY_PI:
  import gpiozero  # pylint: disable=E0401
  import RPi.GPIO  # pylint: disable=E0401


VERBOSE = False  # additional messages logged

SHUTDOWN_SIGNAL = ''
REBOOT_SIGNAL = False





SIMULATION = False
SIMULATION_COUNTER = 0
SIMULATION_PREFIX = 'SIM_'
PICKLE_DUMP_JSON_FILE = 'pickle/dump_json.pk'
PICKLE_FA_JSON_FILE = 'pickle/fa_json.pk'
MEMORY_DIRECTORY = 'memory/'
DUMP_JSONS = None  # loaded only if in simulation mode
FA_JSONS = None  # loaded only if in simulation mode

HOME_LAT = 37.64406
HOME_LON = -122.43463
HOME = (HOME_LAT, HOME_LON) # lat / lon tuple of antenna
HOME_ALT = 29  #altitude in meters
RADIUS = 6371.0e3  # radius of earth in meters

FEET_IN_METER = 3.28084
FEET_IN_MILE = 5280
METERS_PER_SECOND_IN_KNOTS = 0.514444





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




  body_as_file_object = io.StringIO(body_as_json_string)

  # prepare and send. See also: pycurl.READFUNCTION to pass function instead
  curl.setopt(pycurl.READDATA, body_as_file_object)
  curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string))
  failure_message = ''
  try:
    curl.perform()
  except pycurl.error as e:
    timing_message = CurlTimingDetailsToString(curl)
    failure_message = (
        'curl.perform() failed with message %s; timing details: %s' %
        (e, timing_message))
    Log(failure_message)
    error_code = True
  else:
    # you may want to check HTTP response code, e.g.
    timing_message = CurlTimingDetailsToString(curl)
    status_code = curl.getinfo(pycurl.RESPONSE_CODE)
    if status_code != 200:
      Log(
          'Server returned HTTP status code %d for message %s; '
          'timing details: %s' % (status_code, s, timing_message))

      error_code = True

  curl.close()
  UpdateStatusLight(
      GPIO_ERROR_VESTABOARD_CONNECTION, error_code, failure_message)


def CurlTimingDetailsToString(curl):
  """Extracts timing details of a curl request into a readable string."""
  timing = {}
  timing['total-time'] = curl.getinfo(pycurl.TOTAL_TIME)
  timing['namelookup-time'] = curl.getinfo(pycurl.NAMELOOKUP_TIME)
  timing['connect-time'] = curl.getinfo(pycurl.CONNECT_TIME)
  timing['pretransfer-time'] = curl.getinfo(pycurl.PRETRANSFER_TIME)
  timing['redirect-time'] = curl.getinfo(pycurl.REDIRECT_TIME)
  timing['starttransfer-time'] = curl.getinfo(pycurl.STARTTRANSFER_TIME)
  results = [label + '=' + '%.4f' % timing[label] for label in timing]
  results = '; '.join(results)
  return results





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




  """Writes to disk a tuple with status details about a particular system.

  The independent monitoring.py module allows us to see in one place the
  status of all the subsystems and of the overall system; it does that
  monitoring based on these tuples of data.

  Args:
    value: Boolean indicating whether a failure has occurred (True) or
      system is nominal (False).
    subsystem: A tuple describing the system; though that description may
      have multiple attributes, the 0th element is the numeric identifier
      of that system.  monitoring.py depends on other attributes of that
      tuple being present as well.  Since the overall system does not have
      a tuple defined for it, it gets a default identifier of 0.
    failure_message: an (optional) message describing why the system /
      subsystem is being disabled or failing.
  """
  versions = (VERSION_MESSAGEBOARD, VERSION_ARDUINO)
  if subsystem:
    subsystem = subsystem[0]
  PickleObjectToFile(
      (time.time(), subsystem, value, versions, failure_message),
      PICKLE_DASHBOARD, True)


def RemoveFile(file):
  """Removes a file, returning a boolean indicating if it had existed."""
  if os.path.exists(file):

    try:
      os.remove(file)
    except PermissionError:
      return False
    return True

  return False


def ConfirmNewFlight(flight, flights):
  """Replaces last-seen flight with new flight if identifiers overlap.

  Flights are identified by the radio over time by a tuple of identifiers:
  flight_number and squawk.  Due to unknown communication issues, one or the




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




  VERSION_MESSAGEBOARD = MakeVersionCopy('messageboard')
  VERSION_ARDUINO = MakeVersionCopy('arduino')


def MakeVersionCopy(python_prefix):
  """Copies current instance of python file into repository."""
  file_extension = '.py'

  live_name = python_prefix + '.py'
  live_path = os.path.join(CODE_REPOSITORY, live_name)

  epoch = os.path.getmtime(live_path)
  last_modified_suffix = EpochDisplayTime(
      epoch, format_string='-%Y-%m-%d-%H%M')
  version_name = python_prefix + last_modified_suffix + file_extension
  version_path = os.path.join(VERSION_REPOSITORY, version_name)

  if not os.path.exists(version_path):
    shutil.copyfile(live_path, version_path)
  return version_name






















def DumpMemorySnapsnot(
    configuration, iteration, main_start_time, initial_frame_count):
  """Dump the memory snapshot to disk for later analysis.

  This dumps the memory snapshot to disk with a file name defined by the
  timestamp and iteration, in the directory MEMORY_DIRECTORY, for later
  analysis by tracemalloc load class; this can be used to do a memory
  leak detection by looking at a single snapshot, or potentially by doing
  a compare_to to look at the deltas from an earlier snapshot.

  If the 'memory' configuration is greater than 0, then snapshotting is
  enabled and we dump the configuration every time iteration is evenly
  divisible by 1000 times the 'memory' setting (because the setting
  as described on the settings.php page is in thousands of iterations).

  Args:
    configuration: dictionary of configuration attributes.
    iteration: counter that indicates how many times through the main




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




  # Redirect any errors to a log file instead of the screen, and add a datestamp
  if not SIMULATION:
    sys.stderr = open(STDERR_FILE, 'a')
    Log('', STDERR_FILE)

  init_timing.append((time.time(), 1))
  Log('Starting up process %d' % os.getpid())
  already_running_ids = FindRunningParents()
  if already_running_ids:
    for pid in already_running_ids:
      Log('Sending termination signal to %d' % pid)
      os.kill(pid, signal.SIGTERM)
  init_timing.append((time.time(), 2))

  SetPinMode()

  configuration = ReadAndParseSettings(CONFIG_FILE)
  Log('Read CONFIG_FILE at %s: %s' % (CONFIG_FILE, str(configuration)))

  initial_frame_count = configuration.get('memory_frames', 1)
  if configuration.get('memory', 0):

    tracemalloc.start(initial_frame_count)

  startup_time = time.time()
  json_desc_dict = {}

  init_timing.append((time.time(), 3))
  flights = UnpickleObjectFromFile(
      PICKLE_FLIGHTS, True, max_days=MAX_INSIGHT_HORIZON_DAYS, heartbeat=True)
  # Clear the loaded flight of any cached data, identified by keys
  # with a specific suffix, since code fixes may change the values for
  # some of those cached elements
  init_timing.append((time.time(), 4))
  for flight in flights:
    for key in list(flight.keys()):
      if key.endswith(CACHED_ELEMENT_PREFIX):
        flight.pop(key)
  init_timing.append((time.time(), 5))

  screen_history = UnpickleObjectFromFile(PICKLE_SCREENS, True, max_days=2)





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




  # time is long, we don't wait another x seconds after processing completes
  next_loop_time = time.time() + LOOP_DELAY_SECONDS

  # These files are read only if the version on disk has been modified more
  # recently than the last time it was read
  last_dump_json_timestamp = 0

  init_timing.append((time.time(), 7))
  WaitUntilKillComplete(already_running_ids)
  init_timing.append((time.time(), 8))

  personal_message = None  # Unknown what personal message is displayed

  temp_last_logged = 0  # Keeps track of when temperature was last logged

  LogTimes(init_timing)
  reboot = False

  iteration = 0  # counter that tracks how many times thru while loop
  start_time = time.time()


  DumpMemorySnapsnot(configuration, iteration, start_time, initial_frame_count)

  Log('Finishing initialization of %d; starting radio polling loop' %
      os.getpid())
  while ((not SIMULATION or SIMULATION_COUNTER < len(DUMP_JSONS))
         and not SHUTDOWN_SIGNAL):

    last_heartbeat_time = Heartbeat(last_heartbeat_time)

    new_configuration = ReadAndParseSettings(CONFIG_FILE)
    UpdateRollingLogSize(new_configuration)
    CheckForNewFilterCriteria(
        configuration, new_configuration, message_queue, flights)
    configuration = new_configuration

    ResetLogs(configuration)  # clear the logs if requested
    UpdateRollingLogSize(configuration)

    # if this is a SIMULATION, then process every diff dump. But if it
    # isn't a simulation, then only read & do related processing for the
    # next dump if the last-modified timestamp indicates the file has been




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




    tmp_timestamp = 0
    if not SIMULATION:
      dump_json_exists = os.path.exists(DUMP_JSON_FILE)
      if dump_json_exists:
        tmp_timestamp = os.path.getmtime(DUMP_JSON_FILE)
    if (SIMULATION and DumpJsonChanges()) or (
        not SIMULATION and dump_json_exists and
        tmp_timestamp > last_dump_json_timestamp):

      last_dump_json_timestamp = tmp_timestamp

      (persistent_nearby_aircraft,
       flight, now,
       json_desc_dict,
       persistent_path) = ScanForNewFlights(
           persistent_nearby_aircraft,
           persistent_path,
           configuration.get('log_jsons', False),
           flights)












      # because this might just be an updated instance of the previous
      # flight as more identifier information (squawk and or flight number)
      # comes in, we only want to process this if its a truly new flight
      new_flight_flag = ConfirmNewFlight(flight, flights)

      if new_flight_flag:
        flights.append(flight)
        remote, servo = RefreshArduinos(
            remote, servo,
            to_remote_q, to_servo_q, to_main_q, shutdown,
            flights, json_desc_dict, configuration, screen_history)

        if FlightMeetsDisplayCriteria(flight, configuration, log=True):
          personal_message = None  # Any personal message displayed now cleared
          flight_message = (
              FLAG_MSG_FLIGHT, CreateMessageAboutFlight(flight), flight)

          # display the next message about this flight now!
          next_message_time = time.time()
          message_queue.insert(0, flight_message)




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




    # check time & if appropriate, display next message from queue
    next_message_time = ManageMessageQueue(
        message_queue, next_message_time, configuration, screen_history)

    reboot = CheckRebootNeeded(
        startup_time, message_queue, json_desc_dict, configuration)

    temp_last_logged = CheckTemperature(configuration, temp_last_logged)

    if not SIMULATION:
      time.sleep(max(0, next_loop_time - time.time()))
      next_loop_time = time.time() + LOOP_DELAY_SECONDS
    else:
      SIMULATION_COUNTER += 1
      if simulation_slowdown:
        SimulationSlowdownNearFlight(flights, persistent_nearby_aircraft)

    # now that we've completed the loop, lets potentially dump the
    # memory snapshot
    iteration += 1  # this completes the iteration-th time thru the loop

    DumpMemorySnapsnot(
        configuration, iteration, start_time, initial_frame_count)

  if SIMULATION:
    SimulationEnd(message_queue, flights, screen_history)
  PerformGracefulShutdown(shutdown, reboot)


if __name__ == "__main__":
  #interrupt, as in ctrl-c
  signal.signal(signal.SIGINT, InterruptShutdownFromSignal)

  #terminate, when another instance found or via kill
  signal.signal(signal.SIGTERM, InterruptShutdownFromSignal)

  if '-i' in sys.argv:
    BootstrapInsightList()
  else:
    main_settings = ReadAndParseSettings(CONFIG_FILE)
    if 'code_profiling_enabled' in main_settings:
      import cProfile
      cProfile.run(




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





01234567890123456789012345678901234567890123456789012345678901234567890123456789
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273








63856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428








6756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798








691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969








701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056








7100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142








714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194








7259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301








#!/usr/bin/python3

import datetime
import gc
import io
import json
import math
import multiprocessing
import numbers
import os
import pickle
import queue
import re
import shutil
import signal
import statistics
import sys
import textwrap
import time
import tracemalloc
import types

import bs4
import dateutils
import numpy
import matplotlib
import matplotlib.pyplot
import psutil
import pycurl
import pytz
import requests
import tzlocal
import unidecode

# pylint: disable=line-too-long
from constants import RASPBERRY_PI, MESSAGEBOARD_PATH, WEBSERVER_PATH, KEY, SECRET, SUBSCRIPTION_ID
# pylint: enable=line-too-long

import arduino

if RASPBERRY_PI:
  import gpiozero  # pylint: disable=E0401
  import RPi.GPIO  # pylint: disable=E0401


VERBOSE = False  # additional messages logged

SHUTDOWN_SIGNAL = ''
REBOOT_SIGNAL = False

# to be tracked in the dashboard messages so that we know when a
# restart due to exit (vs. a long delay in some processing) happened
INSTANCE_START_TIME = time.time()

SIMULATION = False
SIMULATION_COUNTER = 0
SIMULATION_PREFIX = 'SIM_'
PICKLE_DUMP_JSON_FILE = 'pickle/dump_json.pk'
PICKLE_FA_JSON_FILE = 'pickle/fa_json.pk'
MEMORY_DIRECTORY = 'memory/'
DUMP_JSONS = None  # loaded only if in simulation mode
FA_JSONS = None  # loaded only if in simulation mode

HOME_LAT = 37.64406
HOME_LON = -122.43463
HOME = (HOME_LAT, HOME_LON) # lat / lon tuple of antenna
HOME_ALT = 29  #altitude in meters
RADIUS = 6371.0e3  # radius of earth in meters

FEET_IN_METER = 3.28084
FEET_IN_MILE = 5280
METERS_PER_SECOND_IN_KNOTS = 0.514444





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




  body_as_file_object = io.StringIO(body_as_json_string)

  # prepare and send. See also: pycurl.READFUNCTION to pass function instead
  curl.setopt(pycurl.READDATA, body_as_file_object)
  curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string))
  failure_message = ''
  try:
    curl.perform()
  except pycurl.error as e:
    timing_message = CurlTimingDetailsToString(curl)
    failure_message = (
        'curl.perform() failed with message %s; timing details: %s' %
        (e, timing_message))
    Log(failure_message)
    error_code = True
  else:
    # you may want to check HTTP response code, e.g.
    timing_message = CurlTimingDetailsToString(curl)
    status_code = curl.getinfo(pycurl.RESPONSE_CODE)
    if status_code != 200:
      failure_message = (
          'Server returned HTTP status code %d for message %s; '
          'timing details: %s' % (status_code, s, timing_message))
      Log(failure_message)
      error_code = True

  curl.close()
  UpdateStatusLight(
      GPIO_ERROR_VESTABOARD_CONNECTION, error_code, failure_message)


def CurlTimingDetailsToString(curl):
  """Extracts timing details of a curl request into a readable string."""
  timing = {}
  timing['total-time'] = curl.getinfo(pycurl.TOTAL_TIME)
  timing['namelookup-time'] = curl.getinfo(pycurl.NAMELOOKUP_TIME)
  timing['connect-time'] = curl.getinfo(pycurl.CONNECT_TIME)
  timing['pretransfer-time'] = curl.getinfo(pycurl.PRETRANSFER_TIME)
  timing['redirect-time'] = curl.getinfo(pycurl.REDIRECT_TIME)
  timing['starttransfer-time'] = curl.getinfo(pycurl.STARTTRANSFER_TIME)
  results = [label + '=' + '%.4f' % timing[label] for label in timing]
  results = '; '.join(results)
  return results





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




  """Writes to disk a tuple with status details about a particular system.

  The independent monitoring.py module allows us to see in one place the
  status of all the subsystems and of the overall system; it does that
  monitoring based on these tuples of data.

  Args:
    value: Boolean indicating whether a failure has occurred (True) or
      system is nominal (False).
    subsystem: A tuple describing the system; though that description may
      have multiple attributes, the 0th element is the numeric identifier
      of that system.  monitoring.py depends on other attributes of that
      tuple being present as well.  Since the overall system does not have
      a tuple defined for it, it gets a default identifier of 0.
    failure_message: an (optional) message describing why the system /
      subsystem is being disabled or failing.
  """
  versions = (VERSION_MESSAGEBOARD, VERSION_ARDUINO)
  if subsystem:
    subsystem = subsystem[0]
  PickleObjectToFile((
      time.time(), subsystem, value, versions,
      failure_message, INSTANCE_START_TIME), PICKLE_DASHBOARD, True)


def RemoveFile(file):
  """Removes a file, returning a boolean indicating if it had existed."""
  if os.path.exists(file):

    try:
      os.remove(file)
    except PermissionError:
      return False
    return True

  return False


def ConfirmNewFlight(flight, flights):
  """Replaces last-seen flight with new flight if identifiers overlap.

  Flights are identified by the radio over time by a tuple of identifiers:
  flight_number and squawk.  Due to unknown communication issues, one or the




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




  VERSION_MESSAGEBOARD = MakeVersionCopy('messageboard')
  VERSION_ARDUINO = MakeVersionCopy('arduino')


def MakeVersionCopy(python_prefix):
  """Copies current instance of python file into repository."""
  file_extension = '.py'

  live_name = python_prefix + '.py'
  live_path = os.path.join(CODE_REPOSITORY, live_name)

  epoch = os.path.getmtime(live_path)
  last_modified_suffix = EpochDisplayTime(
      epoch, format_string='-%Y-%m-%d-%H%M')
  version_name = python_prefix + last_modified_suffix + file_extension
  version_path = os.path.join(VERSION_REPOSITORY, version_name)

  if not os.path.exists(version_path):
    shutil.copyfile(live_path, version_path)
  return version_name


BLACKLIST = type, types.ModuleType, types.FunctionType
def GetSize(obj):
  """Returns number of bytes an object uses."""
  if isinstance(obj, BLACKLIST):
    raise TypeError(
        'getsize() does not take argument of type: '+ str(type(obj)))
  seen_ids = set()
  size = 0
  objects = [obj]
  while objects:
    need_referents = []
    for o in objects:
      if not isinstance(o, BLACKLIST) and id(o) not in seen_ids:
        seen_ids.add(id(o))
        size += sys.getsizeof(o)
        need_referents.append(o)
    objects = gc.get_referents(*need_referents)
  return size


def DumpMemorySnapsnot(
    configuration, iteration, main_start_time, initial_frame_count):
  """Dump the memory snapshot to disk for later analysis.

  This dumps the memory snapshot to disk with a file name defined by the
  timestamp and iteration, in the directory MEMORY_DIRECTORY, for later
  analysis by tracemalloc load class; this can be used to do a memory
  leak detection by looking at a single snapshot, or potentially by doing
  a compare_to to look at the deltas from an earlier snapshot.

  If the 'memory' configuration is greater than 0, then snapshotting is
  enabled and we dump the configuration every time iteration is evenly
  divisible by 1000 times the 'memory' setting (because the setting
  as described on the settings.php page is in thousands of iterations).

  Args:
    configuration: dictionary of configuration attributes.
    iteration: counter that indicates how many times through the main




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




  # Redirect any errors to a log file instead of the screen, and add a datestamp
  if not SIMULATION:
    sys.stderr = open(STDERR_FILE, 'a')
    Log('', STDERR_FILE)

  init_timing.append((time.time(), 1))
  Log('Starting up process %d' % os.getpid())
  already_running_ids = FindRunningParents()
  if already_running_ids:
    for pid in already_running_ids:
      Log('Sending termination signal to %d' % pid)
      os.kill(pid, signal.SIGTERM)
  init_timing.append((time.time(), 2))

  SetPinMode()

  configuration = ReadAndParseSettings(CONFIG_FILE)
  Log('Read CONFIG_FILE at %s: %s' % (CONFIG_FILE, str(configuration)))

  initial_frame_count = configuration.get('memory_frames', 1)
  initial_memory_dump = configuration.get('memory', 0)
  if initial_memory_dump:
    tracemalloc.start(initial_frame_count)

  startup_time = time.time()
  json_desc_dict = {}

  init_timing.append((time.time(), 3))
  flights = UnpickleObjectFromFile(
      PICKLE_FLIGHTS, True, max_days=MAX_INSIGHT_HORIZON_DAYS, heartbeat=True)
  # Clear the loaded flight of any cached data, identified by keys
  # with a specific suffix, since code fixes may change the values for
  # some of those cached elements
  init_timing.append((time.time(), 4))
  for flight in flights:
    for key in list(flight.keys()):
      if key.endswith(CACHED_ELEMENT_PREFIX):
        flight.pop(key)
  init_timing.append((time.time(), 5))

  screen_history = UnpickleObjectFromFile(PICKLE_SCREENS, True, max_days=2)





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




  # time is long, we don't wait another x seconds after processing completes
  next_loop_time = time.time() + LOOP_DELAY_SECONDS

  # These files are read only if the version on disk has been modified more
  # recently than the last time it was read
  last_dump_json_timestamp = 0

  init_timing.append((time.time(), 7))
  WaitUntilKillComplete(already_running_ids)
  init_timing.append((time.time(), 8))

  personal_message = None  # Unknown what personal message is displayed

  temp_last_logged = 0  # Keeps track of when temperature was last logged

  LogTimes(init_timing)
  reboot = False

  iteration = 0  # counter that tracks how many times thru while loop
  start_time = time.time()
  if initial_memory_dump:
    DumpMemorySnapsnot(
        configuration, iteration, start_time, initial_frame_count)

  Log('Finishing initialization of %d; starting radio polling loop' %
      os.getpid())
  while ((not SIMULATION or SIMULATION_COUNTER < len(DUMP_JSONS))
         and not SHUTDOWN_SIGNAL):

    last_heartbeat_time = Heartbeat(last_heartbeat_time)

    new_configuration = ReadAndParseSettings(CONFIG_FILE)
    UpdateRollingLogSize(new_configuration)
    CheckForNewFilterCriteria(
        configuration, new_configuration, message_queue, flights)
    configuration = new_configuration

    ResetLogs(configuration)  # clear the logs if requested
    UpdateRollingLogSize(configuration)

    # if this is a SIMULATION, then process every diff dump. But if it
    # isn't a simulation, then only read & do related processing for the
    # next dump if the last-modified timestamp indicates the file has been




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




    tmp_timestamp = 0
    if not SIMULATION:
      dump_json_exists = os.path.exists(DUMP_JSON_FILE)
      if dump_json_exists:
        tmp_timestamp = os.path.getmtime(DUMP_JSON_FILE)
    if (SIMULATION and DumpJsonChanges()) or (
        not SIMULATION and dump_json_exists and
        tmp_timestamp > last_dump_json_timestamp):

      last_dump_json_timestamp = tmp_timestamp

      (persistent_nearby_aircraft,
       flight, now,
       json_desc_dict,
       persistent_path) = ScanForNewFlights(
           persistent_nearby_aircraft,
           persistent_path,
           configuration.get('log_jsons', False),
           flights)

      # DEBUG: As part of the memory instrumentation, let's track
      # the size of these data structures
      iteration_divisor = configuration.get('memory', 0)
      if iteration_divisor and not iteration % iteration_divisor:
        sizes = [
            GetSize(persistent_nearby_aircraft),
            GetSize(flight),
            GetSize(json_desc_dict),
            GetSize(flights)]
        Log('Iteration: %d: object sizes (bytes): %s' % (iteration, sizes))

      # because this might just be an updated instance of the previous
      # flight as more identifier information (squawk and or flight number)
      # comes in, we only want to process this if its a truly new flight
      new_flight_flag = ConfirmNewFlight(flight, flights)

      if new_flight_flag:
        flights.append(flight)
        remote, servo = RefreshArduinos(
            remote, servo,
            to_remote_q, to_servo_q, to_main_q, shutdown,
            flights, json_desc_dict, configuration, screen_history)

        if FlightMeetsDisplayCriteria(flight, configuration, log=True):
          personal_message = None  # Any personal message displayed now cleared
          flight_message = (
              FLAG_MSG_FLIGHT, CreateMessageAboutFlight(flight), flight)

          # display the next message about this flight now!
          next_message_time = time.time()
          message_queue.insert(0, flight_message)




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




    # check time & if appropriate, display next message from queue
    next_message_time = ManageMessageQueue(
        message_queue, next_message_time, configuration, screen_history)

    reboot = CheckRebootNeeded(
        startup_time, message_queue, json_desc_dict, configuration)

    temp_last_logged = CheckTemperature(configuration, temp_last_logged)

    if not SIMULATION:
      time.sleep(max(0, next_loop_time - time.time()))
      next_loop_time = time.time() + LOOP_DELAY_SECONDS
    else:
      SIMULATION_COUNTER += 1
      if simulation_slowdown:
        SimulationSlowdownNearFlight(flights, persistent_nearby_aircraft)

    # now that we've completed the loop, lets potentially dump the
    # memory snapshot
    iteration += 1  # this completes the iteration-th time thru the loop
    if initial_memory_dump:
      DumpMemorySnapsnot(
          configuration, iteration, start_time, initial_frame_count)

  if SIMULATION:
    SimulationEnd(message_queue, flights, screen_history)
  PerformGracefulShutdown(shutdown, reboot)


if __name__ == "__main__":
  #interrupt, as in ctrl-c
  signal.signal(signal.SIGINT, InterruptShutdownFromSignal)

  #terminate, when another instance found or via kill
  signal.signal(signal.SIGTERM, InterruptShutdownFromSignal)

  if '-i' in sys.argv:
    BootstrapInsightList()
  else:
    main_settings = ReadAndParseSettings(CONFIG_FILE)
    if 'code_profiling_enabled' in main_settings:
      import cProfile
      cProfile.run(




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