from PyQt5 import QtCore, QtWidgets
import h5py
import os
import pyqtgraph as pg
import numpy as np

from results import ResultStoring
from filtering.filter_thread import FilterThread

# Here the tab widget, which will be added to the mea_file_view, is created. This class handles the visualization of
# what is going on in the background by a pyqtgraph plot widget which plots data live. Also, in this class a QThread
# is initialized, which will compute the filtering in the background, while the GUI will remain responsive.

# The QWidget class is used whenever you want to create a quite customized widget.
class FilterTab(QtWidgets.QWidget):
    # The FilterTab class receives the MeaFileView as a parent (where it will be embedded), the McsDataReader (another
    # class, which handles the reading of the h5 files of the recordings), the grid  (either all or a selection of grid
    # channels) and the filter settings.
    def __init__(self, parent, reader, grid_indices, grid_labels, settings):
        super().__init__(parent)
        # By setting variables to class variables (done with the 'self.' in front of them) it enables you to use them
        # outside this __init__() function. For example in functions you created yourself further down in the script.
        self.reader = reader
        self.grid_indices = grid_indices
        self.grid_labels = grid_labels
        self.settings = settings
        self.mea_file_view = parent

        # Line 28 and 29 set two class variables to None. This is convenient for the handling of the Thread. As long as
        # the filtering_thread is None, there is no Thread running.
        self.filtered_mat = None
        self.filtering_thread = None

        # Line 33 - 51 sets up different widgets (for detailed explanation see filter_settings_dialog.py and
        # filter_settings_widget.py)
        main_layout = QtWidgets.QVBoxLayout(self)
        main_layout.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignHCenter)

        operation_layout = QtWidgets.QVBoxLayout(self)
        operation_layout.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft)
        self.operation_label = QtWidgets.QLabel(self)
        self.operation_label.setText('Nothing happens so far')
        operation_layout.addWidget(self.operation_label)
        self.progress_label = QtWidgets.QLabel(self)
        operation_layout.addWidget(self.progress_label)

        self.progress_bar = QtWidgets.QProgressBar(self)
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(100)
        self.progress_bar.setTextVisible(True)
        operation_layout.addWidget(self.progress_bar)

        main_layout.addLayout(operation_layout)

        # Line 54 - 73 sets up the pyqtgraph plot widget. Pyqtgraph is a python library designed to enable its users
        # to plot data fast when using PyQt5. The look of the graphs is not as sophisticated as with matplotlib,
        # but the plotting works much faster. So, for any live plotting in MEAsure, the pyqtgraph library is used,
        # while for plotting only circumstances matplotlib is used
        self.plot_widget = pg.PlotWidget()
        # pyqtgraph uses the PyQt5 platform to plot, the setting up of plots works a little different. Happily, their
        # documentation is good (https://pyqtgraph.readthedocs.io/en/latest/index.html) and there are many examples to
        # be found there
        self.plot_widget.setBackground('w')
        styles = {'color': 'k', 'font-size': '10px'}
        self.plot_widget.setLabel('left', 'channel', **styles)
        self.plot_widget.setLabel('bottom', 'time [s]', **styles)
        main_layout.addWidget(self.plot_widget)

        # To be able to show the plot as soon as the tab is added to MeaFileView it needs some variables to plot. So
        # all the needed variables are set to zero at first.
        self.signal = [[0, 0, 0, 0]]
        self.filter = [[0, 0, 0, 0]]
        self.time_s = [[0, 0, 0, 0]]
        self.time_f = [[0, 0, 0, 0]]

        # With the pens in pyqtgraph you design the appearance of your plots
        pen_1 = pg.mkPen(color='#006e7d')
        self.fs = self.reader.sampling_frequency

        # the plot functionality is initially the same as with matplotlib. Later on (in the function on_data_updated in
        # this script), the function setData() will be used.
        self.unfiltered = self.plot_widget.plot(self.time_s[-1], self.signal[-1], pen=pen_1, name='unfiltered')

        pen_2 = pg.mkPen(color='#a7c9ba')
        self.filtered = self.plot_widget.plot(self.time_f[-1], self.filter[-1], pen=pen_2, name='filtered')
        self.plot_widget.addLegend()

    def initialize_filtering(self):
        """
        This function sets up the QThread for filtering
        :return: filtered_mat on triggering other functions, once the QThread is finnished.
        """
        # First we get the settings.
        filter_mode = self.settings.mode
        cutoff_1 = float(self.settings.lower_cutoff)
        cutoff_2 = None
        if self.settings.mode == 2:
            cutoff_2 = float(self.settings.upper_cutoff)
        # if self.settings.channel_selection == 1:

        # Here, it is checked if filtered_mat is None or if it already exists. If it exists, the thread has run before
        # or currently runs.
        if self.filtered_mat is None:
            # Line 103 - 105 are only GUI changes, to tell the user what is going on.
            self.progress_bar.setValue(0)
            self.progress_label.setText('')
            self.operation_label.setText('Filtering')
            # Here, the thread is initialized. We pass the McsDataReader and the setting variables to the Thread.
            self.filtering_thread = FilterThread(self, self.reader, filter_mode, cutoff_1, cutoff_2, self.grid_indices,
                                                 self.grid_labels)
            # The thread sends different signals to this FilterTab. So we have to connect the signals to defined
            # functions.
            self.filtering_thread.progress_made.connect(self.on_progress_made)
            self.filtering_thread.operation_changed.connect(self.on_operation_changed)
            self.filtering_thread.data_updated.connect(self.on_data_updated)
            self.filtering_thread.finished.connect(self.on_filter_thread_finished)

            # Line 116 - 122 are needed to actually start the thread, so in this case, the filtering of the traces.
            debug_mode = False  # set to 'True' in order to debug with embed
            if debug_mode:
                # synchronous filtering (runs in main thread and thus allows debugging)
                self.filtering_thread.run()
            else:
                # asynchronous filtering (default):
                self.filtering_thread.start()  # start will start thread (and run),
                # but main thread will continue immediately

    @QtCore.pyqtSlot(list)
    def on_data_updated(self, data):
        """
        This function handles the on_data_updated signal of the filtering thread. With this signal an update of the
        plot_widget (live plot) is triggered.
        :param data: list of unfiltered and filtered signal and the channel label.
        :return: updated plot widget with the unfiltered and filtered signal of the lastly filtered channel
        """
        signal, filterd, label = data[0], data[1], data[2]  # unpacking of the list got as signal
        # Line 135 - 137 sets the current channel label es ytick
        ay = self.plot_widget.getAxis('left')
        ticks = [0]
        ay.setTicks([[(v, label) for v in ticks]])

        # First, the current channel unfiltered signal has to be appended to the list
        self.signal.append(signal)
        # Normally, it would be enough to define this time list once, but I have not yet found out how to do so.
        self.time_s.append(list(np.arange(0, len(self.signal[-1])*(312/self.fs), (312/self.fs))))
        # unfiltered is the plot_widget with the first pen which was set and by
        # setData(self.time_s[-1], self.signal[-1]) the last entries of the individual lists are plotted
        self.unfiltered.setData(self.time_s[-1], self.signal[-1])

        # Same procedure as for unfiltered.
        self.filter.append(filterd)
        self.time_f.append(list(np.arange(0, len(self.filter[-1])*(312/self.fs), (312/self.fs))))
        self.filtered.setData(self.time_f[-1], self.filter[-1])

    # this function changes the label of the progress bar to inform the user what happens in the background
    @QtCore.pyqtSlot(str)
    def on_operation_changed(self, operation):
        self.operation_label.setText(operation)

    # this function updates the progress bar
    @QtCore.pyqtSlot(float)
    def on_progress_made(self, progress):
        self.progress_bar.setValue(int(progress))
        self.progress_label.setText(str(progress) + "%")

    def on_filter_thread_finished(self):
        """
        This function is triggered once the QThread is finnished. It shows this information in the GUI, but also
        initializes the saving of filtered traces to a .meae (basically .h5, but i just renamend the file format) file,
        if it is set in the settings to do so.
        :return: saved .meae file if it is set, self.filtering_thread is set to None again
        """
        self.progress_label.setText('Finished :)')
        if self.filtering_thread.filtered_mat:
            self.filtered_mat = self.filtering_thread.filtered_mat.copy()
            self.mea_file_view.results.set_filter_mat(self.filtering_thread.filtered_mat)
        self.filtering_thread = None

    def is_busy_filtering(self):
        return self.filtering_thread is not None

    def can_be_closed(self):
        # only allow closing if not busy
        return not self.is_busy_filtering()


from django.shortcuts import render
from django.http import JsonResponse
from django.conf import settings
from . import utils
import json

# Create your views here.
def workflows(request):
    raw_list = utils.read_file()
    df_list = utils.create_df_list(raw_list)
    iteration_list = ['Iteration-' + str(i) for i in range(1, len(df_list)+1)]
    trust_iteration_list = df_list[0].TrustID.tolist()
    context = {'iteration_list': iteration_list, 'trust_iteration_list': trust_iteration_list}
    settings.result_df = df_list

    return render(request, 'workflows/workflows.html', context=context)

def iteration_chart(request):

    iteration_index = request.GET.get('iteration_index', None)
    iter_index = str(iteration_index).split('-')[1]
    df = settings.result_df[int(iter_index)-1]
    x = utils.make_chart(df)
    chart = x.to_json(indent=None)
    data = {'iteration_index': iteration_index, 'chart': chart}

    return JsonResponse(data)

def trust_chart(request):

    trust_id = request.GET.get('trust_id', None)
    trust_df = utils.trust_frame(settings.result_df, trust_id)
    x = utils.trust_chart(trust_df, trust_id)
    trust_chart = x.to_json(indent=None)
    data = {'trust_id': trust_id, 'trust_chart': trust_chart}
    # print(trust_id)

    return JsonResponse(data)

def examples(request):
    raw_list = utils.read_file()
    df_list = utils.create_df_list(raw_list)
    iteration_list = ['Iteration-' + str(i) for i in range(1, len(df_list)+1)]
    trust_iteration_list = df_list[0].TrustID.tolist()
    df = df_list[0]
    x = utils.make_chart(df)
    chart = x.to_json(indent=None)
    # print(chart)
    # spec = x.to_dict()
    context = {
        'iteration_list': iteration_list,
        'trust_iteration_list': trust_iteration_list,
        'chart': chart
    }

    return render(request, 'workflows/example.html', context=context)


class Solution:
    def convertToTitle(self, columnNumber: int) -> str:
        result = ""

        while columnNumber > 0:
            # Subtract 1 to map 1-26 to 0-25 for A-Z
            columnNumber -= 1
            # Get the remainder when divided by 26 to determine the letter
            remainder = columnNumber % 26
            # Convert the remainder to ASCII and append to the result
            result = chr(ord('A') + remainder) + result
            # Update columnNumber to be the result of integer division by 26
            columnNumber //= 26

        return result


import os
import math
import cairo_tools as tools
from functools import wraps, partial

import cairo
from glob import glob

import view, main
from model import prefs
from utils import _T, resolve_path

# Defaults for prefs
prefs.add_default('view-toolswheel-binding',
    ['new layer',
     'open layer manager window',
     'save document as',
     'open preferences window',
     'open color manager window',
     'undo',
     'load document',
     'redo'])

# This list uses Higlander icons
prefs.add_default('view-icons-names',
    ['AddLayer_0',
     'Layer_0',
     'Save_0',
     'Prefs_0',
     'Color_0',
     'Undo_0',
     'Open_0',
     'Redo_0',

     'AddLayer_1',
     'Layer_1',
     'Save_1',
     'Prefs_1',
     'Color_1',
     'Undo_1',
     'Open_1',
     'Redo_1'])

ICONS = {}
ALL_CONTEXTS = {}
ALL_EVENT_TYPES = []
EVENT_TAG_REPEAT = 0x40000000
EVENT_TAG_ANY    = 0x80000000

def reload_icons(path):
    for name in glob(os.path.join(resolve_path(path), '*.png')):
        ICONS[os.path.splitext(os.path.basename(name))[0]] = cairo.ImageSurface.create_from_png(name)

reload_icons(prefs['view-icons-path'])

new_context = lambda name, **kwds: ALL_CONTEXTS[name](**kwds)

#===================================================================================
# Commands handling
#

ALL_COMMANDS = {}
def command(name):
    def decorator(func):
        ALL_COMMANDS[name] = func
        return func
    return decorator

#===================================================================================
# Event base classes
#

