"""
Series of galactic operations (doesn't that sound cool?!).

...as in converting coordinates, calculating DM etc.
"""
from datetime import timedelta
import ctypes as C
import math
import numpy as np
import os
import pandas as pd
import random

from frbpoppy.paths import paths

# Import fortran libraries
uni_mods = os.path.join(paths.models(), 'universe/')
dm_mods = os.path.join(paths.models(), 'ne2001/')
loc = os.path.join(dm_mods, 'libne2001.so')
ne2001lib = C.CDLL(loc)
ne2001lib.dm_.restype = C.c_float

def frac_deg(ra, dec):
    """Convert coordinates expressed in hh:mm:ss to fractional degrees."""
    # Inspired by Joe Filippazzo calculator
    rh, rm, rs = [float(r) for r in ra.split(':')]
    ra = rh*15 + rm/4 + rs/240
    dd, dm, ds = [float(d) for d in dec.split(':')]
    if dd < 0:
        sign = -1
    else:
        sign = 1
    dec = dd + sign*dm/60 + sign*ds/3600
    return ra, dec

def lb_to_xyz(gl, gb, dist):
    """
    Convert galactic coordinates to galactic XYZ.

    Args:
        l (float): Galactic longitude [fractional degrees]
        b (float): Galactic latitude [fractional degrees]
        dist (float): Distance to source [Gpc]

    Returns:
        gx, gy, gz: Galactic XYZ [Gpc]

    """
    rsun = 8.5e-6  # Gpc

    L = np.radians(gl)
    B = np.radians(gb)

    gx = dist * np.cos(B) * np.sin(L)
    gy = rsun - dist * np.cos(B) * np.cos(L)
    gz = dist * np.sin(B)

    return gx, gy, gz

def lb_to_radec(l, b):
    """
    Convert galactic coordinates to RA, Dec.

    Formulas from 'An Introduction to Modern Astrophysics (2nd Edition)' by
    Bradley W. Carroll, Dale A. Ostlie (Eq. 24.19 onwards).

    NOTE: This function is not as accurate as the astropy conversion, nor as
    the Javascript calculators found online. However, as using astropy was
    prohibitively slow while running over large populations, frbpoppy uses this
    function. While this function is not as accurate, the under/over
    estimations of the coordinates are equally distributed meaning the errors
    cancel each other in the limit of large populations.

    Args:
        l (float): Galactic longitude [fractional degrees]
        b (float): Galactic latitude [fractional degrees]

    Returns:
        ra, dec (float): Right ascension and declination [fractional degrees]

    """
    gl = np.radians(l)
    gb = np.radians(b)

    # Coordinates of the galactic north pole (J2000)
    a_ngp = np.radians(12.9406333 * 15.)
    d_ngp = np.radians(27.1282500)
    l_ngp = np.radians(123.9320000)

    sd_ngp = np.sin(d_ngp)
    cd_ngp = np.cos(d_ngp)
    sb = np.sin(gb)
    cb = np.cos(gb)

    # Calculate right ascension
    y = cb*np.sin(l_ngp - gl)
    x = cd_ngp*sb - sd_ngp*cb*np.cos(l_ngp - gl)
    ra = np.arctan2(y, x) + a_ngp
    ra = np.degrees(ra) % 360

    # Calculate declination
    dec = np.arcsin(sd_ngp*sb + cd_ngp*cb*np.cos(l_ngp - gl))
    dec = np.degrees(dec) % 360.
    dec[dec > 270] = -(360 - dec[dec > 270])

    return ra, dec

def radec_to_lb(ra, dec, frac=False):
    """
    Convert from ra, dec to galactic coordinates.

    Formulas from 'An Introduction to Modern Astrophysics (2nd Edition)' by
    Bradley W. Carroll, Dale A. Ostlie (Eq. 24.16 onwards).

    NOTE: This function is not as accurate as the astropy conversion, nor as
    the Javascript calculators found online. However, as using astropy was
    prohibitively slow while running over large populations, we use this
    function. While this function is not as accurate, the under/over
    estimations of the coordinates are equally distributed meaning the errors
    cancel each other in the limit of large populations.

    Args:
        ra (string): Right ascension given in the form '19:06:53'
        dec (string): Declination given in the form '-40:37:14'
        frac (bool): Denote whether coordinates are already fractional or not
    Returns:
        gl, gb (float): Galactic longitude and latitude [fractional degrees]

    """
    if not frac:
        ra, dec = frac_deg(ra, dec)

    a = np.radians(ra)
    d = np.radians(dec)

    # Coordinates of the galactic north pole (J2000)
    a_ngp = np.radians(12.9406333 * 15.)
    d_ngp = np.radians(27.1282500)
    l_ngp = np.radians(123.9320000)

    sd_ngp = np.sin(d_ngp)
    cd_ngp = np.cos(d_ngp)
    sd = np.sin(d)
    cd = np.cos(d)

    # Calculate galactic longitude
    y = cd*np.sin(a - a_ngp)
    x = cd_ngp*sd - sd_ngp*cd*np.cos(a - a_ngp)
    gl = - np.arctan2(y, x) + l_ngp
    gl = np.degrees(gl) % 360

    # Shift so in range -180 to 180
    if isinstance(gl, np.ndarray):
        gl[gl > 180] = -(360 - gl[gl > 180])
    else:
        if gl > 180:
            gl = -(360 - gl)

    # Calculate galactic latitude
    gb = np.arcsin(sd_ngp*sd + cd_ngp*cd*np.cos(a - a_ngp))
    gb = np.degrees(gb) % 360

    if isinstance(gb, np.ndarray):
        gb[gb > 270] = -(360 - gb[gb > 270])
    else:
        if gb > 270:
            gb = -(360 - gb)

    return gl, gb

def separation(ra_1, dec_1, ra_2, dec_2):
    """Separation between points on sky [degrees].

    Using a special case of the Vincenty formula for an ellipsoid with equal
    major and minor axes.

    See https://en.wikipedia.org/wiki/Great-circle_distance for more info.

    """
    # Convert to radians
    ra_1 = np.deg2rad(ra_1)
    dec_1 = np.deg2rad(dec_1)
    ra_2 = np.deg2rad(ra_2)
    dec_2 = np.deg2rad(dec_2)

    # Shortcuts
    sdr = np.sin(ra_2 - ra_1)
    cdr = np.cos(ra_2 - ra_1)
    cd1 = np.cos(dec_1)
    cd2 = np.cos(dec_2)
    sd1 = np.sin(dec_1)
    sd2 = np.sin(dec_2)

    # Calculation
    upper = np.sqrt((cd2*sdr)**2 + (cd1*sd2 - sd1*cd2*cdr)**2)
    lower = sd1*sd2 + cd1*cd2*cdr
    sep = np.arctan2(upper, lower)

    return np.rad2deg(sep)

def ne2001_dist_to_dm(dist, gl, gb):
    """
    Convert position to a dispersion measure using NE2001.

    Args:
        dist (float): Distance to source [Gpc]. Distance will be cut at 100kpc,
                      as NE2001 can not cope with larger distances. This value
                      should be more than enough to clear the Milky Way.
        gl (float): Galactic longitude [fractional degrees]
        gb (float): Galactic latitude [fractional degrees]
    Returns:
        dm (float): Dispersion measure [pc*cm^-3]

    """
    dist *= 1e6  # Convert from Gpc to kpc

    # NE2001 gives errors if distance input is too large! 100 kpc ought to be
    # enough to clear the galaxy.
    if dist > 100:
        dist = 100

    dist = C.c_float(dist)
    gl = C.c_float(gl)
    gb = C.c_float(gb)
    inpath = C.create_string_buffer(dm_mods.encode())
    linpath = C.c_int(len(dm_mods))

    dm = ne2001lib.dm_(C.byref(dist),
                       C.byref(gl),
                       C.byref(gb),
                       C.byref(C.c_int(4)),
                       C.byref(C.c_float(0.0)),
                       C.byref(inpath),
                       C.byref(linpath)
                       )

    return dm

def ne2001_get_smtau(dist, gl, gb):
    """
    Use the NE2001 model to calculate scattering measure.

    Calculations based on work presented in Cordes & Lazio
    (1991, DOI: 10.1086/170261)

    Args:
        dist (array): Distance to source [kpc]. Distance will be cut at 100 kpc
                      as NE2001 can not cope with larger distances. Therefore
                      the calculated scattering will only be that from the
                      Milky Way.
        gl (array): Galactic longitude [fractional degrees]
        gb (array): Galactic latitude [fractional degrees]
    Returns:
        sm (array): Scattering measure
        smtau (array): Scattering measure, but unsure why different to sm

    """
    # NE2001 gives errors if distance input is too large! 100 kpc ought to be
    # enough to clear the galaxy.
    dist[dist > 100] = 100
    sms = np.ones_like(dist)
    smtaus = np.ones_like(dist)

    for i, d in enumerate(dist):

        disti = C.c_float(d)
        # Note the galactic coordinates need to be given in radians
        gli = C.c_float(math.radians(gl[i]))
        gbi = C.c_float(math.radians(gb[i]))

        ndir = C.c_int(-1)
        sm = C.c_float(0.)
        smtau = C.c_float(0.)

        inpath = C.create_string_buffer(dm_mods.encode())
        linpath = C.c_int(len(dm_mods))

        ne2001lib.dmdsm_(C.byref(gli),
                         C.byref(gbi),
                         C.byref(ndir),
                         C.byref(C.c_float(0.0)),
                         C.byref(disti),
                         C.byref(C.create_string_buffer(' '.encode())),
                         C.byref(sm),
                         C.byref(smtau),
                         C.byref(C.c_float(0.0)),
                         C.byref(C.c_float(0.0)),
                         C.byref(inpath),
                         C.byref(linpath)
                         )

        sms[i], smtaus[i] = sm.value, smtau.value

    return sms, smtaus

def ne2001_scint_time_bw(dist, gl, gb, freq):
    """
    Use the NE2001 model to get the diffractive scintillation timescale.

    Args:
        dist (array): Distance to source [Gpc]. Distance will be cut at 100 kpc
                      as NE2001 can not cope with larger distances. Therefore
                      the calculated scintillation timescale will only be that
                      from the Milky Way.
        gl (array): Galactic longitude [fractional degrees]
        gb (array): Galactic latitude [fractional degrees]
        freq (float): Observing frequency [MHz]
    Returns:
        scint_time (float): Diffractive scintillation timescale [Hz]
        scint_bw (float): Scintillation bandwidth [Hz]

    """
    dist *= 1e6  # Convert from Gpc to kpc

    sm, smtau = ne2001_get_smtau(dist, gl, gb)

    scint_time = np.ones_like(dist)
    scint_time[smtau <= 0.] = float('NaN')
    # Eq. 46 of Cordes & Lazio 1991, ApJ, 376, 123 uses coefficient 3.3
    # instead of 2.3. They do this in the code and mention it explicitly,
    # so I trust it! <- From psrpoppy
    scint_time[smtau > 0.] = 3.3 * (freq/1e3)**1.2 * smtau**(-0.6)

    scint_bw = np.ones_like(dist)
    scint_bw[sm <= 0.] = float('NaN')
    # (eq. 48)
    scint_bw[sm > 0.] = 223. * (freq/1e3)**4.4 * sm**(-1.2) / dist

    return scint_time, scint_bw

def scatter_bhat(dm, offset=-6.46, scindex=-3.86, freq=1400.0):
    """
    Calculate scattering timescale (values default to those from Bhat et al.
    (2004, DOI:10.1086/382680) and to simluate the scatter around this
    relationship, draw from a Gaussian around this value.

    Args:
        dm (array): Dispersion measure [pc*cm^-3]
        offset (float): Offset of scattering relationship. Defaults to -6.46
        scindex (float): Scattering index. Defaults to -3.86
        freq (float): Frequency at which to evaluate scattering time [MHz].
                      Defaults to 1400 MHz
    Returns:
        array: Scattering timescale [ms]

    """
    log_t = offset + 0.154*np.log10(dm) + 1.07*np.log10(dm)**2
    log_t += scindex*np.log10(freq/1e3)

    # Width of Gaussian distribution based on values given Lorimer et al (2008)
    t_scat = 10**np.random.normal(log_t, 0.8)

    return t_scat

def load_T_sky():
    """
    Read the Haslam sky temperature map into a list.

    ... from which temperatures can
    be retrieved. The temperature sky map is given in the weird units of
    HealPix, and despite looking up info on this coordinate system, I don't
    have the foggiest idea of how to transform these to galactic coordinates. I
    have therefore directly copied the following code from psrpoppy in the
    assumption Sam Bates managed to figure it out.

    Returns:
        t_sky_list (list): List of sky temperatures in HealPix? coordinates?

    """
    model = os.path.join(os.path.dirname(__file__), '../data/models/tsky/')
    path = os.path.join(model, 'haslam_2014.dat')

    t_sky_list = []
    with open(path) as f:
        for line in f:
            str_idx = 0
            while str_idx < len(line):
                # each temperature occupies space of 5 chars
                temp_string = line[str_idx:str_idx+5]
                try:
                    t_sky_list.append(float(temp_string))
                except ValueError:
                    pass
                str_idx += 5

    return t_sky_list

