import numpy as np
import math
from collections import namedtuple
import matplotlib.pyplot as plt
from spatialmath.base.argcheck import isvector, getvector, isscalar, assertmatrix

def tpoly(q0, qf, t, qd0=0, qdf=0):
    """
    Generate scalar polynomial trajectory

    :param q0: initial value
    :type q0: float
    :param qf: final value
    :type qf: float
    :param t: time
    :type t: float or array_like
    :param qd0: initial velocity, optional
    :type q0: float
    :param qdf: final velocity, optional
    :type q0: float
    :return: trajectory
    :rtype: namedtuple

    - ``tg = lspb(q0, q1, t)`` is a scalar trajectory (Mx1) that varies smoothly
      from ``q0`` to ``qf`` using a quintic polynomial.  The initial and final
      velocity and acceleration are zero. Time ``t`` can be either:

        * an integer scalar, indicating the total number of timesteps

            - Velocity is in units of distance per trajectory step, not per
              second.
            - Acceleration is in units of distance per trajectory step squared,
              *not* per second squared.

        * an array_like, containing the time steps.

            - Results are scaled to units of time.

    - ``tg = lspb(q0, q1, t, qd0, qdf)`` as above but specify the initial and
      final velocity. The initial and final acceleration are zero.

    The return value is a namedtuple (named ``tpoly``) with elements:

        - ``x``  the time coordinate as a numpy ndarray, shape=(M,)
        - ``y``  the position as a numpy ndarray, shape=(M,)
        - ``yd``  the velocity as a numpy ndarray, shape=(M,)
        - ``ydd``  the acceleration as a numpy ndarray, shape=(M,)

    Notes:

        - The time vector T is assumed to be monotonically increasing, and time
        scaling is based on the first and last element.

    References:

    - Robotics, Vision & Control, Chap 3,
      P. Corke, Springer 2011.

    :seealso: :func:`lspb`, :func:`t1plot`, :func:`jtraj`.
    """

    if isinstance(t, int):
        t = np.arange(0, t)
        istime = False
    elif isvector(t):
        t = getvector(t)
        istime = True
    else:
        raise TypeError('bad argument for time, must be int or vector')

    tf = max(t)
    # solve for the polynomial coefficients using least squares
    X = [
            [0,             0,           0,           0,       0,   1],
            [tf ** 5,       tf ** 4,     tf ** 3,     tf ** 2, tf,  1],
            [0,             0,           0,           0,       1,   0],
            [5 * tf ** 4,   4 * tf ** 3, 3 * tf ** 2, 2 * tf,  1,   0],
            [0,             0,           0,           2,       0,   0],
            [20 * tf ** 3, 12 * tf ** 2, 6 * tf,      2,       0,   0]
    ]
    coeffs, resid, rank, s =  np.linalg.lstsq(X, np.r_[q0, qf, qd0, qdf, 0, 0], rcond=None)

    # coefficients of derivatives
    coeffs_d = coeffs[0:5] * np.arange(5, 0, -1)
    coeffs_dd = coeffs_d[0:4] * np.arange(4, 0, -1)

    # evaluate the polynomials
    p = np.polyval(coeffs, t)
    pd = np.polyval(coeffs_d, t)
    pdd = np.polyval(coeffs_dd, t)

    return namedtuple('tpoly', 'x y yd ydd istime')(t, p, pd, pdd, istime)

# -------------------------------------------------------------------------- #

def lspb(q0, qf, t, V=None):
    """
    Scalar trapezoidal trajectory

    :param q0: initial value
    :type q0: float
    :param qf: final value
    :type qf: float
    :param t: time
    :type t: float or array_like
    :param V: velocity of linear segment, optional
    :type V: float
    :return: trajectory
    :rtype: namedtuple

    Computes a trapezoidal trajectory, which has a linear motion segment with
    parabolic blends.

    - ``tg = lspb(q0, qf, t)`` is a scalar trajectory (Mx1) that varies smoothly
      from ``q0`` to ``qf`` in M steps using a constant velocity segment and
      parabolic blends.  Time ``t`` can be either:

        * an integer scalar, indicating the total number of timesteps

            - Velocity is in units of distance per trajectory step, not per
              second.
            - Acceleration is in units of distance per trajectory step squared,
              *not* per second squared.

        * an array_like, containing the time steps.

            - Results are scaled to units of time.

    - ``tg = lspb(q0, q1, t, V)``  as above but specifies the velocity of the
      linear segment which is normally computed automatically.

    The return value is a namedtuple (named ``lspb``) with elements:

        - ``x``  the time coordinate as a numpy ndarray, shape=(M,)
        - ``y``  the position as a numpy ndarray, shape=(M,)
        - ``yd``  the velocity as a numpy ndarray, shape=(M,)
        - ``ydd``  the acceleration as a numpy ndarray, shape=(M,)

    Notes:

    - For some values of V no solution is possible and an error is flagged.
    - The time vector, if given, is assumed to be monotonically increasing, and
      time scaling is based on the first and last element.

    References:

    - Robotics, Vision & Control, Chap 3,
      P. Corke, Springer 2011.

    :seealso: :func:`tpoly`, :func:`t1plot`, :func:`jtraj`.
    """

    if isinstance(t, int):
        t = np.arange(0, t)
        istime = False
    elif isvector(t):
        t = getvector(t)
        istime = True
    else:
        raise TypeError('bad argument for time, must be int or vector')

    tf = max(t)

    if V is None:
        # if velocity not specified, compute it
        V = (qf - q0) / tf * 1.5
    else:
        V = abs(V) * np.sign(qf - q0)
        if abs(V) < (abs(qf - q0) / tf):
            raise ValueError('V too small')
        elif abs(V) > (2 * abs(qf-q0) / tf):
            raise ValueError('V too big')

    if q0 == qf:
        s = np.ones((len(t), len(t))) @ q0
        sd = np.zeros((len(t), len(t)))
        sdd = np.zeros((len(t), len(t)))
        return

    tb = (q0 - qf + V * tf) / V
    a = V / tb

    p = np.zeros((len(t),))
    pd = np.zeros((len(t),))
    pdd = np.zeros((len(t),))

    for i, _t in enumerate(t):

        if _t <= tb:
            # initial blend
            p[i] = q0 + a/2 * _t ** 2
            pd[i] = a * _t
            pdd[i] = a
        elif _t <= (tf - tb):
            # linear motion
            p[i] = (qf + q0 - V * tf) / 2 + V * _t
            pd[i] = V
            pdd[i] = 0
        else:
            # final blend
            p[i] = qf - a / 2 * tf ** 2 + a * tf * _t - a / 2 * _t ** 2
            pd[i] = a * tf - a * _t
            pdd[i] = -a

    return namedtuple('lspb', 'x y yd ydd xblend istime')(t, p, pd, pdd, tb, istime)

# -------------------------------------------------------------------------- #

def  jtraj(q0, qf, tv, qd0=None, qd1=None):
    """
    Compute a joint-space trajectory

    :param q0: initial joint coordinate
    :type q0: N-element array_like
    :param qf: final joint coordinate
    :type qf: N-element array_like
    :param tv: time vector or number of steps
    :type tv: array_like or int
    :param qd0: initial velocity, defaults to zero
    :type qd0: N-element array_like, optional
    :param qd1: final velocity, defaults to zero
    :type qd1: N-element array_like, optional
    :return: trajectory of coordinates and optionally velocity and acceleration
    :rtype: namedtuple

    - ``tg = jtraj(q0, qf, M)`` is a joint space trajectory where the joint
      coordinates vary from ``q0`` (N) to ``qf`` (N).  A quintic (5th order)
      polynomial is used with default zero boundary conditions for velocity and
      acceleration.
      Time is assumed to vary from 0 to 1 in ``M`` steps.

    - ``tg = jtraj(q0, qf, M, qd0, qdf)`` as above but also specifies initial
      ``qd0`` (N) and final ``qdf`` (N) joint velocity for the trajectory.

    - ``tg = jtraj(q0, qf, tv)``, as above but the number of steps in the
      trajectory is defined by the length of the time vector ``tv`` (M).

    - ``tg = jtraj(q0, qf, tv, qd0, qdf)`` as above but specifies initial and
      final joint velocity for the trajectory and a time vector.

    The return value is a namedtuple (named ``jtraj``) with elements:

        - ``t``  the time coordinate as a numpy ndarray, shape=(M,)
        - ``q``  the position as a numpy ndarray, shape=(M,N)
        - ``qd``  the velocity as a numpy ndarray, shape=(M,N)
        - ``qdd``  the acceleration as a numpy ndarray, shape=(M,N)

    Notes:

    - When a time vector is provided the velocity and acceleration outputs
      are scaled assuming that the time vector starts at zero and increases
      linearly.

    :seealso: :func:`ctraj`, :func:`qplot`, :func:`~SerialLink.jtraj`
    """
    # print(f"  --- jtraj: {q0} --> {q1} in {tv}")
    if isinstance(tv, int):
        tscal = 1.0
        t = np.linspace(0, 1, tv) # normalized time from 0 -> 1
    else:
        tscal = max(tv)
        t = tv.flatten() / tscal

    q0 = getvector(q0)
    qf = getvector(qf)
    assert len(q0) == len(qf), 'q0 and q1 must be same size'

    if qd0 is None:
        qd0 = np.zeros(q0.shape)
    else:
        qd0 = getvector(qd0)
        assert len(qd0) == len(q0), 'qd0 has wrong size'
    if qd1 is None:
        qd1 = np.zeros(q0.shape)
    else:
        qd0 = getvector(qd0)
        assert len(qd1) == len(q0), 'qd1 has wrong size'

    # compute the polynomial coefficients
    A =   6 * (qf - q0) - 3 * (qd1 + qd0) * tscal
    B = -15 * (qf - q0) + (8 * qd0 + 7 * qd1) * tscal
    C =  10 * (qf - q0) - (6 * qd0 + 4 * qd1) * tscal
    E =       qd0 * tscal #  as the t vector has been normalized
    F =       q0

    n = len(q0)

    tt = np.array([t**5, t**4, t**3, t**2, t, np.ones(t.shape)]).T
    coeffs = np.array([A, B, C, np.zeros(A.shape), E, F])

    qt = tt @ coeffs

    # compute  velocity
    coeffs = np.array([np.zeros(A.shape), 5 * A, 4 * B, 3 * C, np.zeros(A.shape), E])
    qdt = tt @ coeffs / tscal

    # compute  acceleration
    coeffs = np.array([np.zeros(A.shape), np.zeros(A.shape), 20 * A, 12 * B, 6 * C, np.zeros(A.shape)])
    qddt = tt @ coeffs / tscal ** 2

    return namedtuple('jtraj', 't q qd qdd')(tt, qt, qdt, qddt)