class MetaEvent(type):
    def __new__(metacl, name, bases, dct):
        cl = type.__new__(metacl, name, bases, dct)
        if dct.pop('NAME', None):
            ALL_EVENT_TYPES.append(cl)
        return cl

    def __str__(cl):
        return cl.NAME

class EventBase(object):
    __metaclass__ = MetaEvent

    repeat = False

    def __str__(self):
        return self.NAME

    @property
    def fullkey(self): pass

    @property
    def key(self):
        return self.fullkey

class SetupEvent(EventBase):
    def __str__(self):
        return 'setup'

    @property
    def fullkey(self):
        return 0x0FFFFFFF

    @classmethod
    def encode(cl, key):
        return 0x0FFFFFFF

class CleanupEvent(EventBase):
    def __str__(self):
        return 'cleanup'

    @property
    def fullkey(self):
        return 0x0FFFFFFE

    @classmethod
    def encode(cl, key):
        return 0x0FFFFFFE

#===================================================================================
# Context base classes and functions
#

def action(name):
    def decorator(func):
        func._act_name = name
        func._act_ctx = None
        return func
    return decorator

class MetaContext(type):
    def __new__(meta, clname, bases, dct):
        cl = type.__new__(meta, clname, bases, dct)
        if clname != 'Context':
            if clname != 'ModalContext':
                ALL_CONTEXTS[dct['NAME']] = cl

            cl.AVAIL_ACTIONS = {}
            cl.BINDINGS = {}

            # Inherit BINDINGS and AVAIL_ACTIONS dicts
            for base in bases:
                if hasattr(base, 'AVAIL_ACTIONS'):
                    cl.AVAIL_ACTIONS.update(base.AVAIL_ACTIONS)

            # Construct a list of all available actions for this context
            actdict = cl.AVAIL_ACTIONS
            for v in dct.itervalues():
                if hasattr(v, '_act_name'):
                    if v in actdict:
                        raise SystemError("Already defined action for context %s: %s" % (clname, v._act_name))
                    v._act_ctx = cl
                    actdict[v._act_name] = v

            cl.AVAIL_ACTION_NAMES = sorted(cl.AVAIL_ACTIONS.keys())
        return cl

    def __init__(cl, clname, bases, dct):
        type.__init__(cl, clname, bases, dct)
        cl.reset_bindings()

class Context(object):
    __metaclass__ = MetaContext

    __parent = None
    __next = None

    def __init__(self, **kwds):
        self._data = kwds
        self.__dict__.update(kwds)

    @classmethod
    def reset_bindings(cl):
        cl.BINDINGS = {0x0FFFFFFF: cl.setup, 0x0FFFFFFE: cl.cleanup}

    @classmethod
    def get_action(cls, event):
        # Search with full key (mods+key)
        name = cls.BINDINGS.get(event.fullkey)
        if not name:
            # Repeat events are not accepted
            name = cls.BINDINGS.get(EVENT_TAG_REPEAT | event.fullkey)
            if not name:
                # Search for key + 'any' mods
                name = cls.BINDINGS.get(EVENT_TAG_ANY | event.key)
                if not name:
                    name = cls.BINDINGS.get(EVENT_TAG_ANY | EVENT_TAG_REPEAT | event.key)
                    if not name:
                        return
        elif event.repeat:
            return

        if callable(name):
            return name

        try:
            return getattr(cls, name)
        except:
            return name

    def process(self, event):
        """process(event) -> eat_state, new_context

        Check if context has action to process for the given event.

        Returns 2-tuple:
            - eat_state is a boolean set to True if the system shall stop the event progression.
            - new_context is the next context to use (could be the same one).
        """

        # Check for action in context itself
        action = self.get_action(event)
        #print "[%s] Event: %s: %s" % (self, event, action)

        # If not found check parent if we're not a modal context
        if not action and not isinstance(self, ModalContext):
            ctx = self
            while not action and ctx.__parent:
                ctx = ctx.__parent
                action = ctx.get_action(event)
        else:
            ctx = self

        if action:
            ctx.__next = self
            eat = not action(ctx, event)
            if ctx.__next != self:
                return eat, ctx.__next
            return eat, self

        return False, self

    def enter_context(self, name, **kwds):
        for k, v in self._data.iteritems():
            kwds.setdefault(k, v)
        self.__next = new_context(name, **kwds)
        self.__next.__parent = self
        self.__next.process(SetupEvent())
        return self.__next

    def exit_context(self):
        self.process(CleanupEvent())
        self.__next = self.__parent
        self.__next.process(SetupEvent())
        return self.__next

    def swap_context(self, name, **kwds):
        self.process(CleanupEvent())
        self.__next = new_context(name, **kwds)
        return self.__next

    def _set_parent(self, ctx):
        self.__parent = ctx

    ## Internal actions

    def setup(self, *a): pass
    def cleanup(self, *a): pass

    # User trigged Actions
    #

    @action(_T('eat event'))
    def eat_event(self, event): pass

class ModalContext(Context):
    def on_confirm(ctx, event): pass

    # User trigged Actions
    #

    @action(_T('confirm'))
    def confirm(ctx, event):
        try:
            ctx.viewport.get_device_state(event)
            cmd = ctx.on_confirm(event)
        finally:
            newctx = ctx.exit_context()

        if cmd in ALL_COMMANDS:
            res = ALL_COMMANDS[cmd](view.app.ctx)
            if res:
                # TODO: horrible trick! change me soon!
                ctx.enter_context(res)._set_parent(newctx)

    @action(_T('cancel'))
    def cancel(ctx, event):
        ctx.exit_context()

    @action(_T('eat event'))
    def eat_event(self, event): pass

#===================================================================================
# Contexts
#

class ApplicationCtx(Context):
    NAME = 'Application'

    @action(_T('new-document'))
    def undo(self, event):
        self.app.mediator.new_document()

    @action(_T('load-document'))
    def undo(self, event):
        self.app.mediator.load_document()

class DocumentCtx(Context):
    NAME = 'Document'

    # User trigged Actions
    #

    @action(_T('save-document'))
    def save_document(self, event):
        self.app.mediator.save_document()

    @action(_T('save-as-document'))
    def save_as_document(self, event):
        self.app.mediator.save_as_document()

    @action(_T('undo'))
    def undo(self, event):
        self.docproxy.sendNotification(main.UNDO)

    @action(_T('redo'))
    def redo(self, event):
        self.docproxy.sendNotification(main.REDO)

    @action(_T('lighten brush color of 10%'))
    def color_lighten(self, event):
        self.docproxy.multiply_color(1.0, 1.0, 1.1)

    @action(_T('darken brush color of 10%'))
    def color_darken(self, event):
        self.docproxy.multiply_color(1.0, 1.0, 0.9)

    @action(_T('saturate brush color of 10%'))
    def color_saturate(self, event):
        self.docproxy.multiply_color(1.0, 1.1, 1.0)

    @action(_T('desaturate brush color of 10%'))
    def color_desaturate(self, event):
        self.docproxy.multiply_color(1.0, 0.9, 1.0)

    @action(_T('clear active layer'))
    def clear_active_layer(self, event):
        self.docproxy.clear_layer(self.docproxy.active_layer)

    @action(_T('toggle rulers visibility'))
    def toggle_rulers(self, event):
        self.window.toggle_rulers()