class Redshift:
    """Class for converting redshift to other distance measures."""

    def __init__(self, z, H_0=67.74, W_m=0.3089, W_v=0.6911):
        """
        Convert redshift to a various measures.

        Based on James Schombert's python implementation of Edward L. Wright's
        cosmology calculator.

        Args:
            z (array): Redshift
            self.H_0 (float, optional): Hubble parameter.
            self.W_m (float, optional): Omega matter.
            self.W_v (float, optional): Omega vacuum.

        Returns:
            array: One of the distance measures [Gpc], or comoving volume from
                Earth to the source [Gpc^3]

        """
        self.z = z
        self.H_0 = H_0
        self.W_m = W_m
        self.W_v = W_v

        # Initialize constants
        self.W_r = 0.4165/(self.H_0*self.H_0)  # Omega radiation
        self.W_k = 1.0 - self.W_m - self.W_r - self.W_v  # Omega curvature
        self.c = 299792.458  # Velocity of light [km/sec]
        self.dcmr = 0.
        self.az = 1/(1+self.z)

        # Distance measures
        self.dc_mpc = None
        self.dl_mpc = None

    def dist_co(self):
        """Calculate the corresponding comoving distance [Gpc]."""
        n = 1000

        for i in range(n):
            a = self.az+(1-self.az)*(i+0.5)/n
            s = sum([self.W_k, self.W_m/a, self.W_r/(a*a), self.W_v*a*a])
            adot = np.sqrt(s)
            self.dcmr += 1/(a*adot)

        self.dcmr = (1.-self.az)*self.dcmr/n

        self.dc_mpc = (self.c/self.H_0)*self.dcmr  # Comoving distance [Mpc]

        return self.dc_mpc*1e-3  # Convert to Gpc

    def dist_lum(self):
        """Calculate the corresponding luminosity distance [Gpc]."""
        if self.dc_mpc is None:
            self.dist_co()

        # Calculate luminosity distance
        ratio = np.ones_like(self.dcmr)
        x = np.sqrt(abs(self.W_k))*self.dcmr

        mask = (x > 0.1)

        if self.W_k > 0:
            ratio[mask] = 0.5*(np.exp(x[mask])-np.exp(-x[mask]))/x[mask]
        else:
            ratio[mask] = np.sin(x[mask])/x[mask]

        y = x*x
        if self.W_k < 0:
            y = -y
        ratio[~mask] = 1. + y[~mask]/6. + y[~mask]*y[~mask]/120.

        dcmt = ratio*self.dcmr
        da = self.az*dcmt
        dl = da/(self.az*self.az)
        self.dl_mpc = (self.c/self.H_0)*dl  # Luminosity distance [Mpc]

        return self.dl_mpc*1e-3  # Covert to Gpc

    def vol_co(self):
        """Calculate the corresponding comoving volume [Gpc^3]."""
        if self.dl_mpc is None:
            self.dist_lum()

        ratio = np.ones_like(self.dcmr)
        x = math.sqrt(abs(self.W_k))*self.dcmr

        mask = (x > 0.1)

        if self.W_k > 0:
            n = (0.125*(np.exp(2.*x[mask])-np.exp(-2.*x[mask]))-x[mask]/2.)
            ratio[mask] = n/(x[mask]**3/3)
        else:
            ratio[mask] = (x[mask]/2. - np.sin(2.*x[mask])/4.)/(x[mask]**3/3)

        y = x*x
        if self.W_k < 0:
            y = -y
        ratio[~mask] = 1. + y[~mask]/5. + (2./105.)*y[~mask]*y[~mask]

        v_cm = ratio*self.dcmr**3/3
        self.v_gpc = 4.*math.pi*((1e-3*self.c/self.H_0)**3)*v_cm

        return self.v_gpc

def z_to_d_approx(z, H_0=67.74):
    """
    Calculate distance in Gpc from a redshift.

    Only holds for z <= 2. Formulas from 'An Introduction to Modern
    Astrophysics (2nd Edition)' by Bradley W. Carroll, Dale A. Ostlie.
    (Eq. 27.7)

    Args:
        z (float): Redshift
        H_0 (float, optional): Hubble parameter. Defaults to 67.74
    Returns:
        dist (float): Associated distance [Gpc]
    """
    c = 299792.458  # Velocity of light [km/sec]
    zsq = (z+1)**2
    dist = c/H_0 * (zsq - 1)/(zsq + 1)
    dist /= 1e3  # Mpc -> Gpc
    return dist

def dist_to_z(dist, H_0=67.74):
    """
    Calculate redshift from a distance in Gpc.

    Only holds for z <= 2. Formulas from 'An Introduction to Modern
    Astrophysics (2nd Edition)' by Bradley W. Carroll, Dale A. Ostlie.
    (Eq. 27.7)

    Args:
        dist (float): Distance [Gpc].
        H_0 (float, optional): Hubble parameter. Defaults to 67.74
    Returns:
        z (float): Associated redshift
    """
    c = 299792.458  # Velocity of light [km/sec]
    dist *= 1e3  # Gpc -> Mpc
    dhc = dist*H_0/c
    det = math.sqrt(1 - dhc**2)
    z = -(det + dhc - 1)/(dhc - 1)
    return z

def datetime_to_julian(date):
    """Convert a datetime object into julian float.

    See https://aa.usno.navy.mil/faq/docs/JD_Formula.php for more info.

    Args:
        date (datetime-object): Date in question

    Returns:
        float: Julian calculated datetime.

    """
    # Add support for numpy arrays of datetime64
    if np.issubdtype(date.dtype, np.datetime64):
        date = pd.to_datetime(date)

    # Define terms
    y = date.year
    m = date.month
    d = date.day
    h = date.hour
    min = date.minute
    sec = date.second

    # Calculate julian day number
    jdn = 367*y - ((7*(y + ((m+9)/12).astype(int)))/4).astype(int)
    jdn += ((275*m)/9).astype(int) + d + 1721013.5
    # Add fractional day
    jd = jdn + h/24 + min/1440 + sec/86400

    # Convert to a numpy array
    if isinstance(jd, pd.Float64Index):
        jd = jd.values

    return jd

def datetime_to_gmst(date):
    """Calculate Greenwich Mean Sidereal Time.

    See https://aa.usno.navy.mil/faq/docs/GAST.php for more info.
    """
    jd = datetime_to_julian(date)
    return ((18.697374558 + 24.06570982441908*(jd - 2451545))*15) % 360

def random_date(start, end):
    """Generate a random datetime between two datetime objects."""
    delta = end - start
    int_delta = (delta.days * 24 * 60 * 60) + delta.seconds
    random_second = random.randrange(int_delta)
    return start + timedelta(seconds=random_second)

def coord_to_offset(xref, yref, x, y):
    """
    Convert point (x, y) to projected offset from reference (xref, yref).

    Makes use of a gnomonic projection: see both
        https://github.com/LSSTDESC/Coord/blob/master/coord/celestial.py
        http://mathworld.wolfram.com/GnomonicProjection.html

    Args:
        xref (array): Reference RA or Az [rad]
        yref (array): Reference Dec or Alt [rad]
        x (array): Target RA or Az [rad]
        y (array): Target Dec or Alt [rad]

    Returns:
        array, array: x and y offset [rad]

    """
    # Define convenience numbers
    sinxref = np.sin(xref)
    sinx = np.sin(x)
    cosxref = np.cos(xref)
    cosx = np.cos(x)

    sinyref = np.sin(yref)
    siny = np.sin(y)
    cosyref = np.cos(yref)
    cosy = np.cos(y)

    # Sine and cosine of shift in x
    cosdx = (cosxref * cosx) + (sinxref * sinx)
    sindx = (cosxref * sinx) - (sinxref * cosx)

    # Projection effect cosine
    cosc = sinyref * siny + cosyref * cosy * cosdx

    # Projected offsets
    dx = (cosy * sindx) / cosc
    dy = (cosyref * siny - sinyref * cosy * cosdx) / cosc

    if isinstance(cosc, np.ndarray):
        dx[cosc < 0] = np.nan
        dy[cosc < 0] = np.nan
    elif cosc < 0:
        dx, dy = np.nan, np.nan

    return dx, dy

def hadec_to_azalt(ha, dec, lat):
    """
    Convert hour angle and declination to azimuth and altitude.

    Args:
        ha (array): Hour angle [rad]
        dec (array): Declination [rad]
        lat (float): Latitude [rad]

    Returns:
        array, array: az, alt [rad]

    """
    # Ha and dec should be same type
    assert type(ha) == type(dec)

    # Altitude
    sinalt = np.sin(dec) * np.sin(lat) + np.cos(dec) * np.cos(lat) * np.cos(ha)
    alt = np.arcsin(sinalt)

    # Azimuth (note this uses altitude)
    cosaz = (np.sin(dec)-np.sin(alt)*np.sin(lat)) / (np.cos(alt)*np.cos(lat))

    convert_to_float = False
    if isinstance(cosaz, float):
        cosaz = np.array([cosaz])
        convert_to_float = True

    # Numerical instability can cause cosaz > 1
    cosaz[cosaz > 1] = 1
    cosaz[cosaz < -1] = -1
    az = np.arccos(cosaz)

    # Sign of azimuth is lost, but can be recovered using the input hour angle
    mask = np.sin(ha) > 0
    az[mask] = 2*np.pi - az[mask]

    # Convert back to float if input was float
    if convert_to_float:
        az = float(az)

    return az, alt

def in_region(ra, dec, gl, gb,
              ra_min=0, ra_max=360,
              dec_min=-90, dec_max=90,
              gl_min=-180, gl_max=180,
              gb_min=-90, gb_max=90):
    """
    Check if the given frbs are within the survey region.

    Args:
        ra, dec, gl, gb (float): Coordinates to check whether in region

    Returns:
        array: Boolean mask denoting whether frbs are within survey region

    """
    # Create mask with False
    mask = np.ones_like(ra, dtype=bool)

    # Ensure in correct format
    gl[gl > 180.] -= 360.

    # Create region masks
    gl_limits = (gl > gl_max) | (gl < gl_min)
    gb_limits = (gb > gb_max) | (gb < gb_min)
    ra_limits = (ra > ra_max) | (ra < ra_min)
    dec_limits = (dec > dec_max) | (dec < dec_min)

    mask[gl_limits] = False
    mask[gb_limits] = False
    mask[ra_limits] = False
    mask[dec_limits] = False

    return mask

def calc_sky_radius(area):
    """Determine the radius [deg] along the sky of an area [sq. degrees]."""
    # Check whether the full sky
    if np.allclose(area, 4*np.pi*(180/np.pi)**2):
        return 180
    else:
        cos_r = (1 - (area*np.pi)/(2*180**2))
        # Suppressing warnings when cos_r is invalid (will nan anyway)
        with np.errstate(invalid='ignore'):
            return np.rad2deg(np.arccos(cos_r))

def calc_sky_area(radius):
    """Determine the area [sq. degree] of a radius [deg] along the sky."""
    return (1 - np.cos(np.deg2rad(radius)))*(2*180**2)/np.pi


from reportlab.lib import colors
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.platypus import Paragraph
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.enums import TA_JUSTIFY