def t1plot(tg, block=True):
    """
    Plot 1D trajectories

    :param tg: the trajectory to plot
    :type tg: namedtuple

    Plot the position, velocity and acceleration contained in the namedtuple
    ``tg``.

    :seealso: :func:`~tpoly`, :func:`~lspb`
    """

    plotargs = {'markersize': 3}
    textargs = {'fontsize': 12}

    fig = plt.figure()
    ax = plt.subplot(3, 1, 1)

    # plot position
    if type(tg).__name__ == 'tpoly':
        ax.plot(tg.x, tg.y, '-o', **plotargs);

    elif type(tg).__name__ == 'lspb':
            # accel phase
            tf = tg.x[-1]
            k = tg.x <= tg.xblend
            ax.plot(tg.x[k], tg.y[k], 'ro-', **plotargs)

            # coast phase
            k = (tg.x > tg.xblend) & (tg.x <= (tf-tg.xblend))
            ax.plot(tg.x[k], tg.y[k], 'bo-', **plotargs)
            k = np.where(k)[0][0]
            ax.plot(tg.x[k-1:k+1], tg.y[k-1:k+1], 'b-', **plotargs)

            # decel phase
            k = tg.x > (tf - tg.xblend)
            ax.plot(tg.x[k], tg.y[k], 'go-', **plotargs)
            k = np.where(k)[0][0]
            ax.plot(tg.x[k-1:k+1], tg.y[k-1:k+1], 'g-', **plotargs)

            ax.grid(True)
    else:
        raise TypeError('unknown 1D trajectory tuple')

    ax.grid(True)

    if tg.istime:
        ax.set_ylabel('$s(t)$', **textargs)
    else:
        ax.set_ylabel('$s(k)$', **textargs)

    # plot velocity
    ax = plt.subplot(3, 1, 2)
    ax.plot(tg.x, tg.yd, '-o', **plotargs);
    ax.grid(True)

    if tg.istime:
        ax.set_ylabel('$ds/dt$', **textargs)
    else:
        ax.set_ylabel('$ds/dk$', **textargs)

    # plot acceleration
    ax = plt.subplot(3, 1, 3)
    ax.plot(tg.x, tg.ydd, '-o', **plotargs);
    ax.grid(True)
    if tg.istime:
        ax.set_ylabel('$ds^2/dt^2$', **textargs)
        ax.set_xlabel('t (seconds)')
    else:
        ax.set_ylabel('$ds^2/dk^2$', **textargs)
        ax.set_xlabel('k (step))')

    plt.show(block=block)

def qplot(q, t=None, block=True):
    """
    Plot robot joint angles

    :param q: joint angle trajectory
    :type q: numpy ndarray, shape=(M,N)
    :param t: time vector, optional
    :type t: numpy ndarray, shape=(M,)

    This is a convenience function to plot joint angle trajectories (MxN) for
    an N-axis robot, where each row represents one time step.

    - ``qplot(q)`` plots the joint angles versus row number.  If N==6 a
      conventional 6-axis robot is assumed, and the first three joints are shown
      as solid lines, the last three joints (wrist) are shown as dashed lines.
      A legend is also displayed.

    - ``qplot(q, t)`` as above but displays the joint angle trajectory versus
      time given the time vector T (Mx1).

    :seealso: :func:`jtraj`
    """
    assertmatrix(q)

    if t is None:
        t = np.arange(0, q.shape[0])

    n = q.shape[1]
    fig, ax = plt.subplots()
    if n == 6:
        plt.plot(t, q[:,0:3])
        plt.plot(t, q[:,3:6], '--')
    else:
        plt.plot(t, q)

    ax.legend([f"q{i+1}" for i in range(n)])

    plt.grid(True)
    ax.set_xlabel('Time (s)')
    ax.set_ylabel('Joint coordinates (rad,m)')
    ax.set_xlim(t[0], t[-1])

    plt.show(block=block)

# -------------------------------------------------------------------------- #

def ctraj(T0, T1, s):
    """
    Cartesian trajectory between two poses

    :param T0: initial pose
    :type T0: SE3
    :param T1: final pose
    :type T1: SE3
    :return T0: smooth path from ``T0`` to ``T1``
    :rtype: SE3

    ``ctraj(T0, T1, n)`` is a Cartesian trajectory from SE3 pose ``T0`` to ``T1``
    with ``n`` points that follow a trapezoidal velocity profile along the path.
    The Cartesian trajectory is an SE3 instance containing ``n`` values.

    ``ctraj(T0, T1, s)`` as above but the elements of ``s`` specify the
    fractional distance  along the path, and these values are in the range [0 1].
    The i'th point corresponds to a distance ``s[i]`` along the path.

    Examples::

        >>> tg = ctraj(SE3.Rand(), SE3.Rand(), 20)
        >>> len(tg)
        20

    Notes:

    - In the second case ``s`` could be generated by a scalar trajectory generator
      such as ``tpoly`` or ``lspb`` (default).
    - Orientation interpolation is performed using unit-quaternion interpolation.

    Reference:

    - Robotics, Vision & Control, Sec 3.1.5,
      Peter Corke, Springer 2011

    :seealso: :func:`~roboticstoolbox.trajectory.lspb`, :func:`~spatialmath.unitquaternion.interp`
    """

    if isinstance(s, int):
        s = lspb(0, 1, s).y
    elif isvector(s):
        s = getvector(s)
    else:
        raise TypeError('bad argument for time, must be int or vector')

    return T1.interp(s, start=T0)

def cmstraj():
    pass

# -------------------------------------------------------------------------- #

def mstraj(viapoints, dt, tacc, qdmax=None, tsegment=None, q0=None, qd0=None, qdf=None, verbose=False):
    """
    Multi-segment multi-axis trajectory

    :param viapoints: A set of viapoints, one per row
    :type viapoints: numpy.ndarray
    :param dt: time step
    :type dt: float (seconds)
    :param tacc: acceleration time (seconds)
    :type tacc: float
    :param qdmax: maximum speed, defaults to None
    :type qdmax: array_like or float, optional
    :param tsegment: maximum time of each motion segment (seconds), defaults to None
    :type tsegment: array_like, optional
    :param q0: initial coordinates, defaults to first row of viapoints
    :type q0: array_like, optional
    :param qd0: inital  velocity, defaults to zero
    :type qd0: array_like, optional
    :param qdf: final  velocity, defaults to zero
    :type qdf: array_like, optional
    :param verbose: print debug information, defaults to False
    :type verbose: bool, optional
    :return: trajectory plus extra info
    :rtype: namedtuple

    Computes a trajectory for N axes moving smoothly through a set of viapoints.
    The motion comprises M segments:

    - The initial coordinates are the first row of ``viapoints`` or ``q0`` if
      provided.
    - The final coordinates are the last row of ``viapoints``
    - Each segment is linear motion and polynomial blends connect the viapoints.
    - All joints arrive at each via point at the same time, ie. the motion is
      coordinated across axes

    The time of the segments can be specified in two different ways:

    #. In terms of segment time where ``tsegment`` is an array of segment times
       which is the number of via points minus one::

            ``traj = mstraj(viapoints, dt, tacc, tsegment=TS)``

    #. Governed by the speed of the slowest axis for the segment.  The axis
       speed is a scalar (all axes have the same speed) or an N-vector of speed
       per axis::

            ``traj = mstraj(viapoints, dt, tacc, qdmax=SPEED)``

    The return value is a namedtuple (named ``mstraj``) with elements:

        - ``t``  the time coordinate as a numpy ndarray, shape=(K,)
        - ``q``  the axis values as a numpy ndarray, shape=(K,N)
        - ``arrive`` a list of arrival times for each segment
        - ``info`` a list of named tuples, one per segment that describe the
          slowest axis, segment time,  and time stamp
        - ``via`` the passed set of via points

    The  trajectory proper is (``traj.t``, ``traj.q``).  The trajectory is a
    matrix has one row per time step, and one column per axis.

     Notes:

     - Only one of ``qdmag` or ``tsegment`` can be specified
     - If ``tacc`` is greater than zero then the path smoothly accelerates
       between segments using a polynomial blend.  This means that the the via
       point is not actually reached.
     - The path length K is a function of the number of via
       points and the time or velocity limits that apply.
     - Can be used to create joint space trajectories where each axis is a joint
       coordinate.
     - Can be used to create Cartesian trajectories where the "axes"
       correspond to translation and orientation in RPY or Euler angle form.
     - If ``qdmax`` is a scalar then all axes are assumed to have the same
       maximum speed.

     See also MTRAJ, LSPB, CTRAJ.
    """

    if q0 is None:
        q0 = viapoints[0,:]
        viapoints = viapoints[1:,:]
    else:
        q0 = getvector(q0)
        assert viapoints.shape[1] == len(q0), 'WP and Q0 must have same number of columns'

    ns, nj = viapoints.shape
    Tacc = tacc

    assert not (qdmax is not None and tsegment is not None), 'cannot specify both qdmax and tsegment'
    if qdmax is None:
        assert tsegment is not None, 'tsegment must be given if qdmax is not'
        assert len(tsegment) == ns, 'Length of TSEG does not match number of viapoints'
    if tsegment is None:
        assert qdmax is not None, 'qdmax must be given if tsegment is not'
        if isinstance(qdmax, (int, float)):
            # if qdmax is a scalar assume all axes have the same speed
            qdmax = np.tile(qdmax, (nj,))
        else:
            qdmax = getvector(qdmax)
            assert len(qdmax) == nj, 'Length of QDMAX does not match number of axes'

    if isinstance(Tacc, (int, float)):
        Tacc = np.tile(Tacc, (ns,))
    else:
        assert len(Tacc) == ns, 'Tacc is wrong size'
    if qd0 is None:
        qd0 = np.zeros((nj,))
    else:
        assert len(qd0) == len(q0), 'qd0 is wrong size'
    if qdf is None:
        qdf = np.zeros((nj,))
    else:
        assert len(qdf) == len(q0), 'qdf is wrong size'

    # set the initial conditions
    q_prev = q0;
    qd_prev = qd0;

    clock = 0     # keep track of time
    arrive = np.zeros((ns,))   # record planned time of arrival at via points
    tg = np.zeros((0,nj))
    infolist = []
    info = namedtuple('mstraj_info', 'slowest segtime clock')

    def mrange(start, stop, step):
        """
        mrange(start, stop, step) behaves like MATLAB start:step:stop
        and includes the final value unlike range() or np.arange()
        """
        ret = []
        v = start
        while v <= stop:
            ret.append(v)
            v += step
        return np.r_[ret]

    for seg in range(0, ns):
        q_next = viapoints[seg,:]    # current target

        if verbose:
            print(f"------- segment {seg}: {q_prev} --> {q_next}")

        # set the blend time, just half an interval for the first segment

        tacc = Tacc[seg]

        tacc = math.ceil(tacc / dt) * dt
        tacc2 = math.ceil(tacc / 2 / dt) * dt
        if seg == 0:
            taccx = tacc2
        else:
            taccx = tacc

        # estimate travel time
        #    could better estimate distance travelled during the blend

        dq = q_next - q_prev    # total distance to move this segment

        ## probably should iterate over the next section to get qb right...
        # while 1
        #   qd_next = (qnextnext - qnext)
        #   tb = abs(qd_next - qd) ./ qddmax;
        #   qb = f(tb, max acceleration)
        #   dq = q_next - q_prev - qb
        #   tl = abs(dq) ./ qdmax;

        if qdmax is not None:
            # qdmax is specified, compute slowest axis

            # qb = taccx * qdmax / 2       # distance moved during blend
            tb = taccx

            # convert to time
            tl = abs(dq) / qdmax
            #tl = abs(dq - qb) / qdmax
            tl = np.ceil(tl / dt) * dt

            # find the total time and slowest axis
            tt = tb + tl
            slowest = np.argmax(tt)
            tseg = tt[slowest]

            # best if there is some linear motion component
            if tseg <= 2*tacc:
                tseg = 2 * tacc

        elif tsegment is not None:
            # segment time specified, use that
            tseg = tsegment[seg]
            slowest = math.nan

        infolist.append(info(slowest, tseg, clock))

        # log the planned arrival time
        arrive[seg] = clock + tseg
        if seg > 0:
            arrive[seg] += tacc2

        if verbose:
            print(f"seg {seg}, distance {dq}, slowest axis {slowest}, time required {tseg}")

        ## create the trajectories for this segment

        # linear velocity from qprev to qnext
        qd = dq / tseg

        # add the blend polynomial
        qb = jtraj(q0, q_prev + tacc2 * qd, mrange(0, taccx, dt), qd0=qd_prev, qd1=qd).q
        if verbose:
            print(qb)
        tg = np.vstack([tg, qb[1:,:]])

        clock = clock + taccx     # update the clock

        # add the linear part, from tacc/2+dt to tseg-tacc/2
        for t in mrange(tacc2 + dt, tseg - tacc2, dt):
            s = t / tseg
            q0 = (1 - s) * q_prev + s * q_next       # linear step
            print(t, s, q0)
            tg = np.vstack([tg, q0])
            clock += dt

        q_prev = q_next    # next target becomes previous target
        qd_prev = qd

    # add the final blend
    qb = jtraj(q0, q_next, mrange(0, tacc2, dt), qd0=qd_prev, qd1=qdf).q
    tg = np.vstack([tg, qb[1:,:]])

    infolist.append(info(None, tseg, clock))

    return namedtuple('mstraj', 't q arrive info via')(dt * np.arange(0, tg.shape[0]), tg, arrive, infolist, viapoints)


