import hashlib
import math
import multiprocessing as mp
import time
from math import pi, sqrt

import cython
import numpy as np
import numpy.typing as npt
from scipy.special import erf, expi

from .mesh import Element
from .quadrature import (DuffyScheme2D, ProductScheme2D,
                         gauss_quadrature_scheme, log_quadrature_scheme)
from .single_layer_exact import (spacetime_evaluated_1,
                                 spacetime_integrated_kernel)

FPI_INV = cython.declare(cython.double)
FPI_INV = (4 * pi)**-1
PI_SQRT = cython.declare(cython.double)
PI_SQRT = math.sqrt(pi)

def kernel(t, x):
    assert isinstance(t, float) and isinstance(x, float)
    if (t <= 0): return 0
    else: return FPI_INV * 1. / t * np.exp(-x**2 / (4 * t))

def alpha(z):
    """ Returns lambda a_z(x) """
    return lambda x: np.sum(x**2, axis=0) / (4 * z)

def noop(x):
    return 0

def g(a, b):
    """ Returns g_z for z = a - b. """
    if a <= b:
        return noop
    z = a - b
    return lambda x: FPI_INV * expi(-np.sum(x**2, axis=0) / (4 * z))

def f(a, b):
    """ Returns f_z for z = a - b"""
    if a <= b:
        return noop
    z = a - b

    def f_z(x_sqr):
        a_z = x_sqr / (4 * z)
        return FPI_INV * (z * np.exp(-a_z) + z * (1 + a_z) * expi(-a_z))

    return f_z

def time_integrated_kernel(t, a, b):
    """ Returns heat kernel G(t-s,x) integrated over s in [a,b]. """
    assert a < b
    g_ta = g(t, a)
    g_tb = g(t, b)
    return lambda x: g_tb(x) - g_ta(x)

def double_time_integrated_kernel(a, b, c, d):
    """ Returns kernel integrated in time over [a,b] x [c, d], """
    assert a < b and c < d

    def G(x):
        x_sqr = np.sum(x**2, axis=0) / 4
        result = 0
        if b > d:
            z = b - d
            result += FPI_INV * (z * np.exp(-x_sqr / z) +
                                 (x_sqr + z) * expi(-x_sqr / z))
        if b > c:
            z = b - c
            result -= FPI_INV * (z * np.exp(-x_sqr / z) +
                                 (x_sqr + z) * expi(-x_sqr / z))
        if a > c:
            z = a - c
            result += FPI_INV * (z * np.exp(-x_sqr / z) +
                                 (x_sqr + z) * expi(-x_sqr / z))
        if a > d:
            z = a - d
            result -= FPI_INV * (z * np.exp(-x_sqr / z) +
                                 (x_sqr + z) * expi(-x_sqr / z))

        return result

    return G

def MP_SL_matrix_col(j: int) -> npt.ArrayLike:
    """ Function to evaluate SL in parallel using the multiprocessing library. """
    global __SL, __elems_test, __elems_trial
    elem_trial = __elems_trial[j]
    col = np.zeros(len(__elems_test))
    for i, elem_test in enumerate(__elems_test):
        if elem_test.time_interval[1] <= elem_trial.time_interval[0]:
            continue
        col[i] = __SL.bilform(elem_trial, elem_test)
    return col