def generate_prescription(patient_name, doctor_name, medicine_list, logo_path, rx_path, signature_path, prescription_no, consultation_no, doctor_email, medconnect_id, reg_no, doctor_location, patient_id, patient_location, date, remarks, doctor_title):
    # Create a file named after the patient
    filename = f"{patient_name}_prescription.pdf"
    c = canvas.Canvas(filename, pagesize=A4, bottomup=1)

    # MedConnect Logo
    c.setFillColor(colors.white)
    c.drawImage(logo_path, 12, 759 - 16, width=169, height=83.12)

    # Rx logo
    c.drawImage(rx_path, 595-60-12, 759 - 4, width=60, height=60)

    # Document Nos.
    c.setFillColor(colors.black)

    c.setFont("Courier", 13)
    c.drawRightString(525, 735 , "Prescription No:")
    c.setFont("Courier", 13)
    c.drawRightString(570, 735, f"#{prescription_no}")

    c.drawRightString(525, 720 , "Consultation No:")
    c.setFont("Courier", 13)
    c.drawRightString(570, 720, f"#{consultation_no}")

    #Doctor Details
    c.setFillColor(colors.black)
    c.setFont("Courier", 13)

    c.drawRightString(570, 680 , "+917738118110")

    c.drawRightString(570, 665 , f"{doctor_email}")

    c.drawRightString(450, 650 , "MedConnect Id.: ")
    c.setFont("Courier", 13)
    c.drawRightString(570, 650 , f"{medconnect_id}")

    c.drawRightString(450, 635 , "Reg. No.: ")
    c.setFont("Courier", 13)
    c.drawRightString(570, 635 , f"{reg_no}")

    #Doctor Headers
    c.setFont("Courier-Bold", 21)
    c.drawString(12, 680, f"Dr. {doctor_name}")
    c.setFont("Courier", 13)
    c.drawString(12, 665 , f"{doctor_location}")

    # Patient Details
    c.setFont("Courier", 13)
    c.drawString(12, 620 , "Patient Id:")
    c.drawString(100, 620 , f"# {patient_id}")
    c.drawString(12, 605 , "Patient:")
    c.setFont("Courier-Bold", 13)
    c.drawString(100, 605 , f"{patient_name}")
    c.setFont("Courier", 13)
    c.drawString(100, 590 , f"{patient_location}")
    c.drawString(12, 575 , "Date:")
    c.drawString(100, 575 , f"{date}")

    c.setFont("Courier-Bold", 18)
    c.drawString(12, 530 , "Treatment Advised")

    # Add a table with the medicine list
    c.setFont("Courier-Bold", 13)
    c.drawString(12, 500, "Type")
    c.drawString(97, 500, "Medicine")
    c.drawString(242, 500, "Power")
    c.drawString(346, 500, "Frequency")
    c.drawString(440, 500, "Remarks")
    c.setStrokeColor(colors.grey)
    c.line(12, 490, 570, 490)
    c.setFont("Courier", 13)
    for i, medicine in enumerate(medicine_list):
        c.drawString(12, 475 - i * 25, medicine[0])
        c.drawString(97, 475 - i * 25, medicine[1])
        c.drawString(242, 475 - i * 25, medicine[2])
        c.drawString(346, 475 - i * 25, medicine[3])
        c.drawString(440, 475 - i * 25, medicine[4])

    c.setFont("Courier-Bold", 18)
    c.drawString(12, 280 , "Next Investigation / Other Remarks")
    style = getSampleStyleSheet()["Normal"]
    style.fontName = "Courier"
    style.fontSize = 12
    style.alignment = TA_JUSTIFY

    p = Paragraph(remarks, style)
    p.wrapOn(c, 558, 100)
    p.drawOn(c, 12, 140)

    c.drawImage(signature_path, 456, 66, width=86, height=39)
    c.setFont("Courier-Bold", 13)
    c.drawRightString(570, 47 , f"{doctor_name}")
    c.setFont("Courier", 10)
    c.drawRightString(570, 33 , f"{doctor_title}")

    c.line(12, 18, 570, 18)
    c.setFont("Courier", 10)
    c.drawString(12, 5, "Thank you for choosing MedConnect. Have a Healthy Day!")

    # Save the PDF
    c.save()

medicine_list = [
    ("Tablet","Paracetamol", "500 mg", "1-0-1", "-"),
    ("Tablet","Dolo", "10 mg", "0-1-0", "-"),
    ]

remarks = "Take rest. Do not work more."

generate_prescription("Prem Kothawle", "Dr. Shubham Saroj", medicine_list, "medconnect_logo.jpg", "rx_logo.jpg", "Shubham_Sign.jpeg", "1258", "1279", "drssaroj@gmail.com", "86438648464", "123454321234", "Thane, India", "2547", "Nere, India", "10 February 2023", remarks, "M.B.B.S")

# patient_name, doctor_name, medicine_list, logo_path, rx_path, signature_path, prescription_no, consultation_no, doctor_email, medconnect_id, reg_no, doctor_location, patient_id, patient_location, date, remarks, doctor_title


from django.test import TestCase
from feedback.forms import FeedbackForm

class TestForms(TestCase):

    def test_feedback_form_valid_data(self):
        form = FeedbackForm(data={
            'titolo': 'Recensione',
            'descrizione': 'Una descrizione',
            'voto': 5
        })

        self.assertTrue(form.is_valid())

    def test_user_form_no_data(self):
        form = FeedbackForm(data={})

        self.assertFalse(form.is_valid())
        self.assertEquals(len(form.errors), 3)


#!/usr/bin/python
# -*- coding: UTF-8 -*-
# from multiprocessing.pool import ThreadPool
import threading
from time import sleep
import requests
from selenium import webdriver
from bs4 import BeautifulSoup
import output as op
class FlaskScraper:

	# groupName: webUrl
	dictOfNameAndWebUrl = {}

	# weburl: webCont
	dictOfNameAndWebCont = {}

	# weburl: webCOnt without mark
	dictOfNameAndWebContWithoutMk = {}

	# initialize
	def __init__(self, chatBot, dictOfNameAndWebsite):
		for key in dictOfNameAndWebsite:
			web = dictOfNameAndWebsite[key]
			if(key in FlaskScraper.dictOfNameAndWebUrl.keys()):
				FlaskScraper.dictOfNameAndWebUrl[key] = web
				# if(not web in FlaskScraper.dictOfNameAndWebCont.keys()):
				FlaskScraper.dictOfNameAndWebCont.setdefault(web, ['null'])
				FlaskScraper.dictOfNameAndWebContWithoutMk.setdefault(web, ['null'])
				# FlaskScraper.dictOfNameAndWebCont.setdefault(web, self.ScraperFromFlaskByCheck(key))
			else:
				FlaskScraper.dictOfNameAndWebUrl.setdefault(key, web)
				# if(not web in FlaskScraper.dictOfNameAndWebCont.keys()):
				FlaskScraper.dictOfNameAndWebCont.setdefault(web, ['null'])
				FlaskScraper.dictOfNameAndWebContWithoutMk.setdefault(web, ['null'])
				# FlaskScraper.dictOfNameAndWebCont.setdefault(web, self.ScraperFromFlaskByCheck(key))
				self.MultiClientController(chatBot, {key : web})
		# self.UpdateWebsiteUrl(chatBot, dictOfNameAndWebsite)
		# self.UpdateWebsiteCont(dictOfNameAndWebsite)

	def Scraper(weburl):
		driver = webdriver.Chrome("/usr/local/share/chromedriver")
		driver.get(weburl)
		try:
			driver.find_element_by_xpath("//a[contains(text(),'Show all completed tasks')]").click()
		except:
			pass

		# driver.find_element_by_id()
		# print("------------", driver.page_source)
		sleep(2)
		soup = BeautifulSoup(driver.page_source, "html.parser")
		spanlist = soup.find_all('span', attrs={'class':'best_in_place'})
		driver.quit()
		return spanlist

	# bind group name with url & bind group name with web content
	def UpdateWebsiteUrl(self, chatBot, key, web):
		# for key in incDicOfNameAndWebsite:
		# 	web = incDicOfNameAndWebsite[key]
		# print(1)
		if(web in FlaskScraper.dictOfNameAndWebUrl.values()):
			return "fail"
		# print(2)
		if(key in FlaskScraper.dictOfNameAndWebUrl.keys()):
			FlaskScraper.dictOfNameAndWebUrl[key] = web
			# if(not web in FlaskScraper.dictOfNameAndWebCont.keys()):
			FlaskScraper.dictOfNameAndWebCont.setdefault(web, ['null'])
			FlaskScraper.dictOfNameAndWebContWithoutMk.setdefault(web, ['null'])
			# FlaskScraper.dictOfNameAndWebCont.setdefault(web, self.ScraperFromFlaskByCheck(key))
		else:
			FlaskScraper.dictOfNameAndWebUrl.setdefault(key, web)
			# if(not web in FlaskScraper.dictOfNameAndWebCont.keys()):
			FlaskScraper.dictOfNameAndWebCont.setdefault(web, ['null'])
			FlaskScraper.dictOfNameAndWebContWithoutMk.setdefault(web, ['null'])
			# FlaskScraper.dictOfNameAndWebCont.setdefault(web, self.ScraperFromFlaskByCheck(key))
			self.MultiClientController(chatBot, {key : web})
		return "succeed"

	# multiple clients generator
	def MultiClientController(self, chatBot, nameOfGrp):
		for k in nameOfGrp:
			try:
				thread = threading.Thread(target=ScraperTimeController, args=(k, chatBot, ))
				thread.start()
			except:
				print ("Error: unable to start thread for %s !" %(k))

	# check command
	def ScraperFromFlaskByCheck(self, nameOfGrp):
		# print(dictOfNameAndWebsite.value[0])
		# html = requests.get(dictOfNameAndWebsite.values()[0]).content
		thisKey = FlaskScraper.dictOfNameAndWebUrl[nameOfGrp]
		# html = requests.get(thisKey).content

		# driver.get(thisKey)
		# driver.find_element_by_xpath("//a[contains(text(),'Show all completed tasks')]").click()
		# sleep(2)
		# soup = BeautifulSoup(driver.page_source, "html.parser")
		# spanlist = soup.find_all('span', attrs={'class':'best_in_place'})

		spanlist = FlaskScraper.Scraper(thisKey)

		# print("before")

		MessageWithoutMk, Message = op.ChangeFormatOfOutput(spanlist)
		# print("in")
		if (Message != FlaskScraper.dictOfNameAndWebCont[thisKey]):
			# print("in if")
			FlaskScraper.dictOfNameAndWebCont[thisKey] = Message
			# print("in if 2")
			FlaskScraper.dictOfNameAndWebContWithoutMk[thisKey] = MessageWithoutMk
			# print("in if 3")
		# print("after")

		# Message = []
		# for i in range(1,len(spanlist)):
		# 	checkbox=str(spanlist[i].find_previous_sibling('input'))
		# 	if 'checked' in checkbox:
		# 		Message.append(spanlist[i].text+'-completed')
		# 	else:
		# 		Message.append(spanlist[i].text+'-uncompleted')
		# if (Message != FlaskScraper.dictOfNameAndWebCont[thisKey]):
		# 	FlaskScraper.dictOfNameAndWebCont[thisKey] = Message

		return Message

# time controller, send news to users
def ScraperTimeController(key, chatBot):
	while True:
		weburl = FlaskScraper.dictOfNameAndWebUrl[key]
		Message = ScraperFromFlaskByTime(weburl)
		if(Message != ['null']):
			# News=weburl + '\n' +'Update: \n'
			News = ""
			for strMessage in Message:
				News = News + strMessage + '\n'
			News = News + weburl
			my_friend = chatBot.search(puid=key)[0]
			my_friend.send(News)
		sleep(3)

