# Path: mlat/geodesy.py
# WGS84_A = 6378137.0
# WGS84_F = 1.0/298.257223563
# WGS84_B = WGS84_A * (1 - WGS84_F)
# WGS84_ECC_SQ = 1 - WGS84_B * WGS84_B / (WGS84_A * WGS84_A)
# WGS84_ECC = math.sqrt(WGS84_ECC_SQ)
# SPHERICAL_R = 6371e3
#     N = WGS84_A / math.sqrt(1 - WGS84_ECC_SQ * math.sin(lat)**2)
# def llh2ecef(llh):
# def ecef2llh(ecef):
# def greatcircle(p0, p1):
# def ecef_distance(p0, p1):
# 
# Path: mlat/profile.py
# def trackcpu(f, **kwargs):
# def dump_cpu_profiles(tofile=None):
# def trackcpu(f, name=None, **kwargs):
#     def cpu_measurement_wrapper(*args, **kwargs):
# def dump_cpu_profiles(tofile=sys.stderr):
# 
# Path: mlat/server/clocksync.py
# class Clock(object):
# class ClockPairing(object):
#     def __init__(self, epoch, freq, max_freq_error, jitter):
# def make_clock(clock_type):
#     def __init__(self, base, peer):
#     def is_new(self, base_ts):
#     def variance(self):
#     def error(self):
#     def valid(self):
#     def update(self, address, base_ts, peer_ts, base_interval, peer_interval):
#     def _prune_old_data(self, latest_base_ts):
#     def _update_drift(self, address, base_interval, peer_interval):
#     def _update_offset(self, address, base_ts, peer_ts, prediction_error):
#     def predict_peer(self, base_ts):
#     def predict_base(self, peer_ts):
#     def __str__(self):
#     KP = 0.05
#     KI = 0.01
# 
# Path: mlat/server/config.py
# MIN_NUC = 6
# MAX_RANGE = 500e3
# MAX_INTERMESSAGE_RANGE = 10e3
# MAX_ALT = 50000 * constants.FTOM
# MLAT_DELAY = 2.5
# SOLVER_MAXFEV = 50


import asyncio
import functools
import time
import logging
import modes.message
from mlat import geodesy, constants, profile
from mlat.server import clocksync, config
        # schedule periodic cleanup
        asyncio.get_event_loop().call_later(1.0, self._cleanup)

    def _cleanup(self):
        """Called periodically to clean up clock pairings that have expired."""

        asyncio.get_event_loop().call_later(30.0, self._cleanup)

        now = time.monotonic()
        prune = set()
        for k, pairing in self.clock_pairs.items():
            if pairing.expiry <= now:
                prune.add(k)

        for k in prune:
            del self.clock_pairs[k]

    @profile.trackcpu
    def receiver_clock_reset(self, receiver):
        """
        Called by the coordinator when we should drop our clock sync
        state for a given receiver. This happens on input disconnect/
        reconnect.

        (This is actually the same work as receiver_disconnect for the moment)
        """
        for k in list(self.clock_pairs.keys()):
            if k[0] is receiver or k[1] is receiver:
                del self.clock_pairs[k]


# Path: mlat/geodesy.py
# WGS84_A = 6378137.0
# WGS84_F = 1.0/298.257223563
# WGS84_B = WGS84_A * (1 - WGS84_F)
# WGS84_ECC_SQ = 1 - WGS84_B * WGS84_B / (WGS84_A * WGS84_A)
# WGS84_ECC = math.sqrt(WGS84_ECC_SQ)
# SPHERICAL_R = 6371e3
#     N = WGS84_A / math.sqrt(1 - WGS84_ECC_SQ * math.sin(lat)**2)
# def llh2ecef(llh):
# def ecef2llh(ecef):
# def greatcircle(p0, p1):
# def ecef_distance(p0, p1):
# 
# Path: mlat/profile.py
# def trackcpu(f, **kwargs):
# def dump_cpu_profiles(tofile=None):
# def trackcpu(f, name=None, **kwargs):
#     def cpu_measurement_wrapper(*args, **kwargs):
# def dump_cpu_profiles(tofile=sys.stderr):
# 
# Path: mlat/server/clocksync.py
# class Clock(object):
# class ClockPairing(object):
#     def __init__(self, epoch, freq, max_freq_error, jitter):
# def make_clock(clock_type):
#     def __init__(self, base, peer):
#     def is_new(self, base_ts):
#     def variance(self):
#     def error(self):
#     def valid(self):
#     def update(self, address, base_ts, peer_ts, base_interval, peer_interval):
#     def _prune_old_data(self, latest_base_ts):
#     def _update_drift(self, address, base_interval, peer_interval):
#     def _update_offset(self, address, base_ts, peer_ts, prediction_error):
#     def predict_peer(self, base_ts):
#     def predict_base(self, peer_ts):
#     def __str__(self):
#     KP = 0.05
#     KI = 0.01
# 
# Path: mlat/server/config.py
# MIN_NUC = 6
# MAX_RANGE = 500e3
# MAX_INTERMESSAGE_RANGE = 10e3
# MAX_ALT = 50000 * constants.FTOM
# MLAT_DELAY = 2.5
# SOLVER_MAXFEV = 50


# Path: mlat/server/clocktrack.py
import asyncio
import functools
import time
import logging
import modes.message
from mlat import geodesy, constants, profile
from mlat.server import clocksync, config

        # schedule periodic cleanup
        asyncio.get_event_loop().call_later(1.0, self._cleanup)

    def _cleanup(self):
        """Called periodically to clean up clock pairings that have expired."""

        asyncio.get_event_loop().call_later(30.0, self._cleanup)

        now = time.monotonic()
        prune = set()
        for k, pairing in self.clock_pairs.items():
            if pairing.expiry <= now:
                prune.add(k)

        for k in prune:
            del self.clock_pairs[k]

    @profile.trackcpu
    def receiver_clock_reset(self, receiver):
        """
        Called by the coordinator when we should drop our clock sync
        state for a given receiver. This happens on input disconnect/
        reconnect.

        (This is actually the same work as receiver_disconnect for the moment)
        """
        for k in list(self.clock_pairs.keys()):
            if k[0] is receiver or k[1] is receiver:
                del self.clock_pairs[k]


    @profile.trackcpu