class ViewPortCtx(Context):
    NAME = 'Viewport'

    _rot_ruler_warn = True

    def __init__(self, **kwds):
        super(ViewPortCtx, self).__init__(**kwds)
        self._text = tools.Text()

    # Internal Actions
    #

    def setup(self, event):
        vp = self.viewport
        vp.enable_motion_events()
        vp.show_brush_cursor()

    # User trigged Actions
    #

    @action(_T('activate'))
    def activate(self, event):
        vp = self.viewport
        vp.get_device_state(event)
        vp.show_brush_cursor()
        vp.enable_motion_events()

    @action(_T('desactivate'))
    def desactivate(self, event):
        self.viewport.show_brush_cursor(False)
        self.viewport.enable_motion_events(False)

    @action(_T('move brush cursor'))
    def move_cursor(self, event):
        self.viewport.repaint_cursor(*event.get_cursor_position())

    ## Model modifying actions

    @action(_T('start to stroke or hit handler'))
    def on_selection(self, event):
        handler = self.viewport.get_handler_at_pos(*event.get_cursor_position())
        if handler:
            if handler.kill:
                self.viewport.rem_tool(handler.tool)
            else:
                self.enter_context('Handler', handler=handler)
        else:
            self.viewport.get_device_state(event)
            self.enter_context('Brush Stroke')

    @action(_T('start to drag layer'))
    def start_drag_layer(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Drag Layer')

    @action(_T('start to rotate layer'))
    def start_rotate_layer(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Rotate Layer')

    @action(_T('pick brush color'))
    def get_brush_color(self, event):
        color = self.viewport.get_average_color(*event.get_cursor_position())
        if color:
            self.docproxy.set_brush_color_rgb(*color)

    ## Brush modifying actions

    @action(_T('interactive set max radius'))
    def interactive_radius_max(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Max Radius Interactive')

    @action(_T('interactive set both radius'))
    def interactive_radius(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Both Radius Interactive')

    @action(_T('set erase mode'))
    def set_erase_mode(self, event):
        self.docproxy.drawbrush.set_erase(0.0)

    @action(_T('unset erase mode'))
    def unset_erase_mode(self, event):
        self.docproxy.drawbrush.set_erase(1.0)

    @action(_T('pick pixel color'))
    def get_pixel_color(self, event):
        color = self.viewport.get_exact_color(*event.get_cursor_position())
        if color:
            self.docproxy.set_brush_color_rgb(*color)

    @action(_T('enter in pick color mode'))
    def enter_pick_mode(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Pick Mode')

    ## View modifying actions

    @action(_T('reset all viewport transformations'))
    def reset_view(self, event):
        vp = self.viewport
        vp.mediator.view_reset(vp, event.get_cursor_position())

    @action(_T('viewport zoom in'))
    def zoom_in(self, event):
        vp = self.viewport
        vp.mediator.view_scale_up(vp, event.get_cursor_position())

    @action(_T('viewport zoom out'))
    def zoom_out(self, event):
        vp = self.viewport
        vp.mediator.view_scale_down(vp, event.get_cursor_position())

    @action(_T('reset viewport zoom'))
    def zoom_reset(self, event):
        vp = self.viewport
        vp.mediator.view_scale_reset(vp, event.get_cursor_position())

    @action(_T('start to drag view'))
    def start_drag_view(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Drag Viewport')

    @action(_T('reset viewport translation'))
    def drag_view_reset(self, event):
        vp = self.viewport
        vp.mediator.view_translate_reset(vp)

    @action(_T('start to rotate view'))
    def start_rotate_view(self, event):
        # Check if rulers are hidden or shown
        # Rulers don't work correctly with a view rotation.
        if self.window.rulers:
            if self._rot_ruler_warn:
                self.docproxy.sendNotification(main.SHOW_WARNING_DIALOG,
                                               "View rotation is not possible when rulers are active.\n"
                                               "The next try will automatically remove them.")
                self._rot_ruler_warn = False
                return

        self.viewport.get_device_state(event)
        self.enter_context('Rotate Viewport')

    @action(_T('reset viewport rotation'))
    def rotate_view_reset(self, event):
        vp = self.viewport
        vp.mediator.view_rotate_reset(vp, event.get_cursor_position())

    @action(_T('swap viewport left-right'))
    def swap_x(self, event):
        vp = self.viewport
        vp.mediator.view_swap_x(vp, event.get_cursor_position()[0])

    @action(_T('swap viewport top-bottom'))
    def swap_y(self, event):
        vp = self.viewport
        vp.mediator.view_swap_y(vp, event.get_cursor_position()[1])

    ## Tools actions

    @action(_T('toggle line guide'))
    def toggle_line_guide(self, event):
        vp = self.viewport
        vp.mediator.toggle_guide(vp, 'line')

    @action(_T('toggle ellipse guide'))
    def toggle_ellipse_guide(self, event):
        vp = self.viewport
        vp.mediator.toggle_guide(vp, 'ellipse')

    @action(_T('show last colors used'))
    def last_colors_selector(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Last Colors Selector')

    @action(_T('show tools selector'))
    def start_tools_selector(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Tools Selector')

class BrushStrokeModal(ModalContext):
    NAME = 'Brush Stroke'

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)
        vp.docproxy.draw_start(vp.device)

    def cleanup(self, event):
        vp = self.viewport
        vp.docproxy.draw_end()
        vp.unlock_focus()

    # User trigged Actions
    #

    @action(_T('draw at cursor'))
    def draw(self, event):
        self.viewport.docproxy.record(self.viewport.get_device_state(event))

    @action(_T('set erase mode'))
    def set_erase_mode(self, event):
        self.docproxy.drawbrush.set_erase(0.0)

    @action(_T('unset erase mode'))
    def unset_erase_mode(self, event):
        self.docproxy.drawbrush.set_erase(1.0)

class DragViewModal(ModalContext):
    NAME = 'Drag Viewport'

    def __init__(self, **kwds):
        super(DragViewModal, self).__init__(**kwds)
        self._text = tools.Text()

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

        self._cpos = vp.device.current.cpos
        self._x = 0
        self._y = 0
        self._text.set_text("Dx=%-4u, Dy=%-4u" % (0,0))

        vp.add_tool(self._text)
        vp.enable_fast_filter()

    def cleanup(self, event):
        vp = self.viewport
        vp.unlock_focus()
        vp.rem_tool(self._text)
        vp.enable_fast_filter(False)
        vp.repaint()

    # User trigged Actions
    #

    @action(_T('drag view'))
    def drag_view(self, event):
        vp = self.viewport

        # Compute cursor delta's
        cpos = event.get_cursor_position()
        dx = cpos[0] - self._cpos[0]
        dy = cpos[1] - self._cpos[1]
        self._x += dx
        self._y += dy
        self._cpos = cpos

        # update display
        self._text.set_text("Dx=%-4u, Dy=%-4u" % (self._x, self._y))
        vp.repaint_tools(clip=self._text.area)
        vp.scroll(dx, dy)

class RotateViewModal(ModalContext):
    NAME = 'Rotate Viewport'

    _rot = tools.Rotate()
    _text = tools.Text()

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

        self._angle = 0.
        self._rot.set_cursor_pos(vp.device.current.cpos)
        self._text.set_text("Angle: 0")

        vp.add_tool(self._rot)
        vp.add_tool(self._text)
        vp.enable_fast_filter()

    def cleanup(self, event):
        vp = self.viewport
        vp.unlock_focus()

        vp.rem_tool(self._rot)
        vp.rem_tool(self._text)

        vp.enable_fast_filter(False)
        vp.repaint()

    @action(_T('rotate view'))
    def rotate_view(self, event):
        vp = self.viewport

        self._rot.set_cursor_pos(event.get_cursor_position())
        self._angle = (self._angle + self._rot.dr) % (2*math.pi)
        self._text.set_text("Angle: %u" % math.degrees(self._angle))

        vp.repaint_tools()
        vp.rotate(-self._rot.dr)

class LastColorModal(ModalContext):
    NAME = 'Last Colors Selector'

    _colors = [ None ] * 8

    def __init__(self, **kwds):
        super(LastColorModal, self).__init__(**kwds)
        self._tool = tools.ColorWheel()
        self.push_color(self.viewport.docproxy.get_brush_color_rgb())

    @classmethod
    def push_color(cl, rgb):
        if rgb != cl._colors[0]:
            cl._colors.insert(0, rgb)
            cl._colors.pop(-1)

    def setup(self, event):
        vp = self.viewport
        vp.enable_motion_events()
        vp.show_brush_cursor(False)
        self._tool.set_colors(self._colors)
        self._tool.set_center(vp.device.current.cpos)
        vp.add_tool(self._tool)

    def cleanup(self, event):
        self.viewport.rem_tool(self._tool)

    def on_confirm(self, event):
        i = self._tool.selection
        if i >= 0:
            # Slice the historic and put the selected color as first
            rgb = self._colors.pop(i)
            self._colors.insert(0, rgb)
            self.viewport.docproxy.set_brush_color_rgb(*rgb)

    # User trigged Actions
    #

    @action(_T('check cursor position'))
    def check_cursor(self, event):
        vp = self.viewport
        cpos = event.get_cursor_position()
        if vp.is_tool_hit(self._tool, *cpos):
            # TODO: CPU eating when pen used
            self._tool.cpos = cpos
        elif self._tool.cpos:
            self._tool.cpos = None
        else:
            return

        vp.repaint_tools(self._tool.area)
        vp.redraw(self._tool.area)

class ToolsModal(ModalContext):
    NAME = 'Tools Selector'

    _sel = -1

    def __init__(self, **kwds):
        super(ToolsModal, self).__init__(**kwds)
        self._tool = tools.ToolsWheel()
        self.refresh()

    def refresh(self):
        icons = []
        for name in prefs['view-icons-names']:
            icons.append(ICONS[name])
        self._tool.set_icons(icons)

    def setup(self, event):
        vp = self.viewport
        vp.enable_motion_events()
        vp.show_brush_cursor(False)
        self._tool.set_center(vp.device.current.cpos)
        vp.add_tool(self._tool)

    def cleanup(self, event):
        self.viewport.rem_tool(self._tool)

    def on_confirm(self, event):
        i = self._tool.selection
        if i >= 0:
            return prefs['view-toolswheel-binding'][i]

    # User trigged Actions
    #

    @action(_T('check cursor position'))
    def check_cursor(self, event):
        vp = self.viewport
        cpos = event.get_cursor_position()
        if vp.is_tool_hit(self._tool, *cpos):
            # TODO: CPU eating when pen used
            self._tool.cpos = cpos
        elif self._tool.cpos:
            self._tool.cpos = None
        else:
            return

        vp.repaint_tools(self._tool.area)
        vp.redraw(self._tool.area)

class SetMaxRadiusModal(ModalContext):
    NAME = 'Max Radius Interactive'

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        self._cpos = self._first_cpos = vp.show_brush_cursor()

    def cleanup(self, event):
        self.viewport.unlock_focus()

    # User trigged Actions
    #

    @action(_T('resize brush'))
    def resize_brush(self, event):
        vp = self.viewport
        cpos = event.get_cursor_position()
        dr = self._cpos[1] - cpos[1]
        vp.docproxy.add_brush_radius_max(dr*.25)
        vp.repaint_cursor(*self._first_cpos)
        self._cpos = cpos

class SetBothRadiusModal(ModalContext):
    NAME = 'Both Radius Interactive'

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        self._cpos = self._first_cpos = vp.show_brush_cursor()

    def cleanup(self, event):
        self.viewport.unlock_focus()

    # User trigged Actions
    #

    @action(_T('resize brush'))
    def resize_brush(self, event):
        vp = self.viewport
        cpos = event.get_cursor_position()
        dr = self._cpos[1] - cpos[1]
        vp.docproxy.add_brush_radius(dr*.25)
        vp.repaint_cursor(*self._first_cpos)
        self._cpos = cpos

class DragLayerModal(ModalContext):
    NAME = 'Drag Layer'

    def __init__(self, **kwds):
        super(DragLayerModal, self).__init__(**kwds)
        self._text = tools.Text()

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

        self._old_mat = cairo.Matrix(*self.docproxy.document.active.matrix)
        self._cpos = vp.device.current.cpos
        self._x = 0
        self._y = 0
        self._text.set_text("Dx=%-4u, Dy=%-4u" % (0,0))

        vp.add_tool(self._text)
        vp.enable_fast_filter()

    def cleanup(self, event):
        vp = self.viewport
        vp.unlock_focus()
        vp.rem_tool(self._text)
        vp.enable_fast_filter(False)
        vp.repaint()

    def on_confirm(self, event):
        docproxy = self.viewport.docproxy
        layer = docproxy.active_layer
        docproxy.record_layer_matrix(layer, self._old_mat)

    # User trigged Actions
    #

    @action(_T('drag layer'))
    def drag_layer(self, event):
        vp = self.viewport
        tool = self._text

        # Compute cursor delta's
        cpos = event.get_cursor_position()
        dx = cpos[0] - self._cpos[0]
        dy = cpos[1] - self._cpos[1]
        self._x += dx
        self._y += dy
        self._cpos = cpos

        # update display
        tool.set_text("Dx=%-4u, Dy=%-4u" % (self._x, self._y))
        vp.repaint_tools(tool.area, redraw=True)
        vp.docproxy.layer_translate(*vp.get_model_distance(dx, dy))

class RotateLayerModal(ModalContext):
    NAME = 'Rotate Layer'

    def __init__(self, **kwds):
        super(RotateLayerModal, self).__init__(**kwds)
        self._text = tools.Text()
        self._rot = tools.Rotate()

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

        self._old_mat = cairo.Matrix(*self.docproxy.document.active.matrix)
        pos = vp.width/2, vp.height/2
        pos = vp.get_model_point(*pos)
        self._ro = vp.docproxy.get_layer_pos(*pos)

        self._angle = 0.
        self._rot.set_cursor_pos(vp.device.current.cpos)
        self._text.set_text("Angle: 0")

        vp.add_tool(self._rot)
        vp.add_tool(self._text)
        vp.enable_fast_filter()

    def cleanup(self, event):
        vp = self.viewport
        vp.unlock_focus()
        vp.rem_tool(self._rot)
        vp.rem_tool(self._text)

        # Force fine display
        vp.enable_fast_filter(False)
        vp.repaint()

    def on_confirm(self, event):
        docproxy = self.viewport.docproxy
        layer = docproxy.active_layer
        docproxy.record_layer_matrix(layer, self._old_mat)

    # User trigged Actions
    #

    @action(_T('rotate Layer'))
    def rotate_Layer(self, event):
        vp = self.viewport

        self._rot.set_cursor_pos(event.get_cursor_position())
        self._text.set_text("Angle: %u" % math.degrees(self._angle))

        # update display
        vp.repaint_tools(self._text.area, redraw=True)
        vp.repaint_tools(self._rot.area, redraw=True)
        vp.docproxy.layer_rotate(-self._rot.dr, *self._ro)

        self._angle = (self._angle + self._rot.dr) % (2*math.pi)

class HandlerModal(ModalContext):
    NAME = 'Handler'

    def setup(self, event):
        assert hasattr(self, 'handler')

        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

    def cleanup(self, event):
        self.viewport.unlock_focus()

    # User trigged Actions
    #

    @action(_T('cursor move'))
    def cursor_move(self, event):
        hl = self.handler
        tool = hl.tool
        tool.move_handler(hl, *event.get_cursor_position())

        # Clear old and draw new position
        self.viewport.repaint_tools(tool.area, redraw=True)
        self.viewport.repaint_tools(tool.area, redraw=True)

class PickModal(ModalContext):
    NAME = 'Pick Mode'

    def __init__(self, **kwds):
        super(PickModal, self).__init__(**kwds)

    def setup(self, event):
        vp = self.viewport
        vp.enable_motion_events()
        vp.show_brush_cursor(True)
        vp.pick_mode(True)

    def cleanup(self, event):
        self.viewport.pick_mode(False)

    def on_confirm(self, event):
        color = self.viewport.get_exact_color(*event.get_cursor_position())
        if color:
            self.docproxy.set_brush_color_rgb(*color)

    # User trigged Actions
    #

    @action(_T('move brush cursor'))
    def move_cursor(self, event):
        self.viewport.repaint_cursor(*event.get_cursor_position())


import os
import stat
import tempfile
import exiftool

def exiftool_is_executable():
    """Check whether exiftool is exif_executable if not truthy raises an PermissionError"""
    exif_executable = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "utils", "ExifTool", "exiftool"))
    is_executable = os.access(exif_executable, os.X_OK)
    if not is_executable:
        try:
            os.chmod(exif_executable, os.stat(exif_executable).st_mode | stat.S_IEXEC)
            return True
        except:
            raise PermissionError(f"Cannot execute nor set execution privileges for exiftool. Please run script as sudo or try running 'sudo chmod +x {exif_executable}'")

def get_metadata(response=None, path_to_local_file=None):
    """Returns metadata"""
    exif_executable = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "utils", "ExifTool", "exiftool"))

    if response:
        tmp = tempfile.NamedTemporaryFile()
        with open(tmp.name, 'wb') as f:
            f.write(response.content)
        with exiftool.ExifTool(executable=exif_executable) as et:
            result_dict = et.execute_json(tmp.name)[0]

    elif path_to_local_file:
        with exiftool.ExifTool(executable=exif_executable) as et:
            result_dict = et.execute_json(path_to_local_file)[0]

    blacklist = ["SourceFile", "ExifTool:ExifToolVersion", "File:FileName", "File:Directory", "File:FileSize", "File:FileModifyDate", "File:FileInodeChangeDate", "File:FilePermissions", "File:FileAccessDate", "File:FileType", "File:FileTypeExtension", "File:MIMEType"]
    result_dict = {k: v for k, v in result_dict.items() if k not in blacklist and v}
    return result_dict


#!/usr/bin/env python

import setup_path
import airsim
import csv
import random
import numpy as np
from PIL import Image
from datetime import datetime
import matplotlib.pyplot as plt

# Demonstration script to show how the camera and GPU-LiDAR sensor can be used and their data retrieved.
# See docs/instance_segmentation.md,docs/gpu-lidar.md and docs/image_apis.md#segmentation for more information.
if __name__ == '__main__':

    # Make connection to AirSim API
    client = airsim.CarClient()
    client.confirmConnection()

    # Get an image from the main segmentation camera, show and save it as png
    print("Getting segmentation image from main camera...")
    responses = client.simGetImages([airsim.ImageRequest( "leftcamera", airsim.ImageType.Segmentation, False, False)])
    img_rgb_string = responses[0].image_data_uint8
    rgbarray = np.frombuffer(img_rgb_string, np.uint8)
    rgbarray_shaped = rgbarray.reshape((540,960,3))
    img = Image.fromarray(rgbarray_shaped, 'RGB')
    img.show()
    img.save("segmentation_sample.png", "PNG")
    print("Shown and saved segmentation image from main camera\n")

    # Get an image from the main segmentation camera, show and save it as png
    print("Getting rgb image from main camera...")
    responses = client.simGetImages([airsim.ImageRequest( "leftcamera", airsim.ImageType.Scene, False, False)])
    img_rgb_string = responses[0].image_data_uint8
    rgbarray = np.frombuffer(img_rgb_string, np.uint8)
    rgbarray_shaped = rgbarray.reshape((540,960,3))
    img = Image.fromarray(rgbarray_shaped, 'RGB')
    img.show()
    img.save("rgb_sample.png", "PNG")
    print("Shown and saved RGB image from main camera\n")

    # Get an image from the main segmentation camera, show and save it as png
    print("Getting depth image from main camera...")
    responses = client.simGetImages([airsim.ImageRequest( "leftcamera", airsim.ImageType.DepthPlanner, True, False)])
    img_depth_float = responses[0].image_data_float
    img_depth_float32 = np.asarray(img_depth_float, dtype=np.float32)
    rgbarray_shaped = img_depth_float32.reshape((540,960)).astype(np.float32)
    img = Image.fromarray(rgbarray_shaped)
    img.show()
    img.save("depth_sample.tif")
    print("Shown and saved depth image from main camera\n")

    print("Getting GPU LiDAR data...")
    lidar_data = client.getGPULidarData('lidar1', 'airsimvehicle')
    points = np.array(lidar_data.point_cloud, dtype=np.dtype('f4'))
    points = np.reshape(points, (int(points.shape[0] / 5), 5))

    rgb_values = points[:, 3].astype(np.uint32)
    rgb = np.zeros((np.shape(points)[0], 3))
    xyz = points[:, 0:3]
    for index, rgb_value in enumerate(rgb_values):
        rgb[index, 0] = (rgb_value >> 16) & 0xFF
        rgb[index, 1] = (rgb_value >> 8) & 0xFF
        rgb[index, 2] = rgb_value & 0xFF
    rgb = np.divide(rgb, 255)

    print("Parsing segmentation RGB8 values from float32 data values...")
    fig = plt.figure()
    ax = fig.add_subplot(projection='3d')
    ax.scatter(xyz[:, 0], xyz[:, 1], xyz[:, 2], c=rgb)
    ax.set_xlabel('X Label')
    ax.set_ylabel('Y Label')
    ax.set_zlabel('Z Label')
    ax.set_xlim((-5, 5))
    ax.set_ylim((-5, 5))
    ax.set_zlim((-5, 5))
    plt.show()
    print("Shown and saved 3d segmented pointcloud\n")

    print("All instance segmentation tests completed")


#!/usr/bin/env python
import hashlib
import os
import platform
import shutil
import subprocess
import sys
import tarfile
import textwrap
import time
import urllib.request

from phylofisher import help_formatter

def reporthook(count, block_size, total_size):
    global start_time
    if count == 0:
        start_time = time.time()
        return
    duration = time.time() - start_time
    progress_size = int(count * block_size)
    speed = int(progress_size / (1024 * duration))
    percent = int(count * block_size * 100 / total_size)
    sys.stdout.write("\r%d%%, %d MB, %d KB/s, %d seconds elapsed" %
                    (percent, progress_size / (1024 * 1024), speed, duration))
    sys.stdout.flush()

def bash(cmd):
    subprocess.run(cmd, shell=True)

def is_in_path(cmd):
    """
    Checks to see if command provided is in PATH already. If it is return True, if not returns False
    """
    if shutil.which(cmd) is None:
        in_path = False
    else:
        in_path = True

    return in_path

def download(url):
    fname = url.split('/')[-1]
    urllib.request.urlretrieve(url, f'{fisher_dir}/{fname}', reporthook)

    return fname

def extract(fname):
    tar = tarfile.open(fname, "r:gz")
    tar.extractall()
    tar.close()
    os.remove(fname)

def get_trimal():
    os.chdir(fisher_dir)
    if is_in_path('trimal') is False:
        os.chdir(f'{fisher_dir}/trimAl/source/')
        bash('make')
        os.chdir(fisher_dir)
        # Symlink executables to user bin
        src = f'{fisher_dir}/trimAl/source/trimal'
        des = f'{user_bin}/trimal'
        shutil.copy(src, des)
        src = f'{fisher_dir}/trimAl/source/readal'
        des = f'{user_bin}/readal'
        shutil.copy(src, des)

def get_raxml():
    os.chdir(fisher_dir)
    if is_in_path('raxmlHPC-PTHREADS-AVX2') is False:
        # Download and extract RAxML
        os.chdir(f'{fisher_dir}/standard-RAxML-8.2.12/')
        bash('make -f Makefile.AVX.PTHREADS.gcc')
        # Symlink executables to user bin
        src = f'{fisher_dir}/standard-RAxML-8.2.12/raxmlHPC-PTHREADS-AVX'
        des = f'{user_bin}/raxmlHPC-PTHREADS-AVX2'
        shutil.copy(src, des)

def get_hmmer():
    os.chdir(fisher_dir)
    if is_in_path('hmmsearch') is False:
        # Download and extract hmmer
        os.chdir(f'{fisher_dir}/hmmer-3.3/')
        bash('./configure --prefix=$HOME/.local && make install')

def get_diamond():
    os.chdir(fisher_dir)
    if is_in_path('diamond') is False:
        # Download and extract Diamond
        shutil.copy(f'{fisher_dir}/diamond', f'{user_bin}/diamond')
        os.remove(f'{fisher_dir}/diamond')

def get_fasttree():
    os.chdir(fisher_dir)
    if is_in_path('fasttree') is False:
        # Download and extract Diamond
        bash('gcc -O3 -finline-functions -funroll-loops -Wall -o FastTree FastTree.c -lm')
        shutil.copy(f'{fisher_dir}/FastTree', f'{user_bin}/fasttree')
        os.remove(f'{fisher_dir}/FastTree.c')

def get_blast():
    os.chdir(fisher_dir)
    if is_in_path('blastn') is False:
        if platform.system() == 'Darwin':
            extract(f'{fisher_dir}/ncbi-blast-2.10.1-macosx.tar.gz')
        else:
            extract(f'{fisher_dir}/ncbi-blast-2.10.1-linux.tar.gz')

        src = f'{fisher_dir}/ncbi-blast-2.10.1+/bin/*'
        bash(f'cp {src} {user_bin}')

def get_cd_hit():
    os.chdir(fisher_dir)
    if is_in_path('cd-hit') is False:
        os.chdir(f'{fisher_dir}/cdhit-4.8.1')
        if platform.system() == 'Darwin':
            bash(f'make clean && make CC={args.gxx}')
        else:
            bash('make clean && make')
        exes = ['cd-hit', 'cd-hit-est', 'cd-hit-2d', 'cd-hit-est-2d', 'cd-hit-div', 'cd-hit-454']
        for exe in exes:
            src = f'{fisher_dir}/cdhit-4.8.1/{exe}'
            des = f'{user_bin}/{exe}'
            shutil.copy(src, des)

def get_mafft():
    os.chdir(fisher_dir)
    if is_in_path('mafft') is False:
        os.chdir(f'{fisher_dir}/mafft-7.453-without-extensions/core')
        with open('Makefile', 'r') as infile, open('tmp', 'w') as outfile:
            for line in infile:
                if line.strip() == 'PREFIX = /usr/local':
                    line = f'PREFIX = {fisher_dir}\n'
                elif line.strip() == 'BINDIR = $(PREFIX)/bin':
                    line = f'BINDIR = {user_bin}\n'
                outfile.write(f'{line}')
        print('done')
        shutil.move('tmp', 'Makefile')
        bash('make clean && make && make install')
        os.chdir(fisher_dir)

def get_divvier():
    os.chdir(fisher_dir)
    if is_in_path('divvier') is False:
        os.chdir(f'{fisher_dir}/Divvier-1.01')
        bash('make clean && make')
        src = f'{fisher_dir}/Divvier-1.01/divvier'
        des = f'{user_bin}/divvier'
        shutil.copy(src, des)

def get_prequal():
    os.chdir(fisher_dir)
    if is_in_path('prequal') is False:
        os.chdir(f'{fisher_dir}/prequal-1.02')
        bash('make clean && make')
        src = f'{fisher_dir}/prequal-1.02/prequal'
        des = f'{user_bin}/prequal'
        shutil.copy(src, des)

def get_bmge():
    os.chdir(fisher_dir)
    if is_in_path('BMGE') is False:
        os.chdir(f'{fisher_dir}/BMGE-1.12')
        with open('stub.sh', 'w') as outfile:
            stub = ('#!/bin/sh\n'
                    'MYSELF=`which "$0" 2>/dev/null`\n'
                    '[ $? -gt 0 -a -f "$0" ] && MYSELF="./$0"\n'
                    'java=java\n'
                    'if test -n "$JAVA_HOME"; then\n'
                    '    java="$JAVA_HOME/bin/java"\n'
                    'fi\n'
                    'java_args=-Xmx1g\n'
                    'exec "$java" $java_args -jar $MYSELF "$@"\n'
                    'exit 1\n')
            outfile.write(stub)

        bash('cat stub.sh BMGE.jar > BMGE && chmod +x BMGE ')
        src = f'{fisher_dir}/BMGE-1.12/BMGE'
        des = f'{user_bin}/bmge'
        shutil.copy(src, des)

def get_dist_est():
    os.chdir(fisher_dir)
    if is_in_path('dist_est') is False:
        os.chdir(f'{fisher_dir}/dist_est-1.1')
        bash('make clean && make')
        src = f'{fisher_dir}/dist_est-1.1/dist_est'
        des = f'{user_bin}/dist_est'
        shutil.copy(src, des)

if __name__ == '__main__':
    description = 'Downloads, compiles, and installs trimal, RAxML, hmmer, diamond, FastTree, BLAST+, cd-hit' \
                  'mafft, Divvier, prequal, BMGE, and dist_est'
    parser, optional, required = help_formatter.initialize_argparse(name='install_deps.py',
                                                                    desc=description,
                                                                    usage='install_deps.py [OPTIONS]')

    optional.add_argument('--gxx', type=str, metavar='<path/to/g++>', default=None,
                          help=textwrap.dedent("""\
                            FOR OSX ONLY: Path to g++ compiler.
                            If not provided on OSX, cd-hit installation will be skipped
                            """))

    args = help_formatter.get_args(parser, optional, required, pre_suf=False, inp_dir=False, out_dir=False)

    # home = os.path.expanduser('~')
    home = os.getcwd()

    user_bin = f'{home}/.local/bin'
    fisher_dir = f'{home}/.local/lib/phylofisher'

    # Check if necessary directy structure is already present.
    # If not creates it
    if os.path.isdir(f'{home}/.local') is False:
        os.mkdir(f'{home}/.local')
    if os.path.isdir(f'{home}/.local/lib') is False:
        os.mkdir(f'{home}/.local/lib')
    if os.path.isdir(user_bin) is False:
        os.mkdir(user_bin)
    if os.path.isdir(fisher_dir) is False:
        os.mkdir(fisher_dir)

    os.chdir(fisher_dir)

    # Get tarball with deps from msstate library
    print('Downloading dependencies:')
    url = 'https://ir.library.msstate.edu/bitstream/handle/11668/19731/Tice_etal.PhyloFisher.archives.tar.gz'
    file_name = 'Tice_etal.PhyloFisher.archives.tar.gz'

    if not os.path.isfile(file_name):
        download(url)

    # Correct original md5 goes here
    original_md5 = '062c84f27388304094d35946f5616a79'

    # Open,close, read file and calculate MD5 on its contents
    with open(file_name, 'rb') as file_to_check:
        # read contents of the file
        data = file_to_check.read()
        # pipe contents of the file through
        md5_returned = hashlib.md5(data).hexdigest()

    # Finally compare original MD5 with freshly calculated
    if original_md5 != md5_returned:
        print('download corrupted')
    else:
        extract(file_name)
        files = os.listdir(f'{fisher_dir}/archives')
        for file in files:
            shutil.move(f'{fisher_dir}/archives/{file}', f'{fisher_dir}/{file}')
            if 'blast' not in file:
                extract(f'{fisher_dir}/{file}')

        shutil.rmtree(f'{fisher_dir}/archives')

    get_trimal()
    get_raxml()
    get_hmmer()
    get_diamond()
    get_fasttree()
    get_blast()
    if platform.system() == 'Darwin' and args.gxx is None:
        print('Your operating system is OSX, and a g++ compiler was not provided.\n'
              'cd-hit will NOT be installed')
    else:
        get_cd_hit()
    get_mafft()
    get_divvier()
    get_prequal()
    get_bmge()
    get_dist_est()


def state_to_file(arr):

    arr = arr[0]
    layers = arr.shape[0]

    for l in range(layers):
        rows = arr[l]

        data = ""

        for x in range(rows.shape[0]):
            cols = rows[x]
            for y in range(cols.shape[0]):

                data += str(cols[y]) + " "

            data += "\n"

        print(data)


import os
import sys
root_path = os.path.join(os.getenv("HOME"), "vqa2019")
sys.path.append(root_path)

import numpy as np
import pickle
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.metrics import confusion_matrix

from utils.data_provider import VQADataProvider

def train():
	# prepare the data
	# utils folder is in the root path, which is /home/leishi/vqa2019
	questions, labels = VQADataProvider.label_ques("train_val")
	vectorizer = TfidfVectorizer()
	ques_matrix = vectorizer.fit_transform(questions)

	# build classifier
	# svc
	classifier = SVC(gamma="scale", verbose=False)
	# # rf
	# classifier = RandomForestClassifier()
	# # gb
	# classifier = GradientBoostingClassifier()

	# train
	classifier.fit(ques_matrix, labels)

	# # training accuracy
	train_acc = classifier.score(ques_matrix, labels)
	print("training accuracy: ", train_acc)

	# save tf-idf
	with open(os.path.join(root_path, "models/pretrained/tfidf_train_val.pkl"), "wb") as f:
		pickle.dump(vectorizer, f)

	# save classifier
	with open(os.path.join(root_path, "models/pretrained/pretrained_svm_train_val.pkl"), "wb") as f:
		pickle.dump(classifier, f)

	# # debug
	# print("\nraw questions")
	# print(questions[:5])
	# print("question matrix")
	# print(vectorizer.transform(questions[:5]).todense())
	# # print("corresponding words of transformed questions")
	# # print(vectorizer.inverse_transform(vectorizer.transform(questions[:5])))
	# print("terms used")
	# print(vectorizer.get_feature_names())
	return vectorizer, classifier

# test load model
def test():
	# load tf-idf
	with open(os.path.join(root_path, "models/pretrained/tfidf.pkl"), "rb") as f:
		vectorizer = pickle.load(f)

	# load validation data
	val_ques, val_lab = VQADataProvider.label_ques("val")
	val_ques_matrix = vectorizer.transform(val_ques)

	# load model
	with open(os.path.join(root_path, "models/pretrained/pretrained_svm.pkl"), "rb") as f:
		clf = pickle.load(f)

	# compute validation accuracy
	val_acc = clf.score(val_ques_matrix, val_lab)
	print("validation accuracy")
	print(val_acc)

	# compute validation confusion matrix
	preds = clf.predict(val_ques_matrix)
	val_c_m = confusion_matrix(val_lab, preds)
	print("validation confusion matrix")
	print(val_c_m)

	# # for debug
	# print("\ntest on some validation question")
	# val_some_q = val_ques[5:10]
	# val_some_q_matrix = vectorizer.transform(val_some_q)
	# val_some_lab = val_lab[5:10]
	# print("question")
	# print(val_some_q)
	# print("prediction")
	# print(clf.predict(val_some_q_matrix))
	# print("ground truth")
	# print(val_some_lab)

# predict the category of a list of questions
def predict_q_category(questions):
	# load tf-idf
	with open(os.path.join(root_path, "models/pretrained/tfidf_train_val.pkl"), "rb") as f:
		vectorizer = pickle.load(f)
	# load model
	with open(os.path.join(root_path, "models/pretrained/pretrained_svm_train_val.pkl"), "rb") as f:
		clf = pickle.load(f)
	# create tf-idf matrix
	ques_matrix = vectorizer.transform(questions)
	# make predictions
	preds = clf.predict(ques_matrix)
	return preds

if __name__ == "__main__":
	train()
	# print("test")
	# test()


import os
import arcade

from src.main import Game

def main():
    curr_dir = os.path.dirname(os.path.abspath(__file__))
    window = Game(curr_dir)
    window.setup()
    arcade.run()

if __name__ == "__main__":
    main()


import random

def orgFile(linkPath):
    fileRead = linkPath + "/Links/requestedLinks.txt"
    writedFile = linkPath + "/Links/formatedLinks.txt"
    with open(fileRead, "r") as f, open(writedFile, "w") as nf:

        container = f.readlines()
        f.close()
        container = [x.split("#|#") for x in container]

        random_choice = random.sample(container, 10)

        for everyLine in range(len(random_choice)):
            user, title, vLink, dLink = random_choice[everyLine]
            nf.write("User: " + user + "\nTitle: " + title + "\nVideo_Link: " + vLink + "\nDownload_Link: " + dLink + '\n')
        nf.close()

#orgFile()


"""
Dylan McTigue
lab1.py
Finding monthly interest rate
I did not share my code or discuss my code with anyone. All of this work is mine.
"""

interest_rate = eval(input("enter annual interest rate: "))
billing_cycle_days = eval(input("enter days in billing cycle: "))
previous_balance = eval(input("enter Previous Balance: "))
payment_amount = eval(input("enter Payment Amount: "))
day_payment_made = eval(input("enter day of cycle when payment was made: "))

step1 = previous_balance * billing_cycle_days
step2 = payment_amount * (billing_cycle_days - day_payment_made)
step3 = step1 - step2
avg_daily_balance = step3 / billing_cycle_days
monthly_interest_charge = avg_daily_balance * (interest_rate / 100 / 12)
rmonthly_interest_charge = round(monthly_interest_charge, 2)

print("Your monthly interest charge is $", rmonthly_interest_charge)


import torchvision.models as models
import torch
import torch.nn as nn
import torch.nn.functional as F
from tqdm import tqdm
from torch.utils.data import Dataset, DataLoader
import pickle
import numpy as np
import sys
from sklearn.feature_extraction.text import TfidfVectorizer
from torchvision.transforms import Normalize
from tifffile import imread
import os
import random

emb_dims = 32

# IMAGES NETWORK
class DenseNetTruncated(nn.Module):
  def __init__(self, **kwargs):
    super(DenseNetTruncated, self).__init__()
    self.densenet = models.densenet121(**kwargs)

  def forward(self, x):
    features = self.densenet.features(x)
    out = F.relu(features, inplace=True)
    out = F.avg_pool2d(out, kernel_size=7).view(features.size(0), -1)
    return out

class ModelImages(nn.Module):
  def __init__(self, pretrained=True):
    global emb_dims
    super(ModelImages, self).__init__()
    self.densenet = DenseNetTruncated(pretrained=pretrained)
    self.last_linear = nn.Linear(1024, emb_dims)

  def forward(self, x):
    x = self.densenet(x)
    x = self.last_linear(x)
    return x

class ModelReports(nn.Module):
  def __init__(self):
    global emb_dims
    super(ModelReports, self).__init__()
    self.first_layer = nn.Linear(8919, 64)
    self.middle_layer = nn.Linear(64, 64)
    self.last_layer = nn.Linear(64, emb_dims)

  def forward(self, x):
    x = F.relu(self.first_layer(x))
    x = F.relu(self.middle_layer(x))
    x = F.relu(self.last_layer(x))
    return x

class ModelClassification(nn.Module):
  def __init__(self):
    global emb_dims
    super(ModelClassification, self).__init__()
    self.first_layer = nn.Linear(emb_dims, 14)

  def forward(self, x):
    x = self.first_layer(x)
    return x

class Model(nn.Module):
  def __init__(self):
    super(Model, self).__init__()
    self.image_branch = ModelImages()
    self.text_branch = ModelReports()
    self.classification_branch = ModelClassification()

  def forward(self, images, text):
    image_emb = self.image_branch(images)
    text_emb = self.text_branch(text)
    predictions = self.classification_branch(image_emb)
    return image_emb, text_emb, predictions

def sampled_margin_ranking_loss(emb1, emb2):
  # emb1=images emb2=reports
  N = emb1.shape[0]
  idx = np.random.randint(N - 1, size=[N])
  idx[np.arange(N) == idx] = N - 1
  emb1_neg = emb1[idx]
  emb2_neg = emb2[idx]

  similarity = lambda x, y: (x * y).sum(dim=1)

  IR_gt = similarity(emb1, emb2)
  IR_impR = similarity(emb1, emb2_neg)
  IR_impI = similarity(emb1_neg, emb2)
  zeros = torch.zeros_like(IR_impI)
  loss = torch.max(zeros, 1 + IR_impR - IR_gt) + torch.max(zeros, 1 + IR_impI - IR_gt)
  loss = loss.mean(0)
  return loss

class EMAMeter:
  def __init__(self, decay=0.95):
    self.decay = decay
    self.value = None

  def update(self, value):
    if self.value is None:
      self.value = value
    else:
      self.value = self.value * self.decay + value * (1 - self.decay)

def classification_loss(predictions, labels, gpu):
  num_labels = labels.numel()
  if gpu:
    predictions = predictions.cuda()
    labels = labels.cuda()

  predictions = torch.reshape(predictions, (-1,))
  labels = torch.reshape(labels, (-1,))

  indices_to_use = (labels > -.5) == True
  loss = nn.BCEWithLogitsLoss()
  output = loss(predictions[indices_to_use], labels[indices_to_use])
  return output

def train_epoch(epoch, optim, model, train_loader, w, gpu):
  model.train()
  loss_meter = EMAMeter(0.6)
  for i, (images, text, labels) in enumerate(train_loader):
    if gpu:
      images = images.cuda()
      text = text.cuda()
    optim.zero_grad()
    image_emb, text_emb, predictions = model(images, text)

    loss_1 = sampled_margin_ranking_loss(image_emb, text_emb)
    loss_2 = classification_loss(predictions, labels, gpu)
    #print("loss values: ", loss_1, loss_2)
    loss = loss_1 * torch.tensor(w).expand_as(loss_1) + (loss_2 * torch.tensor(00).expand_as(loss_2))
    loss.backward()
    optim.step()

    loss = float(loss.cpu())
    loss_meter.update(loss)
    if i % 10 == 0:
      print("Epoch %d. Step %d / %d. Loss %.3f" % (epoch, i, len(train_loader), loss_meter.value))
      # NOTE: DEBUG:
      # break

def save_model(expdir, epoch, optim, model, validation_loss, best_validation_loss, w, is_best=False):
  ckpt = os.path.join(expdir, "model.pth")
  best = os.path.join(expdir, "model.best.pth")
  torch.save({
    "model": model.state_dict(),
    "optim": optim.state_dict(),
    "epoch": epoch,
    "loss": validation_loss,
    "best_loss": best_validation_loss,
  }, ckpt)
  if is_best:
    if os.path.exists(best):
      os.unlink(best)
    os.link(ckpt, best)

def read_file(path):
  with open(path, 'rb') as f:
    return f.read()

class MIMICCXRDataset(Dataset):
  def __init__(self, train=False, valid_train=False):
    self.train = train
    self.valid_train = valid_train
    # Load all of the text into memory
    # Pre-compute TF-IDF or whatever other features as a sparse matrix

    if train:
      reports_path = 'data/reports_train'
      images_path = 'data/images_train'
      labels_path = 'data/labels_train.npy'
    else:
      reports_path = 'data/reports_test'
      images_path = 'data/images_test'
      labels_path = 'data/labels_test.npy'

    reports_list = os.listdir(reports_path)
    self.reports = [
      {
        "exid": int(filename.split("_")[0]),
        "text": read_file(os.path.join(reports_path, filename)).decode("utf8")
      }
      for filename in sorted(reports_list, key=lambda x: int(x.split("_")[0]))]

    images_list = os.listdir(images_path)
    self.images = [
      {
        "exid": int(filename.split("_")[0]),
        "file": os.path.join(images_path, filename)
      }
      for filename in sorted(images_list, key=lambda x: int(x.split("_")[0]))]

    self.labels = np.load(labels_path, allow_pickle=True, encoding='bytes')

    image_ids = set([img['exid'] for img in self.images])
    report_ids = set([rep['exid'] for rep in self.reports])
    self.indices = image_ids.intersection(report_ids)
    print(len(self.indices))
    self.reports_map = {}
    self.images_map = {}
    for i, report in enumerate(self.reports):
      if report['exid'] in self.indices:
        self.reports_map[report['exid']] = i
    for i, image in enumerate(self.images):
      if image['exid'] in self.indices:
        self.images_map[image['exid']] = i

    self.indices = sorted(self.indices)

    if not train:
      random.seed(42)
      random.shuffle(self.indices)
      self.indices = self.indices[:4500]

    self.vectorizer = pickle.loads(read_file('vectorizer.pickle'))

  def __len__(self):
    if self.train == True:
      return len(self.indices)
    if self.valid_train == True:
      return 3500
    return 1000

  def __getitem__(self, index):
    # Load image_i into a 3 x 224 x 224 pytorch tensor (use torchvision transformations to crop)
    # Load the row of the sparse matrix of text vectors, convert to a dense vector, text_i as
    #   a torch tensor
    if self.train:
      new_index = 0 + index
    else:
      if self.valid_train:
        new_index = 0 + index
      else:
        new_index = 3500 + index

    report = self.reports[self.reports_map[self.indices[new_index]]]
    image = self.images[self.images_map[self.indices[new_index]]]

    report_vec = torch.from_numpy(self.vectorizer.transform([report['text']]).todense()[0].astype(np.float32))[0]
    image_orig = imread(image['file'])
    image_orig = np.expand_dims(image_orig, axis=0)
    image = np.concatenate((image_orig, image_orig, image_orig), axis=0)
    normalize = Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    image_norm = normalize(torch.from_numpy(np.divide(image, np.max(image)).astype(np.float32)))

    if not self.train:
      labels = torch.from_numpy(self.labels[self.indices[new_index],:].astype(np.float32))
    else:
      # not used so it doesnt matter right now TODO: change if doing joint objective
      labels = torch.from_numpy(self.labels[0,:].astype(np.float32))

    return image_norm, report_vec, labels

def validate_model(model, valid_loader, gpu):
  predictions_list = []
  labels_list = []
  for i, (images, reports, labels) in enumerate(valid_loader):
      if gpu:
        images = images.cuda()
      image_emb = model.image_branch(images)
      predictions = model.classification_branch(image_emb)
      predictions_list.append(predictions.cpu().detach())
      labels_list.append(labels)

  predictions = torch.cat(predictions_list, dim=0)
  labels = torch.cat(labels_list, dim=0)

  return classification_loss(predictions, labels, gpu)

def train(train_loader, validation_loader, valid_train_loader, w=1, lr=0.001, epochs=25, batch_size=32, expdir="exp", gpu=False, n_cpu=8):
  # Create experiment directory
  global emb_dims
  expdir = os.path.join(expdir, "lr%e-epochs%d-bs%d-joint-space%d-fixeddata-w%d" % (lr, epochs, batch_size, emb_dims, w))
  os.makedirs(expdir, exist_ok=True)

  # Create your model
  model = Model()
  if gpu:
    model = model.cuda()

  # Create your optimizer
  optim = torch.optim.Adam(model.parameters(), lr=lr)
  #optim = torch.optim.SGD(model.parameters(), lr=lr, weight_decay=5e-7, momentum=0.9)

  model.image_branch.train()
  model.text_branch.train()
  model.classification_branch.train()

  best_validation_loss = 100000000
  for epoch in range(epochs):
    train_epoch(epoch, optim, model, train_loader, w, gpu)
    validation_loss = float(validate_model(model, validation_loader, gpu))
    print("Epoch Validation Classification Loss: ", validation_loss)
    if validation_loss < best_validation_loss:
      save_model(expdir, epoch, optim, model, validation_loss, best_validation_loss, w, is_best=True)
      best_validation_loss = validation_loss
    else:
      save_model(expdir, epoch, optim, model, validation_loss, best_validation_loss, w, is_best=False)

def main():
  # generate_embedding.py lr epochs batch_size gpu n_cpu w

  print("\nSTARTING TRAINING...")

  if sys.argv[4] == 'True':
    gpu = True
  else:
    gpu = False

  train_ds = MIMICCXRDataset(train=True)
  train_loader = DataLoader(train_ds, batch_size=int(sys.argv[3]), shuffle=True, num_workers=int(sys.argv[5]), pin_memory=gpu)
  valid_train_ds = MIMICCXRDataset(train=False, valid_train=True)
  valid_train_loader = DataLoader(valid_train_ds, batch_size=int(sys.argv[3]), shuffle=True, num_workers=int(sys.argv[5]), pin_memory=gpu)
  valid_ds = MIMICCXRDataset(train=False, valid_train=False)
  valid_loader = DataLoader(valid_ds, batch_size=int(sys.argv[3]), shuffle=True, num_workers=int(sys.argv[5]), pin_memory=gpu)

  train(train_loader, valid_loader, valid_train_loader, lr=float(sys.argv[1]), epochs=int(sys.argv[2]), batch_size=int(sys.argv[3]), gpu=gpu, w=int(sys.argv[6]))

if __name__ == '__main__':
  main()


from sklearn.impute import SimpleImputer
from sklearn.metrics import confusion_matrix as cm
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
from sklearn.metrics import (accuracy_score, f1_score, recall_score, precision_score,
                             classification_report, make_scorer, balanced_accuracy_score,
                             precision_recall_curve, mean_squared_error, roc_auc_score,
                             roc_curve, auc, r2_score, mean_absolute_error,
                             average_precision_score, explained_variance_score)
from sklearn.preprocessing import  OneHotEncoder
from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier, OutputCodeClassifier
from sklearn.calibration import CalibratedClassifierCV

from scipy.stats import pearsonr, stats
from scipy.sparse import hstack, vstack
import joblib
from joblib import Parallel, delayed
import os
import numpy as np
import pandas as pd
import re
pd.set_option('display.max_rows', 100000)
pd.set_option('display.max_columns', 100000)
pd.set_option('display.width', 100000)

from .MLOpenWrite import OpenM, Openf
from .MLEstimators import ML
from .MLPlots import ClusT, ROCPR, MPlot
from .MLUtilities import _predict_proba_lr, CrossvalidationSplit, Check_Label, Check_Binar

class Baseinit:
    def __init__(self, arg, log, score= None , MClass=2, Y_name='Group', model='XGB', Type='C', *array, **dicts):
        self.arg = arg
        self.log = log
        self.array = array
        self.score = score
        self.model = model
        self.dicts = dicts
        self.Type  = Type
        self.MClass= MClass
        self.Y_name= Y_name
class Processing(Baseinit):
    def CVSplit(self, Xdf, Ydf, CVt='SSA', random_state = None ):
        all_test = []
        all_split= []
        if self.arg.crossV ==1:
            all_split = [ [range(Xdf.shape[0]), range(Xdf.shape[0])] ]
        else:
            CVS = CrossvalidationSplit(n_splits=self.arg.crossV, test_size=self.arg.testS, CVt=CVt  , n_repeats=2, leavP=self.arg.leavP )
            SFA = CrossvalidationSplit(n_splits=self.arg.crossV, test_size=self.arg.testS, CVt='SFA', n_repeats=2, leavP=self.arg.leavP )
            for train_index, test_index in CVS.split(Xdf, Ydf):
                all_test.extend( test_index )
                all_split.append( [train_index.tolist(), test_index.tolist()])

            if CVt == 'SSA':
                if len(set(all_test))< len(Ydf):
                    all_add = [ [tr.tolist(), te.tolist()] for tr, te in SFA.split(Xdf, Ydf)]
                    all_split += all_add
        return(all_split)

    def Pdecorator(_func):
        def wrapper(self, *args, **kargs):
            if self.Type=='C':
                self.SSS = CrossvalidationSplit(n_splits=9, test_size=self.arg.GStestS, CVt='SSS')
            elif self.Type=='R':
                self.SSS = CrossvalidationSplit(n_splits=3, n_repeats= 3, CVt='RSKF')
            else:
                self.SSS = ''

            if 'Model'in kargs:
                self.model = kargs['Model']
                self.estimator =  ML(self.model, Type=self.Type).GetPara().estimator
                if self.arg.SearchCV:
                    self.parameters = ML(self.model, Type=self.Type, SearchCV=self.arg.SearchCV ).GetPara().parameters
                else:
                    self.parameters = {}
            return _func(self, *args, **kargs)
        return wrapper

    def Hyperparemet(self, X_train, X_test, y_train, y_test):
        self.log.CIF( 'hyperparameter optimization in the %s model......'%self.model )
        if ( self.MClass >2 ) & (self.model in ['XGB']):
            self.estimator = self.estimator.set_params(objective='multi:softprob')

        if self.model in ['XGB']:
            _n_jobs = 20
            if 'scale_pos_weight' in self.parameters.keys():
                pos_weight = y_train.value_counts(normalize=True)
                self.parameters['scale_pos_weight'] += ( (1-pos_weight)/pos_weight ).to_list()
                self.parameters['scale_pos_weight']  = list(set( self.parameters['scale_pos_weight'] ))
        else:
            _n_jobs = self.arg.n_job

        ## add hyperopt Spearmint hyperparameter
        if not self.arg.SearchCV:
            clf = self.estimator
            self.log.CIF( 'decrepate hyperparameter optimization......' )
        elif self.arg.SearchCV == 'GSCV':
            clf = GridSearchCV(self.estimator, self.parameters,
                               n_jobs=_n_jobs,
                               cv=self.SSS,
                               scoring=self.score,
                               error_score = np.nan,
                               return_train_score=True,
                               refit = True)
            self.log.CIF( 'GSCV hyperparameter optimization......')
        elif self.arg.SearchCV == 'RSCV':
            clf = RandomizedSearchCV(self.estimator, self.parameters,
                                     n_jobs=_n_jobs,
                                     cv=self.SSS,
                                     n_iter = self.arg.n_iter,
                                     scoring=self.score,
                                     return_train_score=True,
                                     refit = True,
                                     error_score='raise')
            self.log.CIF( 'RSCV hyperparameter optimization......')

        if self.model in ['XGB_']:
            clf.fit(X_train, y_train,
                    #eval_metric=["error", "logloss"],
                    #eval_set=[(X_train, y_train), (X_test, y_test)],
                    eval_set=[(X_test, y_test)],
                    eval_metric= 'auc',
                    early_stopping_rounds=15,
                    verbose=False)
        else:
            clf.fit(X_train, y_train)

        if hasattr(clf, 'best_estimator_'):
            self.log.CIF( '%s best parameters in %s: \n%s' %(self.model, self.arg.SearchCV, clf.best_estimator_.get_params()) )
            return clf.best_estimator_
        else:
            self.log.CIF( '%s best parameters: \n%s' %(self.model, clf.get_params()) )
            return clf

    def Featurescoef(self, clf, index_=None):
        if self.model in ['MNB','BNB'] :
            importances= np.exp(clf.coef_)
            self.log.CWA('Note: Use coef_ exp values as the feature importance of the estimator %s.'%self.model)
        elif self.model in ['CNB'] :
            if self.MClass ==2:
                importances= np.exp(-clf.feature_log_prob_)[1]
            else:
                importances= np.exp(-clf.feature_log_prob_)
            self.log.CWA('Note: Use feature_log_prob_ negative exp values as the feature importance of the estimator %s.'%self.model)
        elif self.model in ['GNB'] :
            if self.MClass ==2:
                importances= clf.theta_[1]
            else:
                importances= clf.theta_
            self.log.CWA('Note: Use theta_ values as the feature importance of the estimator %s.'%self.model)
        elif self.model in ['MLP'] :
            def collapse(coefs):
                Coefs = coefs[0]
                for b in coefs[1:]:
                    Coefs = Coefs.dot(b)
                return(Coefs/Coefs.sum(0))
            importances = collapse(clf.coefs_).T
            self.log.CWA('Note: Use coefs_ weighted average as the feature importance of the estimator %s.'%self.model)
        elif self.model in ['SVM', 'SVMrbf', 'nuSVMrbf']:
            dot_coef_ = clf.dual_coef_.dot( clf.support_vectors_ )
            importances = (1-np.exp(-dot_coef_)) / (1+np.exp(-dot_coef_))
            self.log.CWA('Note: Use exp dot of support_vectors_ and dual_coef_ values as the feature importance of the estimator %s.'%self.model)
        else:
            for i in ['feature_importances_', 'coef_']:
                try:
                    importances= eval('clf.%s'%i)
                    self.log.CWA('Note: Use %s as the feature importance of the estimator %s.'%(i,self.model))
                    break
                except AttributeError:
                    importances = []
                    self.log.CWA('Note: Cannot find the feature importance attributes of estimator %s.'%i)

        df_import = pd.DataFrame(np.array(importances).T)
        if not df_import.empty :
            df_import.index=index_
            df_import = df_import[(df_import != 0).any(1)]
        return df_import

    def OneHot(self, _clf, _X_Data, _OHE='N'):
        if  self.model in ['GBDT']:
            _X_Trans = _clf.apply(_X_Data)[:,:,0]
        elif self.model in ['XGB', 'RF']:
            _X_Trans = _clf.apply(_X_Data)
        if _OHE == 'N':
            _OHE = OneHotEncoder(categories='auto')
            _OHE.fit(_X_Trans)
        _X_Trans = _OHE.transform( _X_Trans.astype(np.int32) )
        return [_X_Trans, _OHE]

    def GetPredt_C(self, _clf, X_matrix, y_label=None, mclass=False):
        if y_label:
            _clf.fit(X_matrix, y_label)

        _predict = _clf.predict(X_matrix)
        try:
            _proba = _clf.predict_proba(X_matrix)
        except AttributeError:
            _proba = _clf._predict_proba_lr(X_matrix)
            self.log.CWA('Note: LinearSVC, SGB use _predict_proba_lr based on decision_function as predict_proba in GridsearchCV.')
        except:
            _proba = _predict_proba_lr( _clf.decision_function(X_matrix) )
            self.log.CWA('predict_proba use sigmoid transversion based on decision_function!')

        if (mclass & mclass != _proba.shape[1]):
            raise Exception('The columns length of predict probability is wrong!')
        return np.c_[_predict, _proba]

    def GetEvalu_C(self, y_true, y_predict, y_score, name=None):
        y_trueb = Check_Binar(y_true)

        Model_ = pd.Series({
                    'Accuracy'  : accuracy_score(y_true, y_predict),
                    'Accuracy_B': balanced_accuracy_score(y_true, y_predict),
                    'F1_score'  : f1_score(y_true, y_predict),
                    'Precision' : precision_score(y_true, y_predict),
                    'Recall'    : recall_score(y_true, y_predict),
        })
        Model_['Roc_auc'] = round(roc_auc_score(y_trueb, y_score), 6)
        Model_['Precision_A'] = round(average_precision_score( y_trueb, y_score), 6)

        if y_score.shape[1] > 2:
            for i in range(y_score.shape[1]):
                Model_['Roc_auc_' + str(i)] = round(roc_auc_score(y_trueb[:,i], y_score[:, i]), 6)
                Model_['Precision_A_' + str(i)] = round(average_precision_score( y_trueb[:, i], y_score[:, i]), 6)

        #Report = classification_report(y_true=y_true, y_pred=y_predict, output_dict=False)
        Model_.name = name
        return Model_.sort_index()

    def GetSplit(self, trprpr, label=None):
        _m = [re.sub('^Pred','', _i) for _i in trprpr.columns if re.match('Pred', _i)]
        return pd.concat([ self.GetEvalu_C(trprpr['TRUE'],
                                trprpr['Pred'+_j],
                                trprpr[sorted([_n for _n in trprpr.columns if re.search('Prob'+_j, _n)])],
                                name= label + _j)
                                for _j in _m
                        ], axis=1)

    def GetScore_C(self, train_pre, test_pre):
        return pd.concat( (self.GetSplit(train_pre, label='Train'),
                            self.GetSplit(test_pre, label='Test')), axis=1)

    @Pdecorator
    def GetFit_C(self, X_train, X_test, y_train, y_test, Model=None):
        clf_G = self.Hyperparemet(X_train, X_test, y_train, y_test)

        clf_C = CalibratedClassifierCV(clf_G, cv=self.SSS, method=self.arg.calibme)
        clf_C.fit(X_train, y_train)

        try:
            X_ = pd.concat( (X_train, X_test), axis=0)
        except TypeError:
            X_ = vstack( (X_train, X_test) )

        y_ = pd.concat((y_train, y_test), axis=0)

        G_prepro = self.GetPredt_C(clf_G, X_, mclass=self.MClass)
        C_prepro = self.GetPredt_C(clf_C, X_, mclass=self.MClass)

        Pre_Pro = pd.DataFrame( np.c_[y_, G_prepro, C_prepro], index=y_.index)
        Pre_Pro.columns = ['TRUE', 'Pred_%s'%self.model]+ ['%s_Prob_%s'%(x, self.model)  for x in range(self.MClass) ] + \
                                ['Pred_C_%s'%self.model] + ['%s_Prob_C_%s'%(x, self.model) for x in range(self.MClass) ]

        return { 'clf_G':clf_G, 'clf_C':clf_C, 'Pre_Pro' : Pre_Pro }

    def LearNing_C(self, X_train, X_test, y_train, y_test):
        MODEL = self.GetFit_C(X_train, X_test, y_train, y_test, Model = self.arg.model)

        clf_G = MODEL['clf_G']
        clf_C = MODEL['clf_C']
        Pre_Pro = MODEL['Pre_Pro']
        FeaCoef = self.Featurescoef(clf_G, index_=X_train.columns)

        Best_MD = [ {'model': self.arg.model     , 'clf': clf_G, 'features': X_train.columns.tolist() },
                    {'model': 'C_'+self.arg.model, 'clf': clf_C, 'features': X_train.columns.tolist() },]

        if (self.arg.model in ['GBDT', 'XGB', 'RF']) and (self.arg.Addmode !='N'):
            X_train_N, OHE = self.OneHot(clf_G, X_train)
            X_test_N , OHE = self.OneHot(clf_G, X_test, OHE)

            MODEL_A = self.GetFit_C( X_train_N, X_test_N, y_train, y_test, Model= self.arg.Addmode )
            Pre_ProA = MODEL_A['Pre_Pro'].iloc[:,1:]
            Pre_Pro = pd.concat([Pre_Pro, Pre_ProA], axis=1)

            Best_MD +=[ {'model': self.arg.Addmode     , 'clf': MODEL_A['clf_G'], 'leaf': OHE, 'features': X_train.columns.tolist() },
                        {'model': 'C_'+self.arg.Addmode, 'clf': MODEL_A['clf_C'], 'leaf': OHE, 'features': X_train.columns.tolist() },]

        if len(y_test)>2:
            Test_Mel = self.GetScore_C(Pre_Pro.loc[y_train.index], Pre_Pro.loc[y_test.index])
        else:
            Test_Mel = pd.DataFrame()

        return (Pre_Pro.loc[y_test.index], FeaCoef, Test_Mel, Best_MD)

    def Predicting_C(self,Best_Model,  pDFall, _X_names, _Y_name):
        Y_TRUE  = pDFall[_Y_name].to_frame(name= 'TRUE')
        Y_PRED , Y_Eval = [], []
        for _k, _cv in enumerate(Best_Model):
            Y_pred = [Y_TRUE]
            for _i, _m in enumerate(_cv):
                _mod = _m['model']
                clf_ = _m['clf']
                _Xft = _m['features']

                X_Pred = pDFall[_Xft]
                if 'leaf' in _m.keys():
                    leaf = _m['leaf']
                    X_Pred, _ = self.OneHot(_cv[0]['clf'], X_Pred, leaf)

                _prepro  = self.GetPredt_C(clf_, X_Pred, mclass=self.MClass)

                _prepro = pd.DataFrame( _prepro,
                                        index=pDFall.index,
                                        columns = ['Pred_%s'%_mod] + ['%s_Prob_%s'%(x, _mod) for x in range(self.MClass) ]
                                    )
                Y_pred.append(_prepro)

            Y_pred  = pd.concat( Y_pred, axis=1 )
            Y_predv = Y_pred[ ~Y_pred['TRUE'].isna() ]

            self.log.CIF( ('%s %s Model Predicting Parameters'% (_Y_name, self.arg.model)).center(45, '-') )
            if Y_predv.shape[0] > 2:
                Pred_Mel = self.GetSplit(Y_predv, label='Predict')
                self.log.CIF( "%s Modeling evaluation: \n%s" %(self.arg.model, Pred_Mel) )
            else:
                Pred_Mel = pd.DataFrame()
            self.log.CIF( ('Completed %2d%%'% ((_k+1)*100/len(Best_Model))).center(45, '-') )

            Y_PRED.append(Y_pred)
            Y_Eval.append(Pred_Mel)

        return (Y_PRED, Y_Eval)

    def FeatCoeffs(self, All_import, _Y_name, Xg):
        if All_import:
            All_import = pd.concat(All_import, axis=1,sort=False).fillna(0)
            column = sorted(set(All_import.columns))
            All_import = All_import[column]
            for i in column:
                All_import['%s_mean'%i]  = All_import[i].mean(axis=1)
                All_import['%s_std'%i]   = All_import[i].std(axis=1)
                All_import['%s_median'%i]= All_import[i].median(axis=1)
            All_import.sort_values(by=['%s_mean'%i for i in column], ascending=[False]*len(column), inplace=True, axis=0)

            Openf('%s%s_Class_features_importance.xls' %(self.arg.output, _Y_name), (All_import)).openv()
            MPlot('%s%s_Class_Features_importance.lines.pdf' %(self.arg.output, _Y_name)).Feature_Import_line( All_import, self.arg.model, _Y_name )
            MPlot('%s%s_Class_Features_importance.boxI.pdf'  %(self.arg.output, _Y_name)).Feature_Import_box( All_import, Xg, _Y_name, self.arg.model, sort_by_group=False )
            MPlot('%s%s_Class_Features_importance.boxII.pdf' %(self.arg.output, _Y_name)).Feature_Import_box( All_import, Xg, _Y_name, self.arg.model, sort_by_group=True)

    def ModelScore(self, All_evluat, _Y_name, label='Test'):
        if All_evluat:
            All_pvalues = pd.concat(All_evluat,  axis=0)
            Openf('%s%s_Class_%s_metrics_pvalues.xls'%(self.arg.output, _Y_name, label), (All_pvalues), index=True, index_label='Score').openv()

            All_pvalues['Score'] = All_pvalues.index
            MPlot('%s%s_Class_%s_metrics_scores.pdf'%(self.arg.output, _Y_name, label)).EvaluateCV( All_pvalues, 'Score',  All_pvalues.columns.drop('Score'))

    def CVMerge(self, All_test_pd, DFall, _X_names, _Y_name, Xg, label='Test'):
        All_test_ = pd.concat(All_test_pd,axis=0)

        _model = [re.sub('^Pred_','', _i) for _i in All_test_.columns if re.match('Pred_.*', _i)]
        All_Prob_mean = All_test_.filter(regex=("_Prob_")).groupby([All_test_.index]).mean()
        All_Prob_mean.columns +=  '_mean'
        All_Prob_median = All_test_.filter(regex=("_Prob_")).groupby([All_test_.index]).median()
        All_Prob_median.columns += '_median'
        All_Pred =  All_test_.filter(regex=("^TRUE|^Pred_")).groupby([All_test_.index]).apply(lambda x : x.mode(0).loc[0,:])
        All_Pred.columns = [ i + '_mode' if i !='TRUE' else i for i in All_Pred.columns ]

        def pred_(All_Pb_, All_Pred):
            _m = All_Pb_.columns.str.replace('.*_Prob','Prob').drop_duplicates(keep='first')
            for _x in _m:
                All_Pred[_x.replace('Prob','Pred') ] = All_Pb_.filter(regex=_x, axis=1).values.argmax(1)
            return All_Pred

        All_Pred = pred_(All_Prob_mean, All_Pred)
        All_Pred = pred_(All_Prob_median, All_Pred)

        ALL_Result  = pd.concat([All_Pred, All_Prob_mean, All_Prob_median], axis=1)

        Openf('%s%s_Class_%s_detials.xls'%(self.arg.output, _Y_name, label), (All_test_), index=True, index_label='sample').openv()
        Openf('%s%s_Class_%s_summary.xls'%(self.arg.output, _Y_name, label), (ALL_Result), index=True, index_label='sample').openv()
        ClusT('%s%s_Class_%s_Feature.Data_complete.pdf'%(self.arg.output, _Y_name, label) ).Plot_heat( DFall[_X_names], ALL_Result.filter(regex=("^TRUE|^Pred_.*_mean")), Xg, method='complete')
        ClusT('%s%s_Class_%s_Feature.Data_average.pdf' %(self.arg.output, _Y_name, label) ).Plot_heat( DFall[_X_names], ALL_Result.filter(regex=("^TRUE|^Pred_.*_mean")), Xg, method='average')

        ALL_Resultv = ALL_Result[~ ALL_Result['TRUE'].isna()]
        if ALL_Resultv.shape[0] > 2:
            Parallel( n_jobs=-1 )( delayed( _p)
                                    ( ALL_Resultv['TRUE'], ALL_Resultv['Pred_%s_mean'%_m], ALL_Resultv.filter(regex='.*_Prob_%s_mean'%_m, axis=1), _m )
                                    for _m in _model
                                    for _p in [ ROCPR('%s%s_Class_%s_%s_ROC.pdf'%(self.arg.output, _Y_name, label, _m)).ROC_CImport,
                                                ROCPR('%s%s_Class_%s_%s_PR.pdf' %(self.arg.output, _Y_name, label, _m)).PR_CImport]
                                )

            Parallel( n_jobs=-1 )( delayed( _p)
                        ( All_test_pd, _Y_name, _m )
                        for _m in _model
                        for _p in [ ROCPR('%s%s_Class_%s_%s_CVROC.pdf'%(self.arg.output, _Y_name, label, _m)).ROC_EImport,
                                    ROCPR('%s%s_Class_%s_%s_CVPR.pdf' %(self.arg.output, _Y_name, label, _m)).PR_EImport]
                    )

            ROCPR( '%s%s_Class_%s_All_ROC.pdf' % (self.arg.output, _Y_name, label) ).ROC_MImport(ALL_Resultv, _model, _Y_name)
            ROCPR( '%s%s_Class_%s_All_PR.pdf'  % (self.arg.output, _Y_name, label) ).PR_MImport( ALL_Resultv, _model, _Y_name)

            _EvalueA = self.GetSplit(ALL_Resultv.filter(regex='^TRUE|_mean$', axis=1), label=label)
            self.log.CIF( "The final mean evaluation: \n%s" %_EvalueA )

        self.log.CIF( ('Finish %s'% label).center(45, '-') )

    def LearNing_R(self,):
        X_train, X_test, y_train, y_test = self.array
        Y = y_train.name
        clf = GridSearchCV(self.estimator, self.parameters, n_jobs=self.arg.n_job, cv=10,return_train_score =True,iid=True)
        clf.fit(X_train, y_train)
        if 'joblibR' in self.dicts.keys():
            joblib.dump(clf.best_estimator_, '%sRegress_%s_%s_best_estimator.pkl'%(self.arg.outdir,Y,self.model), compress = 1)

        try:
            importances= clf.best_estimator_.feature_importances_
            df_import = pd.DataFrame(np.array(importances).T,columns=[self.model + '_import'],index=X_train.columns)
            #.sort_values(by=[self.model + '_import'],ascending=[False])
        except AttributeError:
            importances= clf.best_estimator_.coef_
            df_import = pd.DataFrame(np.array(importances).T,columns=[self.model + '_import'],index=X_train.columns)
            #.sort_values(by=[self.model + '_import'],ascending=[False])
        except AttributeError:
            importances= clf.best_estimator_.coefs_
            df_import = pd.DataFrame(np.array(importances).T)
            print(df_import)
        except AttributeError:
            print('aaaaaaaaaa')
        df_import = df_import[df_import[self.model + '_import'] != 0]

        #cross_validate cross_val_score cross_val_predict
        score = clf.score(X_test, y_test)
        Y_trapred = clf.predict(X_train)
        Y_tespred = clf.predict(X_test)

        model_metrics_name = [explained_variance_score, mean_absolute_error, mean_squared_error, r2_score]
        tmp_score = [m(y_test, Y_tespred)  for m in model_metrics_name]
        tmp_score.append( pearsonr(y_test, Y_tespred)[0] )

        print(80 * '-')
        print('The parameters of the best model are: ')
        print(self.model, clf.best_params_, clf.best_score_)
        print(self.model, "_weight:", df_import)
        print(self.model, "_test cor:", tmp_score)
        print(self.model, "_test score:", score)
        print(80 * '-')
        return (tmp_score, df_import, Y_tespred)

    def Predict_R(self):
        (Cf_xy, Xa, Yi ) =self.array
        Y = Yi.name
        clf = joblib.load('%sClass_%s_%s_best_estimator.pkl'%(self.arg.outdir,Y,self.model))
        df_import = Openf('%sClass_%s_%s_best_estimator.imp'%(self.arg.outdir,Y,self.model) , index_col='features', index=True).openb()
        X_predict = Cf_xy[df_import.index]
        All_Y_predict = []
        All_Y_predict_pro = []
        for i in range(10):
            Y_predict = clf.predict(X_predict)
            Y_predict_pro    = clf.predict_proba(X_predict)

            if not Yi.isnull().any():
                Y_predict_accuracy  = accuracy_score(Yi, Y_predict)
                Y_predict_R2_score  = r2_score(Yi, Y_predict)
                Y_predict_pro       = clf.predict_proba(X_predict)
                Y_predict_pro_val   = Y_predict_pro[:, 1]
                fpr,tpr,threshold   = roc_curve(Yi, Y_predict_pro_val)
                roc_auc = auc(fpr,tpr)
                metrics_pvalues = [['Model', 'Y_predict_accuracy', 'Y_predict_R2_score', 'roc_auc'],
                                   [self.model , Y_predict_accuracy, Y_predict_R2_score, roc_auc]]
                metrics_pvalues = pd.DataFrame(metrics_pvalues[1:], columns=metrics_pvalues[0])
                ROC_list        = [fpr, tpr, roc_auc, Y_predict_accuracy, self.model]

class Modeling():
    def __init__(self, arg, log, *array, **dicts):
        self.arg = arg
        self.log = log
        self.array = array
        self.dicts = dicts
        self.MClass= 2
        self.arg.output = '%s/03ModelFit/%s'%( self.arg.outdir, self.arg.header )
        os.makedirs(os.path.dirname(self.arg.output), exist_ok=True)

    def Model_X(self, DFall, _X_names, _Y_name, Xg, Type= 'C'):
        self.MClass = DFall[_Y_name].nunique()
        DFall[_Y_name] = Check_Label(DFall[_Y_name])
        CVRlt = Processing( self.arg, self.log, model=self.arg.model, Y_name=_Y_name, MClass= self.MClass, Type = Type )

        All_Test, All_coefs_, All_evluat, All_estmt_ = [], [], [], []
        for _k in range(self.arg.Repeatime):
            CVM   = CVRlt.CVSplit(DFall[_X_names], DFall[_Y_name], CVt = self.arg.CVfit)
            for _n, (train_index, test_index) in enumerate(CVM):
                _Train , _Test   = DFall.iloc[train_index, :], DFall.iloc[test_index, :]
                X_train, y_train = _Train[_X_names], _Train[_Y_name]
                X_test , y_test  = _Test[ _X_names], _Test[_Y_name]

                self.log.CIF( ('%s %s Model Fitting and hyperparametering.'% (_Y_name, self.arg.model)).center(45, '-') )
                _Test, _coefs_, _evluat, _estmt_  = CVRlt.LearNing_C( X_train, X_test, y_train, y_test )

                All_Test.append(_Test)
                All_estmt_.append(_estmt_)

                if not _coefs_.empty:
                    self.log.CIF( "%s Feature coefficiency: \n%s" % (self.arg.model, _coefs_) )
                    All_coefs_.append(_coefs_)
                if not _evluat.empty:
                    self.log.CIF( "%s Modeling evaluation: \n%s" %(self.arg.model, _evluat) )
                    All_evluat.append(_evluat)

                self.log.CIF( ('Modeling has been Completed %2d%%'% ((_k+1)*(_n+1)*100/(self.arg.Repeatime*len(CVM)))).center(45, '-') )

        ### All_Test_predict
        CVRlt.CVMerge( All_Test, DFall, _X_names, _Y_name, Xg, label='Test' )
        ### All_coefs_
        CVRlt.FeatCoeffs(All_coefs_, _Y_name, Xg)
        ### All_evaluate_score_
        CVRlt.ModelScore(All_evluat, _Y_name, label='Test')
        ### All_evaluate_model_
        joblib.dump(All_estmt_, '%s%s_Class_best_estimator.pkl' %(self.arg.output, _Y_name), compress=1)

    def Fitting(self):
        (group, RYa, CYa, Xa, Xg) = OpenM(self.arg, self.log).openg()
        YType  =  group[ (group.Variables.isin( RYa + CYa)) ][['Variables','Type']]

        for Yi,Typi in YType.values:
            if self.arg.pca:
                Fsltfile = '%s/02FeatureSLT/%s%s_Class_Regress_FeatureSLT.PCA.xls' %(self.arg.outdir, self.arg.header, Yi )
            else :
                Fsltfile = '%s/02FeatureSLT/%s%s_Class_Regress_FeatureSLT.Data.xls'%(self.arg.outdir, self.arg.header, Yi )

            DFall = Openf(Fsltfile, index_col=0).openb()
            _Xi   = list( set(DFall.columns)- set([Yi]) )

            self.log.CIF( ('%s: Supervised MODELing'%Yi).center(45, '*') )
            self.log.NIF( '%s Value Counts:\n%s' %(Yi, DFall[Yi].value_counts().to_string()) )
            self.Model_X( DFall, _Xi , Yi, Xg, Type= Typi )
            self.log.CIF( ('%s: Supervised MODELing Finish'%Yi).center(45, '*') )


from typing import List
import collections
import time

class Solution:
    def maxSlidingWindow(self, nums, k):
        ans = []
        queue = []
        for i, v in enumerate(nums):
            if queue and queue[0] <= i - k:
                queue = queue[1:]
            while queue and nums[queue[-1]] < v:
                queue.pop()
            queue.append(i)
            if i + 1 >= k:
                ans.append(nums[queue[0]])
        return ans

def main():
    sol = Solution()
    inputs = [[1,3,-1,-3,5,3,6,7], [1], [1,-1], [9,11], [4,-2]]
    ks = [3, 1, 1, 2, 2]
    outputs = [[3,3,5,5,6,7], [1], [1,-1], [11], [4]]

    for i in range(len(inputs)):
        start = time.time()
        res = sol.maxSlidingWindow(inputs[i], ks[i])
        end = time.time()
        if outputs[i] == res:
            print("true : ", end-start, " sec")
        else:
            print("false : ", end-start, " sec")

if __name__ == "__main__":
    main()


# Understand:
	# Questions:
		# are we allowed to use built in functions? (Yes)
		# can we have a variable that's NULL? (No)
		# can the word have special chars? (No)
		# Implement in loop? (Whichever)

# Match:
	# Loop or recursion

# Pseudocode:
	# clean the input: Lowercase + remove numbers + remove whitespace
	# use pointers one at the end and the front + compare the values

def isPalindrome(word):

	if word == "" or word == None:
		return False

	# Cleaning the word
	newword = word.replace(" ", "").lower()

	# Two pointers
	p1 = 0
	p2 = len(newword)-1

	# Loop
	# for i in range(0, len(newword)/2):
	while p1 < p2:
		if newword[p1] != newword[p2]:
			print(newword)
			return False

		else:
			p1 =+ 1
			p2 =- 1

	print(newword)
	return True

def main():
	word = "dgradh liujhf woehfe"
	print(isPalindrome(word))

if __name__ == '__main__': main()

# Complexity: O(max(n, n, n)) = O(n)