# listen to the website, return news
def ScraperFromFlaskByTime(weburl):

	spanlist = FlaskScraper.Scraper(weburl)
	print("test1")
	# driver.get(thisKey)
	# driver.find_element_by_xpath("//a[contains(text(),'Show all completed tasks')]").click()
	# sleep(2)
	# soup = BeautifulSoup(driver.page_source, "html.parser")
	# spanlist = soup.find_all('span', attrs={'class':'best_in_place'})

	# html = requests.get(weburl).content
	# soup = BeautifulSoup(html,"html.parser")
	# spanlist = soup.find_all('span',attrs={'class':'best_in_place'})

	MessageWithoutMk, Message = op.ChangeFormatOfOutput(spanlist)
	oldContent = []
	for v in FlaskScraper.dictOfNameAndWebContWithoutMk[weburl]:
		oldContent.append(v)

	# first time to log
	if (FlaskScraper.dictOfNameAndWebCont[weburl] == ['null'] and \
			Message != FlaskScraper.dictOfNameAndWebCont[weburl]):
		FlaskScraper.dictOfNameAndWebCont[weburl] = Message
		FlaskScraper.dictOfNameAndWebContWithoutMk[weburl] = MessageWithoutMk
		return Message
	elif (Message != FlaskScraper.dictOfNameAndWebCont[weburl]):
		print(Message)
		print(MessageWithoutMk)
		print(oldContent)
		print(FlaskScraper.dictOfNameAndWebContWithoutMk[weburl])
		# print("Message",Message)
		# print("FlaskScraper.dictOfNameAndWebCont[weburl])", FlaskScraper.dictOfNameAndWebCont[weburl])
		tmplist = []
		cnt = 0
		for i in range(len(MessageWithoutMk)):
			if MessageWithoutMk[i] in oldContent:
				if Message[i] not in FlaskScraper.dictOfNameAndWebCont[weburl]:
					print("Message[%d]" %(i), Message[i])
					print("oldContent index", oldContent.index(MessageWithoutMk[i]))
					print("oldCOntent", oldContent)
					print("cont",FlaskScraper.dictOfNameAndWebCont[weburl])
					tmplist.append("\u2713 " + MessageWithoutMk[i]) # finished
				oldContent.remove(MessageWithoutMk[i])
				cnt = cnt + 1
			else:
				# print("not in MessageWithoutMk[%d]" %(i), MessageWithoutMk[i])
				# print("oldContent", oldContent)
				# print("tmplist[0]", MessageWithoutMk[i])
				print("--------------------------------")
				tmplist.append("\u2610 " + MessageWithoutMk[i])     # added
		for i in range(len(oldContent)):
			tmplist.append("\u2717 " + oldContent[i])         # delete

		print("final",tmplist)
		if(tmplist != []):
			FlaskScraper.dictOfNameAndWebCont[weburl] = Message
			FlaskScraper.dictOfNameAndWebContWithoutMk[weburl] = MessageWithoutMk
			return tmplist
		else:
			return ['null']
		# cnt = 0

	else:
		return ['null']
	# newContent = []
	# Message = []
	# oldContent = FlaskScraper.dictOfNameAndWebCont[weburl]
	# dictOldContent = {}
	# for cont in oldContent:
	# 	if cont.find('-completed') > 0:
	# 		dictOldContent[cont[:cont.find('-completed')]] ='-completed'
	# 	elif cont.find('-uncompleted') > 0:
	# 		dictOldContent[cont[:cont.find('-uncompleted')]] ='-uncompleted'
	# for i in range(1,len(spanlist)):
	# 	checkbox=str(spanlist[i].find_previous_sibling('input'))
	# 	if 'checked' in checkbox:
	# 		newContent.append(spanlist[i].text+'-completed')
	# 		if spanlist[i].text in dictOldContent.keys():
	# 			if dictOldContent[spanlist[i].text] == '-uncompleted':
	# 				Message.append('completed: '+spanlist[i].text)
	# 			dictOldContent[spanlist[i].text] = '-checked'
	# 		else:
	# 			Message.append('add: '+spanlist[i].text)
	# 	else:
	# 		newContent.append(spanlist[i].text+'-uncompleted')
	# 		if spanlist[i].text in dictOldContent.keys():
	# 			if dictOldContent[spanlist[i].text] == '-completed':
	# 				Message.append('uncompleted: '+spanlist[i].text)
	# 			dictOldContent[spanlist[i].text] = '-checked'
	# 		else:
	# 			Message.append('add: '+spanlist[i].text)
	# for cont in dictOldContent:
	# 	if dictOldContent[cont] != '-checked':
	# 		Message.append('delete: ' + cont)
	# if Message !=[]:
	# 	FlaskScraper.dictOfNameAndWebCont[weburl]=newContent
	# 	return Message
	# else:
	# 	return ['null']


#! /usr/bin/env python

import sys
import copy
import rospy
import actionlib
import moveit_commander
import moveit_msgs.msg
import geometry_msgs.msg
import numpy as np
from std_msgs.msg import Int32
from policies.policies import Policy, PositionPolicy, GripperCurrentPolicy, TactilePolicy
from tams_tactile_sensor_array.msg import TactileSensorArrayData
from geometry_msgs.msg import Twist
from sensor_msgs.msg import Joy, JointState
from controller_manager_msgs.srv import SwitchController
from diana7_msgs.srv import SetControlMode, SetControlModeRequest, SetImpedance, SetImpedanceRequest
from diana7_msgs.msg import CartesianState
from fabric_grasping.msg import GraspAction, GraspResult, GraspFeedback, GraspGoal

class GraspServer:
    def __init__(self):
        moveit_commander.roscpp_initialize(sys.argv)
        rospy.init_node("diana7_grasp_server")

        self.action_name = 'grasp'
        self.max_grasp_torque_2 = 200
        self.max_grasp_torque_3 = 100
        self.max_pressure = 15
        self.pressure_threshold = 5  # pressure hysteresis when approaching table

        self.approach_speed = 0.04
        self.retreat_speed = 0.01
        self.fine_speed = 0.005
        self.gripper_goal = 0.2

        # self.policy = PositionPolicy(gripper_goal=1.0)
        # self.policy = GripperCurrentPolicy(gripper_current_goal=600)
        # self.policy = GripperCurrentPolicy(gripper_current_goal=1000)
        self.policy = TactilePolicy(cell_active_threshold=900, max_gripper_current=1800, max_cell_loss=2)
        self.policy.gripper_goal_cb(self.gripper_goal)

        self.current = False

        self.new_tactile_data = False
        self.last_tactile_sensor_data_1 = None
        self.last_tactile_sensor_data_2 = None
        self.forces = None
        self.torques_2 = np.array([])
        self.torques_3 = np.array([])
        self.cartesian_state = None

        self.robot = moveit_commander.RobotCommander()

        self.scene = moveit_commander.PlanningSceneInterface(synchronous=True)
        self.arm_group = moveit_commander.MoveGroupCommander('arm')
        self.gripper_group = moveit_commander.MoveGroupCommander('gripper')

        rospy.wait_for_service('/controller_manager/switch_controller')
        self.switch_controllers = rospy.ServiceProxy('/controller_manager/switch_controller', SwitchController)
        rospy.wait_for_service('/diana7_hardware_interface/set_control_mode')
        self.set_mode = rospy.ServiceProxy('/diana7_hardware_interface/set_control_mode', SetControlMode)
        rospy.wait_for_service('/diana7_hardware_interface/set_cartesian_impedance')
        self.set_cart_imp = rospy.ServiceProxy('/diana7_hardware_interface/set_cartesian_impedance', SetImpedance)
        rospy.wait_for_service('/diana7_hardware_interface/set_joint_impedance')
        self.set_joint_imp = rospy.ServiceProxy('/diana7_hardware_interface/set_joint_impedance', SetImpedance)

        self.forces_sub = rospy.Subscriber("/diana_gripper/forces_raw", Joy, self.forces_cb)
        self.torques_sub = rospy.Subscriber("/diana_gripper/torques", Joy, self.torques_cb)
        self.joint_state_sub = rospy.Subscriber("/current", Int32, self.current_cb)
        self.cartesian_state_sub = rospy.Subscriber("cartesian_state_controller/cartesian_state", CartesianState, self.cartesian_state_cb)
        self.tactile_sensor_sub_1 = rospy.Subscriber("tactile_sensor_data/1", TactileSensorArrayData, self.tactile_sensor_cb)
        self.tactile_sensor_sub_2 = rospy.Subscriber("tactile_sensor_data/2", TactileSensorArrayData, self.tactile_sensor_cb)

        self.gripper_goal_pub = rospy.Publisher('diana_gripper/simple_goal', JointState, queue_size=10)
        self.arm_vel_pub = rospy.Publisher('/cartesian_twist_controller/command', Twist, queue_size=10)

        self.grasp_action_server = actionlib.SimpleActionServer(self.action_name, GraspAction, execute_cb=self.grasp_cb, auto_start = False)
        self.grasp_action_server.start()

    def grasp_cb(self, goal: GraspGoal):

        self.load_twist_controller()

        print('start control loop.')

        self.policy.reset()

        self.gripper_goal = 0.2
        grasp_finished = False
        first_contact = False
        backdrive = 0

        r = rospy.Rate(50) # 50hz
        while not grasp_finished and not rospy.is_shutdown():
            # contact with the piece (towards the table) has been made, slightly retracting and switching to impedance mode...
            if backdrive > 0:
                self.move_up(self.retreat_speed)
                backdrive -= 1
                if backdrive == 0:
                    self.unload_controllers()
                    self.to_impedance_mode()
                    self.load_twist_controller()
            # not in backdrive mode, acting normally.
            else:
                pressure = self.cartesian_state.wrench.linear.z
                print(pressure)
                if pressure > self.pressure_threshold:
                    # if not in impedance mode already
                    if not first_contact:
                        # move slightly back and switch to impedance mode
                        first_contact = True
                        backdrive = 25
                # move up in case the maximal pressure was surpassed
                if pressure > self.max_pressure + self.pressure_threshold:
                    print('up')
                    self.move_up(self.approach_speed)
                # move down if the pressure is too low
                elif pressure < self.max_pressure - self.pressure_threshold:
                    print('down')
                    # move slowly when first contact was made as collision is imminent.
                    if first_contact:
                        self.move_down(self.fine_speed)
                    else:
                        self.move_down(self.approach_speed)
                # pressure towards the table is in desired zone
                else:
                    self.stop()
                    print('stop')
                    # if len(self.torques_2) and self.torques_2.mean() < self.max_grasp_torque_2:
                    self.apply_policy()
                    self.send_gripper_goal()
                if self.policy.finished():  # self.torques_2.mean() > self.max_grasp_torque_2 or self.torques_3.mean() > self.max_grasp_torque_3:
                    grasp_finished = True
            r.sleep()
        self.grasp_action_server.set_succeeded(GraspResult())

    def move_down(self, speed=0.004):
        speed = -abs(speed)
        msg = Twist()
        msg.linear.z = speed
        self.arm_vel_pub.publish(msg)

    def current_cb(self, msg):
        self.current = msg.data
        self.policy.gripper_current_cb(self.current)

    def move_up(self, speed=0.004):
        speed = abs(speed)
        msg = Twist()
        msg.linear.z = speed
        self.arm_vel_pub.publish(msg)

    def stop(self):
        msg = Twist()
        self.arm_vel_pub.publish(msg)

    def load_position_controller(self):
        print('loading position controller')
        try:
            self.switch_controllers(['joint_position_trajectory_controller'], ['cartesian_twist_controller'], 1, False, 0)
        except rospy.ServiceException as e:
            print("Service did not process request: " + str(e))

    def load_twist_controller(self):
        print('loading twist controller')
        try:
            self.switch_controllers(['cartesian_twist_controller'], ['joint_position_trajectory_controller'], 1, False, 0)
        except rospy.ServiceException as e:
            print("Service did not process request: " + str(e))

    def unload_controllers(self):
        try:
            self.switch_controllers([], ['cartesian_twist_controller', 'joint_position_trajectory_controller'], 1, False, 0)
        except rospy.ServiceException as e:
            print("Service did not process request: " + str(e))

    def move_to_init(self):
        self.load_position_controller()
        print("moving to init pose.")
        # self.move_gripper_to_named_target('wide_open_parallel')
        # self.set_gripper_goal_position(-0.5)
        self.set_gripper_goal_position(0.2)
        self.send_gripper_goal()
        self.move_arm_to_named_target('idle_user_high')

    def forces_cb(self, msg):
        self.forces = msg
        self.policy.force_cb(msg)

    def torques_cb(self, msg):
        # self.torques_2 = np.concatenate((self.torques_2, [msg.axes[2]]))[-10:]
        # self.torques_3 = np.concatenate((self.torques_3, [msg.axes[3]]))[-10:]
        self.policy.torque_cb(msg)

    def tactile_sensor_cb(self, msg):
        self.policy.tactile_cb(msg)
        if msg.sensor_id == 1:
            self.last_tactile_sensor_data_1 = msg.data
        if msg.sensor_id == 2:
            self.last_tactile_sensor_data_2 = msg.data

    def cartesian_state_cb(self, msg):
        self.policy.state_cb(msg)
        self.cartesian_state = msg

    def set_gripper_goal_position(self, pos):
        self.gripper_goal = pos
        self.policy.gripper_goal_cb(self.gripper_goal)

    def apply_policy(self):
        self.change_gripper_goal_position(self.policy.decide_action() * self.policy.gripper_move_speed)

    def change_gripper_goal_position(self, chng):
        self.gripper_goal += chng
        self.policy.gripper_goal_cb(self.gripper_goal)

    def send_gripper_goal(self):
        self.send_gripper_command(self.gripper_goal, 0, 0.06)

    def send_gripper_command(self, angle, proximal, distal):
        goal_msg = JointState()
        goal_msg.name = ['parallel_gripper_angle', 'parallel_gripper_proximal_tilt', 'parallel_gripper_distal_tilt']
        goal_msg.position = [angle, proximal, distal]
        self.gripper_goal_pub.publish(goal_msg)

    def to_impedance_mode(self):
        print("switching to impedance mode...")
        self.unload_controllers()
        try:
            resp1 = self.set_mode(1)
            print(resp1)
            r2 = SetImpedanceRequest()
            r2.stiffness = [2000, 2000, 1700, 1700, 1000, 100, 700]
            r2.damping = [30, 30, 20, 20, 9, 2, 6]
            resp2 = self.set_joint_imp(r2)
            # r2.stiffness = [3000, 3000, 3000, 500, 500, 500]
            # r2.damping = [30, 30, 30, 5, 5, 5]
            # resp2 = self.set_cart_imp(r2)
            print(resp2)
        except rospy.ServiceException as e:
            print("Service did not process request: " + str(e))

    def to_position_mode(self):
        print("switching to position mode...")
        try:
            resp1 = self.set_mode(0)
            print(resp1)
            # input('mode changed?')
        except rospy.ServiceException as e:
            print("Service did not process request: " + str(e))

    def move_gripper_to_named_target(self, target_name):
        t = rospy.Duration(1)
        max_i = 2
        self.gripper_group.set_named_target(target_name)
        success = False
        i = 0
        while not success:
            success = self.gripper_group.go(wait=True)
            if i > max_i:
                x = input()
                if len(x) > 0:
                    sys.exit()
            print(f"retrying gripper motion to \"{target_name}\"")
            i += 1
            rospy.sleep(t)

    def move_arm_to_named_target(self, target_name):
        t = rospy.Duration(1)
        max_i = 2
        self.arm_group.set_named_target(target_name)
        success = False
        i = 0
        while not success:
            success = self.arm_group.go(wait=True)
            if i > max_i:
                x = input()
                if len(x) > 0:
                    sys.exit()
            print(f"retrying arm motion to \"{target_name}\"")
            i += 1
            rospy.sleep(t)

