# -*- coding: utf-8 -*-
"""
Created on Sat Jul 14 12:43:03 2018

@author: vs362
"""

import h5py
import numpy as np
from devices_functions import *

SLASH = '/' #'/' for Mac addresses or '\\' for PC

class Amplifier(object):

    def __init__(self, path, name):
        self.name = name
        self.device_folder = path + self.name + SLASH
        self.data_file = self.device_folder + name + u'.hdf5'
        self.load_attributes()

        self.name = name
        self.device_folder = path + self.name + SLASH
        self.data_file = self.device_folder + name + u'.hdf5'
        self.save_attributes()

    #   saves all device data into 'results' group of the hdf5 file, overwrites existing data!
    def save_attributes(self):
        hdf5_file = h5py.File(self.data_file,'r+')
        try:
            if 'results' not in hdf5_file.keys():
                hdf5_file.create_group('results')
            attributes = [a for a in dir(self) if not a.startswith('__') and not callable(getattr(self,a)) ]
            for field in attributes:
                hdf5_file['results'].attrs[field] = getattr(self,field)
        finally:
            hdf5_file.close()

#   loads existing 'results' group from hdf5 file to python memory
    def load_attributes(self):
        hdf5_file = h5py.File(self.data_file,'r')
        try:
            if 'results' in hdf5_file.keys():
                for attr in hdf5_file['results'].attrs:
                    setattr(self, attr, hdf5_file['results'].attrs.get(attr) )
        finally:
            hdf5_file.close()

    def add_flux_sweep(self, date, time, meas_name='"CH1_S11_1"'):
        self.flux_sweep_date = date
        self.flux_sweep_time = time
        self.flux_sweep_meas_name = meas_name
        self.save_attributes()

#   Adds different components to attenuation of drive/signal/pump
    def add_component_to_line_attenuation(self, component_name, date, time, meas_name, pump=False, signal=False, drive=False):
        hdf5_file = h5py.File(self.data_file,'r+')
        try:
            if pump and 'pump_attenuation' not in hdf5_file.keys():
                hdf5_file.create_group('pump_attenuation')
            elif signal and 'signal_attenuation' not in hdf5_file.keys():
                hdf5_file.create_group('signal_attenuation')
            elif drive and 'drive_attenuation' not in hdf5_file.keys():
                hdf5_file.create_group('drive_attenuation')

            if pump:
                grp = hdf5_file['pump_attenuation'].create_group(component_name)
            elif signal:
                grp = hdf5_file['signal_attenuation'].create_group(component_name)
            elif drive:
                grp = hdf5_file['drive_attenuation'].create_group(component_name)
            grp.attrs['date'] = date
            grp.attrs['time'] = time
            grp.attrs['meas_name'] = meas_name
        finally:
            hdf5_file.close()

#   Fits stark shift to get g4. Before using make sure you saved drive attenuation
    def fit_stark_shift(self, meas_name, flux_calibrated=True):

        hdf5 = h5py.File(self.data_file)
        self.stark_meas_name = meas_name
        currents = np.loadtxt(self.device_folder+'stark'+SLASH+'curr.txt')*1e-3
        dates = np.loadtxt(self.device_folder+'stark'+SLASH+'date.txt')
        times = np.loadtxt(self.device_folder+'stark'+SLASH+'time.txt')
        drive_freqs = np.loadtxt(self.device_folder+'stark'+SLASH+'drive.txt')*1e9
        if flux_calibrated: fluxes = Flux(currents,self.a,self.b)
        Kerr_Data = np.empty(0)
        K_prime_Data = np.empty(0)
        try:
            for j, current in enumerate(currents):
                date = float_to_DateTime( dates[j] )
                time = float_to_DateTime( times[j] )
                f_d = drive_freqs[j]

                #linear scattering data
                f_0 = np.asarray(hdf5[date][time]['fits'][meas_name].get('f0'))
                k_c = np.asarray(hdf5[date][time]['fits'][meas_name].get('kc'))
                k_i = np.asarray(hdf5[date][time]['fits'][meas_name].get('ki'))
                k_t = k_c + k_i

                line_attenuation = attenuation(f_d, self.data_file, 'drive_attenuation')

                if 'powers' in hdf5[date][time]['LIN'].keys():
                    log_powers = np.asarray(hdf5[date][time]['LIN'].get('powers'))
                elif 'powers_swept' in hdf5[date][time]['LIN'].keys():
                    log_powers = np.asarray(hdf5[date][time]['LIN'].get('powers_swept'))
                log_powers = log_powers + line_attenuation
                powers = dBm_to_Watts(log_powers)

                # fit the slope, this formula takes into account some non RWA corrections
                deg = 6
                Kerr = np.polyfit(24/(2*np.pi*h)*powers*k_c[0]/f_0[0]*((2*f_d/(f_0[0]+f_d))**2)/( (f_d-f_0[0])**2 + (k_t[0]/2)**2*((2*f_d/(f_0[0]+f_d))**2) ),f_0,deg)[deg-1]    # in Hz
#                K_prime = np.polyfit(1/(2*np.pi*h)*powers*k_c[0]/f_0[0]*((2*f_d/(f_0[0]+f_d))**2)/( (f_d-f_0[0])**2 + (k_t[0]/2)**2*((2*f_d/(f_0[0]+f_d))**2) ),f_0,2)[0]
                Kerr_Data = np.append(Kerr_Data, Kerr)
#                K_prime_Data = np.append(K_prime_Data,K_prime)
            if 'fit_stark_shift' in hdf5.keys():
                del hdf5['fit_stark_shift']
            print(len(currents))
            grp = hdf5.create_group('fit_stark_shift')
            grp.create_dataset('current', data = currents)
            grp.create_dataset('date', data = dates)
            grp.create_dataset('time', data = times)
            grp.create_dataset('drive_freq', data = drive_freqs)
            if flux_calibrated: grp.create_dataset('flux', data = fluxes)
            grp.create_dataset('g4', data = Kerr_Data)
