# Path: cubical/tools/logger.py
# def logToFile(filename, append=False):
# def getLogFilename():
#     def __init__(self, logger, level, color=None, bold=None):
#     def write(self, message, level_override=None, print_once=None):
#     def print(self, *args):
#     def __init__(self, logger, verbose=None, log_verbose=None):
#     def verbosity(self, set_verb=None):
#     def log_verbosity(self, set_verb=None):
#     def __call__(self, level, color=None):
#     def warn(self, msg, color=None, print_once=None):
#     def error(self, msg, color="red", print_once=None):
#     def info(self, msg, color=None, print_once=None):
#     def critical(self, msg, color=None, print_once=None):
#     def debug(self, msg, color=None, print_once=None):
#     def exception(self, msg, color=None, print_once=None):
#     def print(self, *args):
#     def write(self, message, level=logging.INFO, verbosity=0, print_once=None, color=None):
# def enableMemoryLogging(level=1):
# def set_subprocess_label(label):
# def get_subprocess_label():
# def _sigusr1_handler(signum, frame):
# def _sigusr2_handler(signum, frame):
#     def setMemoryLogging(level):
#     def filter(self, event):
#     def __init__(self, fmt, datefmt, strip=True):
#     def label(self, record):
#     def format(self, record):
# def init(app_name):
# def getLogger(name, verbose=None, log_verbose=None):
# def setBoring(boring=True):
# def setGlobalVerbosity(verbosity):
# def setGlobalLogVerbosity(verbosity):
# def setSilent(Lname):
# def setLoud(Lname):
# class _DefaultWriter(object):
# class LoggerWrapper(object):
# class LogFilter(logging.Filter):
# class ColorStrippingFormatter(logging.Formatter):
# GB = float(1024 ** 3)
#                 KEYS = _log_memory_types[memlevel]
# 
# Path: cubical/tools/ModColor.py
# HEADER = '\033[95m'
# OKBLUE = '\033[94m'
# OKGREEN = '\033[92m'
# WARNING = '\033[93m'
# FAIL = '\033[91m'
# ENDC = '\033[0m'
#     HEADER = ''
#     OKBLUE = ''
#     OKGREEN = ''
#     WARNING = ''
#     FAIL = ''
#     ENDC = ''
# def disableColors():
# def Str(strin0,col="red",Bold=True):
# def Sep(strin=None,D=1):
# def Title(strin,Big=False):
# def disable():


from builtins import range
from cubical.tools import logger, ModColor
import pyrap.quanta as pq
import pyrap.measures
import copy
import numpy as np
import datetime as dt
            if log.verbosity() > 1:
                log(2).print("   PA of first antenna (deg): {}".format(unique_pa[:,0]*180/np.pi))

            for t, pa in zip(unique_times, unique_pa):
                angles[utc_timestamp == t, :, :] += pa[:, np.newaxis]

        return angles


    def __apply_rotation(self, utc_timestamp, vis, a1, a2, angles=None, clockwise=False, row_subset=None, freq_slice=None):
        """
        Pads data and performs anticlockwise rotation by default
        """
        if angles is None:
            angles = self.rotation_angles(utc_timestamp)
        print("Rotation angles (deg): {}".format(angles*180/np.pi), file=log(2))

        ## OMS: Ben had it in the opposite direction originally, but I'm sure this is right, and matches VLA results
        pa = -angles if clockwise else angles
        
        def mat_factory(pa, nchan, aindex, conjugate_transpose=False):
            def give_linear_mat(pa, nchan, aindex, conjugate_transpose=False):
                """ 2D rotation matrix according to Hales, 2017: 
                Calibration Errors in Interferometric Radio Polarimetry """
                c1, s1 = np.cos(pa[:, aindex, 0]).repeat(nchan), np.sin(pa[:, aindex, 0]).repeat(nchan)
                c2, s2 = np.cos(pa[:, aindex, 1]).repeat(nchan), np.sin(pa[:, aindex, 1]).repeat(nchan)
                N = pa.shape[0]
                if N == 0: 
                    return np.zeros((0, nchan, 2, 2)) # special case: no data for this baseline
                if conjugate_transpose:

# Path: cubical/tools/logger.py
# def logToFile(filename, append=False):
# def getLogFilename():
#     def __init__(self, logger, level, color=None, bold=None):
#     def write(self, message, level_override=None, print_once=None):
#     def print(self, *args):
#     def __init__(self, logger, verbose=None, log_verbose=None):
#     def verbosity(self, set_verb=None):
#     def log_verbosity(self, set_verb=None):
#     def __call__(self, level, color=None):
#     def warn(self, msg, color=None, print_once=None):
#     def error(self, msg, color="red", print_once=None):
#     def info(self, msg, color=None, print_once=None):
#     def critical(self, msg, color=None, print_once=None):
#     def debug(self, msg, color=None, print_once=None):
#     def exception(self, msg, color=None, print_once=None):
#     def print(self, *args):
#     def write(self, message, level=logging.INFO, verbosity=0, print_once=None, color=None):
# def enableMemoryLogging(level=1):
# def set_subprocess_label(label):
# def get_subprocess_label():
# def _sigusr1_handler(signum, frame):
# def _sigusr2_handler(signum, frame):
#     def setMemoryLogging(level):
#     def filter(self, event):
#     def __init__(self, fmt, datefmt, strip=True):
#     def label(self, record):
#     def format(self, record):
# def init(app_name):
# def getLogger(name, verbose=None, log_verbose=None):
# def setBoring(boring=True):
# def setGlobalVerbosity(verbosity):
# def setGlobalLogVerbosity(verbosity):
# def setSilent(Lname):
# def setLoud(Lname):
# class _DefaultWriter(object):
# class LoggerWrapper(object):
# class LogFilter(logging.Filter):
# class ColorStrippingFormatter(logging.Formatter):
# GB = float(1024 ** 3)
#                 KEYS = _log_memory_types[memlevel]
# 
# Path: cubical/tools/ModColor.py
# HEADER = '\033[95m'
# OKBLUE = '\033[94m'
# OKGREEN = '\033[92m'
# WARNING = '\033[93m'
# FAIL = '\033[91m'
# ENDC = '\033[0m'
#     HEADER = ''
#     OKBLUE = ''
#     OKGREEN = ''
#     WARNING = ''
#     FAIL = ''
#     ENDC = ''
# def disableColors():
# def Str(strin0,col="red",Bold=True):
# def Sep(strin=None,D=1):
# def Title(strin,Big=False):
# def disable():


# Path: cubical/machines/parallactic_machine.py
from builtins import range
from cubical.tools import logger, ModColor
import pyrap.quanta as pq
import pyrap.measures
import copy
import numpy as np
import datetime as dt

            if log.verbosity() > 1:
                log(2).print("   PA of first antenna (deg): {}".format(unique_pa[:,0]*180/np.pi))

            for t, pa in zip(unique_times, unique_pa):
                angles[utc_timestamp == t, :, :] += pa[:, np.newaxis]

        return angles


    def __apply_rotation(self, utc_timestamp, vis, a1, a2, angles=None, clockwise=False, row_subset=None, freq_slice=None):
        """
        Pads data and performs anticlockwise rotation by default
        """
        if angles is None:
            angles = self.rotation_angles(utc_timestamp)
        print("Rotation angles (deg): {}".format(angles*180/np.pi), file=log(2))

        ## OMS: Ben had it in the opposite direction originally, but I'm sure this is right, and matches VLA results
        pa = -angles if clockwise else angles
        
        def mat_factory(pa, nchan, aindex, conjugate_transpose=False):
            def give_linear_mat(pa, nchan, aindex, conjugate_transpose=False):
                """ 2D rotation matrix according to Hales, 2017: 
                Calibration Errors in Interferometric Radio Polarimetry """
                c1, s1 = np.cos(pa[:, aindex, 0]).repeat(nchan), np.sin(pa[:, aindex, 0]).repeat(nchan)
                c2, s2 = np.cos(pa[:, aindex, 1]).repeat(nchan), np.sin(pa[:, aindex, 1]).repeat(nchan)
                N = pa.shape[0]
                if N == 0: 
                    return np.zeros((0, nchan, 2, 2)) # special case: no data for this baseline
                if conjugate_transpose:

                    return np.array([c1, -s1, s2, c2]).T.reshape(N, nchan, 2, 2)