if __name__ == '__main__':
    try:
        g = GraspServer()
    except KeyboardInterrupt:
        g.stop()
        print( "Received control-c, stopping..." )
        exit( 0 )
    except rospy.ROSInterruptException:
        pass


from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from django.http.response import JsonResponse

from viteproject.models import DesignSave
from viteproject.serializers import DesignSaveSerializer

from django.core.files.storage import default_storage
# Create your views here.

@csrf_exempt
def save_designAPI(request,id=0):
    if request.method == 'GET':
        designSave = DesignSave.objects.all()
        designSaveSerializer = DesignSaveSerializer(designSave,many=True)
        return JsonResponse(designSaveSerializer.data,safe=False)
    elif request.method == 'POST':
        designSave_data = JSONParser().parse(request)
        designSaveSerializer = DesignSaveSerializer(data=designSave_data)
        if designSaveSerializer.is_valid():
            designSaveSerializer.save()
            return JsonResponse("Added Successfully",safe=False)
        return JsonResponse("Failed to Add",safe=False)
    elif request.method == 'PUT':
        designSave_data = JSONParser().parse(request)
        designSave = DesignSave.objects.get(DesignId = designSave_data['DesignId'])
        designSaveSerializer = DesignSaveSerializer(designSave,data=designSave_data)
        if designSaveSerializer.is_valid():
            designSaveSerializer.save()
            return JsonResponse("Update Successfully",safe=False)
        return JsonResponse("Fail Update")
    elif request.method=='DELETE':
        designSave = DesignSave.objects.get(DesignId=id)
        designSave.delete()
        return JsonResponse("Delete Successfully",safe=False)

@csrf_exempt
def SaveFile(request):
    file=request.FILES['file']
    file_name = default_storage.save(file.name,file)
    return JsonResponse(file_name,safe=False)


import multiprocessing

# Gunicorn app
# Tell Gunicorn which application to run
wsgi_app = "django_examples.asgi:application"

# Requests
# Restart workers after so many requests, with some variability.
max_requests = 1000
max_requests_jitter = 50

# Logging
# Use stdout for logging
log_file = "-"

# Workers
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "uvicorn.workers.UvicornWorker"


"""
Plot.py
Created 21/12/2021
"""

from juzzyPython.generic.Tuple import Tuple
from juzzyPython.generalType2zSlices.sets.GenT2MF_Interface import GenT2MF_Interface
from juzzyPython.type1.sets.T1MF_Interface import T1MF_Interface
from juzzyPython.generalType2zSlices.sets.GenT2MF_Triangular import GenT2MF_Triangular
from juzzyPython.intervalType2.sets.IntervalT2MF_Interface import IntervalT2MF_Interface
from juzzyPython.generalType2zSlices.sets.GenT2MF_Trapezoidal import GenT2MF_Trapezoidal
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from typing import List
plt.rcParams.update({'figure.max_open_warning': 0})

class Plot:
    """
    Class Plot:
    Uses the matplotlib to plot various graphs

    Parameters: None

    Funtions:
        plotControlSurface
        show
        figure
        title
        legend
        discretize
        plotMF
    """

    def __init__(self) -> None:
        self.colorList = ['tab:blue','tab:orange','tab:green','tab:red','tab:purple','tab:brown','tab:pink','tab:gray','tab:olive','tab:cyan']

    def show(self):
        """Show all the figures created"""
        plt.show()

    def figure(self):
        """Create a new plot to draw upon"""
        self.fig = plt.figure()

    def figure3d(self):
        """Create a new 3d plot to draw upon"""
        self.fig, self.ax = plt.subplots(subplot_kw={"projection": "3d"})

    def title(self,title: str):
        """Set the title of the current figure"""
        plt.title(title)

    def legend(self):
        """Add legend to the current figure"""
        plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
        plt.tight_layout()

    def plotControlSurface(self,x: List[float],y: List[float],z: List[List[float]],xLabel: str,yLabel: str,zLabel: str) -> None:
        """Plot a 3D surface showcasing the relationship between input (x,y) and output z"""
        fig, ax = plt.subplots(subplot_kw={"projection": "3d"})

        x,y = np.meshgrid(x,y)
        ax.plot_surface(np.asarray(x), np.asarray(y),np.asarray(z))
        ax.set_xlabel(xLabel)
        ax.set_ylabel(yLabel)
        ax.set_zlabel(zLabel)
        plt.title("Control Surface")

    def plotMF2(self,xaxis: str,name: str,sets: IntervalT2MF_Interface,xDisc: int,addExtraEndPoints: bool) -> None:
        x = self.discretize(sets.getSupport(),xDisc)
        y1 = [0] * xDisc
        y2 = [0] * xDisc

        for i in range(xDisc):
            temp = sets.getFS(x[i])
            y1[i] = temp.getRight()
            y2[i] = temp.getLeft()

        if addExtraEndPoints:
            x2 = [0.0] * (len(x)+2)
            y1b = [0.0] * (len(y1)+2)
            y2b = [0.0] * (len(y2)+2)

            x2[0] = sets.getSupport().getLeft()
            x2[-1] = sets.getSupport().getRight()

            y1b[0] = 0.0
            y1b[len(y1)-1] = 0.0
            y2b[0] = 0.0
            y2b[len(y2)-1] = 0.0

            for i in range(len(x)):
                x2[i+1] = x[i]
                y1b[i+1] = y1[i]
                y2b[i+1] = y2[i]
            x = x2
            y1 = y1b
            y2 = y2b
        ax = plt.gca()
        color = next(ax._get_lines.prop_cycler)['color']
        plt.plot(x,y1,label=name+"_upper", color = color)
        plt.plot(x,y2,label=name+"_lower", color = color, alpha=0.5)
        #plt.xlim(xAxisRange.getLeft(),xAxisRange.getRight())
        #plt.ylim(yAxisRange.getLeft(),yAxisRange.getRight())
        plt.ylabel("μ")
        plt.xlabel(xaxis)

    def plotMF(self,xaxis: str,name: str,sets: T1MF_Interface,xDisc: int,xAxisRange: Tuple,yAxisRange: Tuple,addExtraEndPoints: bool) -> None:
        """Plot a membership function on the current figure"""
        x = self.discretize(sets.getSupport(),xDisc)
        y = [0] * xDisc
        for i in range(xDisc):
            y[i] = sets.getFS(x[i])

        if addExtraEndPoints:
            x2 = [0.0] * (len(x)+2)
            y2 = [0.0] * (len(y)+2)
            x2[0] = sets.getSupport().getLeft()
            x2[-1] = sets.getSupport().getRight()
            for i in range(len(x)):
                x2[i+1] = x[i]
                y2[i+1] = y[i]
            x = x2
            y = y2
        plt.plot(x,y,label=name)
        plt.xlim(xAxisRange.getLeft(),xAxisRange.getRight())
        plt.ylim(yAxisRange.getLeft(),yAxisRange.getRight())
        plt.ylabel("μ")
        plt.xlabel(xaxis)

    def plotMFasLines(self,sets: GenT2MF_Interface,xDisc: int) -> None:
        self.ax.set_xlabel("x")
        self.ax.set_ylabel("y")
        self.ax.set_zlabel("z")

        x = self.discretize(sets.getSupport(),xDisc)
        y1 = [[0 for c in range(xDisc)] for r in range(sets.getNumberOfSlices())]
        y2 = [[0 for c in range(xDisc)] for r in range(sets.getNumberOfSlices())]
        z1 = [[0 for c in range(xDisc)] for r in range(sets.getNumberOfSlices())]
        z2 = [[0 for c in range(xDisc)] for r in range(sets.getNumberOfSlices())]

        for zLevel in range(sets.getNumberOfSlices()):
            for i in range(xDisc):
                temp = sets.getZSlice(zLevel).getFS(x[i])
                y1[zLevel][i] = temp.getRight()
                y2[zLevel][i] = temp.getLeft()
                if zLevel==0:
                    z1[zLevel][i] = 0.0
                else:
                    z1[zLevel][i] = sets.getZValue(zLevel-1)
                z2[zLevel][i] = sets.getZValue(zLevel)

        for zLevel in range(sets.getNumberOfSlices()):
            self.ax.plot3D(x,y1[zLevel],z1[zLevel],label=sets.getName()+"_upper",color= self.colorList[zLevel%10])
            self.ax.plot3D(x,y2[zLevel],z1[zLevel],label=sets.getName()+"_lower",color= self.colorList[zLevel%10])
            self.ax.plot3D(x,y1[zLevel],z2[zLevel],label=sets.getName()+"_upper",color= self.colorList[zLevel%10])
            self.ax.plot3D(x,y2[zLevel],z2[zLevel],label=sets.getName()+"_lower",color= self.colorList[zLevel%10])

    def turnOnInteraction(self):
        plt.ion()

    def closeAllFigures(self):
        plt.close('all')

    def plotMFasSurface(self,plotName: str,sets: GenT2MF_Interface,xAxisRange: Tuple,xDisc: int,addExtraPoints: bool):
        self.ax.set_xlabel("X-Axis")
        self.ax.set_ylabel("Z-Axis")
        self.ax.set_zlabel("Y-Axis")

        if isinstance(sets,GenT2MF_Triangular):
            for zLevel in range(sets.getNumberOfSlices()):
                xUpper = [sets.getZSlice(zLevel).getUMF().getStart(), sets.getZSlice(zLevel).getUMF().getPeak(),sets.getZSlice(zLevel).getUMF().getEnd()]
                zUpper = None
                yUpper = [[0 for i in range(3)] for j in range(2)]

                if zLevel == 0:
                    zUpper = [0.0,sets.getZValue(zLevel)]
                else:
                    zUpper = [sets.getZValue(zLevel-1),sets.getZValue(zLevel)]
                for xD in range(3):
                    yUpper[0][xD] = sets.getZSlice(zLevel).getFS(xUpper[xD]).getRight()
                    yUpper[1][xD] = yUpper[0][xD]

                xLower = [sets.getZSlice(zLevel).getLMF().getStart(), sets.getZSlice(zLevel).getLMF().getPeak(),sets.getZSlice(zLevel).getLMF().getEnd()]
                zLower = None
                yLower = [[0 for i in range(3)] for j in range(2)]

                if zLevel == 0:
                    zLower = [0.0,sets.getZValue(zLevel)]
                else:
                    zLower = [sets.getZValue(zLevel-1),sets.getZValue(zLevel)]
                for xD in range(3):
                    yLower[0][xD] = sets.getZSlice(zLevel).getFS(xLower[xD]).getLeft()
                    yLower[1][xD] = yLower[0][xD]
                x,y = np.meshgrid(xUpper,zUpper)
                self.ax.plot_surface(np.asarray(x), np.asarray(y),np.asarray(yUpper),alpha = 0.5,color=self.colorList[zLevel%10])
                x,y = np.meshgrid(xLower,zLower)
                self.ax.plot_surface(np.asarray(x), np.asarray(y),np.asarray(yLower),alpha = 0.5,color=self.colorList[zLevel%10])
        elif isinstance(sets,GenT2MF_Trapezoidal):
            for zLevel in range(sets.getNumberOfSlices()):
                xUpper = [sets.getZSlice(zLevel).getUMF().getA(), sets.getZSlice(zLevel).getUMF().getB(),sets.getZSlice(zLevel).getUMF().getC(),sets.getZSlice(zLevel).getUMF().getD()]
                zUpper = None
                yUpper = [[0 for i in range(4)] for j in range(2)]

                if zLevel == 0:
                    zUpper = [0.0,sets.getZValue(zLevel)]
                else:
                    zUpper = [sets.getZValue(zLevel-1),sets.getZValue(zLevel)]
                for xD in range(4):
                    yUpper[0][xD] = sets.getZSlice(zLevel).getFS(xUpper[xD]).getRight()
                    yUpper[1][xD] = yUpper[0][xD]

                xLower = [sets.getZSlice(zLevel).getLMF().getA(), sets.getZSlice(zLevel).getLMF().getB(),sets.getZSlice(zLevel).getLMF().getC(),sets.getZSlice(zLevel).getLMF().getD()]
                zLower = None
                yLower = [[0 for i in range(4)] for j in range(2)]

                if zLevel == 0:
                    zLower = [0.0,sets.getZValue(zLevel)]
                else:
                    zLower = [sets.getZValue(zLevel-1),sets.getZValue(zLevel)]
                for xD in range(4):
                    yLower[0][xD] = sets.getZSlice(zLevel).getFS(xLower[xD]).getLeft()
                    yLower[1][xD] = yLower[0][xD]
                x,y = np.meshgrid(xUpper,zUpper)
                self.ax.plot_surface(np.asarray(x), np.asarray(y),np.asarray(yUpper),alpha = 0.5,color=self.colorList[zLevel%10])
                x,y = np.meshgrid(xLower,zLower)
                self.ax.plot_surface(np.asarray(x), np.asarray(y),np.asarray(yLower),alpha = 0.5,color=self.colorList[zLevel%10])
        else:
            for zLevel in range(sets.getNumberOfSlices()):
                xUpper = self.discretize(xAxisRange,xDisc)
                zUpper = None
                yUpper = [[0 for i in range(xDisc)] for j in range(2)]

                if zLevel == 0:
                    zUpper = [0.0,sets.getZValue(zLevel)]
                else:
                    zUpper = [sets.getZValue(zLevel-1),sets.getZValue(zLevel)]
                for xD in range(xDisc):
                    yUpper[0][xD] = sets.getZSlice(zLevel).getFS(xUpper[xD]).getRight()
                    yUpper[1][xD] = yUpper[0][xD]

                xLower = self.discretize(xAxisRange,xDisc)
                zLower = None
                yLower = [[0 for i in range(xDisc)] for j in range(2)]

                if zLevel == 0:
                    zLower = [0.0,sets.getZValue(zLevel)]
                else:
                    zLower = [sets.getZValue(zLevel-1),sets.getZValue(zLevel)]
                for xD in range(xDisc):
                    yLower[0][xD] = sets.getZSlice(zLevel).getFS(xLower[xD]).getLeft()
                    yLower[1][xD] = yLower[0][xD]

                if addExtraPoints:
                    x_upper2 = [0.0] * (len(xUpper) + 2)
                    y_upper2 = [[0.0 for i in range(len(yUpper[0]) + 2)] for j in range(2)]
                    x_Lower2 = [0.0] * (len(xLower) + 2)
                    y_Lower2 = [[0.0 for i in range(len(yLower[0]) + 2)] for j in range(2)]

                    x_upper2[0] = sets.getSupport().getLeft()
                    x_upper2[-1] = sets.getSupport().getRight()
                    x_Lower2[0] = x_upper2[0]
                    x_Lower2[-1] = x_upper2[-1]

                    for i in range(len(xUpper)):
                        x_upper2[i + 1] = xUpper[i]
                        x_Lower2[i + 1] = xLower[i]
                        y_upper2[0][i + 1] = yUpper[0][i]
                        y_Lower2[0][i + 1] = yLower[0][i]
                        y_upper2[1][i + 1] = yUpper[1][i]
                        y_Lower2[1][i + 1] = yLower[1][i]

                    xUpper = x_upper2
                    xLower = x_Lower2
                    yUpper = y_upper2
                    yLower = y_Lower2
                x,y = np.meshgrid(xUpper,zUpper)
                self.ax.plot_surface(np.asarray(x), np.asarray(y),np.asarray(yUpper),alpha = 0.5,color=self.colorList[zLevel%10])
                x,y = np.meshgrid(xLower,zLower)
                self.ax.plot_surface(np.asarray(x), np.asarray(y),np.asarray(yLower),alpha = 0.5,color=self.colorList[zLevel%10])

    def discretize(self,support: Tuple,discLevel: int) -> List[float]:
        """Discretize the support values"""
        d = [0] * discLevel
        stepSize = (support.getSize())/(discLevel-1.0)
        d[0] = support.getLeft()
        d[-1] = support.getRight()
        for i in range(1,discLevel-1):
            d[i] = support.getLeft()+i*stepSize
        return d