class SingleLayerOperator:
    def __init__(self, mesh, quad_order=12, pw_exact=False, cache_dir=None):
        self.pw_exact = pw_exact
        self.gauss_scheme = gauss_quadrature_scheme(23)
        self.gauss_2d = ProductScheme2D(self.gauss_scheme)
        self.log_scheme = log_quadrature_scheme(quad_order, quad_order)
        self.log_scheme_m = self.log_scheme.mirror()
        self.log_log = ProductScheme2D(self.log_scheme, self.log_scheme)
        self.duff_log_log = DuffyScheme2D(self.log_log, symmetric=False)
        self.mesh = mesh
        self.gamma_len = self.mesh.gamma_space.gamma_length
        self.glue_space = self.mesh.glue_space
        self.cache_dir = cache_dir
        self._init_elems(self.mesh.leaf_elements)

    def _init_elems(self, elems):
        # For all elements in the mesh, register the log scheme.
        for elem in elems:
            a, b = elem.space_interval
            elem.__log_scheme_y = elem.gamma_space(a + (b - a) *
                                                   self.log_scheme.points)
            elem.__log_scheme_m_y = elem.gamma_space(a + (b - a) *
                                                     self.log_scheme_m.points)

    @cython.locals(h_x=cython.double, h_y=cython.double)
    def __integrate(self, f: object, a: float, b: float, c: float,
                    d: float) -> float:
        """ Integrates a symmetric singular f over the square [a,b]x[c,d]. """
        h_x = b - a
        h_y = d - c
        assert h_x > 1e-8 and h_y > 1e-8
        assert (a < b and c < d)
        assert (a, b) <= (c, d)

        # If are the same panel.
        if a == c and b == d:
            return self.duff_log_log.integrate(f, a, b, c, d)

        # If the panels touch in the middle, split into even parts.
        if b == c:
            if abs(h_x - h_y) < 1e-10:
                return self.duff_log_log.mirror_x().integrate(f, a, b, c, d)
            elif h_x > h_y:
                return self.duff_log_log.mirror_x().integrate(
                    f, b - h_y, b, c, d) + self.__integrate(
                        f, a, b - h_y, c, d)
            else:
                return self.duff_log_log.mirror_x().integrate(
                    f, a, b, c, c + h_x) + self.__integrate(
                        f, a, b, c + h_x, d)
        assert not math.isclose(b, c)

        # If the panels touch through in the glued boundary, split into even parts.
        if a == 0 and d == self.gamma_len and self.glue_space:
            assert b < c
            if abs(h_x - h_y) < 1e-10:
                return self.duff_log_log.mirror_y().integrate(f, a, b, c, d)
            elif h_x > h_y:
                return self.duff_log_log.mirror_y().integrate(
                    f, a, a + h_y, c, d) + self.__integrate(
                        f, a + h_y, b, c, d)
            else:
                return self.__integrate(
                    f, a, b, c,
                    d - h_x) + self.duff_log_log.mirror_y().integrate(
                        f, a, b, d - h_x, d)

        # If we are disjoint.  TODO: Do more singular stuff if close?
        # TODO: Gauss 2d for disjoint..
        if b < c:
            #return self.gauss_2d.integrate(f, a, b, c, d)
            if c - b < self.gamma_len - d + a or not self.glue_space:
                return self.log_log.mirror_x().integrate(f, a, b, c, d)
            else:
                return self.log_log.mirror_y().integrate(f, a, b, c, d)

        # If the first panel is longer than the second panel.
        if d < b:
            # TODO: Is this correct?
            return self.__integrate(
                f, a, d, c, d) + self.duff_log_log.mirror_y().integrate(
                    f, d, b, c, d)

        # First panel is contained in second one.
        if a == c:
            assert b < d
            return self.__integrate(f, a, b, c, b) + self.__integrate(
                f, a, b, b, d)
        assert not math.isclose(a, c)

        # We have overlap, split this in two parts.
        assert a < c
        return self.__integrate(f, a, c, c, d) + self.__integrate(
            f, c, b, c, d)

    @cython.locals(a=cython.double,
                   b=cython.double,
                   c=cython.double,
                   d=cython.double)
    def bilform(self, elem_trial: Element, elem_test: Element) -> float:
        """ Evaluates <V 1_trial, 1_test>. """
        # If the test element lies below the trial element, we are done.
        if elem_test.time_interval[1] <= elem_trial.time_interval[0]:
            return 0

        if self.pw_exact and elem_test.gamma_space is elem_trial.gamma_space:
            return spacetime_integrated_kernel(*elem_test.time_interval,
                                               *elem_trial.time_interval,
                                               *elem_test.space_interval,
                                               *elem_trial.space_interval)

        a, b = elem_test.time_interval
        c, d = elem_trial.time_interval

        # Calculate the time integrated kernel.
        G_time = double_time_integrated_kernel(a, b, c, d)

        gamma_test = elem_test.gamma_space
        gamma_trial = elem_trial.gamma_space

        if elem_test.space_interval <= elem_trial.space_interval:
            G_time_parametrized = lambda x: G_time(
                gamma_test(x[0]) - gamma_trial(x[1]))

            return self.__integrate(G_time_parametrized,
                                    *elem_test.space_interval,
                                    *elem_trial.space_interval)
        else:
            # Swap x,y coordinates.
            G_time_parametrized = lambda x: G_time(
                gamma_test(x[1]) - gamma_trial(x[0]))

            return self.__integrate(G_time_parametrized,
                                    *elem_trial.space_interval,
                                    *elem_test.space_interval)

    def bilform_matrix(self, elems_test=None, elems_trial=None, use_mp=False):
        """ Returns the dense matrix <V 1_trial, 1_test>. """
        if elems_test is None:
            elems_test = list(self.mesh.leaf_elements)
        if elems_trial is None:
            elems_trial = elems_test

        N = len(elems_test)
        M = len(elems_trial)

        # For small N, M, simply construct matrix inline and return.
        if N * M < 100:
            mat = np.zeros((N, M))
            for i, elem_test in enumerate(elems_test):
                for j, elem_trial in enumerate(elems_trial):
                    mat[i, j] = self.bilform(elem_trial, elem_test)
            return mat

        if self.cache_dir is not None:
            md5 = hashlib.md5((str(self.mesh.gamma_space) + str(elems_test) +
                               str(elems_trial)).encode()).hexdigest()
            cache_fn = "{}/SL_{}_{}x{}_{}.npy".format(self.cache_dir,
                                                      self.mesh.gamma_space, N,
                                                      M, md5)
            try:
                mat = np.load(cache_fn)
                print("Loaded Single Layer from file {}".format(cache_fn))
                return mat
            except:
                pass

        time_mat_begin = time.time()

        mat = np.zeros((N, M))
        if not use_mp:
            for i, elem_test in enumerate(elems_test):
                for j, elem_trial in enumerate(elems_trial):
                    mat[i, j] = self.bilform(elem_trial, elem_test)
        else:
            # Set up global variables for parallelizing.
            globals()['__elems_test'] = elems_test
            globals()['__elems_trial'] = elems_trial
            globals()['__SL'] = self
            cpu = mp.cpu_count()
            for j, col in enumerate(
                    mp.Pool(mp.cpu_count()).imap(MP_SL_matrix_col, range(M),
                                                 M // (16 * cpu) + 1)):
                mat[:, j] = col

        if self.cache_dir is not None:
            try:
                np.save(cache_fn, mat)
                print("Stored Single Layer to {}".format(cache_fn))
            except:
                pass

        print('Calculating SL matrix took {}s'.format(time.time() -
                                                      time_mat_begin))
        return mat

    def potential(self, elem_trial, t, x):
        """ Evaluates (V 1_trial)(t,x) for t,x not on the bdr. """
        assert x.shape == (2, 1)
        if t <= elem_trial.time_interval[0]: return 0

        # Calculate the time integrated kernel.
        G_time = time_integrated_kernel(t, *elem_trial.time_interval)
        G_time_parametrized = lambda y: G_time(x - elem_trial.gamma_space(y))
        return self.gauss_scheme.integrate(G_time_parametrized,
                                           *elem_trial.space_interval)

    def potential_vector(self, t, x):
        """ Returns the vector (V 1_elem)(t, x) for all elements in mesh. """
        elems = list(self.mesh.leaf_elements)
        N = len(elems)
        vec = np.zeros(shape=N)
        for j, elem_trial in enumerate(elems):
            vec[j] = self.potential(elem_trial, t, x)
        return vec

    @cython.locals(x_a=cython.double,
                   x_b=cython.double,
                   d_a=cython.double,
                   d_b=cython.double,
                   t_a=cython.double,
                   t_b=cython.double)
    def evaluate(self, elem_trial: Element, t: float, x_hat: float,
                 x: npt.ArrayLike) -> float:
        """ Evaluates (V 1_trial)(t, gamma(x_hat)) for t, x_hat in the param domain. """
        if t <= elem_trial.time_interval[0]: return 0
        #if x is None: x = self.mesh.gamma_space.eval(x_hat)
        x_a = elem_trial.space_interval[0]
        x_b = elem_trial.space_interval[1]
        t_a = elem_trial.time_interval[0]
        t_b = elem_trial.time_interval[1]

        # Check if singularity lies in this element.
        if x_a * (1 + 1e-10) <= x_hat <= x_b * (1 - 1e-10):
            # Calculate the time integrated kernel.
            def G_time_parametrized(y_hat: npt.ArrayLike):
                xy = (x - elem_trial.gamma_space(y_hat))**2
                xy = xy[0] + xy[1]
                a, b = elem_trial.time_interval
                if t <= b:
                    return -FPI_INV * expi(-xy / (4 * (t - a)))
                else:
                    return FPI_INV * (expi(-xy / (4 *
                                                  (t - b))) - expi(-xy /
                                                                   (4 *
                                                                    (t - a))))

            return self.log_scheme_m.integrate(
                G_time_parametrized, x_a, x_hat) + self.log_scheme.integrate(
                    G_time_parametrized, x_hat, x_b)

        # Calculate distance of x_hat to both endpoints.
        if self.glue_space:
            d_a = min(abs(x_hat - x_a), abs(self.gamma_len - x_hat + x_a))
            d_b = min(abs(x_hat - x_b), abs(self.gamma_len - x_b + x_hat))
        else:
            d_a = abs(x_hat - x_a)
            d_b = abs(x_hat - x_b)

        # Calculate |x - gamma(yhat)|^2 for the quadrature rule.
        if d_a <= d_b:
            xy_sqr = (x - elem_trial.__log_scheme_y)**2
        else:
            xy_sqr = (x - elem_trial.__log_scheme_m_y)**2
        xy = xy_sqr[0] + xy_sqr[1]

        # Evaluate the time integrated kernel for the above points.
        if t <= t_b:
            vec = -FPI_INV * expi(-xy / (4 * (t - t_a)))
        else:
            vec = FPI_INV * (expi(-xy / (4 * (t - t_b))) - expi(-xy /
                                                                (4 *
                                                                 (t - t_a))))
        # Return the quadrature result.
        return (x_b - x_a) * np.dot(self.log_scheme.weights, vec)

    def evaluate_exact(self, elem_trial: Element, t: float, x: float) -> float:
        """ Evaluates (V 1_trial)(t, x) for elem_trial lying on the
            same pane as x. """
        if t <= elem_trial.time_interval[0]: return 0
        a, b = elem_trial.space_interval
        if x < a or x > b:
            h = min(abs(a - x), abs(b - x))
            k = max(abs(a - x), abs(b - x))
            a, b = elem_trial.time_interval
            if t <= b:
                return -FPI_INV * (PI_SQRT * (2 * sqrt(
                    (t - a))) * (erf(h / (2 * sqrt(
                        (t - a)))) - erf(k / (2 * sqrt(
                            (t - a))))) - h * expi(-(h**2 / (4 * (t - a)))) +
                                   k * expi(-(k**2 / (4 * (t - a)))))
            else:
                return FPI_INV * (
                    2 * PI_SQRT *
                    (sqrt(t - a) *
                     (-erf(h / (2 * sqrt(t - a))) + erf(k /
                                                        (2 * sqrt(t - a)))) +
                     sqrt(t - b) *
                     (erf(h / (2 * sqrt(t - b))) - erf(k /
                                                       (2 * sqrt(t - b))))) +
                    h * expi(h**2 / (4 * (a - t))) - k * expi(k**2 /
                                                              (4 * (a - t))) -
                    h * expi(h**2 / (4 * (b - t))) + k * expi(k**2 /
                                                              (4 * (b - t))))
        elif a < x < b:
            return spacetime_evaluated_1(
                t, *elem_trial.time_interval, x - a) + spacetime_evaluated_1(
                    t, *elem_trial.time_interval, b - x)
        elif x == a or x == b:
            return spacetime_evaluated_1(t, *elem_trial.time_interval, b - a)

    def evaluate_vector(self, t, x_hat):
        """ Returns the vector (V 1_elem)(t, gamma(x_hat)) for all elements in mesh. """
        elems = list(self.mesh.leaf_elements)
        N = len(elems)
        vec = np.zeros(shape=N)
        x = self.mesh.gamma_space.eval(x_hat)
        for j, elem_trial in enumerate(elems):
            vec[j] = self.evaluate(elem_trial, t, x_hat, x)
        return vec

    def rhs_vector(self, f, gauss_order=23):
        """ Returns the vector f(1_elem) for all elements in the mesh. """
        gauss_scheme = gauss_quadrature_scheme(gauss_order)
        gauss_2d = ProductScheme2D(gauss_scheme, gauss_scheme)
        elems = list(self.mesh.leaf_elements)
        N = len(elems)
        vec = np.zeros(shape=N)
        for i, elem_test in enumerate(elems):
            f_param = lambda tx: f(tx[0], elem_test.gamma_space(tx[1]))
            vec[i] = gauss_2d.integrate(f_param, *elem_test.time_interval,
                                        *elem_test.space_interval)
        return vec


from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import socket_wrapper as sw

from socket_wrapper.utils import time_stamp, unzip_folder
from Qt_thread_aux import ClientConnection as cc

# TODO(Jerry): July 24th, 2019
#  Standardize all messages. Right now, the titles are all different.

client = sw.Client()
current_row = -1

class Ui_frmClient(object):
    def __init__(self, frmClientTerminal):
        self.auto_reconn = True

        self.connection = cc.ClientConnectionThread(client)
        self.connection.sig.connect(self.update_messages)

        self.setupUi(frmClientTerminal)
        self.retranslateUi(frmClientTerminal)
        self.clicked_binding(frmClientTerminal)
        self.menu_actions()

    def setupUi(self, frmClientTerminal):
        frmClientTerminal.setObjectName("frmClientTerminal")
        frmClientTerminal.resize(823, 464)
        self.centralwidget = QtWidgets.QWidget(frmClientTerminal)
        self.centralwidget.setObjectName("centralwidget")
        self.layoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.layoutWidget.setGeometry(QtCore.QRect(10, 0, 641, 22))
        self.layoutWidget.setObjectName("layoutWidget")
        self.horizontalLayout_11 = QtWidgets.QHBoxLayout(self.layoutWidget)
        self.horizontalLayout_11.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_11.setObjectName("horizontalLayout_11")
        self.lblListOfConnection = QtWidgets.QLabel(self.layoutWidget)
        font = QtGui.QFont()
        font.setFamily("Myriad Pro")
        font.setPointSize(12)
        self.lblListOfConnection.setFont(font)
        self.lblListOfConnection.setObjectName("lblListOfConnection")
        self.horizontalLayout_11.addWidget(self.lblListOfConnection)
        self.line = QtWidgets.QFrame(self.centralwidget)
        self.line.setGeometry(QtCore.QRect(90, 265, 721, 31))
        self.line.setFrameShape(QtWidgets.QFrame.HLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.layoutWidget_2 = QtWidgets.QWidget(self.centralwidget)
        self.layoutWidget_2.setGeometry(QtCore.QRect(570, 290, 241, 131))
        self.layoutWidget_2.setObjectName("layoutWidget_2")
        self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.layoutWidget_2)
        self.verticalLayout_9.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_9.setObjectName("verticalLayout_9")
        self.btnStartClient = QtWidgets.QPushButton(self.layoutWidget_2)
        font = QtGui.QFont()
        font.setFamily("Myriad Pro")
        font.setPointSize(22)
        self.btnStartClient.setFont(font)
        self.btnStartClient.setAutoFillBackground(False)
        self.btnStartClient.setObjectName("btnStartClient")
        self.verticalLayout_9.addWidget(self.btnStartClient)
        self.verticalLayout_10 = QtWidgets.QVBoxLayout()
        self.verticalLayout_10.setObjectName("verticalLayout_10")
        self.horizontalLayout_12 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_12.setObjectName("horizontalLayout_12")
        self.lblInputIP = QtWidgets.QLabel(self.layoutWidget_2)
        self.lblInputIP.setObjectName("lblInputIP")
        self.horizontalLayout_12.addWidget(self.lblInputIP)
        spacerItem = QtWidgets.QSpacerItem(38, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_12.addItem(spacerItem)
        self.linInputIP = QtWidgets.QLineEdit(self.layoutWidget_2)
        self.linInputIP.setObjectName("linInputIP")
        self.horizontalLayout_12.addWidget(self.linInputIP)
        self.verticalLayout_10.addLayout(self.horizontalLayout_12)
        self.horizontalLayout_13 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_13.setObjectName("horizontalLayout_13")
        self.lblPort = QtWidgets.QLabel(self.layoutWidget_2)
        self.lblPort.setObjectName("lblPort")
        self.horizontalLayout_13.addWidget(self.lblPort)
        spacerItem1 = QtWidgets.QSpacerItem(28, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_13.addItem(spacerItem1)
        self.linPort = QtWidgets.QLineEdit(self.layoutWidget_2)
        self.linPort.setObjectName("linPort")
        self.horizontalLayout_13.addWidget(self.linPort)
        self.verticalLayout_10.addLayout(self.horizontalLayout_13)
        self.verticalLayout_9.addLayout(self.verticalLayout_10)
        self.lblStatusLog = QtWidgets.QLabel(self.centralwidget)
        self.lblStatusLog.setGeometry(QtCore.QRect(10, 265, 101, 21))
        font = QtGui.QFont()
        font.setFamily("Myriad Pro")
        font.setPointSize(12)
        font.setBold(False)
        font.setWeight(50)
        self.lblStatusLog.setFont(font)
        self.lblStatusLog.setObjectName("lblStatusLog")
        self.txtStatusUpdate = QtWidgets.QTextEdit(self.centralwidget)
        self.txtStatusUpdate.setGeometry(QtCore.QRect(10, 290, 541, 131))
        font = QtGui.QFont()
        font.setFamily("Myriad Pro")
        font.setPointSize(10)
        self.txtStatusUpdate.setFont(font)
        self.txtStatusUpdate.setReadOnly(True)
        self.txtStatusUpdate.setObjectName("txtStatusUpdate")
        self.lstTransferredFiles = QtWidgets.QListWidget(self.centralwidget)
        self.lstTransferredFiles.setGeometry(QtCore.QRect(12, 32, 541, 231))
        self.lstTransferredFiles.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.lstTransferredFiles.setObjectName("lstTransferredFiles")
        self.btnUnzip = QtWidgets.QPushButton(self.centralwidget)
        self.btnUnzip.setGeometry(QtCore.QRect(568, 32, 241, 121))
        font = QtGui.QFont()
        font.setFamily("Myriad Pro")
        font.setPointSize(22)
        self.btnUnzip.setFont(font)
        self.btnUnzip.setAutoFillBackground(False)
        self.btnUnzip.setObjectName("btnUnzip")
        self.linOutput = QtWidgets.QLineEdit(self.centralwidget)
        self.linOutput.setGeometry(QtCore.QRect(630, 160, 181, 20))
        self.linOutput.setObjectName("linOutput")
        self.lblOuput = QtWidgets.QLabel(self.centralwidget)
        self.lblOuput.setGeometry(QtCore.QRect(570, 160, 51, 16))
        self.lblOuput.setObjectName("lblOuput")
        self.widget = QtWidgets.QWidget(self.centralwidget)
        self.widget.setGeometry(QtCore.QRect(640, 200, 171, 51))
        self.widget.setObjectName("widget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.lblLocationResults = QtWidgets.QLabel(self.widget)
        self.lblLocationResults.setObjectName("lblLocationResults")
        self.verticalLayout.addWidget(self.lblLocationResults)
        self.lblTimeResults = QtWidgets.QLabel(self.widget)
        self.lblTimeResults.setObjectName("lblTimeResults")
        self.verticalLayout.addWidget(self.lblTimeResults)
        self.widget1 = QtWidgets.QWidget(self.centralwidget)
        self.widget1.setGeometry(QtCore.QRect(570, 200, 58, 51))
        self.widget1.setObjectName("widget1")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget1)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.lblLocation = QtWidgets.QLabel(self.widget1)
        font = QtGui.QFont()
        font.setPointSize(10)
        self.lblLocation.setFont(font)
        self.lblLocation.setObjectName("lblLocation")
        self.verticalLayout_2.addWidget(self.lblLocation)
        self.lblTime = QtWidgets.QLabel(self.widget1)
        font = QtGui.QFont()
        font.setPointSize(10)
        self.lblTime.setFont(font)
        self.lblTime.setObjectName("lblTime")
        self.verticalLayout_2.addWidget(self.lblTime)
        frmClientTerminal.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(frmClientTerminal)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 823, 21))
        self.menubar.setObjectName("menubar")
        self.menuFile = QtWidgets.QMenu(self.menubar)
        self.menuFile.setObjectName("menuFile")
        self.menuSettings = QtWidgets.QMenu(self.menubar)
        self.menuSettings.setObjectName("menuSettings")
        frmClientTerminal.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(frmClientTerminal)
        self.statusbar.setObjectName("statusbar")
        frmClientTerminal.setStatusBar(self.statusbar)
        self.actionAuto_Reconnect = QtWidgets.QAction(frmClientTerminal)
        self.actionAuto_Reconnect.setObjectName("actionAuto_Reconnect")
        self.actionTimeout = QtWidgets.QAction(frmClientTerminal)
        self.actionTimeout.setObjectName("actionTimeout")
        self.actionReconnect_Time = QtWidgets.QAction(frmClientTerminal)
        self.actionReconnect_Time.setObjectName("actionReconnect_Time")
        self.actionHelp = QtWidgets.QAction(frmClientTerminal)
        self.actionHelp.setObjectName("actionHelp")
        self.actionClose = QtWidgets.QAction(frmClientTerminal)
        self.actionClose.setObjectName("actionClose")
        self.actionReset = QtWidgets.QAction(frmClientTerminal)
        self.actionReset.setObjectName("actionReset")
        self.actionSave_Directory = QtWidgets.QAction(frmClientTerminal)
        self.actionSave_Directory.setObjectName("actionSave_Directory")
        self.actionSave_Log = QtWidgets.QAction(frmClientTerminal)
        self.actionSave_Log.setObjectName("actionSave_Log")
        self.actionAuto_Unzip = QtWidgets.QAction(frmClientTerminal)
        self.actionAuto_Unzip.setObjectName("actionAuto_Unzip")
        self.menuFile.addAction(self.actionSave_Log)
        self.menuFile.addAction(self.actionClose)
        self.menuFile.addAction(self.actionReset)
        self.menuFile.addAction(self.actionHelp)
        self.menuSettings.addAction(self.actionAuto_Reconnect)
        self.menuSettings.addAction(self.actionAuto_Unzip)
        self.menuSettings.addAction(self.actionReconnect_Time)
        self.menuSettings.addAction(self.actionTimeout)
        self.menuSettings.addAction(self.actionSave_Directory)
        self.menubar.addAction(self.menuFile.menuAction())
        self.menubar.addAction(self.menuSettings.menuAction())

        self.retranslateUi(frmClientTerminal)
        QtCore.QMetaObject.connectSlotsByName(frmClientTerminal)

    def retranslateUi(self, frmClientTerminal):
        _translate = QtCore.QCoreApplication.translate
        frmClientTerminal.setWindowTitle(_translate("frmClientTerminal", "Client Terminal"))
        self.lblListOfConnection.setText(_translate("frmClientTerminal", "Transferred Files"))
        self.btnStartClient.setText(_translate("frmClientTerminal", "START"))
        self.lblInputIP.setText(_translate("frmClientTerminal", "IP Address"))
        self.linInputIP.setText(_translate("frmClientTerminal", "192.168.1.118"))
        self.lblPort.setText(_translate("frmClientTerminal", "Port Number"))
        self.linPort.setText(_translate("frmClientTerminal", "8000"))
        self.lblStatusLog.setText(_translate("frmClientTerminal", "Status Log:"))
        self.btnUnzip.setText(_translate("frmClientTerminal", "UNPACT"))
        self.lblOuput.setText(_translate("frmClientTerminal", "Output:"))
        self.lblLocationResults.setText(_translate("frmClientTerminal", "None"))
        self.lblTimeResults.setText(_translate("frmClientTerminal", "None"))
        self.lblLocation.setText(_translate("frmClientTerminal", "Location: "))
        self.lblTime.setText(_translate("frmClientTerminal", "Time: "))
        self.menuFile.setTitle(_translate("frmClientTerminal", "File"))
        self.menuSettings.setTitle(_translate("frmClientTerminal", "Settings"))
        self.actionAuto_Reconnect.setText(_translate("frmClientTerminal", "Auto Reconnect"))
        self.actionTimeout.setText(_translate("frmClientTerminal", "Timeout"))
        self.actionReconnect_Time.setText(_translate("frmClientTerminal", "Reconnect Time"))
        self.actionHelp.setText(_translate("frmClientTerminal", "Help"))
        self.actionClose.setText(_translate("frmClientTerminal", "Close"))
        self.actionReset.setText(_translate("frmClientTerminal", "Reset"))
        self.actionSave_Directory.setText(_translate("frmClientTerminal", "Save Location"))
        self.actionSave_Log.setText(_translate("frmClientTerminal", "Save Log"))
        self.actionAuto_Unzip.setText(_translate("frmClientTerminal", "Auto Unzip"))

    def clicked_binding(self, frmClientTerminal):
        frmClientTerminal.closeEvent = self.close_gui
        self.lstTransferredFiles.clicked.connect(self.file_details)
        self.btnStartClient.clicked.connect(self.set_client_for_ui)
        self.btnUnzip.clicked.connect(self.unpack)

    def menu_actions(self):
        self.actionAuto_Reconnect.triggered.connect(self.auto_reconnect)
        self.actionSave_Directory.triggered.connect(self.change_save_location)
        # self.actionReset.triggered.hconnect(partial(self.reset_client, True))

    def auto_reconnect(self):
        box = QtWidgets.QMessageBox()
        box.setText('Do you want the client to auto reconnect?')
        box.setWindowTitle('Set Auto Connect')
        box.setStandardButtons(QtWidgets.QMessageBox.Yes |
                               QtWidgets.QMessageBox.No)
        box.setIcon(QtWidgets.QMessageBox.Question)

        retval = box.exec_()
        if retval == QtWidgets.QMessageBox.Yes:
            self.auto_reconn = True
        else:
            self.auto_reconn = False

    def file_details(self):
        global current_row
        current_row = self.lstTransferredFiles.currentRow()
        details = client.get_list_of_file(current_row)
        self.lblLocationResults.setText(details.get_location())
        self.lblTimeResults.setText(details.get_time())
        self.linOutput.setText('C:/Users/user/Desktop/ZYNC/save/temp/')

    def change_save_location(self):
        dir_name = QtWidgets.QFileDialog.getExistingDirectory(
            None, 'Select a Directory')

        if dir_name:
            self.txtStatusUpdate.append(
                'Save location changed to: ' + dir_name)

    def close_gui(self, e):
        global client

        client = None
        return self.connection.end()

    def update_messages(self):
        global client

        if not self.connection.get_messages():
            return 1
        for message in self.connection.get_messages():
            splt_message = message.split()
            if splt_message[0] == 'RESET':
                self.txtStatusUpdate.append(time_stamp(
                    2, dates=False) + 'Connection Lost')
                self.connection.pause_communication()
                self.set_client_for_ui()
                break
            elif splt_message[0] == 'BUTTON':
                self.btnStartClient.setText(splt_message[1])
                continue
            elif splt_message[0] == 'FILE':
                row = self.lstTransferredFiles.currentRow()
                self.lstTransferredFiles.addItem(splt_message[1])
                continue

            self.txtStatusUpdate.append(message)
        self.connection.set_messages()

    def set_client_for_ui(self):
        global client

        self.txtStatusUpdate.append(sw.time_stamp(
            dates=False) + 'Initializing client, do not close window...')
        try:
            input_ip = self.linInputIP.text()
            input_port = int(self.linPort.text())
            self.connection.set_ip_port(input_ip, input_port)
        except ValueError:
            self.txtStatusUpdate.append(
                sw.time_stamp(dates=False) + 'Error: Bad Input')
            return 1

        self.btnStartClient.setDisabled(True)
        self.btnStartClient.setText('CONNECTING')
        self.linInputIP.setDisabled(True)
        self.linPort.setDisabled(True)

        self.connection.start_connection()
        self.connection.resume_connection()

    def unpack(self):
        if current_row == -1:
            return 1
        self.txtStatusUpdate.append(time_stamp(dates=False) +'Unpacking target')
        output = self.linOutput.text()
        unzip_folder(self.lblLocationResults.text(), output=output)
        self.txtStatusUpdate.append(time_stamp(dates=False) +'Target unpacked')
        return 0

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    ClientTerminal = QtWidgets.QMainWindow()
    ui = Ui_frmClient(ClientTerminal)

    ClientTerminal.show()
    sys.exit(app.exec_())


import requests
import json
import sys
from elasticsearch import Elasticsearch

#Loop to check which node in cluster is the current master
ESMaster=''
masterIndex=0
while ESMaster == '' and masterIndex <= 2:
   ESMasterResponse=requests.get('http://prod-hq-logging-es-master20{}:9200/_cat/master?pretty&h=node'.format(masterIndex))
   ESMaster = ESMasterResponse.text.replace("\n","")
   masterIndex += 1
   print("Master is {}".format(ESMaster))

#Establish connection to ES master node
es = Elasticsearch("http://{}:9200".format(ESMaster))

#Search cluster for indices with non-null values for read-only block
openIndices_request=requests.get('http://{}:9200/_all/_settings/index.blocks.read_only_allow_delete*'.format(ESMaster))
openIndices_json=json.loads(openIndices_request.text)

#If any found with read-only block, list them
trueRoIndices = [x for x in openIndices_json if openIndices_json[x]['settings']['index']['blocks']['read_only_allow_delete'] == 'true']
falseRoIndices = [x for x in openIndices_json if openIndices_json[x]['settings']['index']['blocks']['read_only_allow_delete'] == 'false']

#If none found, report that and end
if len(trueRoIndices) == 0 and len (falseRoIndices) == 0:
   print("No indices detected with non-null values for read-only setting.")

#If one or more found, fix them and report
else:
   if len(trueRoIndices) > 0:
      print("{} read-only indices detected:".format(len(trueRoIndices)))
      print(trueRoIndices)
      for roIndex in trueRoIndices:
         es.indices.put_settings(index=roIndex, body={
         "index.blocks.read_only_allow_delete": None
         })
         print("Removing true read-only flag from {}".format(roIndex))

   if len(falseRoIndices) > 0:
      print("{} indices detected with read-only flag set to false instead of null:".format(len(falseRoIndices)))
      print(falseRoIndices)
      for roIndex in falseRoIndices:
         es.indices.put_settings(index=roIndex, body={
         "index.blocks.read_only_allow_delete": None
         })
         print("Removing false read-only flag from {}".format(roIndex))


"""Advent Of Code #12."""
import heapq as heap

with open("input") as f:
    data = [d.strip() for d in f.readlines()]

for i, line in enumerate(data):
    if "S" in line:
        start = (i, line.index("S"))
        data[i] = data[i].replace("S", "a")
    if "E" in line:
        end = (i, line.index("E"))
        data[i] = data[i].replace("E", "z")

DELTA = [(-1, 0), (1, 0), (0, -1), (0, 1)]  # (dy, dx)

def dijkstra(graph, start, end):
    """Run dijkstras algorithm."""
    visited = set()
    queue = []
    cost = {start: 0}
    heap.heappush(queue, (0, start))

    while queue:
        _, node = heap.heappop(queue)
        if node == end:
            break
        visited.add(node)
        h = graph[node[0]][node[1]]
        weight = 1

        for (dy, dx) in DELTA:
            y = node[0] + dy
            x = node[1] + dx

            if not (0 <= y < len(graph) and 0 <= x < len(graph[0])):
                continue

            if (y, x) in visited:
                continue

            if ord(graph[y][x]) > ord(h) + 1:
                continue

            if (y, x) not in cost or cost[node] + weight < cost[(y, x)]:
                cost[(y, x)] = cost[node] + weight
                heap.heappush(queue, (cost[node], (y, x)))

    if end in cost:
        return cost[end]
    return None

# Part 1
cost = dijkstra(data, start, end)
print("Part 1:", cost)
assert cost == 468

# Part 2
costs = []
for y, row in enumerate(data):
    for x, h in enumerate(row):
        if h == "a":
            costs.append(dijkstra(data, (y, x), end))
min_cost = min(filter(lambda x: x is not None, costs))

print("Part 2:", min_cost)
assert min_cost == 459


# Autor: Hector Fernandes

import requests as r
import sys as s
from datetime import datetime

emojis = {
	'trânsito': '🚚',
	'entregue': '✅',
	'Correios': '🛬',
	'aduaneira': '🚨',
	'exportação': '🛫',
	'erro': '❌',
	'postado': '📦',
	'saiu': '🚀',
	'confirmado' : '💸',
	'pagamento': '💰',
	'indo' : '➡'
}

def get_status(codigo):
	response = r.get('https://proxyapp.correios.com.br/v1/sro-rastro/' + codigo)
	if response.status_code == 200:
		obj = response.json()['objetos'][0]
		if 'mensagem' in obj:
			if "SRO-019: Objeto inválido" in obj['mensagem']:
				return None
		return obj
	else:
		return None

def create_status_string(item):
	unidade = item['unidade']
	if 'nome' in unidade:
		local = unidade['nome']
	else:
		local = unidade['endereco']['cidade'] + '-' + unidade['endereco']['uf']
	if 'unidadeDestino' in item:
		unidadeDestino = item['unidadeDestino']
		if 'nome' in unidadeDestino:
			dest = unidadeDestino['nome']
		else:
			dest = unidadeDestino['endereco']['cidade'] + '-' + unidadeDestino['endereco']['uf']
		return (f'{local} {emojis["indo"]}  {dest}')
	else:
		return (local)

def create_event_string(item):
	date = item['dtHrCriado']
	hour = date[11:16]
	date = date[8:10] + '/' + date[5:7] + '/' + date[0:4]
	desc = item['descricao']
	string = date + ' - ' + hour + ' - ' + desc
	for emoji in emojis:
		if emoji in desc:
			string = emojis[emoji] + ' ' + string
	status_string = create_status_string(item)
	string = string + " | " + status_string
	return string

def print_status(status):
	events = status['eventos']
	for item in events:
		print(create_event_string(item))

def convert_date(date):
	date = date[8:10] + '/' + date[5:7] + '/' + date[0:4] + ' ' + date[11:16]
	date = datetime.strptime(date, '%d/%m/%Y %H:%M')
	return date

def print_all(status):
	last_date = convert_date(status['eventos'][0]['dtHrCriado'])
	status_date = datetime.now() - last_date
	status_date = status_date.days

	if status_date < 2 and status_date != 0:
		status_date = f'Última atualização há {status_date} dia'
		print(f'\n{emojis["postado"]} Cód: {status["codObjeto"]} - {status_date}')
	else:
		status_date = f'Última atualização há {status_date} dias'
		print(f'\n{emojis["postado"]} Cód: {status["codObjeto"]} - {status_date}')

	print_status(status)

def main():

	if len(s.argv) < 2:
		print('Uso: rastreador "<codigo>" ...')
		return

	for i in range(1, len(s.argv)):
		code = s.argv[i]
		status = get_status(code)

		if status is None:
			print(f'\n{emojis["erro"]} Código {code} inválido')
		else:
			print_all(status)

main()


"""동영상을 프레임 단위로 쪼개주는 코드"""
import cv2

vidcap = cv2.VideoCapture(r'C:\Users\kcjer\OneDrive\바탕 화면\1.mp4')

count = 6000

while (vidcap.isOpened()):
    ret, image = vidcap.read()

    if (int(vidcap.get(1)) % 6000 == 0):
        resized_image = cv2.resize(image, (192, 192))
        cv2.imwrite(f"C:/imgcollect/{count}.jpg", resized_image)
        print(count)
        count += 1

vidcap.release()


#!/usr/bin/python3
from sys import argv
if __name__ == "__main__":
    args = len(argv)
    if args == 1:
        print(("0 arguments."))
    else:
        print("{} {}:".format(args - 1,
                              "argument" if args == 2 else "arguments"))
    for i in range(1, args):
        print("{}: {}".format(i, argv[i]))


import os, sys
import unittest

sys.path.insert(0, os.path.abspath('..'))
from client import RequestHandler

class TestRequestHandler(unittest.TestCase):

    def setUp(self):
        global data
        global r
        data = {}
        r = RequestHandler(data)

    def test_get(self):
        data["url"] = "http://localhost:8000/users/"
        t = r.get(url=data["url"], auth=("willian", "1q2w3e4r"))
        self.assertTrue("results" in t)

    def test_post(self):
        data["headers"] = {"content-type": "application/json"}
        data["url"] = "http://192.168.1.4:8080/jsonrpc"
        data["payload"] = {"jsonrpc": "2.0", "id": 1}
        data["payload"]["method"] = "JSONRPC.Ping"

        s = {u'jsonrpc': u'2.0', u'id': 1, u'result': u'pong'}
        t = r.post(data["payload"])
        self.assertEquals(t, s)

        data["payload"]["method"] = "JSONRPC.Version"
        s = {u'jsonrpc': u'2.0', u'id': 1, u'result': {u'version': {u'major': 6,
            u'minor': 14, u'patch': 3}}}
        t = r.post(data["payload"])
        self.assertEquals(t, s)

    if __name__ == "__main__":
        unittest.main()

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 textwidth=80


from scipy import stats
import copy
import time
import pandas as pd
import numpy as np
from scipy import stats

'''
Info:
    - Python slicing
        Example: a[start:stop:step] # start through not past stop, by step (https://stackoverflow.com/questions/509211/understanding-slicing)
    - Label indexing (with hatchet node as zero index)
        hatchet_node = hatchet.node.Node({'name': '<program root>', 'type': 'function'})
        print(hatchet_node)
        print(type(hatchet_node))
        print(df[hatchet_node, 0]) # <- Does not work :(
    - location indexing
        print(df.iloc[0::step_size]) # Get every node's rank 0
        print(df.iloc[1::step_size]) # Get every node's rank 1
        print(df.index.levels[0]) # node
        print(df.index.levels[1]) # rank
'''

def slice_statistics(a_slice, nobs, N_TRAVERSALS):
    '''Computes statistics on a slice (pandas.core.series.Series). Should be a numeric slice so sum can be computed.

    Args:
        a_slice: Slice of pandas dataframe.
        nobs: Number of observations.

    Returns:
        ?
    '''
    num_rows = len(a_slice)
    deep_slice = copy.deepcopy(a_slice)
    t_arr = []
    dt_arr = []
    bt_arr = []
    bdt_arr = []

    # traversals
    for i in range(nobs):
        start = time.time_ns()
        for index, value in a_slice.iteritems():
            value
        end = (time.time_ns() - start)
        adj_metric = (end*N_TRAVERSALS)/(num_rows)
        t_arr.append(adj_metric)

        start = time.time_ns()
        for index, value in deep_slice.iteritems():
            value
        end = (time.time_ns() - start)
        adj_metric = (end*N_TRAVERSALS)/(num_rows)
        dt_arr.append(adj_metric)

    # built-in
    for i in range(nobs):
        start = time.time_ns()
        s_sum = a_slice.sum()
        end = time.time_ns() - start
        adj_metric = (end*N_TRAVERSALS)/(num_rows)
        bt_arr.append(adj_metric)

        start = time.time_ns()
        ds_sum = deep_slice.sum()
        end = time.time_ns() - start
        adj_metric = (end*N_TRAVERSALS)/(num_rows)
        bdt_arr.append(adj_metric)

        assert(s_sum==ds_sum)

    traversal_stats = stats.describe(t_arr)
    dtraversal_stats = stats.describe(dt_arr)
    built_stats = stats.describe(bt_arr)
    dbuilt_stats = stats.describe(bdt_arr)

    return traversal_stats, dtraversal_stats, built_stats, dbuilt_stats

def slicing_tests(df, nobs, X, N_TRAVERSALS, EXTRA_OUT, DEBUG):
    '''
    Args:
        df: A 2-level multi-indexed pandas dataframe.
        nobs: Number of observations.
    '''
    step_size = df.index.levels[1].size # number of elements in the second level (level 0).

    rank_zero_times = df.iloc[0::step_size]['time']
    rzt_stats, drzt_stats, rzt_built_stats, drzt_built_stats = slice_statistics(rank_zero_times, nobs, N_TRAVERSALS)

    rank_one_times = df.iloc[1::step_size]['time']
    rot_stats, drot_stats, rot_built_stats, drot_built_stats = slice_statistics(rank_one_times, nobs, N_TRAVERSALS)

    rank_ten_times = df.iloc[10::step_size]['time']
    rtt_stats, drtt_stats, rtt_built_stats, drtt_built_stats = slice_statistics(rank_ten_times, nobs, N_TRAVERSALS)

    rank_zero_ten_times = df.iloc[0::10]['time']
    rztt_stats, drztt_stats, rztt_built_stats, drztt_built_stats = slice_statistics(rank_ten_times, nobs, N_TRAVERSALS)

    if EXTRA_OUT:
        slices_dic = {"Rank Zero Times": rank_zero_times, "Rank One Times": rank_one_times, "Rank Ten Times": rank_ten_times, "Rank Zero through Ten Times": rank_zero_ten_times}
        for k in slices_dic:
            print(f"--- {k} ---\n{slices_dic[k]}\n")
        if DEBUG: # See the raw statistics.
            stats_list = [rzt_stats, drzt_stats, rzt_built_stats, drzt_built_stats,
                rot_stats, drot_stats, rot_built_stats, drot_built_stats,
                rtt_stats, drtt_stats, rtt_built_stats, drtt_built_stats,
                rztt_stats, drztt_stats, rztt_built_stats, drztt_built_stats]
            for i in stats_list:
                print(i)

    print(f"*Entries are relative time measurements per-{N_TRAVERSALS} element accesses. X={X}. nobs={nobs}.")
    eval_list=[f'Nodes=all, Rank=0 ({len(rank_zero_times)}x1)',
        f'Nodes=all, Rank=1 ({len(rank_one_times)}x1)',
        f'Nodes=all, Rank=10 ({len(rank_ten_times)}x1)',
        f'Nodes=all, Rank=10x ({len(rank_zero_ten_times)}x1)']
    time_data = {"Slice": [rzt_stats, rot_stats, rtt_stats, rztt_stats], "Deep Copy": [drzt_stats, drot_stats, drtt_stats, drztt_stats]}
    built_data = {"Slice": [rzt_built_stats, rot_built_stats, rtt_built_stats, rztt_built_stats], "Deep Copy": [drzt_built_stats, drot_built_stats, drtt_built_stats, drztt_built_stats]}
    X_lambda_func = lambda x: f"{round(x.mean/X)}*X" if (not np.isnan(x.mean)) else x.mean
    df_time = pd.DataFrame(data=time_data, index=eval_list)
    df_time = df_time.applymap(X_lambda_func)
    print(f"Traversal Times\n{df_time}")
    df_built = pd.DataFrame(data=built_data, index=eval_list)
    df_built = df_built.applymap(X_lambda_func)
    print(f"Built-in (Sum)\n{df_built}")


from typing import Optional
from unittest import TestCase

import pytest
from flexmock import flexmock

from ogr import GithubService
from ogr.abstract import AuthMethod
from ogr.exceptions import GithubAPIException
from ogr.services.github.auth_providers.token import TokenAuthentication
from ogr.services.github.auth_providers.tokman import Tokman
from ogr.services.github.check_run import (
    GithubCheckRunOutput,
    create_github_check_run_output,
)
from ogr.services.github.project import GithubProject
from ogr.services.github.pull_request import GithubPullRequest

@pytest.fixture()
def github_project(mock_github_repo):
    github_project = GithubProject(
        repo="test_repo",
        service="test_service",
        namespace="fork_username",
    )
    parent_github_project = GithubProject(
        repo="test_parent_repo",
        service="test_service",
        namespace="test_parent_namespace",
    )
    flexmock(github_project)
    flexmock(parent_github_project)
    flexmock(GithubPullRequest)

    github_project.should_receive("github_repo").and_return(mock_github_repo())
    parent_github_project.should_receive("github_repo").and_return(mock_github_repo())
    github_project.should_receive("parent").and_return(parent_github_project)
    return github_project

@pytest.fixture()
def mock_pull_request():
    def mock_pull_request_factory(id):
        return flexmock(id=id)

    return mock_pull_request_factory

@pytest.fixture()
def mock_github_repo(mock_pull_request):
    def mock_github_repo_factory():
        return flexmock(create_pull=mock_pull_request(42))

    return mock_github_repo_factory

class TestGithubProject:
    @pytest.mark.parametrize(
        "fork_username",
        [
            pytest.param("fork_username", id="fork_username_set"),
            pytest.param(None, id="fork_username_None"),
        ],
    )
    def test_pr_create_is_not_fork(self, github_project, fork_username):
        github_project.should_receive("is_fork").and_return(False)
        GithubPullRequest.should_receive("__init__").and_return()

        head = ":".join(filter(None, [fork_username, "master"]))

        github_project.github_repo.should_call("create_pull").with_args(
            title="test_title",
            body="test_content",
            base="master",
            head=head,
        )
        github_project.parent.github_repo.should_call("create_pull").never()
        github_project.github_repo.should_call("create_pull").once()

        github_project.create_pr(
            title="test_title",
            body="test_content",
            target_branch="master",
            source_branch="master",
            fork_username=fork_username,
        )

    @pytest.mark.parametrize(
        "fork_username",
        [pytest.param("fork_username", id="fork_username_set")],
    )
    def test_pr_create_is_fork(self, github_project, fork_username):
        github_project.should_receive("is_fork").and_return(True)
        GithubPullRequest.should_receive("__init__").and_return()

        github_project.parent.github_repo.should_call("create_pull").with_args(
            title="test_title",
            body="test_content",
            base="master",
            head=f"{github_project}:master",
            fork_username=fork_username,
        )
        github_project.parent.github_repo.should_call("create_pull").never()
        github_project.github_repo.should_call("create_pull").once()

        github_project.create_pr(
            title="test_title",
            body="test_content",
            target_branch="master",
            source_branch="master",
            fork_username=fork_username,
        )

class TestGitHubService(TestCase):
    def test_hostname(self):
        assert GithubService().hostname == "github.com"

@pytest.mark.parametrize(
    ("title", "summary", "text", "expected"),
    [
        (
            "test",
            "test summary",
            None,
            {
                "title": "test",
                "summary": "test summary",
            },
        ),
        (
            "bigger output",
            "no summary",
            "# Random title\n\n- [ ] TODO list\n---\n_italics_",
            {
                "title": "bigger output",
                "summary": "no summary",
                "text": "# Random title\n\n- [ ] TODO list\n---\n_italics_",
            },
        ),
    ],
)
def test_create_github_check_run_output(
    title: str,
    summary: str,
    text: Optional[str],
    expected: GithubCheckRunOutput,
) -> None:
    assert create_github_check_run_output(title, summary, text) == expected

@pytest.fixture()
def github_service_with_multiple_auth_methods():
    return GithubService(
        token="abcdef",
        github_app_id="123",
        github_app_private_key="id_rsa",
        github_app_private_key_path="/path",
        tokman_instance_url="http://tokman:8080",
        github_authentication=None,
    )

def test_multiple_auth_methods_default_is_tokman(
    github_service_with_multiple_auth_methods,
):
    service = github_service_with_multiple_auth_methods
    assert isinstance(service.authentication, Tokman)

def test_set_reset_customized_auth_method(github_service_with_multiple_auth_methods):
    service = github_service_with_multiple_auth_methods
    assert isinstance(service.authentication, Tokman)
    service.set_auth_method(AuthMethod.token)
    assert isinstance(service.authentication, TokenAuthentication)
    service.reset_auth_method()
    assert isinstance(service.authentication, Tokman)

@pytest.fixture()
def github_service_with_one_auth_method():
    return GithubService(
        tokman_instance_url="http://tokman:8080",
        github_authentication=None,
    )

def test_no_multiple_auth_methods_default_is_tokman(
    github_service_with_one_auth_method,
):
    service = github_service_with_one_auth_method
    assert isinstance(service.authentication, Tokman)

def test_no_set_reset_customized_auth_method(github_service_with_one_auth_method):
    service = github_service_with_one_auth_method
    assert isinstance(service.authentication, Tokman)
    with pytest.raises(GithubAPIException):
        service.set_auth_method(AuthMethod.github_app)
    assert isinstance(service.authentication, Tokman)


import torch
import torch.nn as nn
import torch.nn.functional as F
import time
import torchvision
from torchvision import transforms
import numpy as np
import random
import scipy.io as sio
from sklearn.preprocessing import MinMaxScaler

#MNIST precomputed min_max score
# Pre-computed min and max values (after applying GCN) from train data per class
mnist_min_max = [(-0.8826567065619495, 9.001545489292527),
                   (-0.6661464580883915, 20.108062262467364),
                   (-0.7820454743183202, 11.665100841080346),
                   (-0.7645772083211267, 12.895051191467457),
                   (-0.7253923114302238, 12.683235701611533),
                   (-0.7698501867861425, 13.103278415430502),
                   (-0.778418217980696, 10.457837397569108),
                   (-0.7129780970522351, 12.057777597673047),
                   (-0.8280402650205075, 10.581538445782988),
                   (-0.7369959242164307, 10.697039838804978)]

#CIFAR precomputed in min_max sore
cifar_min_max =    [(-28.94083453598571, 13.802961825439636),
                   (-6.681770233365245, 9.158067708230273),
                   (-34.924463588638204, 14.419298165027628),
                   (-10.599172931391799, 11.093187820377565),
                   (-11.945022995801637, 10.628045447867583),
                   (-9.691969487694928, 8.948326776180823),
                   (-9.174940012342555, 13.847014686472365),
                   (-6.876682005899029, 12.282371383343161),
                   (-15.603507135507172, 15.2464923804279),
                   (-6.132882973622672, 8.046098172351265)]

def generate_data(normal_class = 4,
                  transductive= True,
                  flatten = True,
                  GCN = False,
                  resize = None,
                  dataset = "MNIST"):
    if dataset in ["cardio","thyroid","lympho"]:
        return generate_tabular_dataset(dataset = dataset)
    if transductive:
        dataset = generate_transductive_dataset(normal_class = normal_class,
                                                data_dir= '../dataset',
                                                flatten = flatten,
                                                GCN = GCN ,
                                                resize = resize,
                                                dataset= dataset)
        return generate_numpy_data(dataset)
    else:
        trainset, testset = generate_disjoint_dataset(normal_class = normal_class,
                                                      data_dir= '../dataset',
                                                      flatten = flatten,
                                                      GCN = GCN,
                                                      resize= resize,
                                                      dataset =dataset)
        return generate_numpy_data(trainset), generate_numpy_data(testset)

def global_contrast_normalization(x: torch.tensor, scale='l2'):
    """
    Apply global contrast normalization to tensor, i.e. subtract
    mean across features (pixels) and normalize by scale,
    which is either the standard deviation, L1- or L2-norm across
    features (pixels).
    Note this is a *per sample* normalization globally across
    features (and not across the dataset).
    """

    assert scale in ('l1', 'l2')
    n_features = int(np.prod(x.shape))
    mean = torch.mean(x)  # mean over all features (pixels) per sample
    x -= mean
    if scale == 'l1':
        x_scale = torch.mean(torch.abs(x))
    if scale == 'l2':
        x_scale = torch.sqrt(torch.sum(x ** 2)) / n_features
    x /= x_scale
    return x

def get_target_label_idx(labels, targets):
    """
    Get the indices of labels that are included in targets.
    :param labels: array of labels
    :param targets: list/tuple of target labels
    :return: list with indices of target labels
    """
    return np.argwhere(np.isin(labels, targets)).flatten().tolist()

def generate_downsampled_indices(dataset,
                                 normal_class,
                                 down_sample_rate = 0.1):
    targets = torch.tensor(dataset.targets)
    idx = np.arange(len(targets))
    # Get indices to keep
    idx_to_keep = targets[idx]== normal_class
    down_sampled_idx = targets[idx] != normal_class
    # Nomial idex consists only with 1 label
    # Abnormal idx consists of all other labels
    nomial_idx = idx[idx_to_keep]
    abnormal_idx = idx[down_sampled_idx]
    m = nomial_idx.shape[0]
    np.random.seed(4321)
    abnormal_idx = np.random.choice(abnormal_idx,
                                    size= int(down_sample_rate * m),
                                    replace = False)
    overall_idx  = np.append(nomial_idx, abnormal_idx, axis = 0)
    random.seed(4321)
    random.shuffle(overall_idx)
    return overall_idx

def generate_disjoint_dataset(normal_class,
                              data_dir= 'dataset',
                              flatten = True,
                              GCN = False,
                              resize = None,
                              dataset = "MNIST"):
    if resize != None:
        transform_lst = [transforms.Resize(resize), transforms.ToTensor()]
    else:
        transform_lst = [transforms.ToTensor()]
    if GCN:
        if dataset == "MNIST":
            transform_lst.extend([transforms.Lambda(lambda x: global_contrast_normalization(x, scale='l1')),
                                        transforms.Normalize([mnist_min_max[normal_class][0]],
                                                            [mnist_min_max[normal_class][1] - mnist_min_max[normal_class][0]])])
        elif dataset == "CIFAR10":
            transform_lst.extend([transforms.Lambda(lambda x: global_contrast_normalization(x, scale='l1')),
                                        transforms.Normalize([cifar_min_max[normal_class][0]] * 3,
                                                            [cifar_min_max[normal_class][1] - cifar_min_max[normal_class][0]]*3)])
    if flatten:
        transform_lst.extend([lambda x: x.numpy().flatten()])
    transform = transforms.Compose(transform_lst)
    if dataset == "MNIST":
        train_set = torchvision.datasets.MNIST(data_dir,
                                               train=True,
                                               download=True,
                                               transform = transform)
        test_set = torchvision.datasets.MNIST(data_dir,
                                              train=False,
                                              download=True,
                                              transform = transform)
    elif dataset == "CIFAR10":
        train_set = torchvision.datasets.CIFAR10(data_dir,
                                                 train=True,
                                                 download=True,
                                                 transform = transform)
        test_set = torchvision.datasets.CIFAR10(data_dir,
                                                train=False,
                                                download=True,
                                                transform = transform)
    #Subset the training data
    targets = torch.tensor(train_set.targets)
    idx = get_target_label_idx(targets.clone().data.cpu().numpy(), normal_class)
    #Subset of the sample
    train_set.data = train_set.data[idx]
    train_set.targets = torch.tensor(train_set.targets)[idx]
    test_set.targets = torch.tensor(test_set.targets)
    train_set = relabel_dataset(normal_class, train_set)
    test_set = relabel_dataset(normal_class, test_set)

    return train_set, test_set

def generate_transductive_dataset(normal_class,
                                  data_dir= 'dataset',
                                  flatten = True,
                                  GCN = False ,
                                  resize= None,
                                  dataset = "MNIST"):
    if resize != None:
        transform_lst = [transforms.Resize(resize), transforms.ToTensor()]
    else:
        transform_lst = [transforms.ToTensor()]
    if GCN:
        if dataset == "MNIST":
            transform_lst.extend([transforms.Lambda(lambda x: global_contrast_normalization(x, scale='l1')),
                                        transforms.Normalize([mnist_min_max[normal_class][0]],
                                                            [mnist_min_max[normal_class][1] - mnist_min_max[normal_class][0]])])
        elif dataset == "CIFAR10":
            transform_lst.extend([transforms.Lambda(lambda x: global_contrast_normalization(x, scale='l1')),
                                        transforms.Normalize([cifar_min_max[normal_class][0]] * 3,
                                                            [cifar_min_max[normal_class][1] - cifar_min_max[normal_class][0]]*3)])
    if flatten:
        transform_lst.extend([lambda x: x.numpy().flatten()])
    transform = transforms.Compose(transform_lst)
    if dataset == "MNIST":
        dataset = torchvision.datasets.MNIST(data_dir,
                                             train=True,
                                             download=True,
                                             transform = transform)
    elif dataset == "CIFAR10":
        dataset = torchvision.datasets.CIFAR10(data_dir,
                                               train=True,
                                               download=True,
                                               transform = transform)
    #Downsample the dataset with the normal class
    idx = generate_downsampled_indices(dataset, normal_class)
    #Subset of the sample
    dataset.data = dataset.data[idx]
    dataset.targets = torch.tensor(dataset.targets)[idx]
    #Replacing the label, normal class = 0, abnormal class = 1
    return relabel_dataset(normal_class, dataset)

def relabel_dataset(normal_class, dataset):
    for i in range(len(dataset)):
        if dataset.targets[i] == normal_class:
            dataset.targets[i] = 0
        else:
            dataset.targets[i] = 1
    return dataset

def generate_numpy_data(dataset):
    X = []
    y = []
    for i in range(len(dataset)):
        if type(dataset[i][0]) == np.ndarray:
            X.append(dataset[i][0])
        else:
            X.append(dataset[i][0].detach().cpu().numpy())
        y.append(dataset[i][1])
    return np.array(X), np.array(y)

def generate_tabular_dataset(dataset = "cardio"):
    try:
        data = sio.loadmat('../dataset/tabular/' + dataset + '.mat')
    except:
        print("dataset not found, need to have data in the correct directory")
        return None
    scaler = MinMaxScaler()
    features = data['X']
    scaler.fit(features)
    features = scaler.transform(features)
    labels = data['y']
    count = 0
    for i in labels:
        if i == 1:
            count += 1
    print("percentage of anomaly: %.3f" % (count / labels.shape[0]))
    return features.astype('float32'), labels


import os
from contextlib import contextmanager
from unittest import mock

import pytest

from detect_secrets_server.actions import add_repo
from detect_secrets_server.actions import initialize
from detect_secrets_server.core.usage.parser import ServerParserBuilder
from detect_secrets_server.storage.base import BaseStorage
from testing.factories import metadata_factory
from testing.factories import single_repo_config_factory
from testing.mocks import mock_git_calls
from testing.mocks import SubprocessMock
from testing.util import cache_buster

class TestInitialize:
    def teardown(self):
        cache_buster()

    @staticmethod
    def parse_args(argument_string='', has_s3=False):
        base_argument = (
            'add will_be_mocked --config '
        )
        if has_s3:
            base_argument += '--s3-config examples/s3.yaml '

        with mock.patch(
            'detect_secrets_server.core.usage.s3.should_enable_s3_options',
            return_value=has_s3,
        ):
            return ServerParserBuilder().parse_args(
                (base_argument + argument_string).split()
            )

    def test_no_tracked_repos(self):
        with mock_repos_config({
            'tracked': [],
        }):
            args = self.parse_args()

        assert not initialize(args)

    def test_simple_success(self, mock_rootdir):
        with mock_repos_config({
            'tracked': [
                single_repo_config_factory(
                    'git@github.com:yelp/detect-secrets',
                ),
            ]
        }), mock_repo_class(
            'BaseTrackedRepo'
        ) as repo_class:
            args = self.parse_args(
                '--root-dir {}'.format(mock_rootdir)
            )
            initialize(args)

            kwargs = repo_class.call_args[1]
            assert kwargs['repo'] == 'git@github.com:yelp/detect-secrets'
            assert kwargs['sha'] == ''
            assert kwargs['crontab'] == '0 0 * * *'
            assert kwargs['rootdir'] == mock_rootdir

    @pytest.mark.parametrize(
        'data,expected_repo_class',
        [
            (
                {
                    'is_local_repo': True,
                    'repo': 'examples',
                },
                'LocalTrackedRepo',
            ),
            (
                {
                    'storage': 's3',
                    'repo': 'git@github.com:yelp/detect-secrets',
                },
                'S3TrackedRepo',
            ),
            (
                {
                    'is_local_repo': True,
                    'repo': 'examples',
                    'storage': 's3',
                },
                'S3LocalTrackedRepo',
            ),
        ]
    )
    def test_flags_set_tracked_repo_classes(self, data, expected_repo_class):
        with mock_repos_config({
            'tracked': [
                single_repo_config_factory(
                    **data
                ),
            ]
        }):
            args = self.parse_args(has_s3=data.get('storage') == 's3')

        with mock_repo_class(expected_repo_class) as repo_class:
            initialize(args)
            assert repo_class.called

    def test_repo_config_overrides_defaults(self, mock_rootdir):
        with mock_repos_config({
            'tracked': [
                single_repo_config_factory(
                    'git@github.com:yelp/detect-secrets',
                    plugins={
                        # This checks that CLI overrides config file
                        'HexHighEntropyString': {
                            'hex_limit': 5,
                        },

                        # This checks it overrides default values
                        'Base64HighEntropyString': {
                            'base64_limit': 2,
                        },

                        # This checks for disabling functionality
                        'PrivateKeyDetector': False,
                    },

                    # This checks it overrides CLI (non-plugin)
                    baseline_filename='will_be_overriden',

                    # This checks it overrides default value (non-plugin)
                    exclude_regex='something_here',
                    crontab='* * 4 * *',
                )
            ],
        }):
            args = self.parse_args(
                '--hex-limit 4 '
                '--baseline baseline.file '
                '--root-dir {}'.format(mock_rootdir)
            )

        with mock_repo_class('BaseTrackedRepo') as repo_class:
            initialize(args)

            kwargs = repo_class.call_args[1]
            assert kwargs['repo'] == 'git@github.com:yelp/detect-secrets'
            assert kwargs['sha'] == ''
            assert kwargs['crontab'] == '* * 4 * *'
            # NOTE: This is disabled, since it's `False` above.
            assert 'PrivateKeyDetector' not in kwargs['plugins']
            assert kwargs['plugins']['Base64HighEntropyString']['base64_limit'] == 2.0
            assert kwargs['plugins']['HexHighEntropyString']['hex_limit'] == 4.0
            assert kwargs['rootdir'] == mock_rootdir
            assert kwargs['baseline_filename'] == 'baseline.file'
            assert kwargs['exclude_regex'] == 'something_here'

class TestAddRepo:
    @staticmethod
    def parse_args(argument_string='', has_s3=False):
        with mock.patch(
            'detect_secrets_server.core.usage.s3.should_enable_s3_options',
            return_value=has_s3,
        ):
            return ServerParserBuilder().parse_args(
                argument_string.split()
            )

    def teardown(self):
        cache_buster()

    def test_add_non_local_repo(self, mock_file_operations, mock_rootdir):
        self.add_non_local_repo(mock_rootdir)
        mock_file_operations.write.assert_called_with(
            metadata_factory(
                repo='git@github.com:yelp/detect-secrets',
                sha='mocked_sha',
                json=True,
            ),
        )

    def test_override_meta_tracking_if_already_exists(
        self,
        mock_file_operations,
        mock_rootdir,
    ):
        with mock.patch(
            'detect_secrets_server.storage.file.FileStorage.get_tracked_file_location',

            # This doesn't matter what it is, just that it exists.
            return_value='examples/config.yaml',
        ):
            self.add_non_local_repo(mock_rootdir)

        assert mock_file_operations.write.called

    def add_non_local_repo(self, mock_rootdir):
        repo = 'git@github.com:yelp/detect-secrets'
        directory = '{}/repos/{}'.format(
            mock_rootdir,
            BaseStorage.hash_filename('yelp/detect-secrets'),
        )

        git_calls = [
            SubprocessMock(
                expected_input='git clone {} {} --bare'.format(repo, directory),
            ),
            SubprocessMock(
                expected_input='git rev-parse HEAD',
                mocked_output='mocked_sha',
            ),
        ]

        with mock_git_calls(*git_calls):
            args = self.parse_args('add {} --root-dir {}'.format(repo, mock_rootdir))
            add_repo(args)

    def test_add_local_repo(self, mock_file_operations, mock_rootdir):
        # This just needs to exist; no actual operations will be done to this.
        repo = 'examples'

        git_calls = [
            # repo.update
            SubprocessMock(
                expected_input='git rev-parse HEAD',
                mocked_output='mocked_sha',
            ),
        ]

        with mock_git_calls(*git_calls):
            args = self.parse_args(
                'add {} --baseline .secrets.baseline --local --root-dir {}'.format(
                    repo,
                    mock_rootdir,
                )
            )

            add_repo(args)

        mock_file_operations.write.assert_called_with(
            metadata_factory(
                sha='mocked_sha',
                repo=os.path.abspath(
                    os.path.join(
                        os.path.dirname(__file__),
                        '../../examples',
                    ),
                ),
                baseline_filename='.secrets.baseline',
                json=True,
            ),
        )

    def test_add_s3_backend_repo(self, mock_file_operations, mocked_boto):
        args = self.parse_args(
            'add {} '
            '--local '
            '--storage s3 '
            '--s3-credentials-file examples/aws_credentials.json '
            '--s3-bucket pail'.format('examples'),
            has_s3=True,
        )

        git_calls = [
            # repo.update
            SubprocessMock(
                expected_input='git rev-parse HEAD',
                mocked_output='mocked_sha',
            ),
        ]

        with mock_git_calls(
            *git_calls
        ):
            mocked_boto.list_objects_v2.return_value = {}
            add_repo(args)

@contextmanager
def mock_repos_config(data):
    """Unfortunately, mocking this means that we can't test more than
    one config file at a time. However, all consolidation tests with
    --config-file should have been done in usage_test, so we should
    be OK.
    """
    with mock.patch(
        'detect_secrets_server.core.usage.add.config_file',
        return_value=data,
    ):
        yield

@contextmanager
def mock_repo_class(classname):
    """
    :type classname: str
    """
    with mock.patch(
        'detect_secrets_server.repos.factory.{}'.format(classname),
    ) as repo_class:
        yield repo_class


import os

# function that creates the fibonacci sequence, pulled in main()
def fibonacci_game():
    n1 = 0
    n2 = 1
    count = 0
    lines = int(input("Enter how many lines of fibonacci code you want: "))

# while the counter is less than lines, continue printing the sequence
    while count < lines:
        print(n1)
        nth = n1 + n2
        n1 = n2
        n2 = nth
        count += 1

# function for endgame / retry
def try_again():
    tryagain = str(input("\nDo you want to generate a new fibonacci string? Y/N: "))
    tryagain = tryagain.upper()
    if tryagain == "N":
        exit()
    elif tryagain == "Y":
        main()
    else:
        try_again()

# function for the program that gets run
def main():
    os.system("cls")
    fibonacci_game()
    try_again()

# runs main() function
main()


#### Create Histograms using Numpy library
#import the necessary libraries and load data files

from astropy.table import Table, Column, vstack, MaskedColumn

import matplotlib
import matplotlib.ticker as mtick
import matplotlib.pyplot as plt
import numpy as np

all_tbl = Table.read('./data/all_table.csv', format='csv')

all_tbl['KT_high'].fill_value = -99.9
all_tbl['KT_low'].fill_value = -99.9

all_tbl = all_tbl.filled()

msk_kt = all_tbl['KT_high'] < 0
lo_tbl = all_tbl[msk_kt]
go_tbl = all_tbl[~msk_kt]

#create KT histogram

hist, edges = np.histogram(go_tbl['KT'],bins=7,normed=True)
center = np.array([edges+(12)])
height = hist*21.5
print(type(edges))
print(edges)
print(center)
print(height)
center_2 = np.array([20.57, 42.19, 63.80, 85.42, 128.66, 150.28, 171.9])

x = edges[:-1]

plt.bar(edges[:-1], hist.astype(np.float32)/hist.sum(), width=(edges[1]-edges[0]),
            #align='center',
            bottom=None,
            color='none',alpha=1,edgecolor='black',linewidth=2,linestyle='dashed',
            label='good')
#
plt.show()


import math

import torch

def seq_to_graph(x, stride=None):
    seq_len = x.size(0)
    if stride is None:
        stride = max(math.ceil(math.log(seq_len)), 1)

    src = []
    tgt = []
    for i in range(seq_len):
        num_neighbors = min(stride, seq_len - i)
        src += [i] * num_neighbors
        tgt += [i + k for k in range(num_neighbors)]

    edge_index = torch.tensor([src, tgt], device=x.device, dtype=torch.long)
    return edge_index


from django.shortcuts import render
from django.views.generic.base import TemplateView
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.urls import reverse
from .models import Reservation
from .models import Table

from datetime import datetime
from time import strptime
import re

# Create your views here.
class IndexView(TemplateView):
    template_name = "reservations/index.html"
    confirmation_page = "reservations/confirmation.html"

    def __init__(self):
        self.reservation_concept = Reservation()
        self.reservation_checker = ReservationChecker()
        self.reservation_table = None

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # context['variable'] = self.value
        print('context data called')
        return context

    def validate_email(self, email):
         if re.match("(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email) != None:
             return True
         return False

    def save_reservation(self):
        self.reservation_concept.save()

    def post(self,request,*args,**kwargs):
        #check availability
        context = super().get_context_data(**kwargs)

        if "reservation_check" in request.POST:
            print('this is a check only')
            response_for_customer_options = [ "Our restaurant is closed on this date.",
                                        "Our restaurant has no free tables for this number of guests at the selected time.",
                                        "The selected date and time are available! Please confirm your booking."]

            page_actions = ["request_another_date",
                            "request_another_time",
                            "request_booking_confirmation"]
            self.collect_reservation_data_from_post_request(request)
            self.format_reservation(request)

            datetime_valid = self.future_datetime(self.reservation_concept.start_date_time)

            email_valid = self.validate_email(self.email)
            #print('dt',datetime(self.reservation_concept.start_date_time))

            reservation_table = self.reservation_checker.check_reservation_possible(self.selected_num_people,
                                                                                self.reservation_concept.start_date_time,
                                                                                self.reservation_concept.end_date_time)
            if reservation_table:
                response_for_customer = response_for_customer_options[2]
                page_action = page_actions[2]
            else:
                response_for_customer = response_for_customer_options[1]
                page_action = page_actions[1]

            variable_content = {"response":response_for_customer,
                                "page_action":page_action,
                                "selected_date":self.selected_date,
                                "selected_time_hours":self.selected_time_hours,
                                "selected_time_minutes":self.selected_time_minutes,
                                "selected_num_people":self.selected_num_people,
                                "email":self.email,
                                "email_valid":email_valid,
                                "phone":self.phone,
                                "selected_num_people":self.selected_num_people,
                                "first_name":self.first_name,
                                "last_name":self.last_name,
                                "remark":self.remark}

            return render(request, IndexView.template_name, variable_content)

        elif "reservation_confirmation" in request.POST:
            # check again if all is available
            self.collect_reservation_data_from_post_request(request)
            self.format_reservation(request)
            self.save_reservation()
            return render(request, self.confirmation_page)
        else:
            return render(request, self.template_name)

    def collect_reservation_data_from_post_request(self,request):
        self.selected_date = request.POST.get("date","")
        self.selected_time_hours = request.POST.get("time-hour","12")
        self.selected_time_minutes = request.POST.get("time-minutes","00")
        self.selected_num_people = request.POST.get("people", "2")
        self.email = request.POST.get("email","")
        self.phone = request.POST.get("phone","")
        self.first_name = request.POST.get("first_name","")
        self.last_name = request.POST.get("last_name","")
        self.remark = request.POST.get("remark","")

    def future_datetime(self, rdatetime):
        return rdatetime >= datetime.now()

    def format_reservation(self,request):
        reservation_name = self.first_name + " " + self.last_name
        reservation_day = int(self.selected_date[:2])
        reservation_month = strptime(self.selected_date[3:6],'%b').tm_mon
        reservation_year = int(self.selected_date[7:11])
        reservation_hour = int(self.selected_time_hours)
        reservation_minutes = int(self.selected_time_minutes)

        reservation_start_datetime = datetime(reservation_year,reservation_month,reservation_day, reservation_hour, reservation_minutes)
        reservation_end_datetime = datetime(reservation_year,reservation_month,reservation_day, reservation_hour+3, reservation_minutes)

        reservation_guests = int(self.selected_num_people)
        reservation_special_request = self.remark
        reservation_table = self.reservation_checker.check_reservation_possible(reservation_guests,
                                                                                reservation_start_datetime,
                                                                                reservation_end_datetime)
        print('table in concept:',reservation_table)

        self.reservation_concept = Reservation( name=reservation_name,
                                                num_guests=reservation_guests,
                                                start_date_time=reservation_start_datetime,
                                                end_date_time=reservation_end_datetime,
                                                special_request=reservation_special_request,
                                                table=reservation_table)

        self.reservation_table = reservation_table
        print(self.reservation_concept)

class ReservationChecker:
    def __init__(self):
        pass

    def get_reservations_for_day(self, start_datetime, end_datetime):
        # smarter would be to check for the start time instantly
        # filter range : endtime >=
        try:
            # any reservations that overlap should remain, as their table numbers have to be checked.
            # overlap means:
            # their start datetime falls between start_datetime and end_datetime OR
            # their end datetime falls between start_time and end_time
            # for OR use Q - objects
            reservations1 = Reservation.objects.filter(start_date_time__range=(start_datetime,end_datetime))
        except Reservation.DoesNotExist:
            reservations1 = None

        try:
            reservations2 = Reservation.objects.filter(end_date_time__range=(start_datetime,end_datetime))
        except Reservation.DoesNotExist:
            reservations2 = None

        print('reservations that start in this range:',reservations1)
        print('reservations that end in this range:',reservations2)

        reservations = reservations1 | reservations2

        return reservations

    def filter_time_span(self, reservations, start_time, end_time):
        reservations.filter(start_date_time)
        filtered_reservations = None
        return filtered_reservations

    def check_reservation_possible(self, num_guests, start_date_time, end_date_time):
        # retrieve all reservations for date, so that these tables can be excluded
        #print('checking',start_date_time,end_date_time)
        reservations = self.get_reservations_for_day(start_date_time, end_date_time)
        print('reservations for ',start_date_time,":",reservations)

        try:
            available_tables = set(Table.objects.all())
        except Table.DoesNotExist:
            available_tables = None

        print('all tables:')
        for t in available_tables:
            print(t)

        if reservations and available_tables:
            for r in reservations:
                if r.table:
                    if t in available_tables:
                        available_tables.remove(t)
        else:
            # no reservations yet
            pass

        print('still available:')
        for t in available_tables:
            print(t)

        #with available tables, calculate what's possible
        resulting_table = self.find_exact_table_match(num_guests, available_tables)
        if not resulting_table:
            resulting_table = self.find_larger_table_match(num_guests, available_tables)

        print('result:',resulting_table)

        return resulting_table

    def find_exact_table_match(self, persons, tables):
        # tables = list
        print('guests:',persons,"; received table options:",tables)
        for t in tables:
            if int(t.capacity) == int(persons):
                return t

    def find_larger_table_match(self, persons, tables):
        #print('finding a larger match')
        #print('received these options for iteration: ',tables)
        table_list = [t for t in tables]
        table_list.sort(key=self.sort_by_capacity)
        #print('sorted tables by capacity:',table_list)
        for t in tables:
            #print('iterating... cap:',t.capacity)
            if int(t.capacity) > int(persons):
                return t

    def sort_by_capacity(self,x):
        return x.capacity

class ConfirmationView(TemplateView):
    print('confirmation')


import argparse
from bs4 import BeautifulSoup
import logging
import os
import pandas as pd
from pathlib import Path
import random
import requests
import sys
import time
import tweepy

class Bot:
	def __init__(self):
		auth = tweepy.OAuthHandler(os.environ.get('TWITTER_API_KEY'),
			os.environ.get('TWITTER_API_SECRET_KEY'))

		auth.set_access_token(os.environ.get('TWITTER_API_TOKEN'),
			os.environ.get('TWITTER_API_SECRET_TOKEN'))

		self.api = tweepy.API(auth)

		self.bird_data = pd.read_csv("bird_data/bird_urls.csv")

	def run(self):
		self.verify_credentials()

		while True:
			self.reply_to_mentions()
			logging.info('waiting to check mentions')
			time.sleep(60)

	def reply_to_mentions(self):
		logging.info('reading most recent mention id from file')
		file = open('src/data.txt', 'r')
		since_id = int(file.read())
		file.close()

		logging.info('retrieving mentions')
		new_since_id = since_id

		for tweet in tweepy.Cursor(self.api.mentions_timeline, since_id=since_id).items():
			new_since_id = max(tweet.id, new_since_id)
			if tweet.in_reply_to_status_id is not None:
				continue

			else:
				logging.info(f'replying to mention by {tweet.user.name}')

				if not tweet.user.following:
					tweet.user.follow()

				URL = self.get_random()
				self.send_bird(URL, tweet.id)

		file = open('src/data.txt', 'w')
		file.write(str(new_since_id))
		file.close()

	def send_bird(self, URL, tweet_id):
		page = requests.get(URL)
		soup = BeautifulSoup(page.content, 'html.parser')

		image_sent = False

		try:
			result = soup.find('div',class_="bird-guide-image")
			img_url = result.find('img')['src']
			img = requests.get(img_url)
			file = open('bird_data/bird.jpg', 'wb')
			file.write(img.content)
			file.close()

			image = 'bird_data/bird.jpg'

			tweet_status = self.api.update_with_media(image, status=URL,
				in_reply_to_status_id=tweet_id, auto_populate_reply_metadata=True)

			image_sent = True
			logging.info(f'{Path(URL).stem} image sent')

			os.remove("bird_data/bird.jpg")

		except Exception as e:
			logging.error(e, exc_info=True)
			logging.info(URL + ', problem with bird image')
			image_sent = False

			if (os.path.exists("bird_data/bird.jpg")):
				os.remove("bird_data/bird.jpg")

		if not image_sent:
			return False

		try:
			result = soup.find('div', class_="hide-for-tiny hide-for-small hide-for-medium")
			text = result.text.strip('\t \n')

			if len(text) > 275:
				text = self.trim_text(text)

			self.api.update_status(status=text, in_reply_to_status_id=tweet_status.id)

			logging.info(f'{Path(URL).stem} text sent')

		except Exception as e:
			logging.error(e, exc_info=True)
			logging.info(URL + ', problem with bird text')

	def trim_text(self, text):
		logging.info(f'text too long: {len(text)}')
		text = text.split(".")
		text.pop()
		while len('.'.join(text) + '.') > 275:
			text.pop()
		text = '.'.join(text)
		text = text + '.'

		logging.info(f'text trimmed to {len(text)}')

		return text

	def get_random(self):
		logging.info('picking a random bird')

		number = random.randint(0, self.bird_data.shape[0])

		URL = self.bird_data['BIRD URLs'][number]
		logging.info(f'{Path(URL).stem} picked')
		return URL

	def verify_credentials(self):
		try:
			self.api.verify_credentials()
			logging.info("All clear")

		except Exception as e:
			logging.error(e, exc_info=True)
			logging.info("error during authentication")

def prep_log(debug,console):
	log_format = '%(asctime)s %(funcName)s()_%(lineno)s %(levelname)s: %(message)s'
	date_format = '%m/%d/%Y %I:%M:%S %p'

	logger = logging.getLogger()
	logger.setLevel(logging.DEBUG)
	formatter = logging.Formatter(log_format, datefmt=date_format)
	if console:
		console_handler = logging.StreamHandler(sys.stdout)
		console_handler.setLevel(logging.DEBUG if debug else logging.INFO)
		console_handler.setFormatter(formatter)
		logger.addHandler(console_handler)

	file_handler = logging.FileHandler('logs/log.log')
	file_handler.setLevel(logging.INFO)
	file_handler.setFormatter(formatter)
	logger.addHandler(file_handler)

def setup():
	parser = argparse.ArgumentParser()
	parser.add_argument("-d", "--debug", help="DEBUG MODE", action="store_true")
	parser.add_argument("-c", "--console", help="LOG TO CONSOLE", action="store_true")
	argv = parser.parse_args()

	prep_log(argv.debug, argv.console)

if __name__ == "__main__":
	setup()
	bird = Bot()
	bird.run()


# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html

import re
from bs4 import BeautifulSoup
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import IntegrityError
from scrapy.exceptions import DropItem

from models import Base, Product, BranchProduct

class ProductPipeline(object):
    def __init__(self):
        self.engine = create_engine('sqlite:///db.sqlite')
        Session = sessionmaker(bind=self.engine)
        self.session = Session()

    def process_item(self, item, spider):

        if item.get('image_urls') and len(list(item.get('image_urls'))) > 0:
            item['image_urls'] = ','.join([','.join([x['large']['url'], x['small']['url']]) for x in item.get('image_urls')])

        if item.get('barcodes') and len(list(item.get('barcodes'))) > 0:
            item['barcodes'] = self.arrayToString(item.get('barcodes'))

        if item.get('categories') and len(list(item.get('categories'))) > 0:
            item['categories'] = ','.join([ ','.join(list(map(lambda x: x['seo']['text'] , x['hierarchy']))) for x in item.get('categories')])

        item['description'] = self.removeHTML(item['description']).strip().capitalize()
        item['name'] = item['name'].capitalize()
        item['brand'] = item['brand'].capitalize()
        item['package'] = item['package'] if len(re.findall(r"\d", item['package'])) > 0 else 'n/a'

        return self.save(item)

    def save(self, item):
        try:
            product = Product(
                store='Walmart',
                barcodes=item.get('barcodes'),
                sku=str(item.get('sku')),
                brand=item.get('brand'),
                name=item.get('name'),
                description=item.get('description'),
                package=item.get('package'),
                categories=item.get('categories'),
                image_urls=item.get('image_urls'))

            branch = BranchProduct(
                branch=item.get('store'),
                product=product,
                stock=item['stock'],
                price=float(item.get('price')),
            )

            self.session.add(product)
            self.session.commit()
            return item
        except IntegrityError:
            self.session.rollback()
            return None

    def removeHTML(self, text):
        soup = BeautifulSoup(text)
        return soup.get_text()

    def arrayToString(self, item):
        return ','.join([x for x in item])


"""
CS50 pset6 vigenere
A copy of vigenere from pset2 implemented in python
Link to info page: https://docs.cs50.net/2019/x/psets/6/sentimental/vigenere/vigenere.html
Enda McCarthy - 01/03/19.
"""

import cs50
import sys

def main():
    invalidkey = "Usage: ./vigenere keyword"
    if len(sys.argv) != 2 or sys.argv[1].isalpha() != True:
        print(invalidkey)
        # error handling
        sys.exit(1)

    # creates list to store numeric values (0-26) of each keyword character
    kNum = []
    for i in sys.argv[1]:
        if i.isupper():
            kNum.append(ord(i) - 65)
        else:
            kNum.append(ord(i) - 97)

    p = cs50.get_string("plaintext:  ")
    print("ciphertext: ", end="")

    # n is a counter which ensures that the keyword is not affected by non-alpha characters
    n = 0
    for char in p:
        # loops keyword back to start if end is reached
        if n == len(str(sys.argv[1])):
            n = 0
        if char.isalpha() and char.isupper():
            # modulus is used to wrap around from Z back to A
            num = ((ord(char) - 65 + kNum[n]) % 26) + 65
            n += 1
            print(chr(num), end="")
        elif char.isalpha() and char.islower():
            num = ((ord(char) - 97 + kNum[n]) % 26) + 97
            n += 1
            print(chr(num), end="")
        else:
            print(char, end="")
    print()

# main function called here
if __name__ == "__main__":
    main()


import sublime
import sublime_plugin
from .completion_db import CLASSES

class BrevisCompletions(sublime_plugin.EventListener):
    def __init__(self):
        self.class_completions = [("%s \tBrevis Class" % s, s) for s in CLASSES]

    def on_query_completions(self, view, prefix, locations):
        current_scope = view.scope_name(locations[0]).strip()
        if "string.quoted" in current_scope and "text.html" in current_scope:

            # place search cursor one word back
            cursor = locations[0] - len(prefix) - 1

            # dont start with negative value
            start = max(0, cursor - 250)

            # get part of buffer
            line = view.substr(sublime.Region(start, cursor))

            # split attributes
            parts = line.split('=')

            # is the last typed attribute a class attribute?
            if len(parts) > 1 and parts[-2].strip().endswith("class"):
                return self.class_completions
            else:
                return []
        else:
            return []