#            grp.create_dataset('K_prime', data = K_prime_Data)
        finally:
            hdf5.close()

    #   Loads the data about measured gain points into hdf5 file, then you can use it to plot all kinds of things
    def load_nonlin_characterization(self, meas_name='"CH1_S11_1"',sweep_name='nonlin_characterization'):

        self.pumping_meas_name = meas_name
        nominal_gain_array = np.loadtxt(self.device_folder + sweep_name + SLASH + 'gains.txt')
        nominal_gain_array = [nominal_gain_array]

        hdf5 = h5py.File(self.data_file)
        try:
            if sweep_name in hdf5.keys():
                del hdf5[sweep_name]
            grp = hdf5.create_group(sweep_name)
            grp.create_dataset('gains', data = nominal_gain_array)
        finally:
            hdf5.close()

        for log_g in nominal_gain_array:
            temp_folder = sweep_name + SLASH + 'Gain_'+str(int(log_g))+SLASH
            data_dict = {}
            data_dict['current'] = np.loadtxt(self.device_folder+temp_folder+'curr.txt')*1e-3
            data_dict['date_linear'] = np.loadtxt(self.device_folder+temp_folder+'date_linear.txt')
            data_dict['time_linear'] = np.loadtxt(self.device_folder+temp_folder+'time_linear.txt')
            data_dict['IMD_time'] = np.loadtxt(self.device_folder+temp_folder+'IMD_time.txt')
            data_dict['IMD_date'] = np.loadtxt(self.device_folder+temp_folder+'IMD_date.txt')
            if log_g:
                data_dict['date'] = np.loadtxt(self.device_folder+temp_folder+'date.txt')
                data_dict['time'] = np.loadtxt(self.device_folder+temp_folder+'time.txt')
                data_dict['Pump_power'] = np.loadtxt(self.device_folder+temp_folder+'pump_power.txt')
                data_dict['Pump_freq'] = np.loadtxt(self.device_folder+temp_folder+'pump_freq.txt')*1e9
            g4_IMD = np.zeros(len(data_dict['current']))
            CW_freqs = np.zeros(len(data_dict['current']))
            freq_c = np.zeros(len(data_dict['current']))
            kappa_c = np.zeros(len(data_dict['current']))
            kappa_t = np.zeros(len(data_dict['current']))
            P_1dB = np.zeros(len(data_dict['current']))
            IIP3 = np.zeros(len(data_dict['current']))
            max_Gain = np.zeros(len(data_dict['current']))
            bandwidth = np.zeros(len(data_dict['current']))
            NVR = np.zeros(len(data_dict['current']))
            NVR_spike = np.zeros(len(data_dict['current']))
            Gains = np.zeros((len(data_dict['current']),201))
            Signal_Powers_dBm = np.zeros((len(data_dict['current']),201))
            # TODO change this number to the size of signal powers aray
            hdf5 = h5py.File(self.data_file)
            try:
                for index, current in enumerate(data_dict['current']):
                    # define all data folders (dates/times)
                    IMD_time = float_to_DateTime( data_dict['IMD_time'][index] )
                    IMD_date = float_to_DateTime( data_dict['IMD_date'][index] )
                    time_linear = float_to_DateTime( data_dict['time_linear'][index] )
                    date_linear = float_to_DateTime( data_dict['date_linear'][index] )
                    if log_g:
                        date = float_to_DateTime( data_dict['date'][index] )
                        time = float_to_DateTime( data_dict['time'][index] )

                    # load linear fits
                    freq_c[index] = float( np.asarray(hdf5[date_linear][time_linear]['LIN'][meas_name]['fits'].get('f0')) )
                    kappa_c[index] = float( np.asarray(hdf5[date_linear][time_linear]['LIN'][meas_name]['fits'].get('kc')) )
                    kappa_i = float( np.asarray(hdf5[date_linear][time_linear]['LIN'][meas_name]['fits'].get('ki') ))
                    kappa_t[index] = kappa_c[index] + kappa_i

                    # continuous wave frequency for signal
                    if log_g:
                        freq_CW = hdf5[date][time]['POW']['powers'].attrs.get('freqINP')
                    else:
                        freq_CW = freq_c[index] + 100e6
                    CW_freqs[index] = freq_CW

                    if log_g:
                        # signal powers
                        Signal_Powers_dBm[index] = np.asarray( hdf5[date][time]['POW'].get('powers') )
                        Signal_Powers_dBm[index] = Signal_Powers_dBm[index] + attenuation(freq_CW, self.data_file, 'signal_attenuation')

                        # Gains
                        ind_CW = np.abs(np.asarray(hdf5[date][time]['memory'].get('frequencies'))-freq_CW).argmin() + 2           # index of approximately CW_frequency in the memory trace
                        a_out = np.asarray( hdf5[date][time]['memory'][meas_name].get('real') )+ 1j*np.asarray( hdf5[date][time]['memory'][meas_name].get('imag') )
                        logmag_pump_off = complex_to_PLOG(a_out)[0]
                        logmag_pump_off_ref= logmag_pump_off[ind_CW]
                        a_out = np.asarray( hdf5[date][time]['POW'][meas_name].get('real') )+ 1j*np.asarray( hdf5[date][time]['POW'][meas_name].get('imag') )
                        logmag_pump_on = complex_to_PLOG(a_out)[0]
                        logmag_pump_on_ref = logmag_pump_on[0]      # logmag at the lowest CW power where amplifier is presumably not saturated yet
                        gain_ref = logmag_pump_on_ref-logmag_pump_off_ref
                        Gains[index] = logmag_pump_on - logmag_pump_on_ref + gain_ref
                        max_Gain[index] = gain_ref

                        # Figuring out gain profile in frequency
                        a_out = np.asarray( hdf5[date][time]['memory'][meas_name].get('real') )+ 1j*np.asarray( hdf5[date][time]['memory'][meas_name].get('imag') )
                        logmag_pump_off = complex_to_PLOG(a_out)[0]
                        a_out = np.asarray( hdf5[date][time]['LIN'][meas_name].get('real') )+ 1j*np.asarray( hdf5[date][time]['LIN'][meas_name].get('imag') )
                        logmag_pump_on = complex_to_PLOG(a_out)[0]
                        gain_profile = logmag_pump_on - logmag_pump_off

                        # Finding the 3 dB bandwidth relative to CW frequency
                        ind_left, ind_right = find_3dB_bandwidth(gain_profile, ind_CW)
                        bandwidth[index] = np.asarray(hdf5[date][time]['memory'].get('frequencies'))[ind_right]-np.asarray(hdf5[date][time]['memory'].get('frequencies'))[ind_left]

                        # P_1dB and IIP3 points
                        Saturation_power_ind = find_1dB_compression_point(Gains[index], gain_ref)
                        P_1dB[index] = Signal_Powers_dBm[index][Saturation_power_ind]

                        if 'noise' in hdf5[date][time]['fits'].keys():
                            noise_flag = True
                            key1 = list(hdf5[date][time]['fits']['noise'].keys())[0]
                            key2 = list(hdf5[date][time]['fits']['noise'][key1].keys())[0]

                            noise_raise = np.asarray(hdf5[date][time]['noise'][key1][key2].get('logmag')) - np.asarray(hdf5[date][time]['noise'][key1]['memory'][key2].get('logmag'))
                            NVR[index] = noise_raise[ind_CW]
                            NVR_spike[index] = max(noise_raise) - NVR[index]
                        else:
                            noise_flag = False

                    data = np.asarray(hdf5[IMD_date][IMD_time]['POW']['"CH5_IIP3_11"'].get('logmag'))

                    derivative = derivative_smooth(data, N_smooth=15)
                    Ind = np.argmin( np.abs(derivative) )

                    IIP3[index] =np.mean(data[max(Ind-5,0):min(Ind+5,len(data)-1)])
                    IIP3[index] = IIP3[index] + attenuation( float(hdf5[IMD_date][IMD_time]['POW']['xs'].attrs.get('imd_f1_cw')), self.data_file, 'signal_attenuation' )
                    IIP_3 = dBm_to_Watts( IIP3[index] )
                    if log_g:
                        G = np.power(10, max_Gain[index]/10 )
                        g4_IMD[index] = float(kappa_c[index]**2*freq_c[index]/12/IIP_3*(2*np.pi*h)*( (np.sqrt(G)-1)/(G-1) )**3 )
                    else:
                        G=1
                        g4_IMD[index] = float(kappa_c[index]**2*freq_c[index]/12/IIP_3*(2*np.pi*h)/8 )

                if 'pumping_data_'+str(int(log_g)) in hdf5[sweep_name].keys():
                    del hdf5[sweep_name]['pumping_data_'+str(int(log_g))]
                grp = hdf5[sweep_name].create_group('pumping_data_'+str(int(log_g)))
                grp.create_dataset('freq_c', data = freq_c)
                grp.create_dataset('kappa_c', data = kappa_c)
                grp.create_dataset('kappa_t', data = kappa_t)
                grp.create_dataset('CW_freq', data = CW_freqs)              # CW frequencies
                grp.create_dataset('current', data = data_dict['current'])
                grp.create_dataset('date_linear', data = data_dict['date_linear'])
                grp.create_dataset('time_linear', data = data_dict['time_linear'])
                grp.create_dataset('IIP3', data = IIP3)
                grp.create_dataset('IMD_time', data = data_dict['IMD_time'])
                grp.create_dataset('IMD_date', data = data_dict['IMD_date'])
                grp.create_dataset('g4_IMD', data = g4_IMD)
                if log_g:
                    if noise_flag:
                        grp.create_dataset('NVR', data = NVR)
                        grp.create_dataset('NVR_spike', data = NVR_spike)
                    grp.create_dataset('P_1dB', data = P_1dB)
                    grp.create_dataset('Bandwidth', data = bandwidth)
                    grp.create_dataset('Gain', data = max_Gain)                 # gain at CW frequency
                    grp.create_dataset('Pump_power', data = data_dict['Pump_power'] + attenuation( data_dict['Pump_freq'], self.data_file, 'pump_attenuation') )
                    grp.create_dataset('Gain_array', data = Gains)
                    grp.create_dataset('Signal_pow_array', data = Signal_Powers_dBm)
                    grp.create_dataset('Pump_freq', data = data_dict['Pump_freq'])
                    grp.create_dataset('time', data = data_dict['time'])
                    grp.create_dataset('date', data = data_dict['date'])
            finally:
                hdf5.close()

    def load_pump_power_sweep(self):

        new_folder = self.device_folder+'pump_power_sweep'+SLASH
        gains = np.loadtxt(new_folder+'gain_sweep.txt')
        currents = np.loadtxt(new_folder+'curr.txt')
        pump_powers = np.loadtxt(new_folder+'pump_powers.txt')

        attributes = [a for a in dir(self) if not a.startswith('__') and not callable(getattr(self,a)) ]
        flux_calibrated = True if ('a' in attributes) and ('b' in attributes) else False

        hdf5 = h5py.File(self.data_file)
        try:
            if 'pump_power_sweep' in hdf5.keys():
                del hdf5['pump_power_sweep']
            grp = hdf5.create_group('pump_power_sweep')
            grp.create_dataset('current', data = currents)
            grp.create_dataset('pump_powers', data = pump_powers)
            grp.create_dataset('gains', data = gains)
            if flux_calibrated:
                flux = Flux(currents,self.a,self.b)
                grp.create_dataset('flux', data = flux)
        finally:
            hdf5.close()

    def add_two_tone_spectroscopy_data(self):

        new_path = self.device_folder + SLASH + 'two_tone_spectroscopy' + SLASH

        currents = np.loadtxt(new_path + 'current.txt')
        ag_freqs = np.loadtxt(new_path + 'ag_freqs.txt')
        real = np.loadtxt(new_path + 'real.txt')
        imag = np.loadtxt(new_path + 'imag.txt')
        ag_powers = np.loadtxt(new_path + 'ag_pows.txt')
        res_freqs = np.loadtxt(new_path + 'res_freq.txt')
        # normalize the phase to have 0 for no response
        data = np.vectorize(complex)(real, imag)
        z = data / np.abs(data)
        for ind,I in enumerate(currents):
            z0 = z[ind][0]
            z[ind] = z[ind]/z0
        z = np.angle(z,deg=True)

        hdf5 = h5py.File(self.data_file)
        try:
            if 'two_tone_spectroscopy_data' in hdf5.keys():
                del hdf5['two_tone_spectroscopy_data']
            grp = hdf5.create_group('two_tone_spectroscopy_data')
            grp.create_dataset('currents', data = currents)
            grp.create_dataset('ag_freqs', data = ag_freqs)
            grp.create_dataset('real', data = real)
            grp.create_dataset('imag', data = imag)
            grp.create_dataset('ag_powers', data = ag_powers)
            grp.create_dataset('res_freqs', data = res_freqs)
            grp.create_dataset('phase_normalized', data = z)
        finally:
            hdf5.close()

        self.plot_two_tone_spectroscopy()

    def plot_two_tone_spectroscopy(self):

        hdf5 = h5py.File(self.data_file)
        try:
            z = np.asarray(hdf5['two_tone_spectroscopy_data'].get('phase_normalized'))
            ag_freqs = np.asarray(hdf5['two_tone_spectroscopy_data'].get('ag_freqs'))
            currents = np.asarray(hdf5['two_tone_spectroscopy_data'].get('currents'))
        finally:
            hdf5.close()
        # colorplot the two-tone spectroscopy data
        dpi = 150
        fig1, ax1 = plt.subplots(1,dpi=dpi)
        p1 = ax1.pcolormesh(currents*1e3, ag_freqs*1e-9, np.transpose(z), cmap='RdBu',vmin=-180,vmax=180)
        fig1.colorbar(p1,ax=ax1, label=r'$\rm Phase \,(deg)$')
        ax1.set_ylabel(r'${\rm Frequency \,(GHz)}$')
        ax1.set_xlabel(r'${\rm Current\,(mA)}$')
        fig1.savefig(self.device_folder + 'phase_colormap.png',dpi=dpi)

    def load_pump_params_sweep(self, meas_name, sweep_name='pump_params_sweep', IMD_flag=False, NVR_flag=True):

        self.pumping_meas_name = meas_name
        nominal_gain_array = np.loadtxt(self.device_folder+sweep_name+SLASH+'gains.txt')

        nominal_gain_array = [nominal_gain_array]

        hdf5 = h5py.File(self.data_file)
        try:
            if sweep_name in hdf5.keys():
                del hdf5[sweep_name]
            grp = hdf5.create_group(sweep_name)
            grp.create_dataset('gains', data = nominal_gain_array)

            for log_g in nominal_gain_array:
                temp_folder = sweep_name+SLASH+'Gain_'+str(int(log_g))+SLASH
                data_dict = {}
                print(np.loadtxt(self.device_folder+temp_folder+'date_linear.txt'))
                date_linear = float_to_DateTime(np.loadtxt(self.device_folder+temp_folder+'date_linear.txt'))
                time_linear = float_to_DateTime(np.loadtxt(self.device_folder+temp_folder+'time_linear.txt'))
                current = np.loadtxt(self.device_folder+temp_folder+'current.txt')

                # load linear fits
                freq_c = float( np.asarray(hdf5[date_linear][time_linear]['LIN'][meas_name]['fits'].get('f0')) )
                kappa_c = float( np.asarray(hdf5[date_linear][time_linear]['LIN'][meas_name]['fits'].get('kc')) )
                kappa_i = float( np.asarray(hdf5[date_linear][time_linear]['LIN'][meas_name]['fits'].get('ki') ))
                kappa_t = kappa_c + kappa_i

                data_dict['date'] = np.loadtxt(self.device_folder+temp_folder+'date.txt')
                data_dict['time'] = np.loadtxt(self.device_folder+temp_folder+'time.txt')
                if IMD_flag:
                    data_dict['IMD_time'] = np.loadtxt(self.device_folder+temp_folder+'IMD_time.txt')
                    data_dict['IMD_date'] = np.loadtxt(self.device_folder+temp_folder+'IMD_date.txt')

                data_dict['Pump_power'] = np.loadtxt(self.device_folder+temp_folder+'pump_power.txt')
                data_dict['Pump_freq'] = np.loadtxt(self.device_folder+temp_folder+'pump_freq.txt')*1e9
                CW_freqs = np.zeros(len(data_dict['Pump_freq']))
                P_1dB = np.zeros(len(data_dict['Pump_freq']))
                NVR = np.zeros(len(data_dict['Pump_freq']))
                period_doubling_peak = np.zeros(len(data_dict['Pump_freq']))
                IIP3 = np.zeros(len(data_dict['Pump_freq']))
                max_Gain = np.zeros(len(data_dict['Pump_freq']))
                bandwidth = np.zeros(len(data_dict['Pump_freq']))
                Gains = np.zeros((len(data_dict['Pump_freq']),201))
                Signal_Powers_dBm = np.zeros((len(data_dict['Pump_freq']),201))
                # TODO change this number to the size of signal powers array

                for index, pump_freq in enumerate(data_dict['Pump_freq']):

                    grp.attrs['freq_c'] = freq_c
                    grp.attrs['kappa_i'] = kappa_i
                    grp.attrs['kappa_c'] = kappa_c
                    grp.attrs['kappa_t'] = kappa_t
                    grp.attrs['current'] = current

                    # define all data folders (dates/times)
                    date = float_to_DateTime( data_dict['date'][index] )
                    time = float_to_DateTime( data_dict['time'][index] )

                    if IMD_flag:
                        IMD_time = float_to_DateTime( data_dict['IMD_time'][index] )
                        IMD_date = float_to_DateTime( data_dict['IMD_date'][index] )

                    # continuous wave frequency for signal
                    freq_CW = hdf5[date][time]['POW']['powers'].attrs.get('freqINP')
                    CW_freqs[index] = freq_CW

                    # signal powers
                    Signal_Powers_dBm[index] = np.asarray( hdf5[date][time]['POW'].get('powers') )
                    Signal_Powers_dBm[index] = Signal_Powers_dBm[index] + attenuation(freq_CW, self.data_file, 'signal_attenuation')

                    # Gains
                    ind_CW = np.abs(np.asarray(hdf5[date][time]['memory'].get('frequencies'))-freq_CW).argmin() + 2            # index of approximately CW_frequency in the memory trace
                    a_out = np.asarray( hdf5[date][time]['memory'][meas_name].get('real') )+ 1j*np.asarray( hdf5[date][time]['memory'][meas_name].get('imag') )
                    logmag_pump_off = complex_to_PLOG(a_out)[0]
                    logmag_pump_off_ref= logmag_pump_off[ind_CW]
                    a_out = np.asarray( hdf5[date][time]['POW'][meas_name].get('real') )+ 1j*np.asarray( hdf5[date][time]['POW'][meas_name].get('imag') )
                    logmag_pump_on = complex_to_PLOG(a_out)[0]
                    logmag_pump_on_ref = logmag_pump_on[0]      # logmag at the lowest CW power where amplifier is presumably not saturated yet
                    gain_ref = logmag_pump_on_ref-logmag_pump_off_ref
                    Gains[index] = logmag_pump_on - logmag_pump_on_ref + gain_ref
                    max_Gain[index] = gain_ref

                    # Figuring out gain profile in frequency
                    a_out = np.asarray( hdf5[date][time]['memory'][meas_name].get('real') )+ 1j*np.asarray( hdf5[date][time]['memory'][meas_name].get('imag') )
                    logmag_pump_off = complex_to_PLOG(a_out)[0]
                    a_out = np.asarray( hdf5[date][time]['LIN'][meas_name].get('real') )+ 1j*np.asarray( hdf5[date][time]['LIN'][meas_name].get('imag') )
                    logmag_pump_on = complex_to_PLOG(a_out)[0]
                    gain_profile = logmag_pump_on - logmag_pump_off

                    # Finding the 3 dB bandwidth relative to CW frequency
                    ind_left, ind_right = find_3dB_bandwidth(gain_profile, ind_CW)
                    bandwidth[index] = np.asarray(hdf5[date][time]['memory'].get('frequencies'))[ind_right]-np.asarray(hdf5[date][time]['memory'].get('frequencies'))[ind_left]

                    # P_1dB and IIP3 points
                    Saturation_power_ind = find_1dB_compression_point(Gains[index], gain_ref)
                    P_1dB[index] = Signal_Powers_dBm[index][Saturation_power_ind]
                    if IMD_flag:
                        data = np.asarray(hdf5[IMD_date][IMD_time]['POW']['"CH5_IIP3_11"'].get('logmag'))
                        derivative = derivative_smooth(data, N_smooth=15)
                        Ind = np.argmin( np.abs(derivative) )

                        IIP3[index] =np.mean(data[max(Ind-10,0):min(Ind+10,len(data)-1)])
                        IIP3[index] = IIP3[index] + attenuation( float(hdf5[IMD_date][IMD_time]['POW']['xs'].attrs.get('imd_f1_cw')), self.data_file, 'signal_attenuation' )
                        IIP_3 = dBm_to_Watts( IIP3[index] )

                    if NVR_flag:
                        # NVR
                        key1 = list(hdf5[date][time]['fits']['noise'].keys())[0]
                        key2 = list(hdf5[date][time]['fits']['noise'][key1].keys())[0]
    #                        NVR[index] = np.asarray(hdf5[date][time]['fits']['noise'][key1][key2].get('nvr'))
                        noise_raise = np.asarray(hdf5[date][time]['noise'][key1][key2].get('logmag')) - np.asarray(hdf5[date][time]['noise'][key1]['memory'][key2].get('logmag'))
                        ind_CW = np.abs(np.asarray(hdf5[date][time]['noise'][key1].get('frequencies'))-freq_CW).argmin() + 2
                        NVR[index] = noise_raise[ind_CW]