from typing import Tuple
from random import randint
from math import gcd, log, floor

class RSA():
    def __init__(self) -> None:
        pass

    def encrypt(self, message, public_key):
        # Unpack Tuple
        exponent, modulus = public_key

        return self._modExp(message, exponent, modulus)

    def decrypt(self, ciphertext, private_key):
        # Unpack Tuple
        private_exponent, prime1, prime2 = private_key

        # Pre-Requisites to use the Chinese Remainder Theorem
        X1 = self._modExp(ciphertext % prime1, private_exponent % (prime1 - 1), prime1)
        X2 = self._modExp(ciphertext % prime2, private_exponent % (prime2 - 1), prime2)

        # Per the Chinese Remainder Theorem, there is an m such that m % prime1 = x1
        # m % prime2 = x2
        # m is our original message (named as such)

        M_1 = (prime1 * prime2) // prime1
        M_2 = (prime1 * prime2) // prime2

        M_1_INV = self._inverse_mod(M_1, prime1)
        M_2_INV = self._inverse_mod(M_2, prime2)

        plaintext = (X1*M_1*M_1_INV + X2*M_2*M_2_INV) % (prime1*prime2)
        return plaintext

    def sign(self, message, private_key):
        # Un-Pack Tuple
        private_exponent, prime1, prime2 = private_key

        # Pre-Requisites to use the Chinese Remainder Theorem
        X1 = self._modExp(message, private_exponent % (prime1 - 1), prime1)
        X2 = self._modExp(message, private_exponent % (prime2 - 1), prime2)

        # Per the Chinese Remainder Theorem, there is an s such that s % prime1 = x1
        # s % prime2 = x2
        # s is our signature

        M_1 = (prime1 * prime2) // prime1
        M_2 = (prime1 * prime2) // prime2

        M_1_INV = self._inverse_mod(M_1, prime1)
        M_2_INV = self._inverse_mod(M_2, prime2)

        signature = (X1*M_1*M_1_INV + X2*M_2*M_2_INV) % (prime1*prime2)

        return (message, signature)

    def verify(self, signed_message, public_key):
        # Unpack Tuples
        message, signature = signed_message
        public_modulus, public_exponent = public_key

        return message == self._modExp(signature, public_exponent, public_modulus)

    def primeTest(self, canidate: int) -> bool:
        """Use the Miller-Rabin Primality Test to see if a number is prime"""
        # For efficiency, we will see if the number is divisible
        # By the first 100 primes
        PRIME_LIST: Tuple[int] = (2, 3, 5, 7, 11,
                                    13, 17, 19, 23,
                                    29, 31, 37, 41,
                                    43, 47, 53, 59,
                                    61, 67, 71, 73,
                                    79, 83, 89, 97,
                                    101, 103, 107, 109, 113,
                                    127, 131, 137, 139, 149,
                                    151, 157, 163, 167, 173,
                                    179, 181, 191, 193, 197,
                                    199, 211, 223, 227, 229,
                                    233, 239, 241, 251, 257,
                                    263, 269, 271, 277, 281,
                                    283, 293, 307, 311, 313,
                                    317, 331, 337, 347, 349,
                                    353, 359, 367, 373, 379,
                                    383, 389, 397, 401, 409,
                                    419, 421, 431, 433, 439,
                                    443, 449, 457, 461, 463,
                                    467, 479, 487, 491, 499,
                                    503, 509, 521, 523, 541)
        if canidate in PRIME_LIST:
            return True
        else:
            for prime in PRIME_LIST:
                if canidate % prime == 0:
                    return False

        # Otherwise, begin the test:

        # Find u,r such that canidate - 1 = (2**u)*r
        u = 0
        while (canidate - 1) % (2 ** (u+1)) == 0:
            u += 1
        r = (canidate - 1) // 2 ** u

        SECURITY_PARAMETER = 100
        for i in range(SECURITY_PARAMETER):
            rand_num = randint(2, canidate - 2)
            iterator = self._modExp(rand_num, r, canidate)
            if iterator == 1 or iterator == canidate - 1:
                return True
            else:
                for j in range(1, u-1):
                    iterator = self._modExp(iterator, 2, canidate)
                    if iterator == 1 and not iterator != canidate - 1:
                        return False

        return True

    def generate_keys(self, p,q) -> Tuple[Tuple[int], int]:
        # Validate p and q are prime
        if not self.primeTest(p) or not self.primeTest(q):
            raise ValueError("One of the arguments is not a prime number.")

        phi_n = (p-1)*(q-1)

        # We will intentionally pick the value of e
        # to be in the form 2^k + 1 for faster
        # encryption
        k_max = floor(log(phi_n - 1))
        k = randint(1, k_max)

        e = (2**k) + 1
        while gcd(e, phi_n) != 1:
            k = randint(1, k_max)
            e = (2**k) + 1

        # Calculate the private key
        # Which is e^-1 mod phi_n
        e_neg1 = self._inverse_mod(e, phi_n)

        return (p*q, e), (e_neg1, p, q) # public_key, private_key

    def _modExp(self, base, power, modulus) -> int:
        """Use the Square and Multiply Algorithm to calculate base^power modulo (modulus)"""

        exponent: bin = bin(power)[2:]

        output = base
        for bit in exponent[1:]:
            output = (output**2) % modulus
            if bit == '1':
                output = (output*base) % modulus

        return output

    def _inverse_mod(self, element, modulus):
        """Compute the multiplicative inverse of element mod modulus"""
        # (The code below is the relevant part of the Extended Euclidean Algorithm)
        v0, element_inverse = 0,1

        remainder_iminus1 = modulus           # Aliases
        remainder = element     # So its value can change in the loop
        while remainder > 1: # We have verified that gcd(element, modulus) = 1. So this will work
            quotient = remainder_iminus1 // remainder
            remainder, remainder_iminus1 = remainder_iminus1 % remainder, remainder
            # Needs to be assigned on one line. Otherwise the new value of remainder will affect the remainder variable
            # Update values of u and v
            v0, element_inverse = element_inverse, v0 - quotient * element_inverse

        return element_inverse

def main() -> None:
    r = RSA()

if __name__ == "__main__":
    main()


class Solution:
    def removeKdigits(self, num: str, k: int) -> str:
        # 给定一个数字序列 ABCDEF,如果数字A大于数字B,则应该删掉A
        # 所以在可以删除的情况下,序列应该是一个非递减序列
        stack = []
        for n in num:
            while k > 0 and stack and stack[-1] > n:
                stack.pop()
                k -= 1
            stack.append(n)
        if k > 0:
            stack = stack[:-k]
        return ''.join(stack).lstrip('0') or '0'


"""
Created on Thu Nov 19 20:34:13 2020

@author: erick
"""
import csv
import numpy as np
from matplotlib import pyplot as plt

filename = 'Copia_de_pulso_eco_tanque.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader)

    #Obteniendo valores  de la primera grafica
    volts1,volts2 = [], []

    for row in reader:
        if row[1] == '':
            continue

        volt1 = float(row[1])
        volts1.append(volt1)

        volt2 = float(row[2])
        volts2.append(volt2)

    h = np.array(volts1)

    x = np.array(volts2)

    def correlacion(h,x):

        #Arreglo de salida de la correlacion
        rc = np.zeros(h.size + x.size - 1 )

        #Señal enviada con zeros al inicio y al final
        cx = np.insert(x,0,np.zeros(h.size - 1)) #zeros al inicio
        cx = np.insert(cx,cx.size,np.zeros(h.size - 1))#zeros al final

        #Ciclos for para calculo de valores
        for n in np.arange(rc.size):
            for j in np.arange(h.size):
                idcx = j + n
                rc[n]= rc[n] + h[j] * cx[idcx]

        return rc

    result = np.array(correlacion(h, x))

    #Graficando informacion
    fig = plt.figure(dpi=128, figsize=(10,6))
    plt.plot(np.arange(result),result, c= 'red')

    #Formateando la grafica
    plt.title("Correlation", fontsize=20)
    plt.xlabel('Samples',fontsize=16)
    fig.autofmt_xdate()
    plt.ylabel("Value", fontsize=16)
    plt.tick_params(axis='both',which='major',labelsize=16)

    plt.show()


import ROOT as rt
from array import array
rt.gROOT.SetBatch(True)
rt.gStyle.SetOptTitle(0)
#run from FAnalysis folder with python macros/sfABCD/draw_sfABCD.py

list16 = ["QCD16","TTJets16","WJets16","ZJets16"]
list17 = ["QCD17","TTJets17","WJets17","ZJets17"]
list18PRE = ["QCD18PRE","TTJets18PRE","WJets18PRE","ZJets18PRE"]
list18POST = ["QCD18POST","TTJets18POST","WJets18POST","ZJets18POST"]

listZ = ["z15", "z20", "z25", "base", "z35", "z40","z45"]
listD = ["d10","base","d40","d60","d80","d00"]
listR = ["r02","base","r05","r07","r08"]
listA = ["adl", "base", "adh"]

colorDict = {"QC":602, "TT":798,"WJ":801,"ZJ":881,"Bk":2,"Da":1}

def makePng(LoHi, name, direc, doLeg = True, log = False, nBinsX = 50, stackLines = True):
	c1 = rt.TCanvas("c1","c1",1200,900)
	if log:
		c1.SetLogy()
	stack = rt.THStack()
	LoH = []
	for h in LoHi:
		print(h.GetName(),h.Integral())
		LoH.append(h.Clone())
	LoH.sort(key=lambda x: x.Integral())
	if stackLines:
		for i in range(len(LoH)):
			LoH[i].SetLineColor(colorDict[LoH[i].GetName()[:2]])
			#if LoH[i].GetNbinsX() != nBinsX:
			#	LoH[i].Rebin(LoH[i].GetNbinsX()/nBinsX)
			stack.Add(LoH[i])
		#base = LoHi[-1].Clone()
		#if base.GetNbinsX() != nBinsX:
		#	base.Rebin(base.GetNbinsX()/nBinsX)
		#base.SetLineColor(rt.kRed)
		stack.Draw("nostack hist")
		#base.Draw("same")
	else:
		for i in range(len(LoH)):
			LoH[i].SetLineColor(colorDict[LoH[i].GetName()[:2]])
			LoH[i].SetFillColor(colorDict[LoH[i].GetName()[:2]])
			LoH[i].SetFillStyle(1001)
			#if LoH[i].GetNbinsX() != nBinsX:
			#	LoH[i].Rebin(LoH[i].GetNbinsX()/nBinsX)
			stack.Add(LoH[i])
		#base = LoHi[-1].Clone()
		#if base.GetNbinsX() != nBinsX:
		#	base.Rebin(base.GetNbinsX()/nBinsX)
		#base.SetLineColor(rt.kRed)
		stack.Draw("hist")
		#base.Draw("same")
	stack.GetXaxis().SetTitle(LoH[0].GetXaxis().GetTitle())
	stack.GetYaxis().SetTitle("Count")
	stack.SetTitle(name)
	stack.SetMaximum(10**5)
	stack.SetMinimum(10**-2)
	c1.Modified()
	if doLeg:
		c1.BuildLegend(0.4,0.7,0.6,0.9)
	c1.SaveAs(direc+name+".png")
	normStack = rt.THStack()
	for i in range(len(LoH)):
		if LoH[i].Integral() != 0:
			LoH[i].Scale(1/LoH[i].Integral())
		normStack.Add(LoH[i])
	normStack.Draw("hist")
	normStack.GetXaxis().SetTitle(LoH[0].GetXaxis().GetTitle())
	normStack.GetYaxis().SetTitle("a.u.")
	c1.Modified()
	if doLeg:
		c1.BuildLegend(0.4,0.7,0.6,0.9)
	c1.SaveAs(direc+name+"_norm.png")

