"""
Utility module for miscellaneous stuff
"""
import fractions
import math
import sys

def isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0):
    """
    Python 3.4 does not have math.isclose, so we need to steal it and add it here.
    """
    try:
        return math.isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol)
    except AttributeError:
        # Running on older version of python, fall back to hand-rolled implementation
        if (rel_tol < 0.0) or (abs_tol < 0.0):
            raise ValueError("Tolerances must be non-negative, but are rel_tol: {} and abs_tol: {}".format(rel_tol, abs_tol))
        if math.isnan(a) or math.isnan(b):
            return False  # NaNs are never close to anything, even other NaNs
        if (a == b):
            return True
        if math.isinf(a) or math.isinf(b):
            return False  # Infinity is only close to itself, and we already handled that case
        diff = abs(a - b)
        return (diff <= rel_tol * abs(b)) or (diff <= rel_tol * abs(a)) or (diff <= abs_tol)

def lcm(a, b):
    """
    Python 3.4 and others differ on how to get at the least common multiple.
    """
    major, minor, _micro, _level, _serial = sys.version_info

    if major > 3 or minor > 4:
        return a * b // math.gcd(a, b)
    else:
        return a * b // fractions.gcd(a, b)