#                        period_doubling_peak[index] = max(noise_raise) - NVR[index]
#                        period_doubling_peak[index] = noise_raise[ind_CW+3] - NVR[index]

#                if 'pump_params_sweep_'+str(int(log_g)) in grp.keys():
#                    del grp['pump_params_sweep_'+str(int(log_g))]
                grp1 = grp.create_group('pump_params_sweep_'+str(int(log_g)))

                grp1.create_dataset('CW_freq', data = CW_freqs)              # CW frequencies
                grp1.create_dataset('P_1dB', data = P_1dB)
                grp1.create_dataset('Bandwidth', data = bandwidth)
                grp1.create_dataset('Gain', data = max_Gain)                 # gain at CW frequency
                grp1.create_dataset('Pump_power', data = data_dict['Pump_power'] + attenuation( data_dict['Pump_freq'], self.data_file, 'pump_attenuation') )
                grp1.create_dataset('Gain_array', data = Gains)
                grp1.create_dataset('Signal_pow_array', data = Signal_Powers_dBm)
                grp1.create_dataset('Pump_freq', data = data_dict['Pump_freq'])
                grp1.create_dataset('time', data = data_dict['time'])
                grp1.create_dataset('date', data = data_dict['date'])
                if NVR_flag:
                    grp1.create_dataset('NVR', data = NVR)
                    grp1.create_dataset('period_doubling_peak', data = period_doubling_peak)
                if IMD_flag:
                    grp1.create_dataset('IIP3', data = IIP3)
                    grp1.create_dataset('IMD_time', data = data_dict['IMD_time'])
                    grp1.create_dataset('IMD_date', data = data_dict['IMD_date'])
        finally:
            hdf5.close()

    def add_array_modes_v2(self, array):
        if array != {}:
            hdf5 = h5py.File(self.data_file)
            try:
                if 'array_modes' in hdf5.keys():
                    del hdf5['array_modes']
                grp = hdf5.create_group('array_modes')
                for n in array:
                    i,f = array[n]
                    mode_grp = grp.create_group(n)
                    mode_grp.create_dataset('currents', data = i)
                    mode_grp.create_dataset('res_freqs', data = f)
            finally:
                hdf5.close()

    def load_array_modes_v2(self):
        hdf5 = h5py.File(self.data_file)
        try:
            if 'array_modes' in hdf5.keys():
                array = {}
                for x in hdf5['array_modes'].keys():
                    currents = np.asarray(hdf5['array_modes'][x].get('currents'))
                    freqs = np.asarray(hdf5['array_modes'][x].get('res_freqs'))
                    array[x] = (currents, freqs)
                flag = True
            else:
                flag = False
        finally:
            hdf5.close()
        return array if flag else None

    def mode_detector_flux_sweep(self, date_time=None, meas_name='"CH1_S11_1"'):

        date, time = date_time if date_time else [self.flux_sweep_date, self.flux_sweep_time]
        array_modes = mode_detector_flux_sweep(self.data_file, date, time, meas_name = meas_name,
                                               savepath = self.device_folder, ftype='.png')
        self.add_array_modes_v2(array_modes)


import functools
import inspect
import warnings

def experimental(reason):
    """
    This is a decorator which can be used to mark classes and functions
    as experimental. It will result in a warning being emitted
    when the class is used.

    # Example of usage:

    # Example 1: Use with class inheritance
        @experimental("Because it's experimental")
        class ExperimentalBaseClass:
            def __init__(self):
                print("Creating an instance of ExperimentalBaseClass")

        @experimental("Derived from experimental class")
        class ExperimentalClass(ExperimentalBaseClass):
            def __init__(self):
                ExperimentalBaseClass.__init__(self)
                print("Creating an instance of ExperimentalClass")

        # Testing the experimental class
        experimental_instance = ExperimentalClass()  # This should emit two experimental warnings for base and derived class.

    # Example 2: Use with functions
        @experimental("Experimental function")
        def test_f(a, b):
            print(f"hello {a} and {b}")

        # Testing the experimental function
        test_f("Adam", "Eve")  # This should emit an experimental warning for use of the function.
    """

    def decorator(obj):
        if inspect.isclass(obj):
            fmt = "Use of experimental class {name}{reason}."
            orig_cls_name = obj.__name__

            class ExperimentalClass(obj):
                def __new__(obj, *args, **kwargs):
                    warnings.simplefilter("always", Warning)
                    warnings.warn(
                        fmt.format(
                            name=orig_cls_name,
                            reason=f" ({reason})" if reason else "",
                        ),
                        category=Warning,
                        stacklevel=2,
                    )
                    warnings.simplefilter("default", Warning)
                    return super(ExperimentalClass, obj).__new__(obj)

            return ExperimentalClass
        else:  # function
            fmt = "Call to experimental function {name}{reason}."

            @functools.wraps(obj)
            def new_func(*args, **kwargs):
                warnings.simplefilter("always", Warning)
                warnings.warn(
                    fmt.format(
                        name=obj.__name__,
                        reason=f" ({reason})" if reason else "",
                    ),
                    category=Warning,
                    stacklevel=2,
                )
                warnings.simplefilter("default", Warning)
                return obj(*args, **kwargs)

            return new_func

    if inspect.isclass(reason) or inspect.isfunction(reason):
        # The @experimental is used without any 'reason'.
        return decorator(reason)
    elif isinstance(reason, str):
        # The @experimental is used with a 'reason'.
        return decorator
    else:
        raise TypeError(f"@experimental decorator `reason` expected to be string but got {type(reason)}")


from django.shortcuts import render
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post
from .forms import PostForm
from django.views.decorators.http import require_POST
from django.db.models import Q

def main(request):
    return render(request, 'posts/main.html')

def show(request):
    posts = Post.objects.order_by('-updated_at')
    post_sorted3 = []
    post_sorted2 = []
    post_sorted0 = []

    for post in posts:
        if post._type == 3:
            post_sorted3.append(post)
        elif post._type == 2:
            post_sorted2.append(post)
        elif post._type == 0:
            post_sorted0.append(post)

    context = {
        'posts': posts,
        'post_sorted3': post_sorted3,
        'post_sorted2': post_sorted2,
        'post_sorted0': post_sorted0,
    }
    return render(request, 'posts/show.html', context)

def service(request):
    return render(request, 'posts/service.html')

def detail(request, post_id):
    post = get_object_or_404(Post, pk=post_id)
    post.save()
    context = {
        'post': post
    }
    return render(request, 'posts/detail.html', context)

def search(request):
    posts = Post.objects.all().order_by('-id')

    q = request.POST.get('q', "")

    if q:
        posts = posts.filter(Q(title__icontains=q) | Q(content__icontains=q))
        return render(request, 'posts/search.html', {'posts': posts, 'q': q})
    else:
        return render(request, 'posts/show.html')