def makeRatio(histCR, histSR , name, direc, doLeg = True, log = False, doNorm = True):
	# C++ Author: Olivier Couet, adapted to python by Colin Fallon
	# Define the Canvas
	c = rt.TCanvas("c", "canvas", 800, 800)
	print(histCR.GetName(), histCR.Integral())
	print(histSR.GetName(), histSR.Integral())
	# Upper plot will be in pad1
	pad1 = rt.TPad("pad1", "pad1", 0, 0.3, 1, 1.0)
	pad1.SetBottomMargin(0) # Upper and lower plot are joined
	pad1.SetGridx()         # Vertical grid
	pad1.Draw()             # Draw the upper pad: pad1
	pad1.cd()               # pad1 becomes the current pad
	if log:
		pad1.SetLogy()
	histCR.SetStats(0)       # No statistics on upper plot
	if histSR.GetNbinsX() == 1000:
		histSR.Rebin(20)
		histCR.Rebin(20)
	histSR.SetTitle("Low #Delta#eta")
	histCR.SetTitle("High #Delta#eta")
	histSR.SetLineColor(1)
	histCR.SetLineColor(2)
	if doNorm:
		try:
			histCR.Scale(1/histCR.Integral())
			histSR.Scale(1/histSR.Integral())
		except ZeroDivisionError:
			pass
	stack = rt.THStack()
	stack.Add(histCR)
	stack.Add(histSR)
	stack.SetTitle(name)
	stack.Draw("nostack hist")
	#histCR.Draw("hist")
	#histSR.Draw("same hist")
	if doLeg:
		pad1.BuildLegend(0.75,0.75,0.95,0.95)

	# Do not draw the Y axis label on the upper plot and redraw a small
	# axis instead, in order to avoid the first label (0) to be clipped.
	#h1.GetYaxis().SetLabelSize(0.)
	#axis = rt.TGaxis( -5, 20, -5, 220, 20,220,510,"")
	#axis.SetLabelFont(43) # Absolute font size in pixel (precision 3)
	#axis.SetLabelSize(15)
	#axis.Draw()

	# lower plot will be in pad
	c.cd()          # Go back to the main canvas before defining pad2
	pad2 = rt.TPad("pad2", "pad2", 0, 0.05, 1, 0.3)
	pad2.SetTopMargin(0)
	pad2.SetBottomMargin(0.2)
	pad2.SetGridx() # vertical grid
	pad2.Draw()
	pad2.cd()       # pad2 becomes the current pad

	# Define the ratio plot
	h3 = histSR.Clone("h3")
	h3.SetLineColor(rt.kBlack)
	h3.SetMinimum(0.00)  # Define Y ..
	if doNorm:
		h3.SetMaximum(2.00)
	else:
		h3.SetMaximum(1.50) # .. range
	h3.Sumw2()
	h3.SetStats(0)      # No statistics on lower plot
	h3.Divide(histCR)
	h3.SetMarkerStyle(21)
	h3.Draw("ep")       # Draw the ratio plot

	# Y axis h1 plot settings
	histSR.GetYaxis().SetTitleSize(20)
	histSR.GetYaxis().SetTitleFont(43)
	histSR.GetYaxis().SetTitleOffset(1.55)

	# Ratio plot (h3) settings
	h3.SetTitle("") # Remove the ratio title

	one = rt.TF1("one", '1', h3.GetXaxis().GetXmin(), h3.GetXaxis().GetXmax())
	one.SetLineStyle(2)
	one.SetLineColor(rt.kBlack)
	one.Draw("same")

	# Y axis ratio plot settings
	h3.GetYaxis().SetTitle("SR/CR")
	h3.GetYaxis().SetNdivisions(505)
	h3.GetYaxis().SetTitleSize(20)
	h3.GetYaxis().SetTitleFont(43)
	h3.GetYaxis().SetTitleOffset(1.55)
	h3.GetYaxis().SetLabelFont(43) # Absolute font size in pixel (precision 3)
	h3.GetYaxis().SetLabelSize(15)

	# X axis ratio plot settings
	h3.GetXaxis().SetTitleSize(20)
	h3.GetXaxis().SetTitleFont(43)
	h3.GetXaxis().SetTitleOffset(4.)
	h3.GetXaxis().SetLabelFont(43); # Absolute font size in pixel (precision 3)
	h3.GetXaxis().SetLabelSize(15)

	c.Update()
	#save as .png
	c.SaveAs(direc+name+"_ratio.png")

bkgList = [list16, list17, list18PRE, list18POST]
sigList = [listZ, listD, listR, listA]

# Getting a 1D histgoram with the correct events:
# The 3D histos are X:Y:Z -> nSVJtags:RT:variable
#		nSVJtags has 3 bins with edges [0,1,2,3]
#		RT has 100 same-width bins with range [0,1] #this might change to 0.15 to 0.8
#		ingeneral, varaible has 1k bins with various ranges
# so, to plot the variable for Region A1:
# 	take the histgram (hA1) from _dEtaLow for the varaible you want
#	and call hA1.ProjectionZ("_A1",2,2,25,100)
# 		where 	"_A1" is appended to the name
#				2,2 is the limits of the X axis (nSVJ) (in bin index)
#				25,100 is the limits of the Y axis (RT) (in bin index)

# Regions unprime and prime are _dEtaLow and _dEtaHigh, respectivly.
# regions A and B are RT > .25 (iBin 26) and 0.15 < RT < 0.25 (iBins 16 and 25)
# regions 0, 1, and 2 are numSVJtags == 0, == 1, == 2, (iBins 1, 2, 3)

#Lets start with just getting nEvents from various places...
direc = "outputs/sfABCD/plots_sameMTcut_correct/"

dictOfBackgroundTotals = {}

#	'LeadJetPt'
#	'SubLeadJetPt'
#	'BothJetPt'
#	'MT'
#	'MET'
#	'METPhi'
#	'DeltaEta'
#	'nSVJTag'
#	'RT'

#for var1 in ["LeadJetPt", "SubLeadJetPt","BothJetPt","MT","MET","METPhi","DeltaEta","nSVJTag","RT"]:
for var1 in ["METPhi"]: # use code JFURND to find lines for tesing METPhi problem
#	var1 = "MT"
#	stackDict_nSVJ = {}
#	stackDict_RT = {}
#	stackDict_dEta = {}
	stackDict_var1 = {}
	listOfRegions = ["A0","A1","A2","B0","B1","B2"]
	for region in listOfRegions:
#		stackDict_nSVJ[region] = {"ZJets16":rt.TH1D(), "WJets16":rt.TH1D(), "TTJets16":rt.TH1D(), "QCD16":rt.TH1D()}#rt.THStack(region+"_nSVJ",region+"_nSVJ;nSVJ;events")
#		stackDict_RT[region] = {"ZJets16":rt.TH1D(), "WJets16":rt.TH1D(), "TTJets16":rt.TH1D(), "QCD16":rt.TH1D()}#rt.THStack(region+"_RT",region+"_RT;RT;events")
#		stackDict_dEta[region] = {"ZJets16":rt.TH1D(), "WJets16":rt.TH1D(), "TTJets16":rt.TH1D(), "QCD16":rt.TH1D()}#rt.THStack(region+"_dEta",region+"_dEta;dEta;events")
		stackDict_var1[region] = {"ZJets16":rt.TH1D(), "WJets16":rt.TH1D(), "TTJets16":rt.TH1D(), "QCD16":rt.TH1D()}#rt.THStack(region+"_"+var1,region+"_"+var1+";"+var1+";events")
		dictOfBackgroundTotals["high_"+var1+"_"+region] = rt.TH1F("high_METPhi_"+region,"high_METPhi_"+region,20, -rt.TMath.Pi(),rt.TMath.Pi())

	for bkg in ["ZJets16","WJets16","TTJets16","QCD16"]:
		for region in listOfRegions:
			_file1 = rt.TFile.Open("outputs/sfABCD/"+bkg+"/sfABCD_test2_dEtaHigh.root","read")

#			temp_nSVJ =  _file1.Get(bkg+"_nSVJTag_"+region)
#			temp_RT = _file1.Get(bkg+"_RT_"+region)
#			temp_dEta = _file1.Get(bkg+"_DeltaEta_"+region)
			temp_var1 = _file1.Get(bkg+"_"+var1+"_"+region)

#			temp_nSVJ.SetDirectory(0)
#			temp_RT.SetDirectory(0)
#			temp_dEta.SetDirectory(0)
			temp_var1.SetDirectory(0)
			print(var1, region, bkg, temp_var1.GetName(), temp_var1.Integral()) #JFURND

			_file1.Close()
			if temp_var1.GetNbinsX() == 1000:
				temp_var1.Rebin(50)

#			stackDict_nSVJ[region][bkg] = temp_nSVJ.Clone()
#			stackDict_RT[region][bkg] = temp_RT.Clone()
#			stackDict_dEta[region][bkg] = temp_dEta.Clone()
			stackDict_var1[region][bkg] = temp_var1.Clone()
			dictOfBackgroundTotals["high_"+var1+"_"+region].Add(stackDict_var1[region][bkg])

#			stackDict_nSVJ[region][bkg].SetTitle(region[0]+"'"+region[1]+stackDict_nSVJ[region][bkg].GetTitle()[2:])
#			stackDict_RT[region][bkg].SetTitle(region[0]+"'"+region[1]+stackDict_RT[region][bkg].GetTitle()[2:])
#			stackDict_dEta[region][bkg].SetTitle(region[0]+"'"+region[1]+stackDict_dEta[region][bkg].GetTitle()[2:])
			stackDict_var1[region][bkg].SetTitle(region[0]+"'"+region[1]+stackDict_var1[region][bkg].GetTitle()[2:])

	for region in listOfRegions:
#		makePng([stackDict_nSVJ[region]["QCD16"],stackDict_nSVJ[region]["TTJets16"],stackDict_nSVJ[region]["WJets16"],stackDict_nSVJ[region]["ZJets16"]], region+"_dEtaHigh_nSVJ", direc, doLeg = True, log = True, nBinsX = 50, stackLines = False)
#		makePng([stackDict_RT[region]["QCD16"],stackDict_RT[region]["TTJets16"],stackDict_RT[region]["WJets16"],stackDict_RT[region]["ZJets16"]], region+"_dEtaHigh_RT", direc, doLeg = True, log = True, nBinsX = 50, stackLines = False)
#		makePng([stackDict_dEta[region]["QCD16"],stackDict_dEta[region]["TTJets16"],stackDict_dEta[region]["WJets16"],stackDict_dEta[region]["ZJets16"]], region+"_dEtaHigh_dEta", direc, doLeg = True, log = True, nBinsX = 50, stackLines = False)
		makePng([stackDict_var1[region]["QCD16"],stackDict_var1[region]["TTJets16"],stackDict_var1[region]["WJets16"],stackDict_var1[region]["ZJets16"]], region+"_dEtaHigh_"+var1, direc, doLeg = True, log = True, nBinsX = 50, stackLines = False)

#	stackDict_nSVJ = {}
#	stackDict_RT = {}
#	stackDict_dEta = {}
	stackDict_var1l = {}
	for region in listOfRegions:
#		stackDict_nSVJ[region] = {"ZJets16":rt.TH1D(), "WJets16":rt.TH1D(), "TTJets16":rt.TH1D(), "QCD16":rt.TH1D()}#rt.THStack(region+"_nSVJ",region+"_nSVJ;nSVJ;events")
#		stackDict_RT[region] = {"ZJets16":rt.TH1D(), "WJets16":rt.TH1D(), "TTJets16":rt.TH1D(), "QCD16":rt.TH1D()}#rt.THStack(region+"_RT",region+"_RT;RT;events")
#		stackDict_dEta[region] = {"ZJets16":rt.TH1D(), "WJets16":rt.TH1D(), "TTJets16":rt.TH1D(), "QCD16":rt.TH1D()}#rt.THStack(region+"_dEta",region+"_dEta;dEta;events")
		stackDict_var1l[region] = {"ZJets16":rt.TH1D(), "WJets16":rt.TH1D(), "TTJets16":rt.TH1D(), "QCD16":rt.TH1D()}#rt.THStack(region+"_"+var1,region+"_"+var1+";"+var1+";events")
		dictOfBackgroundTotals["low_"+var1+"_"+region] = rt.TH1F("low_METPhi_"+region,"low_METPhi_"+region,20, -rt.TMath.Pi(),rt.TMath.Pi())

	for bkg in ["ZJets16","WJets16","TTJets16","QCD16"]:
		for region in listOfRegions:
			_file1 = rt.TFile.Open("outputs/sfABCD/"+bkg+"/sfABCD_test2_lowdEta_mt1850.root","read")

#			temp_nSVJ =  _file1.Get(bkg+"_nSVJTag_"+region)
#			temp_RT = _file1.Get(bkg+"_RT_"+region)
#			temp_dEta = _file1.Get(bkg+"_DeltaEta_"+region)
			temp_var1 = _file1.Get(bkg+"_"+var1+"_"+region)

#			temp_nSVJ.SetDirectory(0)
#			temp_RT.SetDirectory(0)
#			temp_dEta.SetDirectory(0)
			temp_var1.SetDirectory(0)
			print(var1, region, bkg, temp_var1.GetName(), temp_var1.Integral()) #JFURND

			_file1.Close()
			if temp_var1.GetNbinsX() == 1000:
				temp_var1.Rebin(50)

#			stackDict_nSVJ[region][bkg] = temp_nSVJ.Clone()
#			stackDict_RT[region][bkg] = temp_RT.Clone()
#			stackDict_dEta[region][bkg] = temp_dEta.Clone()
			stackDict_var1l[region][bkg] = temp_var1.Clone()
			dictOfBackgroundTotals["low_"+var1+"_"+region].Add(stackDict_var1l[region][bkg])

	for region in listOfRegions:
#		makePng([stackDict_nSVJ[region]["QCD16"],stackDict_nSVJ[region]["TTJets16"],stackDict_nSVJ[region]["WJets16"],stackDict_nSVJ[region]["ZJets16"]], region+"_dEtaLow_nSVJ", direc, doLeg = True, log = True, nBinsX = 50, stackLines = False)
#		makePng([stackDict_RT[region]["QCD16"],stackDict_RT[region]["TTJets16"],stackDict_RT[region]["WJets16"],stackDict_RT[region]["ZJets16"]], region+"_dEtaLow_RT", direc, doLeg = True, log = True, nBinsX = 50, stackLines = False)
#		makePng([stackDict_dEta[region]["QCD16"],stackDict_dEta[region]["TTJets16"],stackDict_dEta[region]["WJets16"],stackDict_dEta[region]["ZJets16"]], region+"_dEtaLow_dEta", direc, doLeg = True, log = True, nBinsX = 50, stackLines = False)
		makePng([stackDict_var1l[region]["QCD16"],stackDict_var1l[region]["TTJets16"],stackDict_var1l[region]["WJets16"],stackDict_var1l[region]["ZJets16"]], region+"_dEtaLow_"+var1, direc, doLeg = True, log = True, nBinsX = 50, stackLines = False)
		makeRatio(dictOfBackgroundTotals["high_"+var1+"_"+region], dictOfBackgroundTotals["low_"+var1+"_"+region], region+"_"+var1, direc, doLeg = True, log = True)


from polyphony import testbench

class C:
    def __init__(self, v):
        self.v = v

    def get_v(self):
        return self.v

class D:
    def __init__(self, c):
        self.c = c

def alias06(p, x, y):
    c0 = C(x)
    c1 = C(y)
    if p:
        d = D(c0)
    else:
        d = D(c1)
    c0.v += 10
    return d.c.get_v()

@testbench
def test():
    assert 11 == alias06(True, 1, 2)
    assert 12 == alias06(True, 2, 3)
    assert 2 == alias06(False, 1, 2)
    assert 3 == alias06(False, 2, 3)

test()


from spelltutor.core.play import Tutor
from termcolor import colored

def main():
    print("Welcome to SPELL TUTOR \n")
    user_name = input("Enter your name: ")
    age = input("Enter your age: ")
    _display_welcome_message(user_name)

def _display_welcome_message(user_name):
    number = _display_wc_message_and_get_number(user_name)
    play_message = Tutor(number).play()
    if play_message:
        print(play_message)
        number = _display_wc_message_and_get_number(user_name)
        play_message = Tutor(number).play()
        if play_message:
            print(play_message+"\n")
            print(colored("Choice has been entered incorrectly mulitple times restart the game and provide correct number to continue".upper(), "red", attrs=['underline','bold']))

def _display_wc_message_and_get_number(user_name):
    print(colored("Hi {},What would you like to learn? Choose from below and enter the number \n".format(user_name), "blue"))
    print("1. Spellings \n")
    print("2. Jumbled words \n")
    number = input("Enter your choice: ")
    return number

if __name__ == '__main__':
    main()


"""adding_long_read_models

Revision ID: 1929562f5d92
Revises: 0e3a27ee14c8, 140ad44cd00f
Create Date: 2023-03-29 17:05:29.795410

"""
from alembic import op
import sqlalchemy as sa
import rdr_service.model.utils

from rdr_service.participant_enums import PhysicalMeasurementsStatus, QuestionnaireStatus, OrderStatus
from rdr_service.participant_enums import WithdrawalStatus, WithdrawalReason, SuspensionStatus, QuestionnaireDefinitionStatus
from rdr_service.participant_enums import EnrollmentStatus, Race, SampleStatus, OrganizationType, BiobankOrderStatus
from rdr_service.participant_enums import OrderShipmentTrackingStatus, OrderShipmentStatus
from rdr_service.participant_enums import MetricSetType, MetricsKey, GenderIdentity
from rdr_service.model.base import add_table_history_table, drop_table_history_table
from rdr_service.model.code import CodeType
from rdr_service.model.site_enums import SiteStatus, EnrollingStatus, DigitalSchedulingStatus, ObsoleteStatus

# revision identifiers, used by Alembic.
revision = '1929562f5d92'
down_revision = ('0e3a27ee14c8', '140ad44cd00f')
branch_labels = None
depends_on = None

def upgrade(engine_name):
    globals()["upgrade_%s" % engine_name]()

def downgrade(engine_name):
    globals()["downgrade_%s" % engine_name]()