from memoizer import Memoizer
import re
import os
import glob
from crawl_utils import RAWDATA_PATH

R = re.compile

MORGUE_BASES = [
 [ R(r'cao-.*'),       'http://crawl.akrasiac.org/rawdata' ],
 [ R(r'cdo.*-0.4$'),   'http://crawl.develz.org/morgues/0.4' ],
 [ R(r'cdo.*-0.5$'),   'http://crawl.develz.org/morgues/0.5' ],
 [ R(r'cdo.*-0.6$'),   'http://crawl.develz.org/morgues/0.6' ],
 [ R(r'cdo.*-0.7'),    'http://crawl.develz.org/morgues/0.7' ],
 [ R(r'cdo.*-0.8'),    'http://crawl.develz.org/morgues/0.8' ],
 [ R(r'cdo.*-0.10'),   'http://crawl.develz.org/morgues/0.10' ],
 [ R(r'cdo.*-svn$'),   'http://crawl.develz.org/morgues/trunk' ],
 [ R(r'cdo.*-zd$'),    'http://crawl.develz.org/morgues/trunk' ],
 [ R(r'cdo.*-spr$'),   'http://crawl.develz.org/morgues/sprint' ],
 [ R(r'rhf.*-0.5$'),   'http://rl.heh.fi/crawl/stuff' ],
 [ R(r'rhf.*-0.6$'),   'http://rl.heh.fi/crawl-0.6/stuff' ],
 [ R(r'rhf.*-0.7$'),   'http://rl.heh.fi/crawl-0.7/stuff' ],
 [ R(r'rhf.*-trunk$'), 'http://rl.heh.fi/trunk/stuff' ],
 [ R(r'rhf.*-spr$'),   'http://rl.heh.fi/sprint/stuff' ],
]

CAO_MORGUE_BASE = 'http://crawl.akrasiac.org/rawdata'
CDO_MORGUE_BASE = 'http://crawl.develz.org/morgues/stable'
R_MORGUE_TIME = re.compile(r'morgue-\w+-(.*?)\.txt$')

def morgue_time_string(raw_time):
  return raw_time[:8] + "-" + raw_time[8:]

def morgue_filename(name, timestr):
  return RAWDATA_PATH + "/" + name + "/morgue-" + name + "-" + timestr + ".txt"

def cao_morgue_url(name, timestr):
  return "%s/%s/morgue-%s-%s.txt" % (CAO_MORGUE_BASE, name, name, timestr)

def cao_morgue_files(name):
  rawmorgues = glob.glob(morgue_filename(name, '*'))
  rawmorgues.sort()
  return rawmorgues

def morgue_binary_search(morgues, guess):
  size = len(morgues)
  if size == 1:
    return guess < morgues[0] and morgues[0]

  s = 0
  e = size
  while e - s > 1:
    pivot = int((s + e) / 2)
    if morgues[pivot] == guess:
      return morgues[pivot]
    elif morgues[pivot] < guess:
      s = pivot
    else:
      e = pivot
  return e < size and morgues[e]

@Memoizer
def find_cao_morgue_link(name, end_time):
  fulltime = end_time
  if os.path.exists(morgue_filename(name, fulltime)):
    return cao_morgue_url(name, fulltime)

  # Drop seconds for really ancient morgues.
  parttime = fulltime[:-2]
  if os.path.exists(morgue_filename(name, parttime)):
    return cao_morgue_url(name, parttime)

  # At this point we have no option but to brute-force the search.
  morgue_list = cao_morgue_files(name)

  # morgues are sorted. The morgue date should be greater than the
  # full timestamp.
  best_morgue = morgue_binary_search(morgue_list,
                                     morgue_filename(name, fulltime))
  if best_morgue:
    m = R_MORGUE_TIME.search(best_morgue)
    if m:
      return cao_morgue_url(name, m.group(1))
  return None

def game_is_cao(g):
  return g['source_file'].find('cao') >= 0

def format_time(time):
  return "%04d%02d%02d-%02d%02d%02d" % (time.year, time.month, time.day,
                                       time.hour, time.minute, time.second)

def morgue_link(g):
  """Given a game dictionary, returns a URL to the game's morgue."""
  src = g['source_file']
  name = g['name']
  stime = format_time( g['end_time'] )
  v_regex = R(r'^0\.([0-9]+)')
  v_search = v_regex.search(g['v'])
  if not v_search:
    return ''
  version = int(v_search.group(1))
  if version < 4:
    if game_is_cao(g):
      return find_cao_morgue_link(name, stime)
    # Nothing we can do for anyone else with old games.
    return ''
  if version == 9 and not game_is_cao(g):
    # CDO logs and milestones for 0.9 were placed in the same file as trunk
    # games, so we need to handle this specially.
    if stime > "20110819-1740":
      return "http://crawl.develz.org/morgues/0.9/%s/morgue-%s-%s.txt" % (name, name, stime)
  for regex, url in MORGUE_BASES:
    if regex.search(src):
      return "%s/%s/morgue-%s-%s.txt" % (url, name, name, stime)

  # Unknown morgue:
  raise Exception("Unknown source for morgues: %s" % src)


import re

from odoo import api, fields, models, tools, _
from odoo.exceptions import ValidationError
from odoo.osv import expression
from odoo.exceptions import UserError, ValidationError
import odoo.addons.decimal_precision as dp

class ProductCategory(models.Model):
    _inherit="product.category"

    @api.model
    def create(self,vals):
        seq_list = []
        att_list = []
        seq_list1 = []
        categ_list = []
        seq = ''
        att = ''
        categ = ' '
        seq1 = ' '
        name = ' '
        name_list = []
        count = 1
        product_categ_id =  super(ProductCategory,self).create(vals)
        categ_obj = self.env['product.category'].browse(product_categ_id)
        attribute = self.env['attribute.line'].search([('category_id1','=',categ_obj.id.id)])
        for val in attribute:
            attribute_obj = self.env['attribute.line'].browse(val.id)
            att_list.append(attribute_obj.attribute_id.id)
        if att_list:
            for val3 in att_list:
                att = val3
                count = 1
                for val4 in att_list:
                    if att == val4:
                        count = count + 1
                    else:
                        count = count
                if count != 2:
                    raise UserError(_('Attribute can not be repeat in Attribute for Grades'))
        categ_template  = self.env['category.template'].search([('category_id1','=',categ_obj.id.id)])
        for val in categ_template:
            categ_template_obj = self.env['category.template'].browse(val.id)
            seq_list.append(categ_template_obj.seq_no)
            categ_list.append(categ_template_obj.category_id.id)
        if categ_list:
            for val3 in categ_list:
                categ = val3
                count = 1
                for val4 in categ_list:
                    if categ == val4:
                        count = count + 1
                    else:
                        count = count
                if count != 2:
                    raise UserError(_('Category can not be repeat in Category Template'))
        if seq_list:
            for val1 in seq_list:
                seq = val1
                count = 1
                for val2 in seq_list:
                    if seq == val2:
                        count = count + 1
                    else:
                        count = count
                if count != 2:
                    raise UserError(_('Sequence can not be repeat in Category Template'))
        spec_template = self.env['specification.line'].search([('category_id1','=',categ_obj.id.id)])
        for each in spec_template:
            spec_template_obj = self.env['specification.line'].browse(each.id)
            seq_list1.append(spec_template_obj.seq_no)
            name_list.append(spec_template_obj.name)
        if seq_list1:
            for each1 in seq_list1:
                seq1 = each1
                count = 1
                for each2 in seq_list1:
                    if seq1 == each2:
                        count = count + 1
                    else:
                        count = count
                if count != 2:
                    raise UserError(_('Sequence can not be repeat in Specifications'))
        if name_list:
            for each3 in name_list:
                name = each3
                count = 1
                for each4 in name_list:
                    if name == each4:
                        count = count + 1
                    else:
                        count = count
                if count != 2:
                    raise UserError(_('Name can not be repeat in Specifications'))
        return product_categ_id

    numbered = fields.Boolean('Numbered',track_visibility="onchange")
    can_altered = fields.Boolean('Can Be Altered',track_visibility="onchange")
    category_template_lines = fields.One2many('category.template','category_id1','Product Category',track_visibility="onchange")
    prefix = fields.Char('Prefix',track_visibility="onchange")
    specification_lines = fields.One2many('specification.line','category_id1','Specifications',track_visibility="onchange")
    attribute_lines = fields.One2many('attribute.line','category_id1','Attribute Value',track_visibility="onchange")