# -*- coding: utf-8 -*-
"""
Created on Fri Jan  8 13:18:28 2021

@author: Sunidhi Thakur
"""

from matplotlib import pyplot as plt

# Ques 6 - Pie Chart

activities = ["Sleeping", "Eating", "Studying","Coding", "Playing"]
slices = [6, 1, 13, 2, 2]
cols = ["orange", "g", "c", "r", "b"]

plt.pie(slices, labels = activities, colors = cols, startangle = 90, shadow = True, explode = (0, 0, 0.05, 0.05, 0), autopct = "%1.1f%%")

plt.title("PIE CHART")

plt.legend()
plt.show()

# # Ques 5 - Plotting Scatter Plot
# x = [1,2,3,4,5,6,7,8,9,10,11, 12]
# y1 = [7, 1, 4, 3, 5, 2, 8, 11, 7, 12, 1, 7]
# y2 = [1, 3, 5, 7, 9, 9, 9, 7, 5, 3, 1, 9]

# plt.scatter(x,y1, label = 'Scatter 1', color = "r", s = 65, marker = "d")
# plt.scatter(x,y2, label = 'Scatter 2', color = "b", s = 65, marker = "X")

# plt.title("SCATTERED PLOT")
# plt.xlabel("Age")
# plt.ylabel("Frequency")
# plt.legend()
# plt.show()

# Ques 4 - Plotting Histogram
# plt.figure(figsize=(10,6))
# ax = plt.axes()
# ax.set_facecolor("grey")
# population = [5, 10,45, 36, 98, 44, 78, 23, 20, 21, 18, 11, 20, 30, 40, 14, 66, 5, 50, 60, 72, 47, 80, 90, 100, 110]
# bins = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120]

# plt.hist(population, bins, histtype = "bar", rwidth = 0.8, color="k")
# plt.title("HISTOGRAM")
# plt.xlabel("Age")  # Assume Product IDs(cyan = Haircare products, blue = Skincare Products)
# plt.ylabel("Frequency")  # Profit
# plt.legend()
# plt.show()

# #Ques 3 - Plotting Bar Graphs

# plt.bar([2001, 2003, 2005, 2007, 2009],[7, 5, 2, 4, 6], label = "Product X", color = 'b')
# plt.bar([2002, 2004, 2006, 2008, 2010],[6, 4, 2, 5, 7], label = "Product Y", color = 'c')

# plt.title("BAR GRAPHS")
# plt.xlabel("X-axis")  # Assume Product IDs(cyan = Haircare products, blue = Skincare Products)
# plt.ylabel("Y-axis")  # Profit
# plt.legend()
# plt.show()

# Ques 2 - Plotting Two lines Together

# from matplotlib import pyplot as plt
# from matplotlib import style

# x1 = [6,9,11]
# y1 = [6,10,7]
# x2 = [5,8,10]
# y2 = [2,16,6]

# plt.plot(x1,y1,"g", label="Line 1", linewidth = 5)
# plt.plot(x2,y2,"r", label="Line 2", linewidth = 5)

# plt.title("INFO")
# plt.xlabel("X-axis")
# plt.ylabel("Y-axis")
# plt.legend()
# plt.grid(True, color = "k")

# plt.show()

# Ques 1 - Plotting a simple line

# from matplotlib import pyplot as plt

# plt.plot([1,2,3],[4,5,6])

# plt.title("info")
# plt.xlabel("X-axis")
# plt.ylabel("Y-axis")

# plt.show()


import os
import pickle
import numpy as np
import matplotlib.pyplot as plt
from parameters import *
from utils import figure_plot
from data.feature_extraction import mfcc_extraction

# path
dir_path = os.path.dirname(os.path.realpath(__file__))
path_pretrained_model = os.path.join(dir_path, 'pretrained_models/mfcc_delta')
path_training_data = os.path.join(dir_path, 'training_data/pomegranate_mfcc_delta')
test_wav_file = './test/reference_exercise_01_norm.wav'
scaler = pickle.load(open(os.path.join(path_training_data, 'scaler.pkl'), 'rb'))

# load the recognition HMM
hmm_conc = pickle.load(open(os.path.join(path_pretrained_model, 'hmm_conc.pkl'), 'rb'))

mfcc_test, sr_test = mfcc_extraction(test_wav_file, framesize_t=framesize_t, hopsize_t=hopsize_t)

# obtain the decoding path
path = hmm_conc.predict(scaler.transform(mfcc_test.T), algorithm='viterbi')

dict_state = dict()
for id, state in enumerate(hmm_conc.states):
    dict_state[id] = state.name

path = [dict_state[id] for id in path if dict_state[id] != 'hmm_conc-start']
onset_label = [[0, path[0]]]
for ii in range(1, len(path)):
    if path[ii].split('-')[0] != path[ii-1].split('-')[0] and path[ii][0] != path[ii-1][0]:
        onset_label.append((ii, path[ii]))

print(len(mfcc_test.T))
print(len(path))
print(onset_label)

figure_plot(plt=plt, mfcc=mfcc_test.T, onset_label=onset_label)
plt.show()


from django.http import Http404, HttpResponse
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated

from alert.models import Projects, Contributors, Issues, Comments
from alert.serializers import ProjectsListSerializer, ProjectsDetailSerializer,\
    ContributorsSerializer, IssuesSerializer, CommentsSerializer
from alert.permissions import ProjectIsUserAuthorOrContributorPermissions,\
    IssuesPermissions, CommentsPermissions

# 3 Récupérer la liste de tous les projets (projects) rattachés à l'utilisateur (user) connecté
# 5 Récupérer les détails d'un projet (project) via son id