def upgrade_rdr():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('genomic_lr_raw',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('created', sa.DateTime(), nullable=True),
    sa.Column('modified', sa.DateTime(), nullable=True),
    sa.Column('file_path', sa.String(length=255), nullable=True),
    sa.Column('ignore_flag', sa.SmallInteger(), nullable=False),
    sa.Column('biobank_id', sa.String(length=255), nullable=True),
    sa.Column('genome_type', sa.String(length=255), nullable=True),
    sa.Column('parent_tube_id', sa.String(length=255), nullable=True),
    sa.Column('lr_site_id', sa.String(length=255), nullable=True),
    sa.Column('long_read_platform', sa.String(length=255), nullable=True),
    sa.PrimaryKeyConstraint('id')
    )
    op.create_index(op.f('ix_genomic_lr_raw_file_path'), 'genomic_lr_raw', ['file_path'], unique=False)
    op.create_table('genomic_long_read',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('created', sa.DateTime(), nullable=True),
    sa.Column('modified', sa.DateTime(), nullable=True),
    sa.Column('genomic_set_member_id', sa.Integer(), nullable=False),
    sa.Column('biobank_id', sa.String(length=128), nullable=False),
    sa.Column('sample_id', sa.String(length=80), nullable=True),
    sa.Column('genome_type', sa.String(length=80), nullable=False),
    sa.Column('lr_site_id', sa.String(length=11), nullable=False),
    sa.Column('long_read_platform', sa.String(length=80), nullable=False),
    sa.Column('ignore_flag', sa.SmallInteger(), nullable=False),
    sa.ForeignKeyConstraint(['genomic_set_member_id'], ['genomic_set_member.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    op.create_index(op.f('ix_genomic_long_read_biobank_id'), 'genomic_long_read', ['biobank_id'], unique=False)
    op.create_index(op.f('ix_genomic_long_read_genomic_set_member_id'), 'genomic_long_read', ['genomic_set_member_id'], unique=False)
    op.create_index(op.f('ix_genomic_long_read_long_read_platform'), 'genomic_long_read', ['long_read_platform'], unique=False)
    op.create_index(op.f('ix_genomic_long_read_sample_id'), 'genomic_long_read', ['sample_id'], unique=False)
    # ### end Alembic commands ###

def downgrade_rdr():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_index(op.f('ix_genomic_long_read_sample_id'), table_name='genomic_long_read')
    op.drop_index(op.f('ix_genomic_long_read_long_read_platform'), table_name='genomic_long_read')
    op.drop_index(op.f('ix_genomic_long_read_genomic_set_member_id'), table_name='genomic_long_read')
    op.drop_index(op.f('ix_genomic_long_read_biobank_id'), table_name='genomic_long_read')
    op.drop_table('genomic_long_read')
    op.drop_index(op.f('ix_genomic_lr_raw_file_path'), table_name='genomic_lr_raw')
    op.drop_table('genomic_lr_raw')
    # ### end Alembic commands ###

def upgrade_metrics():
    # ### commands auto generated by Alembic - please adjust! ###
    pass
    # ### end Alembic commands ###

def downgrade_metrics():
    # ### commands auto generated by Alembic - please adjust! ###
    pass
    # ### end Alembic commands ###


import numpy as np
from PIL import Image
import random
import pickle
import re

wordPrefix = "../extract/"
dataPrefix = "../text/"
imagePrefix = "../imageVector2/"

class TextItem():
    def __init__(self, sentence, label):
        self.sentence = sentence
        self.label = label
        self.words = None

class TextIterator():
    def __init__(self, batchSize, seqLen):
        self.batchSize = batchSize
        self.seqLen = seqLen
        self.textData = dict()
        self.trainNum = []
        self.validNum = []
        self.testNum = []
        self.word2id = self.getVocab()
        self.attribute2id = self.getVocabAttr()
        dictExtractWords = self.getExtractDict()
        for i in range(3):
            self.readData(i, dictExtractWords)
        self.batchInd = 0
        self.validInd = 0
        self.testInd = 0
        self.epoch = 0
        self.threshold = int(len(self.trainNum) / self.batchSize)
        print(len(self.trainNum), len(self.validNum), len(self.testNum))
        print("rate: ", self.rate)

    def getExtractDict(self):
        file = open(wordPrefix+"extract_all")
        dic = {}
        for line in file:
            ls = eval(line)
            dic[int(ls[0])] = ls[1:]
        return dic

    def getVocab(self):
        file = open("../words/vocab")
        return pickle.load(file)

    def getVocabAttr(self):
        file = open("../ExtractWords/vocab")
        return pickle.load(file)

    def readData(self, i, dic):
        p = n = 0
        if i == 0:
            file = open(dataPrefix+"train.txt")
            ls = self.trainNum
        elif i == 1:
            file = open(dataPrefix+"valid2.txt")
            ls = self.validNum
        else:
            file = open(dataPrefix+"test2.txt")
            ls = self.testNum
        for line in file:
            lineLS = eval(line)
            tmpLS = lineLS[1].split()
            if "sarcasm" in tmpLS:
                continue
            if "sarcastic" in tmpLS:
                continue
            if "reposting" in tmpLS:
                continue
            if "<url>" in tmpLS:
                continue
            if "joke" in tmpLS:
                continue
            if "humour" in tmpLS:
                continue
            if "humor" in tmpLS:
                continue
            if "jokes" in tmpLS:
                continue
            if "irony" in tmpLS:
                continue
            if "ironic" in tmpLS:
                continue
            if "exgag" in tmpLS:
                continue
            assert int(lineLS[0]) not in self.textData
            ls.append(int(lineLS[0]))
            if i == 0:
                if lineLS[-1] == 1:
                    p += 1
                else:
                    n += 1
            self.textData[int(lineLS[0])] = TextItem(lineLS[1], int(lineLS[-1]))
            self.textData[int(lineLS[0])].words = dic[int(lineLS[0])]
        random.shuffle(ls)
        if i == 0:
            self.rate = float(n) / p

    def nextBatch(self):
        images = []
        retText = np.zeros([self.batchSize, self.seqLen])
        retY = np.zeros([self.batchSize, 1])
        retWords = np.zeros([self.batchSize, 5], dtype='int32')
        for i in range(self.batchSize):
            ID = self.trainNum[self.batchSize*self.batchInd+i]
            textItem = self.textData[ID]
            senLS = textItem.sentence.split()
            minLength = min(self.seqLen, len(senLS))
            for j in range(minLength):
                if senLS[j] in self.word2id:
                    retText[i][j] = self.word2id[senLS[j]]
                else:
                    retText[i][j] = self.word2id["<unk>"]
            retY[i][0] = textItem.label
            image = np.load(imagePrefix+str(ID)+".npy")
            images.append(image)
            for j in range(5):
                if textItem.words[j] in self.attribute2id:
                    retWords[i][j] = self.attribute2id[textItem.words[j]]
                else:
                    retWords[i][j] = self.attribute2id["<unk>"]
        images = np.asarray(images).transpose([1, 0, 2])
        self.batchInd += 1
        if self.batchInd == self.threshold:
            self.batchInd = 0
            self.epoch += 1
            random.shuffle(self.trainNum)
        return retText, images, retWords, retY

    def getValid(self, validLen=None):
        if validLen is None:
            validLen = self.batchSize
        minLen = min(validLen, len(self.validNum) - self.validInd*validLen)
        if minLen <= 0:
            self.validInd = 0
            return None, None, None, None, False
        retText = np.zeros([minLen, self.seqLen])
        retY = np.zeros([minLen, 1])
        retWords = np.zeros([minLen, 5], dtype='int32')
        images = []
        for i in range(minLen):
            ID = self.validNum[validLen*self.validInd+i]
            textItem = self.textData[ID]
            senLS = textItem.sentence.split()
            minLength = min(self.seqLen, len(senLS))
            for j in range(minLength):
                if senLS[j] in self.word2id:
                    retText[i][j] = self.word2id[senLS[j]]
                else:
                    retText[i][j] = self.word2id["<unk>"]
            retY[i][0] = textItem.label
            image = np.load(imagePrefix+str(ID)+".npy")
            images.append(image)
            for j in range(5):
                if textItem.words[j] in self.attribute2id:
                    retWords[i][j] = self.attribute2id[textItem.words[j]]
                else:
                    retWords[i][j] = self.attribute2id["<unk>"]
        images = np.array(images).transpose([1, 0, 2])
        self.validInd += 1
        return retText, images, retWords, retY, True

    def getTest(self, testLen=None):
        if testLen is None:
            testLen = self.batchSize
        minLen = min(testLen, len(self.testNum) - self.testInd*testLen)
        if minLen <= 0:
            self.testInd = 0
            return None, None, None, None, False, None
        retText = np.zeros([minLen, self.seqLen])
        retY = np.zeros([minLen, 1])
        fileNameLS = []
        retWords = np.zeros([minLen, 5], dtype='int32')
        images = []
        for i in range(minLen):
            ID = self.testNum[testLen*self.testInd+i]
            fileNameLS.append(ID)
            textItem = self.textData[ID]
            senLS = textItem.sentence.split()
            minLength = min(self.seqLen, len(senLS))
            for j in range(minLength):
                if senLS[j] in self.word2id:
                    retText[i][j] = self.word2id[senLS[j]]
                else:
                    retText[i][j] = self.word2id["<unk>"]
            retY[i][0] = textItem.label
            image = np.load(imagePrefix+str(ID)+".npy")
            images.append(image)
            for j in range(5):
                if textItem.words[j] in self.attribute2id:
                    retWords[i][j] = self.attribute2id[textItem.words[j]]
                else:
                    retWords[i][j] = self.attribute2id["<unk>"]
        images = np.array(images).transpose([1, 0, 2])
        self.testInd += 1
        return retText, images, retWords, retY, True, fileNameLS


from toondere.RecommendationSystem import GradingNSimilarities as GNS
from toondere.RecommendationSystem import ToonsfromSimilars as TfS
from toondere.RecommendationSystem import ToonsfromGenre as TfG
from toondere.RecommendationSystem import FPTree as FP
from toondere.RecommendationSystem import ToonsfromLike as TfL
from toondere.RecommendationSystem import PredictRatingsNToons as PRNT
# from toondere.RecommendationSystem import CrossValidation as CV

import random as rd
import numpy as np
import math

# 사용자 가입시 행렬 추가
def addUserRow(ucRatings, numofAddedUser):
    numofToons = ucRatings.shape[1]
    newRow = np.array([0] * numofToons)

    for _ in range(numofAddedUser):
        ucRatings = np.vstack((ucRatings, newRow))

    return ucRatings

def recommendfromLike(likeList, userNo, support):
    '''
    likelist = [[toons..],[toons..], ...]
    '''
    initSet = FP.createInitSet(likeList)
    FPtree, Header = FP.createTree(initSet, support)
    freqItemList = []
    FP.mineTree(FPtree, Header,support, set([]), freqItemList)
    freqLike = FP.tidyFreqList(freqItemList)
    del freqItemList
    recommends = TfL.treeLike(freqLike, likeList, userNo)
    return recommends

def predictRatingToon(genres, ucRatings, userNo, toonNo):
    uGradesGenre = GNS.gradingGroupsforAll(genres, ucRatings)
    simsUsers = GNS.calculateSimsforAll(uGradesGenre)

    prediction = PRNT.predictRatingsfor1Toon(
                            ucRatings, simsUsers, userNo, toonNo)
    return prediction

def recommendfromGenre(genres, ucRatings, userNo):
    '''
    # 유사한 사용자를 계산해서 만화 목록을 추천 받음.
    '''
    userNo = int(userNo) - 1
    assert userNo < len(ucRatings) or userNo > 0

    uGradesGenre = GNS.gradingGroupsforAll(genres, ucRatings)
    simsUsers = GNS.calculateSimsforAll(uGradesGenre)

    bestGenresforUser = TfG.pickBestGenre(genres, uGradesGenre, userNo)

    if -1 in bestGenresforUser:  # 좋은 점수의 장르가 없을 때
        bestGenresforUser.remove(-1)
        numofGenre = len(genres)
        for _ in range(math.log(numofGenre) - len(bestGenresforUser)):
            bestGenresforUser.append(rd.randrange(numofGenre))

    eachGenre = {}
    for genreNo in bestGenresforUser:
        if genreNo == -1:
            continue
        recommends = TfG.toonsfrom1Genre(
                                genres, ucRatings,
                                genreNo, userNo)
        toonsNPred, userMean = PRNT.predictRatings(
                        ucRatings, simsUsers, recommends, userNo)
        eachGenre[genreNo] = PRNT.doRecommend(genres,
                                        toonsNPred, userNo, userMean)

    # 추천할 만화 목록을 사전으로 반환
    print(eachGenre)
    return eachGenre

def recommendfromSimilars(genres, ucRatings, userNo):
    '''
    # 유사한 사용자를 계산해서 만화 목록을 추천 받음.
    '''
    userNo = int(userNo) - 1
    assert userNo < len(ucRatings) or userNo > 0

    if np.count_nonzero(ucRatings[userNo]) == 0:
        return []

    uGradesGenre = GNS.gradingGroupsforAll(genres, ucRatings)
    simsUsers = GNS.calculateSimsforAll(uGradesGenre)
    # print(uGradesGenre)
    print("                         ")
    # print(simsUsers)

    simUserIndices = TfS.bestSimilarUsers(simsUsers, userNo)

    # 유사한 사용자 없음에 대한 처리
    noSimUser = [x for x in simUserIndices if x == -1]
    if noSimUser != []:
        simUserIndices.remove(-1)
        for user in range(len(ucRatings)):
            if np.count_nonzero(ucRatings[user]) > 10:
                simUserIndices.append(user)
            if len(simUserIndices) > math.log(len(ucRatings)) + 1:
                break

    recommendCandidate = TfS.toonsfromSimilars(
                                    ucRatings, simUserIndices, userNo)

    toonsNPred, userMean = PRNT.predictRatings(
                    ucRatings, simsUsers, recommendCandidate, userNo)

    # 추천할 만화 목록을 list로 반환
    recommends = PRNT.doRecommend(genres, toonsNPred, userNo, userMean)

    # CV.crossValidation(genres, ucRatings, simsUsers)

    return recommends


def get_price(age):
	if age <= 16:
		return 'Pay 5 euro'
	if age > 60:
		return 'Pay 7 euro'
	else:
		return 'Pay 10 euro'

def merge_lists(l1,l2):
	i = 0
	merging1 = l1.append[i]
	i = i + 2
	j = 0
	merging2 = l2.append[i]
	j = j + 2
	mergedlist = merging1 + merging2
	return mergedlist


grafo = {}

# digitar os vertices
vertices = input("Digite os vértices do grafo separados por espaço: ").split()

# conjunto vazio para armazenar as arestas
arestas = set()

# digitar as arestas do grafo
while True:
    aresta = input("Digite uma aresta do grafo (ou digite 'fim' para encerrar): ")
    if aresta == "fim":
        break
    else:
        aresta = tuple(aresta.split())
        if len(aresta) != 2 or aresta[0] not in vertices or aresta[1] not in vertices:
            print("Aresta inválida! Digite novamente.")
        else:
            arestas.add(aresta)

# criar o grafo a partir dos vértices e arestas
for v in vertices:
    grafo[v] = set()

for u, v in arestas:
    grafo[u].add(v)
    grafo[v].add(u)

# verifica se a aresta ('A', 'C') está presente no grafo
if ('A', 'C') in arestas:
    print("A aresta ('A', 'C') está presente no grafo!")
else:
    print("A aresta ('A', 'C') não está presente no grafo.")


# Codigo de prueba para obtener informacion de un un artista usando su ID
import requests
import base64
import json
from dotenv import load_dotenv #Ocultar keys usando varianbles del sistema
import os

load_dotenv()

# Your client credentials
client_id = os.getenv('client_id')
client_secret = os.getenv('client_secret')

# Artist ID
artist_id = '1McMsnEElThX1knmY4oliG'

# Base64 encode the client_id and client_secret
credentials = base64.b64encode(f'{client_id}:{client_secret}'.encode('utf-8')).decode('utf-8')

headers = {
    'Authorization': f'Basic {credentials}',
    'Content-Type': 'application/x-www-form-urlencoded'
}

data = {
    'grant_type': 'client_credentials'
}

# Make a POST request to get the access token
response = requests.post('https://accounts.spotify.com/api/token', headers=headers, data=data)

if response.status_code == 200:
    access_token = response.json().get('access_token')
else:
    print(f'Error: {response.status_code}')
    access_token = None

if access_token:
    actualAccessToken = {
        'Authorization': f'Bearer {access_token}',
    }

    # Make a GET request to get the artist data
    responseArtistData = requests.get(f'https://api.spotify.com/v1/artists/{artist_id}', headers=actualAccessToken)

    if responseArtistData.status_code == 200:
        print(json.dumps(responseArtistData.json(), indent=4)) #Usar JSON para que los datos no se impriman en una sola linea
    else:
        print(f'Error: {responseArtistData.status_code}')


from pgadmin.tools.search_objects.utils import SearchObjectsHelper, current_app
from pgadmin.utils.route import BaseTestGenerator
from unittest.mock import patch, MagicMock

class SearchObjectsHelperTest(BaseTestGenerator):
    scenarios = [
        ('scenario', dict(
            node_blueprints=[
                dict(node_type='table', coll_label='Tables',
                     backend_supported=True),
                dict(node_type='view', coll_label='Views',
                     backend_supported=False),
                dict(node_type='index', coll_label='Indexes',
                     backend_supported=True),
                dict(node_type='role', coll_label='Roles',
                     backend_supported=True)
            ],
            all_node_types=['table', 'view', 'index'],
            expected_show_node_prefs=dict(table=True, view=False, index=True),
            expected_supported_types=dict(table='Tables', index='Indexes'),
            expected_supported_types_skip=dict(table='Tables', view='Views',
                                               index='Indexes'),
            execute_dict_return_value=(
                True, dict(rows=[
                    dict(obj_name='name1', obj_type='table',
                         obj_path='some/path', show_node=True,
                         other_info=None, catalog_level='N'),
                    dict(obj_name='name2', obj_type='view',
                         obj_path='some1/path', show_node=True,
                         other_info=None, catalog_level='D'),
                    dict(obj_name='name3', obj_type='index',
                         obj_path='some2/path1', show_node=True,
                         other_info='oid', catalog_level='O'),
                ])),
            expected_search_op=(
                True, [
                    dict(name='name1', type='table', type_label='Tables',
                         path='some/path',
                         show_node=True, other_info=None, catalog_level='N'),
                    dict(name='name2', type='view', type_label='Views',
                         path='some1/path',
                         show_node=True, other_info=None, catalog_level='D'),
                    dict(name='name3', type='index', type_label='Indexes',
                         path='some2/path1',
                         show_node=True, other_info='oid', catalog_level='O'),
                ]
            )
        ))
    ]

    def __create_manager(self):
        connection = MagicMock(
            execute_dict=MagicMock(),
            db='somedb'
        )
        connection.execute_dict.return_value = self.execute_dict_return_value

        def connection_function(did):
            return connection

        return MagicMock(
            connection=connection_function
        )

    @patch('pgadmin.tools.search_objects.utils.get_node_blueprint')
    @patch('pgadmin.tools.search_objects.utils.get_driver')
    def runTest(self, get_driver_mock, get_node_blueprint_mock):
        manager = self.__create_manager()

        get_driver_mock.return_value = MagicMock(
            connection_manager=lambda session_id: manager)

        def __get_node_blueprint_mock(node_type):
            blueprints = self.node_blueprints
            blueprint = None
            for data in blueprints:
                if node_type == data['node_type']:
                    blueprint = MagicMock(
                        backend_supported=MagicMock(
                            return_value=data['backend_supported']),
                        collection_label=data['coll_label'],
                        show_node=data['backend_supported'],
                    )
            return blueprint

        get_node_blueprint_mock.side_effect = __get_node_blueprint_mock

        with self.app.app_context():

            so_obj = SearchObjectsHelper(2, 18456,
                                         node_types=self.all_node_types)
            so_obj.get_sql = MagicMock(return_value='dummy query')

            # test template path
            manager.server_type = 'pg'
            manager.version = 906000
            self.assertEqual(so_obj.get_template_path(),
                             'search_objects/sql/pg/#906000#')

            self.assertEqual(so_obj.get_show_node_prefs(),
                             self.expected_show_node_prefs)

            self.assertEqual(so_obj.get_supported_types(),
                             self.expected_supported_types)

            self.assertEqual(so_obj.get_supported_types(skip_check=True),
                             self.expected_supported_types_skip)

            self.assertEqual(so_obj.search('searchtext', 'all'),
                             self.expected_search_op)


from transformers import AutoTokenizer

class text2id():
    """mapping natural language to numeric identifiers.
    """
    def __init__(self, args) -> None:
        if args.encoder_architecture == "Fixed":
            self.encoder = None
        elif args.encoder_architecture == "BERT":
            self.model_name = 'bert-base-cased'
            self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
        else:
            raise NotImplementedError

    def encoder(self, sample):
        encodings = self.tokenizer(sample, truncation=True, padding=True)
        return encodings["input_ids"], encodings['token_type_ids'], encodings['attention_mask']


## 该文件放置在Flutter项目根目录（与同pubspec.yaml 同级目录）
## 运行即可将文件assets下面的资源文件添加到 assets 标签下

## version 1.0
import os
from os import path

# 获取配置文件信息

def getYamlConfig():
    with open("pubspec.yaml") as f:
        line = [line.rstrip() for line in f]
    return line

config = getYamlConfig()
newConfig = config

print(config)

def getAssets():
    rootPath = os.getcwd()
    dirPath = rootPath + "\\assets"
    files = os.listdir(dirPath)
    return files

for index in range(len(config)):
    print("index = ", index)

for index in range(len(config)):
    if (config[index] == "  assets:"):
        assets = getAssets()
        for k in range(len(assets)):
            assets_k_ = "      - " + assets[k]
            newConfig.insert(index + 1, assets_k_)
            print(newConfig[index + k + 1])

with open("pubspec2.yaml", mode="w") as f:
    for line in newConfig:
        f.write(line)
        f.write("\n")


import requests
from lxml import etree
import re
import pymysql

class GovementSpider(object):
    def __init__(self):
        self.url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/'
        self.headers = {"User-Agent": "Mozilla/5.0"}
        # 创建2个对象
        self.db = pymysql.connect("127.0.0.1", "root", "123456", "govdb", charset="utf8")
        self.cursor = self.db.cursor()

    # 获取假链接
    def get_false_link(self):
        html = requests.get(url=self.url, headers=self.headers).text
        # 解析
        parse_html = etree.HTML(html)
        a_list = parse_html.xpath('//a[@class="artitlelist"]')
        for a in a_list:
            # title=a.xpath('./@title')[0]
            # get()方法:获取某个属性的值
            title = a.get("title")
            if title.endswith("代码"):
                false_link = "http://www.mca.gov.cn" + a.get("href")
                break
        self.incr_spider(false_link)

    # 增量函数
    def incr_spider(self, false_link):
        sel = "select url from version where url=%s"
        self.cursor.execute(sel, [false_link])
        # fetchall:(('http://xxx.html'),)
        result = self.cursor.fetchall()
        if not result:
            self.get_true_link(false_link)
            #可选操作：数据库version表中保留最新1条数据
            dele="delete from version"
            self.cursor.execute(dele)
            # 把提取后的url插入到version中
            ins = "insert into version values(%s)"
            self.cursor.execute(ins, [false_link])
            self.db.commit()
        else:
            print("数据已是最新,无需爬取")

    # 获取真链接
    def get_true_link(self, false_link):
        html = requests.get(url=false_link, headers=self.headers).text
        # 正则获取真是数据
        re_bds = r'window.location.href="(.*?)"'
        pattern = re.compile(re_bds, re.S)
        true_link = pattern.findall(html)[0]
        self.save_data(true_link)

    # 数据提取
    def save_data(self, true_link):
        html = requests.get(url=true_link, headers=self.headers).text
        parse_html = etree.HTML(html)
        tr_list = parse_html.xpath('//tr[@height=19 ]')
        for tr in tr_list:
            code = tr.xpath("./td[2]/text()")[0].strip()
            name = tr.xpath("./td[3]/text()")[0].strip()
            print(code, name)

    # 主函数
    def main(self):
        spider.get_false_link()

if __name__ == "__main__":
    spider = GovementSpider()
    spider.main()


import torch
import random
import logging
import numpy as np
from typing import List, Tuple, Dict, Union

logger = logging.getLogger(__name__)

__all__ = [
    'manual_seed',
    # 'seq_len_to_mask',
    # 'to_one_hot',
]

def manual_seed(seed: int = 1) -> None:
    """
        设置seed。
    """
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False


# -*- coding: utf-8 -*-
'''
Created on 2015年12月30日

@author: hustcc
'''

# repo name
def get_repo_name(hook_data):
    return hook_data.get('repository', {}).get('name', '') \
        or hook_data.get('push_data', {}).get('repository', {}).get('name', '')

# repo branch
def get_repo_branch(hook_data):
    branch = hook_data.get('ref', '')  # github, gitlib
    if not branch:
        branch = hook_data.get('push_data', {}).get('ref', '')
    if '/' in branch:
        return branch[branch.rfind("/") + 1:]
    return branch

# push user name
def get_push_name(hook_data):
    uid = hook_data.get('pusher', {}).get('name', None)  # github的data格式
    if uid:
        return uid
    uid = hook_data.get('user_name', None)  # gitlib 格式
    if uid:
        return uid
    uid = hook_data.get('pusher', {}).get('username', None)  # gogs 格式
    if uid:
        return uid

    uid = hook_data\
        .get('push_data', {})\
        .get('user', {}).get('name', None)  # gitosc的data格式
    if uid:
        return uid
    return ''

# push user email
def get_push_email(hook_data):
    uid = hook_data.get('pusher', {}).get('email', None)  # github的data格式
    if uid:
        return uid
    uid = hook_data.get('user_email', None)  # gitlib 格式
    if uid:
        return uid

    uid = hook_data\
        .get('push_data', {})\
        .get('user', {}).get('email', None)  # gitosc的data格式
    if uid:
        return uid
    return ''


#!/usr/bin/env python
from vtkmodules.vtkCommonCore import vtkPoints
from vtkmodules.vtkCommonDataModel import (
    vtkCellArray,
    vtkPolyData,
)
from vtkmodules.vtkFiltersModeling import vtkCookieCutter
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer,
)
import vtkmodules.vtkInteractionStyle
import vtkmodules.vtkRenderingFreeType
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.util.misc import vtkGetDataRoot

# This tests reversing loops and other weird situations

# create planes
# Create the RenderWindow, Renderer
#
ren = vtkRenderer()
renWin = vtkRenderWindow()
renWin.AddRenderer( ren )

iren = vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)

# Custom polydata to test intersections. Loop are ordered in
# reverse directions.
polysData = vtkPolyData()
polysPts = vtkPoints()
polysPolys = vtkCellArray()
polysData.SetPoints(polysPts)
polysData.SetPolys(polysPolys)

polysPts.SetNumberOfPoints(8)
polysPts.SetPoint(0, 0.0,0.0,0.0)
polysPts.SetPoint(1, 2.0,0.0,0.0)
polysPts.SetPoint(2, 2.0,2.0,0.0)
polysPts.SetPoint(3, 0.0,2.0,0.0)
polysPts.SetPoint(4, -2.0,-2.0,0.0)
polysPts.SetPoint(5,  0.0,-2.0,0.0)
polysPts.SetPoint(6,  0.0, 0.0,0.0)
polysPts.SetPoint(7, -2.0, 0.0,0.0)

polysPolys.InsertNextCell(4)
polysPolys.InsertCellPoint(0)
polysPolys.InsertCellPoint(1)
polysPolys.InsertCellPoint(2)
polysPolys.InsertCellPoint(3)
polysPolys.InsertNextCell(4)
polysPolys.InsertCellPoint(4)
polysPolys.InsertCellPoint(7)
polysPolys.InsertCellPoint(6)
polysPolys.InsertCellPoint(5)

# Create a loop for cookie cutting
loops = vtkPolyData()
loopPts = vtkPoints()
loopPolys = vtkCellArray()
loops.SetPoints(loopPts)
loops.SetPolys(loopPolys)

loopPts.SetNumberOfPoints(4)
loopPts.SetPoint(0, -1,-1,0)
loopPts.SetPoint(1,  1,-1,0)
loopPts.SetPoint(2,  1, 1,0)
loopPts.SetPoint(3, -1, 1,0)

loopPolys.InsertNextCell(4)
loopPolys.InsertCellPoint(0)
loopPolys.InsertCellPoint(1)
loopPolys.InsertCellPoint(2)
loopPolys.InsertCellPoint(3)

cookie = vtkCookieCutter()
cookie.SetInputData(polysData)
cookie.SetLoopsData(loops)
cookie.Update()

mapper = vtkPolyDataMapper()
mapper.SetInputConnection(cookie.GetOutputPort())

actor = vtkActor()
actor.SetMapper(mapper)

loopMapper = vtkPolyDataMapper()
loopMapper.SetInputData(loops)

loopActor = vtkActor()
loopActor.SetMapper(loopMapper)
loopActor.GetProperty().SetColor(1,0,0)
loopActor.GetProperty().SetRepresentationToWireframe()

ren.AddActor(actor)
ren.AddActor(loopActor)

renWin.Render()
iren.Start()


from django.contrib import admin
from django.urls import path, include, re_path
from web.views import account, project, manage, wiki, file, setting, issues

urlpatterns = [
    re_path(r'^phone/$', account.send_code, name='sms'),
    re_path(r'^reg/$', account.reg, name='reg'),
    re_path(r'^sms_login/$', account.sms_login, name='sms_login'),
    re_path(r'^login/$', account.normal_login, name='login'),

    re_path(r'^index/$', account.index, name='index'),

    # ======== 获取图片验证码
    re_path(r'^code/$', account.get_code, name='code'),

    # ======== 退出登录
    re_path(r'^exit/$', account.login_exit, name='exit'),

    # ======== 项目管理
    re_path(r'^project/list/$', project.project_list, name='project_list'),

    # ======== 星标项目确认和取消
    re_path(r'^project/star/(?P<project_type>\w+)/(?P<project_id>\d+)/$', project.project_star, name='project_star'),

    # ======== 项目下的功能模块
    re_path(r'^manage/(?P<project_id>\d+)/', include([
        re_path(r'^dashboard/$', manage.dashboard, name='dashboard'),
        re_path(r'^statistics/$', manage.statistics, name='statistics'),

        # ======== 文件上传
        re_path(r'^file/$', file.file, name='file'),
        # ======== ajax文件删除
        re_path(r'^file/del/$', file.file_delete, name='file_del'),
        # ======== 上传文件到cos桶获取临时凭证
        re_path(r'^cos/credential/$', file.cos, name='cos'),
        # ======== 文件上传同步到后端
        re_path(r'^file/post/$', file.file_post, name='file_post'),
        # ======== 文件下载
        re_path(r'^file/download/(?P<download_id>\w+)$', file.file_download, name='file_download'),

        re_path(r'^wiki/$', wiki.wiki, name='wiki'),
        # ======== 添加wiki文件
        re_path(r'^wiki/add/$', wiki.wiki_add, name='wiki_add'),
        # ======== 获取项目下对应的wiki文件目录
        re_path(r'^wiki/menu/$', wiki.wiki_menu, name='wiki_menu'),
        # ======== 删除wiki文件
        re_path(r'^wiki/delete/(?P<wiki_id>\d+)/$', wiki.wiki_delete, name='wiki_delete'),
        # ======== 编辑wiki文件
        re_path(r'^wiki/edit/(?P<wiki_id>\d+)/$', wiki.wiki_edit, name='wiki_edit'),
        # ======== wiki中md上传文件
        re_path(r'^wiki/upload/$', wiki.wiki_upload, name='wiki_upload'),

        # ======== 配置相关操作
        re_path(r'^setting/$', setting.setting, name='setting'),
        # ======== 配置中删除项目
        re_path(r'^setting/delete/$', setting.setting_delete, name='setting_delete'),

        # ======== 问题展示
        re_path(r'^issues/$', issues.issues, name='issues'),
        # ======== 问题编辑
        re_path(r'^issues/detail/(?P<detail_id>\w+)$', issues.issues_detail, name='issues_detail'),
        # ======== 显示问题相关的评论和操作记录
        re_path(r'^issues/record/(?P<record_id>\w+)$', issues.issues_record, name='issues_record'),
        # ======== 前端字段的值更新同步后端接口
        re_path(r'^issues/change/(?P<change_id>\w+)$', issues.issues_change, name='issues_change'),

        # ======== 获取邀请码接口
        re_path(r'^invite/url/$', issues.invite_url, name='invite_url'),

    ], None)),

    # ======== 访问邀请码接口
    re_path(r'^invite/join/(?P<code>\w+)/$', issues.invite_join, name='invite_join'),
]


#!/usr/bin/env python3
# Path: solutions/day07/solution.py
import os, pprint

# Read the input file
with open("input.txt", "r") as f:
    input_data = f.read()

# Write your solution here
def solution_part_1(input_data):
    input_data = input_data.split("\n")
    input_data = [x.split(" | ") for x in input_data]
    input_data = [x[1].split(" ") for x in input_data]

    count = 0
    for line in input_data:
        for word in line:
            if len(word) in [2, 3, 4, 7]:
                count += 1

    print("Part 1:", count)

def output_to_digit(output, mapping):
    if len(output) == 2:
        return 1
    elif len(output) == 3:
        return 7
    elif len(output) == 4:
        return 4
    elif len(output) == 7:
        return 8
    else:
        indexes = sorted([mapping.index(x) for x in output])
        digit = None

        if indexes == [0, 1, 2, 4, 5, 6]:
            digit = 0
        elif indexes == [0, 2, 3, 4, 6]:
            digit = 2
        elif indexes == [0, 2, 3, 5, 6]:
            digit = 3
        elif indexes == [0, 1, 3, 5, 6]:
            digit = 5
        elif indexes == [0, 1, 3, 4, 5, 6]:
            digit = 6
        elif indexes == [0, 1, 2, 3, 5, 6]:
            digit = 9

        return digit

def solution_part_2(input_data):
    input_data = input_data.split("\n")
    input_data = [x.split(" | ") for x in input_data]

    signals = [sorted(x[0].split(" "), key=lambda y: len(y)) for x in input_data]
    outputs = [x[1].split(" ") for x in input_data]

    sum_of_outputs = 0

    for line_index in range(len(input_data)):
        mapping = [""] * 7
        mappings = [mapping] * 8

        for signal in signals[line_index]:
            if len(signal) == 2:
                for i in range(8):
                    if i in [0, 1, 4, 5]:
                        mappings[i] = ["", "", signal[0], "", "", signal[1], ""]
                    elif i in [2, 3, 6, 7]:
                        mappings[i] = ["", "", signal[1], "", "", signal[0], ""]

            elif len(signal) == 3:
                for i in range(8):
                    not_in_mapping = [x for x in signal if x not in mappings[i]]
                    mappings[i][0] = not_in_mapping[0]

            elif len(signal) == 4:
                for i in range(8):
                    not_in_mapping = [x for x in signal if x not in mappings[i]]
                    if i in [0, 2, 4, 6]:
                        mappings[i] = [
                            mappings[i][0],
                            not_in_mapping[0],
                            mappings[i][2],
                            not_in_mapping[1],
                            "",
                            mappings[i][5],
                            "",
                        ]
                    elif i in [1, 3, 5, 7]:
                        mappings[i] = [
                            mappings[i][0],
                            not_in_mapping[1],
                            mappings[i][2],
                            not_in_mapping[0],
                            "",
                            mappings[i][5],
                            "",
                        ]

            elif len(signal) == 7:
                for i in range(8):
                    not_in_mapping = [x for x in signal if x not in mappings[i]]
                    if i in [0, 1, 2, 3]:
                        mappings[i] = [
                            mappings[i][0],
                            mappings[i][1],
                            mappings[i][2],
                            mappings[i][3],
                            not_in_mapping[0],
                            mappings[i][5],
                            not_in_mapping[1],
                        ]
                    elif i in [4, 5, 6, 7]:
                        mappings[i] = [
                            mappings[i][0],
                            mappings[i][1],
                            mappings[i][2],
                            mappings[i][3],
                            not_in_mapping[1],
                            mappings[i][5],
                            not_in_mapping[0],
                        ]

        best_mapping = None
        for curr_mapping in mappings:
            count_valid = 0

            for signal in signals[line_index]:
                if output_to_digit(signal, curr_mapping) is not None:
                    count_valid += 1

            if count_valid == len(signals[line_index]):
                best_mapping = curr_mapping
                break

        curr_output = 0
        for output in outputs[line_index]:
            digit = output_to_digit(output, best_mapping)
            curr_output = curr_output * 10 + digit

        sum_of_outputs += curr_output

    print("Part 2:", sum_of_outputs)

if __name__ == "__main__":
    solution_part_1(input_data)
    solution_part_2(input_data)


# -*- coding: UTF-8 -*-
"""
title：二叉树的后序遍历
Given the root of a binary tree, return the postorder traversal of its nodes' values.

Example 1:
Input: root = [1,null,2,3]
Output: [3,2,1]

Example 2:
Input: root = []
Output: []

Example 3:
Input: root = [1]
Output: [1]

Constraints:
The number of the nodes in the tree is in the range [0, 100].
-100 <= Node.val <= 100

Follow up: Recursive solution is trivial, could you do it iteratively?
"""
from typing import List

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:

    def postorderTraversal(self, root: TreeNode) -> List[int]:
        res = []

        def dfs(node: TreeNode) -> None:
            if not node:
                return
            dfs(node.left)
            dfs(node.right)
            res.append(node.val)

        dfs(root)
        return res

    def postorderTraversal_2(self, root: TreeNode) -> List[int]:
        """后序遍历的迭代版本。若类似于前序遍历直接写，会有些麻烦，因为这里需要判断节点的访问状态，根节点需要最后出栈。
        转换思路，将后序(左->右->根)看作是(根->右->左)的逆序。这里本质上还是前序遍历，并不是真正的后序遍历，因此不建议这种写法"""
        res = []
        if not root:
            return res
        stack = [root]
        while stack:
            node = stack.pop()
            # 先打印根节点
            res.append(node.val)
            # 左孩子先入栈，后出栈
            if node.left:
                stack.append(node.left)
            # 右孩子后入栈，因此会先出栈，也就是会先打印右孩子，然后再打印左孩子
            if node.right:
                stack.append(node.right)
        res.reverse()
        # 注意：不能直接return res.reverse()，因为reverse()方法没有返回值。
        # 逆序也可以使用 return res[::-1]
        return res

    def postorderTraversal_3(self, root: TreeNode) -> List[int]:
        """迭代。不用逆序"""
        res = []
        stack = []
        pre_node = None
        cur_node = root
        while cur_node or stack:
            # 若存在左孩子，则一路向左。否则向右走一步，接着继续遍历左，直到既没有左孩子，也没有右孩子。
            # 此时才开始加入res，使用变量pre_node来记录上一次加入到res的节点，从而避免重复加入，进入死循环。
            while cur_node:
                stack.append(cur_node)
                cur_node = cur_node.left
            cur_node = stack.pop()
            if not cur_node.right or cur_node.right == pre_node:
                res.append(cur_node.val)
                # 使用pre_node来记录上一次加入到res的节点，从而避免重复加入，进入死循环。想象一条只有右节点的边，从下往上逐个将节点加入res
                pre_node = cur_node
                cur_node = None
            else:
                # 存在右孩子节点，且该右孩子节点不等于pre_node，则先将前面pop出来的节点加回stack，然后向右走一步
                stack.append(cur_node)
                cur_node = cur_node.right
        return res


class RentalProperty:
    def __init__(self, purchase_price, rental_income, operating_expenses, holding_period_years, selling_price):
        self.purchase_price = purchase_price
        self.rental_income = rental_income
        self.operating_expenses = operating_expenses
        self.holding_period_years = holding_period_years
        self.selling_price = selling_price

    def calculate_roi(self):
        total_income = self.rental_income * self.holding_period_years
        total_expenses = self.operating_expenses * self.holding_period_years
        net_profit = (self.selling_price - self.purchase_price) - total_expenses
        total_investment = self.purchase_price + total_expenses
        roi = (net_profit / total_investment) * 100
        return roi

property1 = RentalProperty(purchase_price=500000, rental_income=2000, operating_expenses=1000, holding_period_years=5, selling_price=600000)

# Calculate the ROI
roi = property1.calculate_roi()
print(f"The ROI for this rental property is {roi:.2f}%")