class category_template(models.Model):
    _name="category.template"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    category_id = fields.Many2one('product.category','Category',track_visibility="onchange")
    seq_no = fields.Integer('Sequence No',track_visibility="onchange")
    part_name = fields.Boolean('Part of Name',track_visibility="onchange")
    mandatory = fields.Boolean('Mandatory',track_visibility="onchange")
    category_id1 = fields.Many2one('product.category','Category',track_visibility="onchange")

class specification_line(models.Model):
    _name="specification.line"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    seq_no = fields.Integer('Sequence No',track_visibility="onchange")
    name = fields.Char('Name',track_visibility="onchange")
    category_id1 = fields.Many2one('product.category','Category',required="1",track_visibility="onchange")

class attribute_line(models.Model):
    _name="attribute.line"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    attribute_id = fields.Many2one('product.attribute','Attribute',track_visibility="onchange")
    category_id1 = fields.Many2one('product.category','Category',required="1",track_visibility="onchange")


class Solution(object):
    def sortPeople(self, names, heights):
        """
        :type names: List[str]
        :type heights: List[int]
        :rtype: List[str]
        """

        dList = []

        for i in range(len(heights)):

            temp = [heights[i], [names[i]]]
            dList.append(temp)

        sort = sorted(dList)
        sort = sort[::-1]

        nameList = []

        for i in range(len(names)):
            nameList.append(sort[i][1][0])

        return nameList


'''Hash Table

Description: Are used to store [key-value] pairs, they are like arrays, but the
keys are not ordened. Unlike arrays, hash tables are fast for all of the follo
wing operations: finding values, adding new values, or removing values.

Big O: Average Case

Insert: O(1)
Deletion: O(1)
Access: O(1)
'''

WEIRD_PRIME = 31

class HashTable():
    def __init__(self, size=53) -> None:
        self.key_map = [None for _ in range(0, size)]

    def _hash(self, key):
        total = 0
        for i in range(0, min(len(key), 100)):
            char = key[i]
            value = ord(char) - 96
            total = (total * WEIRD_PRIME + value) % len(self.key_map)
        return total

    def set(self, key, value):
        idx = self._hash(key)
        if not self.key_map[idx]:
            self.key_map[idx] = []
        self.key_map[idx].append([key, value])

    def get(self, key):
        idx = self._hash(key)

        if self.key_map[idx]:
            for i, v in enumerate(range(0, len(self.key_map[idx]))):
                if self.key_map[idx][i][0] == key:
                    return self.key_map[idx][i][1]
        return None

    def values(self):
        values  = []

        for p in self.key_map:
            if p:
                for c in p:
                    if c:
                        values.append(c[1])

        return values

    def keys(self):
        values  = []

        for p in self.key_map:
            if p:
                for c in p:
                    if c:
                        values.append(c[0])

        return values

ht = HashTable(17)
ht.set('maroon', '#800000')
ht.set('yellow', '#FFFF00')
ht.set('olive', '#808000')
ht.set('a', '#809000')
ht.set('a', '#807000')
print(ht.key_map)
print(ht.get('a'))
print(ht.keys())


#/usr/env/python3

"""
This program combines the data directory reference file with
a .words file to create a vardial3 format gold file.
"""

import sys

# list of dialects borrowed from ../scripts/eval.py
langList=['EGY', 'GLF', 'LAV', 'MSA','NOR']

# first set up hash from metadata to dialect number
fr = open('../../reference','r')
rdict = dict()
for line in fr:
    sp = line.find(' ')
    meta = line[:sp]
    dialect = line[sp+1:sp+2]
    rdict[meta] = dialect

# now read through .words file
fin = open(sys.argv[1],'r')
for line in fin:
    line = line.strip()
    sp = line.find(' ')
    meta = line[:sp]
    text = line[sp+1:]

    standard = rdict[meta]
    ts = langList[int(standard)-1]
    # write out line in gold format
    print(text+'\tQ\t'+ts)


#Calculating tax for multiple state

from my_functions import conv_numbers

while True:
    order = conv_numbers(input('Enter your order amount :'))
    if order:
        break

state = input("Enter your state of residence :")
state = state.lower()

if state == 'wisconsin' or state == 'wi':
    county = input("""Enter your county of
    residence (dunn / eau claire) : """)
    county = county.lower()
    if county == 'dunn':
        tax = order * 0.004
    else:
        tax = order * 0.005

    total = order + tax
    total = round(total, 1)

    print(f"Your tax is : {tax}")
    print(f"Your total is : {total}")

elif state == 'illinois' or state == 'il':
    tax = order * 0.08
    total = order + tax
    total = round(total,2)

    print(f"Your tax is : {tax}")
    print(f"Your total is : {total}")


#Adding Elements to a Queue
class Queue:

  def __init__(self):
      self.queue = list()

  def addtoq(self,dataval):
# Insert method to add element
      if dataval not in self.queue:
          self.queue.insert(0,dataval)
          return True
      return False

  def size(self):
      return len(self.queue)

TheQueue = Queue()
TheQueue.addtoq("Mon")
TheQueue.addtoq("Tue")
TheQueue.addtoq("Wed")
print(TheQueue.size())

print("------------------------------------------------------------------------")

#removing elements
class Queue:
  def __init__(self):
      self.queue = list()

  def addtoq(self,dataval):
# Insert method to add element
      if dataval not in self.queue:
          self.queue.insert(0,dataval)
          return True
      return False
# Pop method to remove element
  def removefromq(self):
      if len(self.queue)>0:
          return self.queue.pop()
      return ("No elements in Queue!")

TheQueue = Queue()
TheQueue.addtoq("Mon")
TheQueue.addtoq("Tue")
TheQueue.addtoq("Wed")
print(TheQueue.removefromq())
print(TheQueue.removefromq())

print("_--------------------------------------------------------------")

# Python program to
# demonstrate queue implementation
# using list

# Initializing a queue
queue = []

# Adding elements to the queue
queue.append('a')
queue.append('b')
queue.append('c')

print("Initial queue")
print(queue)

# Removing elements from the queue
print("\nElements dequeued from queue")
print(queue.pop(0))
print(queue.pop(0))
print(queue.pop(0))

print("\nQueue after removing elements")
print(queue)

# Uncommenting print(queue.pop(0))
# will raise and IndexError
# as the queue is now empty


import time
import pandas as pd

# df = pd.read_csv("trades.csv", header=None, names=["num","time","side","lot","sym","o","c","pip","size","pips"])
df = pd.read_csv("FASTWAY.csv")
# df = pd.read_csv("FASTWAYINETH.csv")
# df = pd.read_csv("NORTHEASTWAYINBTC.csv")
df.drop(columns=["num"], inplace=True)
pd.to_datetime(df["time"])
df.sort_values(by=["time"], inplace=True)
df.set_index(pd.DatetimeIndex(df["time"]), inplace=True)
df.drop(columns=["time"], inplace=True)

pnl = df["size"].astype(float).sum()

deposit_df  = df[df["side"]=="DEPOSIT"]
deposit     = deposit_df["sym"].astype(float).sum()

withdraw_df = df[df["side"]=="WITHDRAWAL"]
withdraw    = withdraw_df["sym"].astype(int).sum()

trade_df    = df[df["side"]!="DEPOSIT"]
trade_df    = trade_df[trade_df["side"]!="WITHDRAWAL"]
n_trade_df  = trade_df[trade_df["size"]<0]
p_trade_df  = trade_df[trade_df["size"]>0]
trade_df["side"].astype(str)
monthly_pnl = trade_df["size"].resample("M").sum()
monthly_negative_pnl = n_trade_df["size"].resample("M").sum()
monthly_positive_pnl = p_trade_df["size"].resample("M").sum()

print("********************************************************************trades")
print(trade_df)
print("********************************************************************deposit")
print(deposit_df)
print("********************************************************************withdraw")
print(withdraw_df)

print("********************************************************************negative_pnl")
print(monthly_negative_pnl)
print("********************************************************************positive_pnl")
print(monthly_positive_pnl)
print("********************************************************************pnl")
print(monthly_pnl)
print("********************************************************************pnl")
print(pnl)

# print(trade_df["2022-02-28":"2022-03-31"])

# print(trade_df.dtypes)


import pyperclip
import re

matchPhone = re.compile(r'''(
                        (\d{3}|\(\d{3}\))   # area code
                        (\s|-|\.)           # separator
                        (\d{3})             # first 3 digits
                        (\s|-|\.)           # separator
                        (\d{4})             # last 4 digits
                        (\s*(ext|x|ext.)\s*(\d{2,5}))? #extension
                        )''', re.VERBOSE)

matchEmail = re.compile(r'''(
                        [a-zA-Z0-9._%+-]+    # address
                        @[a-zA-Z0-9.-]+      # domain name
                        \.(\w*)              # domain suffix
                        )''', re.VERBOSE)

matchURL = re.compile(r'''(
                      (http://|https://)   # prefix
                      (.*)                 # domain name
                      (\.\w{2,})           # suffix
                      )''', re.VERBOSE)

text = pyperclip.paste()

matches = []

for match in matchPhone.findall(text):
    phoneNum = '-'.join([match[1], match[3], match[5]])
    if match[8] != '':
        phoneNum += ' x' + match[8]
    matches.append(phoneNum)

for match in matchEmail.findall(text):
    matches.append(match[0])

for match in matchURL.findall(text):
    matches.append(match[0])

print('\n'.join(matches))
pyperclip.copy('\n'.join(matches))


from Qt import QtGui, QtCore, QtWidgets, Qt

from ts2.scenery import abstract, helper
from ts2 import utils

translate = QtWidgets.qApp.translate

class TextItem(abstract.TrackItem):
    """A TextItem is a prop to display simple text on the layout
    """
    def __init__(self, parameters):
        """Constructor for the TextItem class"""
        super().__init__(parameters)
        self._rect = QtCore.QRectF()
        self.updateBoundingRect()
        gi = helper.TrackGraphicsItem(self)
        gi.setPos(self.origin)
        gi.setToolTip(self.toolTipText)
        gi.setZValue(0)
        self._gi[0] = gi

    def initialize(self, simulation):
        """Initialize the item after all items are loaded."""
        if simulation.context in utils.Context.EDITORS:
            self._gi[0].setCursor(Qt.PointingHandCursor)
        else:
            self._gi[0].setCursor(Qt.ArrowCursor)
        super().initialize(simulation)

    @staticmethod
    def getProperties():
        return [
            helper.TIProperty("tiTypeStr", translate("TextItem", "Type"), True),
            helper.TIProperty("tiId", translate("TextItem", "id"), True),
            helper.TIProperty("text", translate("TextItem", "Text")),
            helper.TIProperty("originStr", translate("TextItem", "Point 1"))
        ]

    @property
    def text(self):
        """Returns the text to display"""
        return self._name

    @text.setter
    def text(self, value):
        """Setter function for the text property"""
        if self.simulation.context == utils.Context.EDITOR_SCENERY:
            self.graphicsItem.prepareGeometryChange()
            self._name = value
            self.graphicsItem.setToolTip(self.toolTipText)
            self.updateBoundingRect()
            self.updateGraphics()

    def updateBoundingRect(self):
        """Updates the bounding rectangle of the graphics item"""
        tl = QtGui.QTextLayout(self.text)
        tl.beginLayout()
        tl.createLine()
        tl.endLayout()
        self._rect = tl.boundingRect()

    def graphicsBoundingRect(self, itemId):
        """This function is called by the owned TrackGraphicsItem to return
        its bounding rectangle"""
        if self.text is None or self.text == "":
            return super().boundingRect()
        else:
            if self.tiId.startswith("__EDITOR__"):
                # Toolbox item
                return QtCore.QRectF(-36, -15, 100, 50)
            else:
                return self._rect

    def graphicsPaint(self, p, options, itemId, widget=None):
        """This function is called by the owned TrackGraphicsItem to paint its
        painter."""
        super().graphicsPaint(p, options, itemId, widget)
        pen = self.getPen()
        pen.setWidth(0)
        pen.setColor(Qt.white)
        p.setPen(pen)
        p.drawText(self._rect.bottomLeft(), self.text)


from os import name
from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name="home"),
    path('about/', views.about, name="about"),
    path('join_us/', views.join_us, name="join_us"),
    path('hotel_detail/<int:hotel_id>/',
         views.hotel_detail, name="hotel_detail"),
    path('hotel_detail/<int:hotel_id>/<slug:extra>/',
         views.hotel_detail, name="hotel_detail"),
    path('cart/', views.my_cart, name="my_cart"),
    path('cart/plus', views.plus_cart, name="plus_cart"),
    path('cart/minus', views.minus_cart, name="minus_cart"),
    path('verify_payment/', views.verifyPayment, name='verify_payment'),
    path('order/', views.orders, name="order"),
    path('search/', views.search_items, name="search"),
    path('all_hotel/', views.all_hotel, name="all_hotel"),
    path('all_menu/', views.all_menu, name="all_menu"),
    path('health/', views.health, name="health"),
]