class ProjectsViewset(ModelViewSet):

    permission_classes = [IsAuthenticated, ProjectIsUserAuthorOrContributorPermissions]

    serializer_class = ProjectsDetailSerializer

    def get_queryset(self):
        # si l'url est /api/projects/, alors self.kwargs = {}
        # si l'url est /api/projects/2/, alors self.kwargs = {'pk': '2'}
        # Si je veux le détail d'un projet, je retourne toutes les valeurs à la permission
        # (l'affichage du détail étant géré par modelVieSet)
        if self.kwargs:
            return Projects.objects.all()
        # sinon, je n'adresse que ce qui ne concerne que l'utilisateur
        return Projects.objects.filter(author_user=self.request.user)

    # Pour pouvoir faire un update partiel
    # https://tech.serhatteker.com/post/2020-09/enable-partial-update-drf/
    def update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return super().update(request, *args, **kwargs)

    # Surcharge du class DestroyModelMixin pour modifier le message retourné
    # à l'origine "return Response(status=status.HTTP_204_NO_CONTENT)"
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response({"message": "Le projet et ses problèmes associés ont bien été supprimés."},
                        status=200)

    # --------------------------C O N T R I B U T O R S (USERS)----------------------

    # ------------------------------------------------------------------------------ #
    # Via @action, création de l'url : /projects/<id>/users (ici, users est
    # automatiquement le nom de la fonction, car aucun url_path de précisé)
    # ------------------------------------------------------------------------------ #
    @action(detail=True, methods=['get', 'post'])
    def users(self, request, pk=None):
        """Création d'un path /projects/<id>/users pour afficher les contributeurs sur un projet,
        et enregistrer de nouveaux contributors"""
        if request.method == "GET":
            queryset = Contributors.objects.filter(project=pk)
            if len(queryset) == 0:
                raise Http404(f"Aucun projet {pk} n'a de contributeur.")

            serializer = ContributorsSerializer(queryset, many=True)
            return Response(serializer.data, status=200)

        # Ajout d'un contributeur :
        if request.method == "POST":
            # Vérification que le projet existe
            try:
                project = Projects.objects.get(pk=pk)
            except Projects.DoesNotExist:
                return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

            # Si vérification passée :
            # Informations partielles adressées au sérializer (pas le projet puisque abs du body)
            serializer = ContributorsSerializer(data=request.data,
                                                partial=True)
            if serializer.is_valid():
                # Si Informations partielles validées :
                # Création du contributeur par le serializer en lui adressant le projet récupéré
                # dans le try précédent, grace au pk de l'url
                contributor = serializer.create(project=project)
                return Response(contributor, status=200)

            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    # ------------------------------------------------------------------------------ #
    # Via @action, création de l'url : /project/{id}/users/{id}/ ici, l'url n'est pas
    # le nom de la fonction mais remplacé par url_path. Comme pk, user_id devient
    # récupérable
    # ------------------------------------------------------------------------------ #
    @action(detail=True, methods=['delete'], url_path='users/(?P<user_id>\d+)')
    def remove_contributor_from_project(self, request, user_id, pk=None):
        # Attention : même si le paramètre request n'est pas utilisé,
        # il faut le conserver à défaut d'obtenir un mesage d'erreur :
        # TypeError: remove_contributor_from_project() got multiple values for argument 'user_id'

        # Vérification que le projet existe
        try:
            Projects.objects.get(pk=pk)
        except Projects.DoesNotExist:
            return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

        # récupération des contributions liées au projet et à l'user (auteur et contributeur)
        contribution_concerned = Contributors.objects.filter(project=pk).filter(user=user_id)

        # Si ce contibuteur n'est pas associé à ce projet, alors len = 0 :
        if len(contribution_concerned) == 0:
            return HttpResponse({f"Aucun contributeur {user_id} associé au projet {pk}."},
                                status=404
                                )
        else:
            for contribution in contribution_concerned:
                contribution.delete()

        return Response({"message": "L'utilisateur a bien été supprimé de ce projet."}, status=200)

    # -------------------------------I S S U E S-------------------------------------

    # GET: /project/{id}/issues/
    @action(detail=True, methods=['get', 'post'], permission_classes=[IssuesPermissions])
    def issues(self, request, pk=None):
        """Création d'un path /projects/<id>/issues pour afficher les problèmes d'un projet,
        et en enregistrer de nouveaux """
        # récupération de <id> du projet dans /projects/<id>/issues via pk
        if request.method == "GET":
            # Vérification qu'il y a un problème d'enregisté sur le projet
            queryset = Issues.objects.filter(project=pk)
            if not queryset:
                return HttpResponse({"Aucun problème pour ce projet, ou projet inexistant."},
                                    status=404)

            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            serializer = IssuesSerializer(queryset, many=True)
            return Response(serializer.data, status=200)
            # for element in queryset:
            #     if element.author_user != request.user:
            #         return Response({f"Vous n'avez pas accès à cet objet"}, status=404)
            # self.check_object_permissions(request, Issues.objects.get(pk=queryset.first().pk))
            # serializer = IssuesSerializer(queryset, many=True)
            # return Response(serializer.data, status=200)

        # Enregistrer un problème pour un projet
        if request.method == "POST":
            # Vérification que le projet existe
            try:
                project = Projects.objects.get(pk=pk)
            except Projects.DoesNotExist:
                return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

            # Si vérification passée :
            # Informations partielles adressées au sérializer (pas le projet puisque abs du body et
            # présent dans l'url)
            serializer = IssuesSerializer(data=request.data, partial=True)
            if serializer.is_valid():
                # Si Informations partielles validées :
                # Vérification des permissions
                self.check_object_permissions(request, Projects.objects.get(pk=pk))
                # Enregistrement du problème par le serializer en lui adressant le projet récupéré
                # dans le try précédent, grace au pk de l'url et l'auteur via request.user
                issue = serializer.create(project=project, author_user=request.user)
                return Response(issue, status=200)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        # ------------------------------------------------------------------------------ #
        # Via @action, création de l'url : /project/{id}/issues/{id}/ ici, l'url n'est pas
        # le nom de la fonction mais remplacé par url_path. Comme pk, issue_id devient
        # récupérable
        # ------------------------------------------------------------------------------ #
    # @action(detail=True, methods=['put', 'delete'], url_path='issues/(?P<issue_id>\d+)',
    #         permission_classes=[AuthorIsRequestUserPermissions])
    @action(detail=True, methods=['put', 'delete'], url_path='issues/(?P<issue_id>\d+)',
            permission_classes=[IssuesPermissions])
    def update_or_delete_issue(self, request, issue_id, pk=None):
        """Création d'un path /projects/<id>/issues/<id> pour mettre à jour un problème,
        ou le supprimer"""
        # Vérification que le projet existe
        try:
            Projects.objects.get(pk=pk)
        except Projects.DoesNotExist:
            return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

        # récupération des problèmes liés au projet
        issue_concerned = Issues.objects.filter(project=pk).filter(pk=issue_id)
        # Si aucun problème n'est associé à ce projet, alors len = 0 :
        if len(issue_concerned) == 0:
            return HttpResponse({f"Aucun problème {issue_id} associé au projet {pk}."},
                                status=404
                                )

        if request.method == "PUT":
            serializer = IssuesSerializer(partial=True)
            print("ICI PUT COTE VIEW")
            # Pas de création d'un update dans le serializers.py car utilisation de ipdate()
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            issue_modified = serializer.update(instance=issue_concerned.first(),
                                               validated_data=request.data)

            # reserialization de issue_modified pour passage en Response
            issue_serialized = IssuesSerializer(instance=issue_modified).data

            return Response(issue_serialized, status=200)

        if request.method == "DELETE":
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            # si permission, suppression du problème :
            issue_concerned.delete()

            return Response({"message": "Le problème a bien été supprimé."}, status=200)

        # ----------------------------------C O M M E N T S-----------------------------

        # ------------------------------------------------------------------------------ #
        # Via @action, création de l'url : /project/{id}/issues/{id}/comments/
        # ici, l'url n'est pas le nom de la fonction mais remplacé par url_path.
        # Comme pk, issue_id devient récupérable
        # ------------------------------------------------------------------------------ #
    @action(detail=True, methods=['post', 'get'],
            url_path='issues/(?P<issue_id>\d+)/comments', permission_classes=[CommentsPermissions])
    def comments(self, request, issue_id, pk=None):
        """Création d'un path /projects/<id>/issues/<id>/comments pour créer, récupérer
         un commentaire"""
        # Vérification que le projet existe
        try:
            Projects.objects.get(pk=pk)
        except Projects.DoesNotExist:
            return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

        # Vérification qu'il y a bien un problème 'issue_id' lié au projet
        issue_concerned = Issues.objects.filter(project=pk).filter(pk=issue_id)
        # Si aucun problème n'est associé à ce projet, alors len = 0 :
        if len(issue_concerned) == 0:
            return HttpResponse({f"Aucun problème {issue_id} associé au projet {pk}."},
                                status=404
                                )
        # Enregistrer un commentaire pour un problème
        if request.method == "POST":
            # Informations partielles adressées au sérializer (pas l'ID de l'issue puisque abs
            # du body et présent dans l'url). Ci-dessous, request.data est vide, donc utilisation
            # de request.query_params (phénomène inverse, le lendemain, retour au request.data)
            # serializer = CommentsSerializer(data=request.query_params, partial=True)

            serializer = CommentsSerializer(data=request.data, partial=True)
            if serializer.is_valid():
                # Si Informations partielles validées :
                # Vérification des permissions
                self.check_object_permissions(request, Projects.objects.get(pk=pk))
                # Enregistrement du commentaire par le serializer en lui adressant l'issue concernée
                # dans le try précédent, grace au issue_id de l'url
                # !!! si, issue_concerned récupérée avec filter et non get, il faut ajouter .first()
                # car il s'agit alors d'un queryset et non plus d'une instance avec get
                # issue_concerned = Issues.objects.get(pk=issue_id)
                comment = serializer.create(issue_concerned=issue_concerned.first(),
                                            author_user=request.user)
                return Response(comment, status=200)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        # Récupérer les commentaires d'un problème
        if request.method == 'GET':
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            # récupération des commentaires liés à une issue
            all_comments_for_issue = Comments.objects.filter(issue=issue_id)
            datas = []
            for comment in all_comments_for_issue:
                serializer = CommentsSerializer(comment)
                datas.append(serializer.data)

            return Response(datas, status=200)

        # ------------------------------------------------------------------------------ #
        # Via @action, création de l'url : /project/{id}/issues/{id}/comments/{id}
        # ici, l'url n'est pas le nom de la fonction mais remplacé par url_path.
        # Comme pk, issue_id et comment_id deviennent récupérables
        # ------------------------------------------------------------------------------ #
    @action(detail=True, methods=['get', 'put', 'delete'],
            url_path='issues/(?P<issue_id>\d+)/comments/(?P<comment_id>\d+)',
            permission_classes=[CommentsPermissions])
    def update_or_delete_or_get_comment(self, request, issue_id, comment_id, pk=None):
        """Création d'un path /projects/<id>/issues/<id>/comments pour créer, récupérer,
        modifier, supprimer un commentaire"""
        # Vérification qu'il y a bien un projet pk
        try:
            Projects.objects.get(pk=pk)
        except Projects.DoesNotExist:
            return HttpResponse({f"Le projet {pk} n'existe pas."}, status=404)

        # Vérification qu'il y a bien un problème 'issue_id' lié au projet
        issue_concerned = Issues.objects.filter(project=pk).filter(pk=issue_id)
        # Si aucun problème n'est associé à ce projet, alors len = 0 :
        if len(issue_concerned) == 0:
            return HttpResponse({f"Aucun problème {issue_id} associé au projet {pk}."},
                                status=404
                                )
        # Enfin, vérification que le commentaire existe et est bien lié à issue_id
        comment_concerned = Comments.objects.filter(pk=comment_id).filter(issue=issue_id)

        # Si aucun problème n'est associé à ce projet, alors len = 0 :
        if len(comment_concerned) == 0:
            return HttpResponse({f"Aucun commentaire {comment_id} associé au problème {issue_id}."},
                                status=404
                                )

        # Modifier un commentaire
        if request.method == "PUT":
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            serializer = CommentsSerializer(partial=True)

            # Pas de création d'un update dans le serializers.py car utilisation de update()
            comment_modified = serializer.update(instance=comment_concerned.first(),
                                                 validated_data=request.data)

            # reserialization de comment_modified pour passage en Response
            comment_serialized = CommentsSerializer(instance=comment_modified).data

            return Response(comment_serialized, status=200)

        if request.method == "DELETE":
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            comment_concerned.delete()

            return Response({"message": "Le commentaire a bien été supprimé."}, status=200)

        # Récupérer un commentaire
        if request.method == "GET":
            # Vérification des permissions
            self.check_object_permissions(request, Projects.objects.get(pk=pk))
            # reserialization de comment_modified pour passage en Response
            comment_find = CommentsSerializer(instance=comment_concerned.first()).data

            return Response(comment_find, status=200)


def part2(input):
    sum = 0
    lines = input.readlines()
    for i in range(2, len(lines), 3):
        one, two, three = lines[i-2], lines[i-1], lines[i]
        intersect = set(one).intersection(
            set(two)).intersection(set(three))
        for char in list(intersect):
            if 'a' <= char <= 'z':
                # print(char, ord(char) - 96)
                sum += ord(char) - 96
            elif 'A' <= char <= 'Z':
                # print(char, ord(char) - 64+26)
                sum += ord(char) - 64+26
    return sum

def part1(input):
    sum = 0
    for line in input.readlines():
        line = line[:-1]
        middle = int(len(line)/2)
        left, right = line[:middle], line[middle:]
        intersect = set(left).intersection(set(right))
        if len(intersect) == 0:
            print(left, right)
            continue
        char = list(intersect)[0]
        if 'a' <= char <= 'z':
            # print(char, ord(char) - 96)
            sum += ord(char) - 96
        elif 'A' <= char <= 'Z':
            # print(char, ord(char) - 64+26)
            sum += ord(char) - 64+26
    return sum

for file_name in ['example.txt', 'input.txt']:
    # for file_name in ['example.txt']:
    print(f'{file_name}:')
    with open(file_name) as file:
        print(f'    part1 {part1(file)}')
    with open(file_name) as file:
        print(f'    part2 {part2(file)}')


import sys
sys.setrecursionlimit(10**6)

def dfs(start, tree, parent):
    for i in tree[start]:
        if parent[i] == 0:
            parent[i] = start
            dfs(i, tree, parent)

if __name__ == "__main__":
    n      = int(sys.stdin.readline())
    tree   = [[] for _ in range(n+1)]
    parent = [0 for _ in range(n+1)]

    for _ in range(n-1):
        a, b = map(int, sys.stdin.readline().split())
        tree[a].append(b)
        tree[b].append(a)

    dfs(1, tree, parent)

    for i in range(2, n+1):
        print(parent[i])

김동현_11725_트리의 부모 찾기.py


import cv2, sys, time
import matplotlib.pyplot as plt
import subprocess

def Foto(Nombre):

#video_capture = cv2.VideoCapture(0)
 video_capture=cv2.VideoCapture("/dev/video0") #Escogiendo la camara
 # Check success
 if not video_capture.isOpened():
    raise Exception("Could not open video device")
 # Read picture. ret === True on success
 ret, frame = video_capture.read()
 # Close device
 video_capture.release()
 #print(ret)
 #img = cv2.imread('1.jpg',1)  #Leyendo imagenes
 #print(frame.shape)
 frameRGB = frame[:,:,::-1] # BGR => RGB
 #cv2.imshow(frameRGB, img)
 #cv2.imwrite('/home/debian/MicroSD/Codigos/Fotos/CameraPhoto.jpg',frameRGB)
 a='/home/debian/'
 cv2.imwrite(a+Nombre ,frameRGB)
 cv2.imshow('image',frameRGB)
 cv2.waitKey(0)
 cv2.destroyAllWindows()

print("Tomando Imagen")
Name="Camara.jpg"
Foto(Name)
print("FOto tomada")
bashCommand = "mv /home/debian/"+Name+" /home/debian/MicroSD/Codigos/Fotos"
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()


import re, os
from utils import Utils

util = Utils()

class NameParser:
    def Scan(data,byLongest=True,allResults=False,anySequence=False):
        """Returns a dict of {'last_names':<list of strings>,'first_names':<list of strings>}
        :type data: string or list of strings
        :param byLongest: returns longest matches. Alternative is by Popularity: the most common names, as defined in the values of the JSON database (lower rank is more common).
        :param allResults: Limits best guesses from both categories, for each string if supplied a list.
        :param anySequence: =False discards all invalid orders of name types (eg. first,last,first). Use =True with allResults=True to get all possible names.
        """
        results = {'last_names':[],'first_names':[]}
        if type(data) is str: return _scanDatum(data,byLongest=byLongest,allResults=allResults,anySequence=anySequence)
        elif type(data) is list:
            for item in data:
                result = _scanDatum(item,byLongest=byLongest,allResults=allResults,anySequence=anySequence)
                results['last_names'] += result['last_names']
                results['first_names'] += result['first_names']
            return results
        else: raise TypeError("Scan() data needs to be a list or a string. Input type was "+str(type(data)))

class _NameMatch:
    '''A string match with the name database'''
    def __init__(self,_isLname,_value,_popularity,_endIndex):
        assert(type(_popularity) is int)
        self.isLname, self.value, self.popularity, self.endIndex = _isLname, _value, _popularity, _endIndex
    @property
    def normalisedPopularity(self):
        if self.isLname: return (util.lenLast - self.popularity) /util.lenLast
        else: return (util.lenFirst - self.popularity) / util.lenFirst

class _NameMatchesGroup: #add variety checks and illegal order
    '''Multiple name matches derived from the same string'''
    def __init__(self, nameList,searchedLenString):
        self.searchedStringLength, self.names = searchedLenString, []
        self.addMatchesList(nameList)

    def addMatchesList(self,nameList):
        if type(nameList) is not list : raise TypeError("type is "+str(type(nameList)))
        for name in nameList:
            if type(name) is not _NameMatch: raise TypeError("type is "+str(type(name)))
            self.names.append(name)

    def toDictionary(self):
        dictionary = {'last_names':[],'first_names':[]}
        for name in self.names:
            if name.isLname: dictionary['last_names'].append(name.value)
            else: dictionary['first_names'].append(name.value)
        return dictionary

    ''' returns a _NameMatchesGroup
    Checks for [F,L,F] or [L,F,L] sequences in this nameGroup and takes the better group. '''
    def validatedOrder(self,popularityMode=False,longestMode=False):
        assert(popularityMode != longestMode) # pick a mode !
        prevWasFirst,firstExists,lastExists,splitSequencesMode = None, False, False,False
        sequencesDB = _NameGroupsDatabase(self.searchedStringLength)
        currentSequence, previousSequence = _NameMatchesGroup([],self.searchedStringLength), _NameMatchesGroup([],self.searchedStringLength)
        currentUniformStreak = []
        firstStreak = []
        for i,name in enumerate(self.names):
            if name.isLname:
                if prevWasFirst == True:
                    if lastExists: prevWasFirst,firstExists,splitSequencesMode= False,False,True  # invalid currentSequence [L,F,L] , splitSequencesMode
                    elif previousSequence.isEmpty:
                        prevWasFirst = False
                        firstStreak = list(currentUniformStreak)
                        currentUniformStreak = []
                else:
                    currentUniformStreak.append(name)
                    prevWasFirst,lastExists = False,True
                    currentSequence.addMatchesList([name])
            else: #first name
                if prevWasFirst == False:
                    if firstExists: prevWasFirst,lastExists,splitSequencesMode = True,False,True   # invalid currentSequence [F,L,F] , splitSequencesMode
                    elif previousSequence.isEmpty:
                        prevWasFirst = True
                        firstStreak = list(currentUniformStreak)
                        currentUniformStreak = []
                else:
                    currentUniformStreak.append(name)
                    prevWasFirst,firstExists = True,True
                    currentSequence.addMatchesList([name])
            if splitSequencesMode:
                if previousSequence.isEmpty==False: #previous sequence needs the rest of current streak
                    previousSequence.addMatchesList(currentUniformStreak)
                    sequencesDB.addValue(previousSequence)
                else: sequencesDB.addValue( _NameMatchesGroup(firstStreak+currentUniformStreak,self.searchedStringLength) )
                if i == len(self.names)-1: #save current as well
                    currentSequence.addMatchesList(currentUniformStreak)
                    sequencesDB.addValue(currentSequence)
                else:
                    previousSequence = _NameMatchesGroup(currentSequence.names,self.searchedStringLength)
                    currentSequence = _NameMatchesGroup([name],self.searchedStringLength)
                currentUniformStreak = []
                splitSequencesMode = False
        #process results
        if len(sequencesDB.groups) > 1:
             if popularityMode: return sequencesDB.getPopularGuess()
             if longestMode: return sequencesDB.getLongestWords()
        else: return self #is valid

    @property
    def isEmpty(self): return True if len(self.names)==0 else False
    @property
    def lastnames(self): return [name for name in self.names if name.isLname == True]
    @property
    def firstnames(self): return [name for name in self.names if name.isLname == False]
    @property
    def longestLastAndFirst(self):
        fn, ln = self.firstnames, self.lastnames
        if len(fn)==0:
            if len(ln)==0:      return _NameMatchesGroup([],self.searchedStringLength)
            else:               return _NameMatchesGroup([max(ln, key=lambda x: len(x.value))],self.searchedStringLength)
        if len(ln)==0:          return _NameMatchesGroup([max(fn, key=lambda x: len(x.value))],self.searchedStringLength)
        else:                   return _NameMatchesGroup([max(ln, key=lambda x: len(x.value)),
                                                         max(fn, key=lambda x: len(x.value))],self.searchedStringLength)
    @property
    def mostPopularLastAndFirst(self): #doesn't handle empty lists well
        fn, ln = self.firstnames, self.lastnames
        if len(fn)==0:
            if len(ln)==0:      return _NameMatchesGroup([],self.searchedStringLength)
            else:               return _NameMatchesGroup([max(ln, key=lambda x: x.normalisedPopularity)],self.searchedStringLength)
        if len(ln)==0:          return _NameMatchesGroup([max(fn, key=lambda x: x.normalisedPopularity)],self.searchedStringLength)
        else:                   return _NameMatchesGroup([max(ln, key=lambda x: x.normalisedPopularity),
                                                         max(fn, key=lambda x: x.normalisedPopularity)],self.searchedStringLength)
    @property
    def longestWordsRank(self): return sum([len(name.value)**2 for name in self.names])
    @property
    def popularityRank(self): return sum([name.normalisedPopularity * len(name.value)**2 for name in self.names])
    @property
    def popularityRankValidatedSequence(self): return sum([name.normalisedPopularity * len(name.value)**2 for name in self.validatedOrder(popularityMode=True).names])
    @property
    def longestWordsRankValidatedSequence(self): return sum([len(name.value)**2 for name in self.validatedOrder(longestMode=True).names])

class _NameGroupsDatabase:
    '''Contains all name match groups for a specific string (or substring)'''
    def __init__(self, stringLength):  self.groups, self.strLen = [], stringLength
    def addValue(self, nameMatchesGroup):
        if type(nameMatchesGroup) is not _NameMatchesGroup: raise TypeError("type = "+str(type(nameMatchesGroup)))
        assert(nameMatchesGroup.searchedStringLength == self.strLen) #making sure the group are derived from the same string
        self.groups.append(nameMatchesGroup)

    '''Inserts all groups from another database into this database, and inserts the same group/match in front of them'''
    def expandInputDatabase(self, aGroupOrMatch,aDatabase):
        matchesList = []
        if type(aGroupOrMatch) == _NameMatch:  matchesList = [aGroupOrMatch]
        elif type(aGroupOrMatch) == _NameMatchesGroup: matchesList = aGroupOrMatch.names
        else: raise TypeError("aGroupOrMatch type is: "+str(type(aGroupOrMatch))+"value: "+str(aGroupOrMatch))
        for group in aDatabase.groups: self.addValue(_NameMatchesGroup(matchesList + group.names,self.strLen))

    def envelopName(self, aName):
        if type(aName) is not _NameMatch: raise TypeError("type = "+str(type(aName)))
        if len(self.groups) == 0: self.addValue(_NameMatchesGroup([aName],self.strLen))
        else:
            for group in self.groups: group.addMatchesList([aName])

    def envelopGroup(self,aMatchGroup):
        if type(aMatchGroup) is not _NameMatchesGroup: raise TypeError("type = "+str(type(aName)))
        if len(self.groups) == 0 : self.addValue(_NameMatchesGroup(aMatchGroup,self.strLen))
        else:
            for group in self.groups: group.addMatchesList(aMatchGroup.names)

    """Caution: merges regardless of databases' searched string lengths, should be used for merging a database into a larger one. """
    def envelopDatabase(self, aDatabase):
        if type(aDatabase) is not _NameGroupsDatabase: raise TypeError("type = "+str(type(aName)))
        if len(self.groups) == 0:
                for inputGroup in aDatabase.groups: self.addValue(_NameMatchesGroup(inputGroup.names,self.strLen))
        else:
            oldGroups = self.groups
            self.groups = []
            while len(oldGroups) > 0:
                currentGroup = oldGroups.pop()
                for inputGroup in aDatabase.groups: self.addValue(_NameMatchesGroup(currentGroup.names+inputGroup.names,self.strLen))

    def isEmpty(self): return True if len(self.groups)==0 else False
    def getLongestWords(self): return _NameMatchesGroup([],self.strLen) if len(self.groups)==0 else max(self.groups,key=lambda x: x.longestWordsRank)
    def getPopularGuess(self): return _NameMatchesGroup([],self.strLen) if len(self.groups)==0 else max(self.groups,key=lambda x: x.popularityRank)
    """validated guesses don't contain [F,L,F] or [L,F,L] sequences"""
    def getValidatedPopularGuess(self): return _NameMatchesGroup([],self.strLen) if len(self.groups)==0 else max(self.groups,key=lambda x: x.popularityRankValidatedSequence)
    def getValidatedLongestWords(self):  return _NameMatchesGroup([],self.strLen) if len(self.groups)==0 else max(self.groups,key=lambda x: x.longestWordsRankValidatedSequence)

def _searchSubtrings(string,substringLen):
    '''
    Extracts names by checking for substrings of a specified length.
    Returns list of _NameMatch objects
    '''
    matches = {} #dict to avoid the same name saved, also prefers the earlier occurrence of multiple names
    for i in range(len(string)-substringLen+1):
        check = str.title(string[i:i+substringLen])
        if check in util.fnames:
            if check not in matches: matches[check] = _NameMatch(False,check,int(util.fnames[check]),i+substringLen)
        elif check in util.lnames:
            if check not in matches: matches[check] = _NameMatch(True,check,int(util.lnames[check]),i+substringLen)
    if len(matches) > 0: return list(matches.values())

def _findNames(string):
    '''
    Returns either a _NameMatch  or a NameGroupDatabase
    '''
    #quick check block
    check = str.title(string)
    if check in util.fnames: return _NameMatch(False,check,int(util.fnames[check]),len(string))
    if check in util.lnames: return _NameMatch(True,check,int(util.lnames[check]),len(string))

    database = _NameGroupsDatabase(len(string))
    floored, topped, sign, i, stringLenToCheck, ceil = False, False, 1, 1, 7, min(len(string), 15)
    if len(string) < 7:
        topped, stringLenToCheck, sign = True, len(string)-1, -1

    while not floored or not topped:
        if stringLenToCheck <= 2: floored = True
        elif stringLenToCheck >= ceil: topped = True
        nameMatches = _searchSubtrings(string,stringLenToCheck)
        if nameMatches:
            for nameMatch in nameMatches:
                if nameMatch.endIndex < len(string) -1: #possibility of further names matches in remaining string, recurse
                    nextNameMatches = _findNames(string[nameMatch.endIndex:])
                    if nextNameMatches:
                        if type(nextNameMatches) is _NameMatch:
                            database.addValue( _NameMatchesGroup([nameMatch,nextNameMatches],len(string)))
                        if type(nextNameMatches) is _NameGroupsDatabase: database.expandInputDatabase(nameMatch,nextNameMatches)
                    else:
                        database.addValue(_NameMatchesGroup([nameMatch],len(string)))
                else:
                    database.addValue(_NameMatchesGroup([nameMatch],len(string)))
        if floored: i, sign = 1,1
        elif topped: i, sign = 1,-1
        else: #alternating one up one down
            sign = sign*(-1)
            i +=1
        stringLenToCheck += i*sign
    if database.isEmpty() == False: return database