import codecs
import unittest

from asyncssh.asn1 import der_encode, der_decode
from asyncssh.asn1 import ASN1EncodeError, ASN1DecodeError
from asyncssh.asn1 import BitString, IA5String, ObjectIdentifier
from asyncssh.asn1 import RawDERObject, TaggedDERObject, PRIVATE

class _TestASN1(unittest.TestCase):
    """Unit tests for ASN.1 module"""

    tests = [
        (None,                                '0500'),

        (False,                               '010100'),
        (True,                                '0101ff'),

        (0,                                   '020100'),
        (127,                                 '02017f'),
        (128,                                 '02020080'),
        (256,                                 '02020100'),
        (-128,                                '020180'),
        (-129,                                '0202ff7f'),
        (-256,                                '0202ff00'),

        (b'',                                 '0400'),
        (b'\0',                               '040100'),
        (b'abc',                              '0403616263'),
        (127*b'\0',                           '047f' + 127*'00'),
        (128*b'\0',                           '048180' + 128*'00'),

        ('',                                  '0c00'),
        ('\0',                                '0c0100'),
        ('abc',                               '0c03616263'),

        ((),                                  '3000'),
        ((1,),                                '3003020101'),
        ((1, 2),                              '3006020101020102'),

        (frozenset(),                         '3100'),
        (frozenset({1}),                      '3103020101'),
        (frozenset({1, 2}),                   '3106020101020102'),
        (frozenset({-128, 127}),              '310602017f020180'),

        (BitString(b''),                      '030100'),
        (BitString(b'\0', 7),                 '03020700'),
        (BitString(b'\x80', 7),               '03020780'),
        (BitString(b'\x80', named=True),      '03020780'),
        (BitString(b'\x81', named=True),      '03020081'),
        (BitString(b'\x81\x00', named=True),  '03020081'),
        (BitString(b'\x80', 6),               '03020680'),
        (BitString(b'\x80'),                  '03020080'),
        (BitString(b'\x80\x00', 7),           '0303078000'),
        (BitString(''),                       '030100'),
        (BitString('0'),                      '03020700'),
        (BitString('1'),                      '03020780'),
        (BitString('10'),                     '03020680'),
        (BitString('10000000'),               '03020080'),
        (BitString('10000001'),               '03020081'),
        (BitString('100000000'),              '0303078000'),

        (IA5String(b''),                      '1600'),
        (IA5String(b'\0'),                    '160100'),
        (IA5String(b'abc'),                   '1603616263'),

        (ObjectIdentifier('0.0'),             '060100'),
        (ObjectIdentifier('1.2'),             '06012a'),
        (ObjectIdentifier('1.2.840'),         '06032a8648'),
        (ObjectIdentifier('2.5'),             '060155'),
        (ObjectIdentifier('2.40'),            '060178'),

        (TaggedDERObject(0, None),            'a0020500'),
        (TaggedDERObject(1, None),            'a1020500'),
        (TaggedDERObject(32, None),           'bf20020500'),
        (TaggedDERObject(128, None),          'bf8100020500'),
        (TaggedDERObject(0, None, PRIVATE),   'e0020500'),

        (RawDERObject(0, b'', PRIVATE),       'c000')
    ]

    encode_errors = [
        (range, [1]),                         # Unsupported type

        (BitString, [b'', 1]),                # Bit count with empty value
        (BitString, [b'', -1]),               # Invalid unused bit count
        (BitString, [b'', 8]),                # Invalid unused bit count
        (BitString, [b'0c0', 7]),             # Unused bits not zero
        (BitString, ['', 1]),                 # Unused bits with string
        (BitString, [0]),                     # Invalid type

        (ObjectIdentifier, ['']),             # Too few components
        (ObjectIdentifier, ['1']),            # Too few components
        (ObjectIdentifier, ['-1.1']),         # First component out of range
        (ObjectIdentifier, ['3.1']),          # First component out of range
        (ObjectIdentifier, ['0.-1']),         # Second component out of range
        (ObjectIdentifier, ['0.40']),         # Second component out of range
        (ObjectIdentifier, ['1.-1']),         # Second component out of range
        (ObjectIdentifier, ['1.40']),         # Second component out of range
        (ObjectIdentifier, ['1.1.-1']),       # Later component out of range

        (TaggedDERObject, [0, None, 99]),     # Invalid ASN.1 class

        (RawDERObject, [0, None, 99]),        # Invalid ASN.1 class
    ]

    decode_errors = [
        '',                                   # Incomplete data
        '01',                                 # Incomplete data
        '0101',                               # Incomplete data
        '1f00',                               # Incomplete data
        '1f8000',                             # Incomplete data
        '1f0001',                             # Incomplete data

        '1f80',                               # Incomplete tag

        '0180',                               # Indefinite length

        '050001',                             # Unexpected bytes at end

        '2500',                               # Constructed null
        '050100',                             # Null with content

        '2100',                               # Constructed boolean
        '010102',                             # Boolean value not 0x00/0xff

        '2200',                               # Constructed integer

        '2400',                               # Constructed octet string

        '2c00',                               # Constructed UTF-8 string

        '1000',                               # Non-constructed sequence

        '1100',                               # Non-constructed set

        '2300',                               # Constructed bit string
        '03020800',                           # Invalid unused bit count

        '3600',                               # Constructed IA5 string

        '2600',                               # Constructed object identifier
        '0600',                               # Empty object identifier
        '06020080',                           # Invalid component
        '06020081'                            # Incomplete component
    ]

    def test_asn1(self):
        """Unit test ASN.1 module"""

        for value, data in self.tests:
            data = codecs.decode(data, 'hex')

            with self.subTest(msg='encode', value=value):
                self.assertEqual(der_encode(value), data)

            with self.subTest(msg='decode', data=data):
                decoded_value = der_decode(data)
                self.assertEqual(decoded_value, value)
                self.assertEqual(hash(decoded_value), hash(value))
                self.assertEqual(repr(decoded_value), repr(value))
                self.assertEqual(str(decoded_value), str(value))

        for cls, args in self.encode_errors:
            with self.subTest(msg='encode error', cls=cls.__name__, args=args):
                with self.assertRaises(ASN1EncodeError):
                    der_encode(cls(*args))

        for data in self.decode_errors:
            with self.subTest(msg='decode error', data=data):
                with self.assertRaises(ASN1DecodeError):
                    der_decode(codecs.decode(data, 'hex'))


# coding=utf8
from validate_email import validate_email

if __name__ == '__main__':
	f = open("stargazers_email.txt", "r")
	emails = f.readlines()
	emails = [line.rstrip('\n') for line in emails]
	valid_email = []

	for i in range(len(emails)):
		is_valid = validate_email(emails[i], verify=True)
		print(is_valid)
		if is_valid == 'True':
			valid_email.append(emails[i])

	print(len(valid_email))
	with open('valid_email.txt', 'w') as f:
		for item in valid_email:
			f.write("%s\n" % item)


#!/usr/bin/env python3
import time
from pymavlink import mavutil
from trunk import *
#from colored import fg, bg, attr
from colored import fg, bg, attr

#if get_Setting('mainLoopStatus', 'status.json', 0) == "closed":
#	print("Warning: Manual override enabled")
#	set_Setting('mainLoopStatus', 'manual', 'status.json', 1)

print("Hello, Launching MavLink viewer...")
timer1 = time.time()

# Start a connection listening to a UDP port
#the_connection = mavutil.mavlink_connection('udpin:localhost:14540')

time.sleep(1)
print("--->Looking for ports, please wait... Can take up to a minute...")
print("")

port1 = '/dev/ttyACM1'
port2 = '/dev/ttyACM2'
current = port1

while 1:
	try:
		the_connection = mavutil.mavlink_connection(current)
		time.sleep(1)
		the_connection.wait_heartbeat()
		break
	except:
		pass
		if current == port1:
			current = port2
		elif current == port2:
			current = port1
		time.sleep(1)

print("Connected to port: " + current)
print("Heartbeat from System %u, Component %u" % (the_connection.target_system, the_connection.target_system))
time.sleep(4)
#https://mavlink.io/en/messages/common.html#MAV_DATA_STREAM_EXTENDED_STATUS
for i in range(0, 3):
	the_connection.mav.request_data_stream_send(the_connection.target_system, the_connection.target_component, mavutil.mavlink.MAV_DATA_STREAM_ALL, 4, 1)

pevent = mavutil.periodic_event(5)

while(1):
	the_connection.recv_msg()
	if pevent.trigger():
		try:
			IMU = the_connection.messages['RAW_IMU']
			IMU2= the_connection.messages['SCALED_IMU2']
			try:
				IMU3= the_connection.messages['SCALED_IMU3']
			except:
				pass
			PR1= the_connection.messages['SCALED_PRESSURE']
			GPS_RAW= the_connection.messages['GPS_RAW_INT']
			#print(IMU)
			print("\tAx\tAy\tAz\t|Gx\tGy\tGz\t|Mx\tMy\tMz")
			print(f"0|\t{IMU.xacc:.0f}\t{IMU.yacc:.0f}\t{IMU.zacc:.0f}\t|{IMU.xgyro:.0f}\t{IMU.ygyro:.0f}\t{IMU.zgyro:.0f}\t|{IMU.xmag:.0f}\t{IMU.ymag:.0f}\t{IMU.zmag:.0f}")
			print(f"1|\t{IMU2.xacc:.0f}\t{IMU2.yacc:.0f}\t{IMU2.zacc:.0f}\t|{IMU2.xgyro:.0f}\t{IMU2.ygyro:.0f}\t{IMU2.zgyro:.0f}\t|{IMU2.xmag:.0f}\t{IMU2.ymag:.0f}\t{IMU2.zmag:.0f}")
			print(f"2|\t{IMU3.xacc:.0f}\t{IMU3.yacc:.0f}\t{IMU3.zacc:.0f}\t|{IMU3.xgyro:.0f}\t{IMU3.ygyro:.0f}\t{IMU3.zgyro:.0f}\t|{IMU3.xmag:.0f}\t{IMU3.ymag:.0f}\t{IMU3.zmag:.0f}")
			print(f"Pressure1 Abs: {PR1.press_abs:.2f} \tDif: {PR1.press_diff:.1f} \tTemp: {PR1.temperature:.0f}" + "\tSats in View: " + str(GPS_RAW.satellites_visible))
			#print("Sats in View: " + str(GPS_RAW.satellites_visible))

		except:
			print("Error")

		try:
			PR2= the_connection.messages['SCALED_PRESSURE2']
			print(f"Pressure2 Abs: {PR2.press_abs:.2f} \tDif: {PR2.press_diff:.1f} \tTemp: {PR2.temperature:.0f}")
			#print(" ")
		except:
			print(f"Pressure2 Abs: INOP \tDif: INOP \tTemp: INOP")

		#print("...Press ctrl+c to exit...")
		print('%s ...Press ctrl+c to exit... %s' % (fg(3), attr(0)))
		print(" ")

	time.sleep(.005)

	#ALL = the_connection.recv_match(blocking=True)
	#print(ALL)


import numpy as np
import cv2 as cv

image = cv.imread('lena.jpg')
image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)

img = np.array(image)
height = image.shape[0]
width = image.shape[1]

kernel= np.array([[-1, -1, -1],[-1, 8, -1], [-1, -1, -1]])
#print(kernel)
m= kernel.shape[0]//2
w=h=3
conv= np.zeros(image.shape)
for i in range(m,height-m):
    for j in range(m, width-m):
        s=0
        for k in range(h):
            for l in range(w):
                s=s+img[i-m+k][j-m+l]*kernel[k][l]

        conv[i][j]=s

#print(img)
cv.imshow('img', conv)
cv.waitKey()
#cv.destroyAllWindows()


import urllib.request, json
import pytz
from datetime import datetime
dateTimeStr=datetime.utcnow().replace(tzinfo=pytz.utc)
def jsonReaderScooter(urlToOpen):
    with urllib.request.urlopen(urlToOpen) as url:
        data = json.loads(url.read().decode())
    retStr='lat,lon,isdisabled,time\n'
    try:
        with open('outputDataUpdated.csv','r') as reader:
            if retStr in reader:
                retStr=''
    except:
        pass
    for item in data["data"]["bikes"]:
        retStr+=str(item['lat'])+','+str(item['lon'])+','+str(item['is_disabled'])+','+str(dateTimeStr)+'\n'
    with open('outputDataUpdated.csv', 'a+') as writer:
        writer.writelines(retStr)
    return True
url = ["https://mds.bird.co/gbfs/los-angeles/free_bikes","https://s3.amazonaws.com/lyft-lastmile-production-iad/lbs/lax/free_bike_status.json","https://la-gbfs.getwheelsapp.com/free_bike_status.json"]
for i in url:
    jsonReaderScooter(i)