def _nameMatchString(string,byLongest=True,allResults=False,anySequence=False):
    '''Handles _findNames() output.'''

    words = re.findall('[a-z]+',str.lower(string))
    database = _NameGroupsDatabase(sum([len(word) for word in words]))
    returnDict = {'last_names':[],'first_names':[]}
    if len(words)==0: return returnDict
    elif len(words)==1:
        result = _findNames(words[0])
        if type(result) is _NameMatch:
            returnDict['last_names' if result.isLname else 'first_names' ] = [result.value]
            return returnDict
        if type(result) is _NameGroupsDatabase: database = result
    else:
        results = []
        for word in words:
            results.append(_findNames(word))
        for result in results:
            if type(result) is _NameMatch: database.envelopName(result)
            elif type(result) is _NameMatchesGroup: database.envelopGroup(result)
            elif type(result) is _NameGroupsDatabase: database.envelopDatabase(result)
            else: raise TypeError("type = "+str(type(result)))

    #process results
    if anySequence:
        if byLongest: finalGroup = database.getPopularGuess()
        else: finalGroup = database.getLongestWords()
    else: #only validated sequences
        if byLongest: finalGroup = database.getValidatedPopularGuess()
        else: finalGroup = database.getValidatedLongestWords()
    #output results as dictionaries
    if allResults: return finalGroup.toDictionary()  #all resutls
    else:
        if byLongest: return finalGroup.longestLastAndFirst.toDictionary()
        else: return finalGroup.mostPopularLastAndFirst.toDictionary()

def _scanDatum(datum,byLongest=True,allResults=False,anySequence=False):
    '''breaks up input for _nameMatchString'''
    if type(datum) is not str: datum = str(datum)
    words = re.findall('[a-z]+',str.lower(datum))
    if len(words) > 7 or len(words)> 1 and sum([len(word) for word in words])>20: #long input, split to avoid memory hog.
        results = {'last_names':[],'first_names':[]}
        for word in words:
            result = _nameMatchString(word,byLongest=byLongest,allResults=allResults,anySequence=anySequence)
            results['last_names'] += result['last_names']
            results['first_names'] += result['first_names']
        return results
    else:
        return _nameMatchString(datum,byLongest=byLongest,allResults=allResults,anySequence=anySequence)


# import pandas, numpy, and matplotlib
import pandas as pd
from feature_engine.encoding import OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
import sklearn.metrics as skmet
#import matplotlib.pyplot as plt
pd.set_option('display.width', 75)
pd.set_option('display.max_columns', 20)
pd.set_option('display.max_rows', 200)
pd.options.display.float_format = '{:,.2f}'.format

nls97compba = pd.read_csv("data/nls97compba.csv")

feature_cols = ['satverbal','satmath','gpaoverall',
  'parentincome','gender']

# separate NLS data into train and test datasets
X_train, X_test, y_train, y_test =  \
  train_test_split(nls97compba[feature_cols],\
  nls97compba[['completedba']], test_size=0.3, random_state=0)

# do one hot encoding and scaling
ohe = OneHotEncoder(drop_last=True, variables=['gender'])
ohe.fit(X_train)
X_train_enc, X_test_enc = \
  ohe.transform(X_train), ohe.transform(X_test)

scaler = StandardScaler()
standcols = X_train_enc.iloc[:,:-1].columns
scaler.fit(X_train_enc[standcols])
X_train_enc = \
  pd.DataFrame(scaler.transform(X_train_enc[standcols]),
  columns=standcols, index=X_train_enc.index).\
  join(X_train_enc[['gender_Female']])
X_test_enc = \
  pd.DataFrame(scaler.transform(X_test_enc[standcols]),
  columns=standcols, index=X_test_enc.index).\
  join(X_test_enc[['gender_Female']])

# k nearest neighbor classification
knn = KNeighborsClassifier(n_neighbors = 5)
knn.fit(X_train_enc, y_train.values.ravel())
pred = knn.predict(X_test_enc)

# show a confusion matrix
cm = skmet.confusion_matrix(y_test, pred, labels=knn.classes_)
cmplot = skmet.ConfusionMatrixDisplay(confusion_matrix=cm, \
 display_labels=['Negative--No BA', 'Positive--Completed BA'])
cmplot.plot()
cmplot.ax_.set(title='Confusion Matrix',
  xlabel='Predicted Value', ylabel='Actual Value')

# calculate accuracy, sensitivity, specificity, and precision
tn, fp, fn, tp = skmet.confusion_matrix(y_test.values.ravel(), pred).ravel()
tn, fp, fn, tp
accuracy = (tp + tn) / pred.shape[0]
accuracy
sensitivity = tp / (tp + fn)
sensitivity
specificity = tn / (tn+fp)
specificity
precision = tp / (tp + fp)
precision

print("accuracy: %.2f, sensitivity: %.2f, specificity: %.2f, precision: %.2f"  %
  (skmet.accuracy_score(y_test.values.ravel(), pred),
  skmet.recall_score(y_test.values.ravel(), pred),
  skmet.recall_score(y_test.values.ravel(), pred, pos_label=0),
  skmet.precision_score(y_test.values.ravel(), pred)))

# try this with a random forest classifier
rfc = RandomForestClassifier(n_estimators=100, max_depth=2,
  n_jobs=-1, random_state=0)
rfc.fit(X_train_enc, y_train.values.ravel())
pred = rfc.predict(X_test_enc)
tn, fp, fn, tp = skmet.confusion_matrix(y_test.values.ravel(), pred).ravel()
tn, fp, fn, tp

print("accuracy: %.2f, sensitivity: %.2f, specificity: %.2f, precision: %.2f"  %
  (skmet.accuracy_score(y_test.values.ravel(), pred),
  skmet.recall_score(y_test.values.ravel(), pred),
  skmet.recall_score(y_test.values.ravel(), pred, pos_label=0),
  skmet.precision_score(y_test.values.ravel(), pred)))


import os
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import struct
#os.environ['MPLCONFIGDIR'] = "/home/rsa/.config/matplotlib"
#os.environ['MPLCONFIGDIR'] = "/home/rsa/.cache/matplotlib"
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation

#print (matplotlib.rcParams['backend']) #Muestra en backend utilizado: QtAgg
#matplotlib.use('QtAgg') #Forza a ultizar el backend QtAgg

#********************************************************************************
#Variables y parametros
#********************************************************************************

filepath = "/home/rsa/TMP/temporalCanal.txt"

#Variables globales
valCH1 = 0
valCH2 = 0
valCH3 = 0

#********************************************************************************
#Parametros del grafico

x_len = 120         # Number of points to display
y_range = [0, 4095]  # Range of possible Y values to display

# Crea la figura y los subplots
plt.style.use('dark_background') #Utiliza el modo oscuro
plt.rcParams['toolbar'] = 'None' #Oculta la barra de tareas
fig = plt.figure()
plt.get_current_fig_manager().full_screen_toggle() #Fullscreen mode

ax1 = fig.add_subplot(3, 1, 1)
ax2 = fig.add_subplot(3, 1, 2)
ax3 = fig.add_subplot(3, 1, 3)

#Establece los limistes del eje X
xs = list(range(0, 120))
ys1 = [0] * x_len
ys2 = [0] * x_len
ys3 = [0] * x_len

#Establece los limites del eje Y
ax1.set_ylim(y_range)
ax2.set_ylim(y_range)
ax3.set_ylim(y_range)

#Establece los colores de fondo de los subplots
ax1.set_facecolor('#181c1fff')
ax2.set_facecolor('#181c1fff')
ax3.set_facecolor('#181c1fff')

#Establece el estilo del grid
ax1.grid(linestyle='-',linewidth=0.2)
ax2.grid(linestyle='-',linewidth=0.2)
ax3.grid(linestyle='-',linewidth=0.2)

#Establece las marcas del eje X
plt.setp(ax1.get_xticklabels(), visible=False)     #Borra las marcar del plot x1
plt.setp(ax2.get_xticklabels(), visible=False)     #Borra las marcar del plot x2
ax3.set_xticks([0,20,40,60,80,100,120])            #Selecciona las marcas de los puntos extremos y mitad del eje X
ax3.set_xticklabels([-60,'','',-30,'','',0])       #Remplaza las marcas seleccionadas por los valores 0, 30 y 60
ax1.tick_params(labelsize=9,labelcolor='gray')
ax2.tick_params(labelsize=9,labelcolor='gray')
ax3.tick_params(labelsize=9,labelcolor='gray')

#Establece las etiquetas de los ejes X y Y
ax1.set_ylabel('CH1')
ax2.set_ylabel('CH2')
ax3.set_ylabel('CH3')
ax3.set_xlabel('Tiempo [seg]')

# Create a blank line. We will update the line in animate
line1, = ax1.plot(xs, ys1, color='#5bd15eff')
line2, = ax2.plot(xs, ys2, color='#5bd15eff')
line3, = ax3.plot(xs, ys3, color='#5bd15eff')

#********************************************************************************

#********************************************************************************
#Metodo para leer el archivo de texto y extraer los valores de los 3 ejes:
#********************************************************************************
def LeerArchivo():

    #variables globales
    global valCH1
    global valCH2
    global valCH3

    formatoUnpack = '<' + '3' + 'I'

    #print("imprimiendo...")
    # Abre el archivo para lectura de binarios "rb"
    #objFile = open(filepath, "rb")
    with open(filepath, "rb") as objFile:
        # Lee el total de bytes del archivo, se guarda en un array de bytes
        bytesLeidos = objFile.read()
        # Realiza la conversion de array de bytes a lista de enteros
        vectorDatos = struct.unpack(formatoUnpack, bytesLeidos)
    #Extrae los valores de los 3 ejes
    valCH1 = vectorDatos[0]
    valCH2 = vectorDatos[1]
    valCH3 = vectorDatos[2]
    print("%d   %d   %d" % (valCH1, valCH2, valCH3))

    # Al final cierra el archivo de lectura
    #objFile.close()
#********************************************************************************

#********************************************************************************
#Esta funcion se llama periodicamente desde FuncAnimation
#********************************************************************************
def animate(i):

    global xs
    global ys1
    global ys2
    global ys3

    # Actualiza la medicion de los canales CH1, CH2 y CH3
    medCH1 = valCH1
    medCH2 = valCH2
    medCH3 = valCH3

    # Add x and y to lists
    ys1.append(medCH1)
    ys2.append(medCH2)
    ys3.append(medCH3)

    # Limit y list to set number of items
    ys1 = ys1[-x_len:]
    ys2 = ys2[-x_len:]
    ys3 = ys3[-x_len:]

    line1.set_data(xs,ys1)
    line2.set_data(xs,ys2)
    line3.set_data(xs,ys3)

    return line1,line2,line3
#********************************************************************************

#********************************************************************************
#Clase para monitorizar cambios en los archivos:
#********************************************************************************
class MyEventHandler(FileSystemEventHandler):
    # def on_modified(self, event):
    #     #print(event.src_path, "modificado.")
    #     LeerArchivo()

    def on_closed(self, event):
        LeerArchivo()
#********************************************************************************

#********************************************************************************
#Main
#********************************************************************************
observer = Observer()
observer.schedule(MyEventHandler(), filepath, recursive=False)
observer.start()

# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig, animate, interval=500, blit=True)
plt.show()

try:
    while observer.is_alive():
        observer.join(1)
        print("Verificando archivo...")
except KeyboardInterrupt:
    observer.stop()
observer.join()

#********************************************************************************


def house(plan):
    char = '#'
    # create new list by splitting our plan to lines by '\n'
    li_plan = plan.strip().split('\n')
    # Initilize new list were we will put positions of our '#' character in each separate line
    # add +1 to each position to avoid zero division in case searched '#' in position with index 0
    width_list = []
    for line in enumerate(li_plan):
        for element in enumerate(line[1]):
            if element[1] == char:
                position = element[0] + 1
                width_list.append(position) # Append position to searcher character to the new list
    # If we have not founr '#' in any of lines  - return 0 (no characters found)
    if len(width_list) == 0:
        return 0
    # Defining min and max positions to calculate the width of the house
    # from minimal position extracted -1 to revert the length of the original line from plan
    min_position, max_position = min(width_list), max(width_list)
    house_width = max_position - (min_position - 1)

    # define the lenth of the house iterating through lines
    house_length = 0
    for line in li_plan:
        if char in line: # if '#' in line increase the length of the house by 1
            house_length += 1
        # In case if we have inside our plan lines with no '#' we choul also include such lilnes to our house length
        if char not in line and max_position > 0 and line != li_plan[0]:
            house_length += 1
    # Find house area by multiplying lenth of house by its width
    size_of_house = house_width * house_length
    return size_of_house

if __name__ == '__main__':
    print("Example:")
    print(house('''
0000000
##00##0
######0
##00##0
#0000#0
'''))

    #These "asserts" using only for self-checking and not necessary for auto-testing
    assert house('''
0000000
##00##0
######0
##00##0
#0000#0
''') == 24

    assert house('''00#
0#0
#00
''') == 9

    assert house('''0000
0000
#000
''') == 1

    assert house('''0000
0000
''') == 0

    assert house('''
0##0
0000
#00#
''') == 12
    assert house('''0000000000
0000000000
#00000000#
##########
##00000000
#000000000
''') == 40
    assert house('''
0000000000
000###0000
000#######
000###0000
''') == 21

    print("Coding complete? Click 'Check' to earn cool rewards!")


from UM.Scene.ToolHandle import ToolHandle
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Math.Vector import Vector

import math

##  Provides the circular toolhandles for each axis for the rotate tool

class RotateToolHandle(ToolHandle):
    def __init__(self, parent = None):
        super().__init__(parent)

        self._name = "RotateToolHandle"
        self._inner_radius = 40
        self._outer_radius = 40.5
        self._line_width = 0.5
        self._active_inner_radius = 37
        self._active_outer_radius = 44
        self._active_line_width = 3

    def buildMesh(self):
        #SOLIDMESH
        mb = MeshBuilder()

        mb.addDonut(
            inner_radius = self._inner_radius,
            outer_radius = self._outer_radius,
            width = self._line_width,
            color = self._z_axis_color
        )

        mb.addDonut(
            inner_radius = self._inner_radius,
            outer_radius = self._outer_radius,
            width = self._line_width,
            axis = Vector.Unit_X,
            angle = math.pi / 2,
            color = self._y_axis_color
        )

        mb.addDonut(
            inner_radius = self._inner_radius,
            outer_radius = self._outer_radius,
            width = self._line_width,
            axis = Vector.Unit_Y,
            angle = math.pi / 2,
            color = self._x_axis_color
        )
        self.setSolidMesh(mb.build())

        #SELECTIONMESH
        mb = MeshBuilder()

        mb.addDonut(
            inner_radius = self._active_inner_radius,
            outer_radius = self._active_outer_radius,
            width = self._active_line_width,
            color = ToolHandle.ZAxisSelectionColor
        )

        mb.addDonut(
            inner_radius = self._active_inner_radius,
            outer_radius = self._active_outer_radius,
            width = self._active_line_width,
            axis = Vector.Unit_X,
            angle = math.pi / 2,
            color = ToolHandle.YAxisSelectionColor
        )

        mb.addDonut(
            inner_radius = self._active_inner_radius,
            outer_radius = self._active_outer_radius,
            width = self._active_line_width,
            axis = Vector.Unit_Y,
            angle = math.pi / 2,
            color = ToolHandle.XAxisSelectionColor
        )

        self.setSelectionMesh(mb.build())


from django.contrib import admin
from contact import models

@admin.register(models.Message)
class MessageAdmin(admin.ModelAdmin):
    search_fields = [
        "name",
        "email",
        "phone",
        "country",
        "city",
        "subject",
        "message",
    ]
    list_display = [
        "subject",
        "name",
        "email",
        "date_created",
        "is_read",
    ]
    list_filter = ["country", "city"]
    readonly_fields = [
        "name",
        "email",
        "phone",
        "country",
        "city",
        "subject",
        "message",
    ]

    def has_add_permission(self, request, obj=None):
        return False


from flask import abort, flash, redirect, render_template

from settings import INDEX_URL, MAIN_PAGE_TEMPLATE, MAIN_URL, REDIRECT_URL
from yacut.forms import UrlForm
from yacut.models import URLMap
from . import app, db

@app.route(REDIRECT_URL, methods=['GET'])
def redirect_view(custom_id):
    urlmap = URLMap.check_custom_id_exists(custom_id)
    if urlmap is not None:
        original_url = urlmap.original
        return redirect(original_url)
    abort(404)

@app.route(INDEX_URL, methods=['GET', 'POST'])
def index_view():
    form = UrlForm()
    if form.validate_on_submit():
        custom_id = form.custom_id.data
        if custom_id is None or len(custom_id) == 0:
            custom_id = URLMap.generate_custom_id()
            short_url = URLMap.create_short_link(custom_id)
        else:
            if URLMap.check_custom_id_exists(custom_id):
                flash(f'Имя {custom_id} уже занято!')
                return render_template(MAIN_PAGE_TEMPLATE, form=form)
        urlmap = URLMap(
            original=form.original_link.data,
            short=custom_id
        )
        short_url = MAIN_URL + custom_id
        db.session.add(urlmap)
        db.session.commit()
        return render_template(MAIN_PAGE_TEMPLATE, short_url=short_url, form=form)
    return render_template(MAIN_PAGE_TEMPLATE, form=form)


#list

list=['q','w','e','r']
while 1==1:
    add=input("What do you want to do? Add/Delete/Print all/specific item")
    if add=='Add':
        i=input('Which item do you want to add?')
        list.append(i)
        if list.count(i)>1:
            list.remove(i)
            print('The item already exist, try again')
        else:
            print('Now the list include')
            print(','.join(list))

    elif add=='Delete':
        d=input('Which item do you want to delete?')
        if d in list:
            list.remove(d)
            print('Now the list inculde')
            print(','.join(list))
        else:
            print('Can not find the item, try again')

    elif add=='Print all':
        print(','.join(list))

    elif add=='specific item':
        k=int(input('Which one you want to find(specific nember)'))
        if k<(len(list)+1):
            print('The item you want to find is')
            print(list[k-1])
        elif k<1:
            print('Can not find the item, try again')
        else:
            print('Can not find the item, try again')

    else:
        print('Sorry I do not understant, please try again')


import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

def draw(xCords, yCords, filename, col):
    plt.xlabel("x")
    plt.ylabel("y")
    plt.title(filename)
    plt.plot(xCords, yCords, '-o', color=col, markersize = 1, linewidth = 2)
    for xy in zip(xCords, yCords): # If you don't want the co-ordinates to show up delete this loop
        ax.annotate('(%s, %s)' % xy, xy=xy, textcoords='data')

def toXandY(unorderedData):
    "This method converts seperates x and y co-ordinates for plotting"
    orderedData = []
    orderedData.append([])        # Add a new sublist every time
    orderedData.append([])        # Add a new sublist every time
    listSize = len(unorderedData)
    for x in range(0, listSize):
        orderedData[0].append(unorderedData[x][0])  # Seperates the x-cords
    for y in range(0, listSize):
        orderedData[1].append(unorderedData[y][1])  # Seperates the y-cords
    return orderedData

def plotLines(data):
    "Pass list of points to this method, two consecutive points must be a line"
    newData = []
    line_x = []
    line_y = []
    file_name = "file"
    list_size = len(data)
    for i in range(0, list_size):    # Converting the string list to float
        newData.append([])          # Add a new sublsit every time
        for j in range(0, 2):       # Append converted data to the new list
            newData[i].append(float(data[i][j]))
    DataXandY = toXandY(newData)     # DataXandY -> [[Xs][Ys]]
    while len(DataXandY[0]) != 0:
        # Pop two points to form a line
        line_x.append(DataXandY[0].pop(0))
        line_y.append(DataXandY[1].pop(0))
        line_x.append(DataXandY[0].pop(0))
        line_y.append(DataXandY[1].pop(0))
        draw(line_x, line_y, file_name, "g")
        line_x[:] = []          # Delete the contents
        line_y[:] = []          # Delete the contents

    plt.gca().set_aspect('equal', adjustable='box')
    plt.show()

def main():
    data = [[5.09,5.80], [1.68,4.90],[1.68,4.90], [1.48,1.38],[1.48,1.38], [4.76,0.10],[4.76,0.10], [7.00,2.83],[7.00,2.83],[5.09,5.80]]
    plotLines(data)
    # Plot pentagon

if __name__ == "__main__":
    main()


import random
import string

inteiro = random.randint(10, 20)
inteiro_range = random.randrange(900, 1000, 10)
flutuante = random.uniform(10, 20)

lista = ['pedro', 'Juliana', 'marcela', 'Alice', 'Daniel', 'Marcos']
sorteio = random.choice(lista)
sorteio_duplo = random.choices(lista, k=2)
sorteio_duplo_sem_repetir = random.sample(lista, 2)

print(inteiro)
print(flutuante)
print(inteiro_range)
print(sorteio)
print(sorteio_duplo)
print(sorteio_duplo_sem_repetir)

# Embaralhar a lista
print(lista)
random.shuffle(lista)
print(lista)

# Gerar senha aleatória
letras = string.ascii_letters
digitos = string.digits
caracteres = "!@#$%¨&*()_+"
geral = letras + digitos + caracteres
senha = "".join(random.choices(geral, k=20))

print(senha)


from django.db import models
from django.utils.safestring import mark_safe
from edc_constants.choices import YES_NO, YES_NO_NA
from edc_constants.constants import NOT_APPLICABLE
from edc_model import models as edc_models
from edc_model.models import date_not_future

class ClinicalReviewBaselineHtnModelMixin(models.Model):

    htn_test = models.CharField(
        verbose_name="Has the patient ever tested for Hypertension?",
        max_length=15,
        choices=YES_NO,
    )

    htn_test_ago = edc_models.DurationYMDField(
        verbose_name="If Yes, how long ago was the patient tested for Hypertension?",
        null=True,
        blank=True,
    )

    htn_test_estimated_datetime = models.DateTimeField(
        null=True, blank=True, help_text="calculated by the EDC using `htn_test_ago`",
    )

    htn_test_date = models.DateField(
        verbose_name="Date of patient's most recent Hypertension test?",
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    htn_dx = models.CharField(
        verbose_name=mark_safe("Has the patient ever been diagnosed with Hypertension"),
        max_length=15,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
        help_text="If yes, complete form `Hypertension Initial Review`",
    )

    def save(self, *args, **kwargs):
        if self.htn_test_ago:
            self.htn_test_estimated_datetime = edc_models.duration_to_date(
                self.htn_test_ago, self.report_datetime
            )
        super().save(*args, **kwargs)

    class Meta:
        abstract = True