import scipy.stats
import numpy as np
from numpy.testing import assert_allclose, assert_equal, assert_almost_equal
from patsy import dmatrices  # pylint: disable=E0611
import statsmodels.api as sm
from statsmodels.regression.quantile_regression import QuantReg
from .results.results_quantile_regression import (
    biweight_chamberlain, biweight_hsheather, biweight_bofinger,
    cosine_chamberlain, cosine_hsheather, cosine_bofinger,
    gaussian_chamberlain, gaussian_hsheather, gaussian_bofinger,
    epan2_chamberlain, epan2_hsheather, epan2_bofinger,
    parzen_chamberlain, parzen_hsheather, parzen_bofinger,
    # rectangle_chamberlain, rectangle_hsheather, rectangle_bofinger,
    # triangle_chamberlain, triangle_hsheather, triangle_bofinger,
    # epanechnikov_chamberlain, epanechnikov_hsheather, epanechnikov_bofinger,
    epanechnikov_hsheather_q75, Rquantreg)

idx = ['income', 'Intercept']

class CheckModelResultsMixin:
    def test_params(self):
        assert_allclose(np.ravel(self.res1.params.loc[idx]),
                        self.res2.table[:, 0], rtol=1e-3)

    def test_bse(self):
        assert_equal(self.res1.scale, 1)
        assert_allclose(np.ravel(self.res1.bse.loc[idx]),
                        self.res2.table[:, 1], rtol=1e-3)

    def test_tvalues(self):
        assert_allclose(np.ravel(self.res1.tvalues.loc[idx]),
                        self.res2.table[:, 2], rtol=1e-2)

    def test_pvalues(self):
        pvals_stata = scipy.stats.t.sf(self.res2.table[:, 2], self.res2.df_r)
        assert_allclose(np.ravel(self.res1.pvalues.loc[idx]),
                        pvals_stata, rtol=1.1)

        # test that we use the t distribution for the p-values
        pvals_t = scipy.stats.t.sf(self.res1.tvalues, self.res2.df_r) * 2
        assert_allclose(np.ravel(self.res1.pvalues),
                        pvals_t, rtol=1e-9, atol=1e-10)

    def test_conf_int(self):
        assert_allclose(self.res1.conf_int().loc[idx],
                        self.res2.table[:, -2:], rtol=1e-3)

    def test_nobs(self):
        assert_allclose(self.res1.nobs, self.res2.N, rtol=1e-3)

    def test_df_model(self):
        assert_allclose(self.res1.df_model, self.res2.df_m, rtol=1e-3)

    def test_df_resid(self):
        assert_allclose(self.res1.df_resid, self.res2.df_r, rtol=1e-3)

    def test_prsquared(self):
        assert_allclose(self.res1.prsquared, self.res2.psrsquared, rtol=1e-3)

    def test_sparsity(self):
        assert_allclose(np.array(self.res1.sparsity),
                        self.res2.sparsity, rtol=1e-3)

    def test_bandwidth(self):
        assert_allclose(np.array(self.res1.bandwidth),
                        self.res2.kbwidth, rtol=1e-3)

d = {('biw', 'bofinger'): biweight_bofinger,
     ('biw', 'chamberlain'): biweight_chamberlain,
     ('biw', 'hsheather'): biweight_hsheather,
     ('cos', 'bofinger'): cosine_bofinger,
     ('cos', 'chamberlain'): cosine_chamberlain,
     ('cos', 'hsheather'): cosine_hsheather,
     ('gau', 'bofinger'): gaussian_bofinger,
     ('gau', 'chamberlain'): gaussian_chamberlain,
     ('gau', 'hsheather'): gaussian_hsheather,
     ('par', 'bofinger'): parzen_bofinger,
     ('par', 'chamberlain'): parzen_chamberlain,
     ('par', 'hsheather'): parzen_hsheather,
     # ('rec','bofinger'): rectangle_bofinger,
     # ('rec','chamberlain'): rectangle_chamberlain,
     # ('rec','hsheather'): rectangle_hsheather,
     # ('tri','bofinger'): triangle_bofinger,
     # ('tri','chamberlain'): triangle_chamberlain,
     # ('tri','hsheather'): triangle_hsheather,
     ('epa', 'bofinger'): epan2_bofinger,
     ('epa', 'chamberlain'): epan2_chamberlain,
     ('epa', 'hsheather'): epan2_hsheather
     # ('epa2', 'bofinger'): epan2_bofinger,
     # ('epa2', 'chamberlain'): epan2_chamberlain,
     # ('epa2', 'hsheather'): epan2_hsheather
     }

def setup_fun(kernel='gau', bandwidth='bofinger'):
    data = sm.datasets.engel.load_pandas().data
    y, X = dmatrices('foodexp ~ income', data, return_type='dataframe')
    statsm = QuantReg(y, X).fit(vcov='iid', kernel=kernel, bandwidth=bandwidth)
    stata = d[(kernel, bandwidth)]
    return statsm, stata

def test_fitted_residuals():
    data = sm.datasets.engel.load_pandas().data
    y, X = dmatrices('foodexp ~ income', data, return_type='dataframe')
    res = QuantReg(y, X).fit(q=.1)
    # Note: maxabs relative error with fitted is 1.789e-09
    assert_almost_equal(np.array(res.fittedvalues), Rquantreg.fittedvalues, 5)
    assert_almost_equal(np.array(res.predict()), Rquantreg.fittedvalues, 5)
    assert_almost_equal(np.array(res.resid), Rquantreg.residuals, 5)

class TestEpanechnikovHsheatherQ75(CheckModelResultsMixin):
    # Vincent Arel-Bundock also spot-checked q=.1
    @classmethod
    def setup_class(cls):
        data = sm.datasets.engel.load_pandas().data
        y, X = dmatrices('foodexp ~ income', data, return_type='dataframe')
        cls.res1 = QuantReg(y, X).fit(q=.75, vcov='iid', kernel='epa',
                                      bandwidth='hsheather')
        cls.res2 = epanechnikov_hsheather_q75

class TestEpanechnikovBofinger(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('epa', 'bofinger')

class TestEpanechnikovChamberlain(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('epa', 'chamberlain')

class TestEpanechnikovHsheather(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('epa', 'hsheather')

class TestGaussianBofinger(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('gau', 'bofinger')

class TestGaussianChamberlain(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('gau', 'chamberlain')

class TestGaussianHsheather(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('gau', 'hsheather')

class TestBiweightBofinger(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('biw', 'bofinger')

class TestBiweightChamberlain(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('biw', 'chamberlain')

class TestBiweightHsheather(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('biw', 'hsheather')

class TestCosineBofinger(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('cos', 'bofinger')

class TestCosineChamberlain(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('cos', 'chamberlain')

class TestCosineHsheather(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('cos', 'hsheather')

class TestParzeneBofinger(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('par', 'bofinger')

class TestParzeneChamberlain(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('par', 'chamberlain')

class TestParzeneHsheather(CheckModelResultsMixin):
    @classmethod
    def setup_class(cls):
        cls.res1, cls.res2 = setup_fun('par', 'hsheather')

# class TestTriangleBofinger(CheckModelResultsMixin):
#    @classmethod
#    def setup_class(cls):
#        cls.res1, cls.res2 = setup_fun('tri', 'bofinger')

# class TestTriangleChamberlain(CheckModelResultsMixin):
#    @classmethod
#    def setup_class(cls):
#        cls.res1, cls.res2 = setup_fun('tri', 'chamberlain')

# class TestTriangleHsheather(CheckModelResultsMixin):
#    @classmethod
#    def setup_class(cls):
#        cls.res1, cls.res2 = setup_fun('tri', 'hsheather')

def test_zero_resid():
    # smoke and regression tests

    X = np.array([[1, 0], [0, 1], [0, 2.1], [0, 3.1]], dtype=np.float64)
    y = np.array([0, 1, 2, 3], dtype=np.float64)

    res = QuantReg(y, X).fit(0.5, bandwidth='chamberlain')  # 'bofinger')
    res.summary()

    assert_allclose(res.params,
                    np.array([0.0, 0.96774163]),
                    rtol=1e-4, atol=1e-20)
    assert_allclose(res.bse,
                    np.array([0.0447576, 0.01154867]),
                    rtol=1e-4, atol=1e-20)
    assert_allclose(res.resid,
                    np.array([0.0, 3.22583680e-02,
                              -3.22574272e-02, 9.40732912e-07]),
                    rtol=1e-4, atol=1e-20)

    X = np.array([[1, 0], [0.1, 1], [0, 2.1], [0, 3.1]], dtype=np.float64)
    y = np.array([0, 1, 2, 3], dtype=np.float64)

    res = QuantReg(y, X).fit(0.5, bandwidth='chamberlain')
    res.summary()

    assert_allclose(res.params, np.array([9.99982796e-08, 9.67741630e-01]),
                    rtol=1e-4, atol=1e-20)
    assert_allclose(res.bse, np.array([0.04455029, 0.01155251]), rtol=1e-4,
                    atol=1e-20)
    assert_allclose(res.resid, np.array([-9.99982796e-08, 3.22583598e-02,
                                         -3.22574234e-02, 9.46361860e-07]),
                    rtol=1e-4, atol=1e-20)

def test_use_t_summary():
    X = np.array([[1, 0], [0, 1], [0, 2.1], [0, 3.1]], dtype=np.float64)
    y = np.array([0, 1, 2, 3], dtype=np.float64)

    res = QuantReg(y, X).fit(0.5, bandwidth='chamberlain', use_t=True)
    summ = res.summary()
    assert 'P>|t|' in str(summ)
    assert 'P>|z|' not in str(summ)

def test_alpha_summary():
    X = np.array([[1, 0], [0, 1], [0, 2.1], [0, 3.1]], dtype=np.float64)
    y = np.array([0, 1, 2, 3], dtype=np.float64)

    res = QuantReg(y, X).fit(0.5, bandwidth='chamberlain', use_t=True)
    summ_20 = res.summary(alpha=.2)
    assert '[0.025      0.975]' not in str(summ_20)
    assert '[0.1        0.9]' in str(summ_20)

def test_remove_data():
    X = np.array([[1, 0], [0, 1], [0, 2.1], [0, 3.1]], dtype=np.float64)
    y = np.array([0, 1, 2, 3], dtype=np.float64)

    res = QuantReg(y, X).fit(0.5)
    res.remove_data()

def test_collinear_matrix():
    X = np.array([[1, 0, .5], [1, 0, .8],
                  [1, 0, 1.5], [1, 0, .25]], dtype=np.float64)
    y = np.array([0, 1, 2, 3], dtype=np.float64)

    res_collinear = QuantReg(y, X).fit(0.5)
    assert len(res_collinear.params) == X.shape[1]

def test_nontrivial_singular_matrix():
    x_one = np.random.random(1000)
    x_two = np.random.random(1000)*10
    x_three = np.random.random(1000)
    intercept = np.ones(1000)

    y = np.random.random(1000)*5
    X = np.column_stack((intercept, x_one, x_two, x_three, x_one))

    assert np.linalg.matrix_rank(X) < X.shape[1]
    res_singular = QuantReg(y, X).fit(0.5)
    assert len(res_singular.params) == X.shape[1]
    assert np.linalg.matrix_rank(res_singular.cov_params()) == X.shape[1] - 1

    # prediction is correct even with singular exog
    res_ns = QuantReg(y, X[:, :-1]).fit(0.5)
    assert_allclose(res_singular.fittedvalues, res_ns.fittedvalues, rtol=0.01)


from . import constants, fluiderror, utility

class FluidSynth():
    ''' Represents the FluidSynth synth object as defined in synth.h.

    This class is inspired by the FluidSynth object from pyfluidsynth by MostAwesomeDude. Method
    documentation is mostly taken from FluidSynth's official API.

    Member:
    handle -- The handle to the FluidSynth library. Should be FluidHandle but a raw handle will
              probably work, too (FluidHandle).
    settings -- The settings object (FluidSettings).
    synth -- The FluidSynth synth object (fluid_synth_t).
    _sf_dict -- Dictionary of soundfonts (dict).
    '''

    def __init__( self, handle, settings ):
        ''' Creates a new FluidSynth synth instance using the given handle and settings. '''
        self.handle = handle
        self.settings = settings
        self.synth = self.handle.new_fluid_synth( self.settings.settings )
        self._sf_dict = {}

    def __del__( self ):
        ''' Removes all soundfonts and deletes synth instance. '''
        failed = []
        for sf in self._sf_dict:
            result = self.handle.fluid_synth_sfunload( self.synth, self._sf_dict[sf], True )
            if result is constants.FAILED:
                failed.append(sf)
        self.handle.delete_fluid_synth( self.synth )

        if failed:
            raise fluiderror.FluidError( "Couldn't unload soundfonts: {0}".format(failed) )

    def load_soundfont( self, sf, reload_presets = True ):
        ''' Load soundfont. If reload presets is true FluidSynth will reassign all MIDI channels. '''
        sf_raw = sf
        sf = utility.fluidstring( sf )

        if sf in self._sf_dict:
            result = self.handle.fluid_synth_sfreload( self.synth, self._sf_dict[sf] )
            if result is constants.FAILED:
                raise fluiderror.FluidError( "Couldn't reload soundfont {0}".format(sf_raw) )

        else:
            result = self.handle.fluid_synth_sfload( self.synth, sf, reload_presets )
            if result is constants.FAILED:
                raise fluiderror.FluidError( "Couldn't load soundfont {0}".format(sf_raw) )
            else:
                self._sf_dict[sf_raw] = result

    def unload_soundfont( self, sf, reload_presets = True ):
        ''' Unload soundfont. If reload presets is true FluidSynth will reassign all midi channels. '''
        sf_raw = sf
        sf = utility.fluidstring( sf )

        if sf not in self._sf_dict:
            raise fluiderror.FluidError( "Soundfont {0} never loaded".format(sf_raw) )

        result = self.handle.fluid_synth_sfunload( self.synth, self._sf_dict[sf], reload_presets )
        if result is constants.FAILED:
            raise fluiderror.FluidError( "Couldn't unload soundfont %s".format(sf_raw) )
        else:
            del self._sf_dict[sf_raw]

    def noteon( self, channel, pitch, velocity ):
        ''' Send a note-on event to a FluidSynth object. Returns true in case of success else
        false. '''
        if isinstance( velocity, float ):
            velocity = int( velocity * 127 )
        result = self.handle.fluid_synth_noteon( self.synth, channel, pitch, velocity )
        return result == constants.OK

    def noteoff( self, channel, pitch ):
        ''' Send a note-off event to a FluidSynth object. Returns true in case of success else
        false. '''
        result = self.handle.fluid_synth_noteoff( self.synth, channel, pitch )
        return result == constants.OK

    def cc( self, channel, control, value ):
        ''' Send a MIDI controller event on a MIDI channel. An alias method "constrol_change"
        exists. Returns true in case of success else false. '''
        result = self.handle.fluid_synth_cc( self.synth, channel, control, value )
        return result == constants.OK

    control_change = cc

    def pitch_bend( self, channel, value ):
        ''' Set the MIDI pitch bend controller value on a MIDI channel. Returns true in case of
        success else false. '''
        result = self.handle.fluid_synth_pitch_bend( self.synth, channel, value )
        return result == constants.OK

    def pitch_wheel_sens( self, channel, value ):
        ''' Set MIDI pitch wheel sensitivity on a MIDI channel. An alias method
        "pitch_wheel_sensitivity" exists. Returns true in case of success else false. '''
        result = self.handle.fluid_synth_pitch_wheel_sens( self.synth, channel, value )
        return result == constants.OK

    pitch_wheel_sensitivity = pitch_wheel_sens

    def program_change( self, channel, program ):
        ''' Send a program change event on a MIDI channel. Returns true in case of success else
        false. '''
        result = self.handle.fluid_synth_program_change( self.synth, channel, program )
        return result == constants.OK

    def bank_select( self, channel, bank ):
        ''' Set instrument bank number on a MIDI channel. Returns true in case of success else
        false. '''
        result = self.handle.fluid_synth_bank_select( self.synth, channel, bank )
        return result == constants.OK


import sys
import random
def gen(num_of_records, filename):
    with open(filename,'w') as f:
        for i in range(0,int(num_of_records)):
            x = random.uniform(-100,100)
            y = random.uniform(-100,100)
            f.write("%.2f\t%.2f\n" % (x,y))
    f.close()

if __name__ == "__main__":
    if len(sys.argv) > 2:
        sys.exit(gen(sys.argv[1],sys.argv[2]))
    else:
        print("USAGE: python3 generate.py <number_of_records> <file_name>")


# %%

from matplotlib import tight_layout
import matplotlib.pyplot as plt

from skimage import data, io
from skimage.color import rgb2gray
from skimage.filters import difference_of_gaussians, gaussian

def set_style():
    """set the style of the plots"""
    plt.style.use('fivethirtyeight')
    plt.rcParams['figure.figsize'] = [9.0, 5.0]
    plt.rcParams['figure.dpi'] = 240
    plt.rcParams['axes.linewidth'] = 1.25
    plt.rcParams['savefig.pad_inches'] = 0.2
    plt.rcParams['savefig.bbox'] = 'tight'

set_style()

# %%

image = rgb2gray(data.astronaut())
filtered_image = difference_of_gaussians(image, 1.5)

fig, ax = plt.subplots(1, 2)
ax[0].imshow(image, cmap='gray')
ax[0].title.set_text('Original')
ax[0].axis('off')
ax[1].imshow(filtered_image, cmap='gray')
ax[1].title.set_text('Difference of Gaussians')
ax[1].axis('off')

fig.savefig('dog-example.png')

# %%

img1 = rgb2gray(io.imread('data/norwich_cathedral.png')[:, :, :3])

# %%

fig, axs = plt.subplots(2, 4, tight_layout=True)
for i, ax in enumerate(axs.flat):
    if i == 0:
        im, title = img1, 'original'
    else:
        sigma = 2**(i-1)
        title = fr'$\sigma$ = {sigma}'
        im = gaussian(img1, sigma=sigma)
    ax.imshow(im, cmap='gray')
    ax.set_title(title, fontsize=12)
    ax.axis('off')

fig.savefig('scale-space.png')

# %%


# Given an integer x, return true if x is a  palindrome, and false otherwise.

# Example 1:

# Input: x = 121
# Output: true
# Explanation: 121 reads as 121 from left to right and from right to left.
# Example 2:

# Input: x = -121
# Output: false
# Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.

x = 1001
def check(x):
    if x <0:
        return False
    string = str(x)
    mid = int(len(string)/2)
    if len(string)%2 == 0:
        mid2 = mid
    else:
        mid2 = mid+1
    return ''.join(list(reversed(string[:mid]))) == string[mid2:]
check(x)#should return true


# Lisa Brown
# Jan 2023
# Code to DrawContours from label image onto raw image
# and Perform Geometric Interpolation:
#   start with label image (anisotropic)
#   create new label image at higher resolution (isotropic)

import os
import cv2
import numpy as np
import tifffile as tiff
import copy
import math
#import h5py
import argparse

def DrawContourForLabel(label_im,im,ilabel,icolor):
    nslices,h,w = label_im.shape
    for islice in range(1,nslices):
        mask_indices = np.where(label_im[islice,:,:] == ilabel)
        #print(mask_indices[0].shape)
        this_mask_slice = np.zeros([h,w],dtype=np.uint8)
        this_mask_slice[mask_indices] = 255
        ret, thresh = cv2.threshold(this_mask_slice, 1, 255, 0, cv2.THRESH_BINARY)
        threshcopy = thresh.copy()
        contours, hierarchy = cv2.findContours(threshcopy, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        #if (len(contours) > 0):
        #    print('number of contours ',len(contours)) # draw on image slice
        im[islice,:] = cv2.drawContours(im[islice,:], contours, -1, icolor, 3)
    return im

# one tube per label - just gives you the mask index
# from mask index - for each slice we need the mask..
# from mask - get points on border for two slices
# then interpolate to get masks for slices in between
# create tubes with new slice between each slice based on interpolating
def InterpolateTubes(label_img,upscale_factor):
    d,h,w = label_img.shape
    new_label_img = np.zeros([d*upscale_factor,h,w],dtype=np.uint8)
    unique_labels = np.unique(label_img)
    #print('unique labels ',unique_labels)
    for ilabel in unique_labels:  # for each tube
        if (ilabel != 0):
            ind = np.where(label_img == ilabel)
            minSlice = np.min(ind[0])
            # maybe we should get first larger 67slice with no pixels
            maxSlice = np.max(ind[0]) # this imyplies there are pixels in this slice (not in an inbetween slice ?)
            #print('ilabel min/max slice ',ilabel,minSlice,maxSlice)
            for islice in range(minSlice+1, maxSlice):
                # first slice with no pixels
                imask = np.where(label_img[islice, :, :] == ilabel)
                #print(islice,len(imask[0]))
                if (len(imask[0]) < 1):
                    maxSlice = islice
                    #print('new max slice ',maxSlice)
                    continue
            for islice in range(minSlice+1, maxSlice):
                imask1 = np.where(label_img[islice,:,:] == ilabel)
                imask2 = np.where(label_img[islice+1,:,:] == ilabel)
                #print('islice ',islice)
                nAngles = 100 # should be 100
                #print('len msk1 and msk2 ', len(imask1[0]), len(imask2[0]))
                if (len(imask1[0]) < 1):
                    pts1 = []
                else:
                    pts1 = GetMaskContourPointsForInterpolation(imask1,nAngles,ilabel,islice,h,w,label_img)
                if (len(imask2[0]) < 1):
                    pts2 = []
                    #print('returning imask2 no pixels',islice)
                    #continue
                    #return new_label_img
                else:
                    pts2 = GetMaskContourPointsForInterpolation(imask2,nAngles,ilabel,islice+1,h,w,label_img)
                    #print('len pts1 and pts2 ',len(pts1),len(pts2))
                    nNewSlices = upscale_factor
                    new_label_img = InterpolatePoints(pts1,pts2,nNewSlices,islice*nNewSlices, ilabel, new_label_img)
    return new_label_img

# nNewSlice is the upscale factor
# iStartSlice is the current slice we are expanding to
# p1 are the points from mask in below slice
# p2 are the points from mask in the above slice
def InterpolatePoints(p1,p2,nNewSlices,iStartSlice, label, label_img):
    #print('Interpolating Points')
    n = len(p1)
    h = label_img.shape[1]
    w = label_img.shape[2]
    #print('w,h ',w,h)

    for j in range(0,nNewSlices+1): # for each of the new slices
        mask_slice=np.zeros((w,h),dtype=np.uint8)
        newpts = np.zeros((n, 2), dtype=np.int32)
        for i in range(n): # interpolate each of n points
            y1 = p1[i,0]
            y2 = p2[i,0]
            x1 = p1[i,1]
            x2 = p2[i,1]
            sf1 = j/nNewSlices
            sf2 = (nNewSlices - j)/nNewSlices
            #print(j,i,sf1,sf2)
            newpts[i,1] = int ( y1*sf2 + y2*sf1 )
            newpts[i,0] = int ( x1*sf2 + x2*sf1 )
        # now put the contour in the label_img on the appropriate slice
        #print('newpts ',newpts)
        contours = [newpts]
        #print('contours ',contours)

        color = (255,255,255)
        mask_slice = cv2.drawContours(mask_slice, contours, -1, color, -1)
        #mask_slice =  cv2.cvtColor(mask_slice, cv2.COLOR_BGR2GRAY)
        mask_indices = np.nonzero(mask_slice)
        count = np.count_nonzero(mask_slice)
        #print('count for label for slice ',count,label,iStartSlice + j)
        this_slice = label_img[iStartSlice + j,:]
        this_slice[mask_indices] = label

    return label_img

# get N points around contour every 360/N degrees
# imask is now indices (x,y) of points at this label
def GetMaskContourPointsForInterpolation(imask,N,ilabel,islice,h,w,label_img):
    # m1 is mask
    cY = np.mean(imask[0])
    cX = np.mean(imask[1])
    # get the centroid
    #gray_image = cv2.cvtColor(m1, cv2.COLOR_BGR2GRAY)
    #ret, thresh = cv2.threshold(gray_image, 224, 255, 0)
    #M = cv2.moments(thresh)
    m1_centroid = (cY, cX)
    #print('centroid ',cY,cX)
    # for every 360/N degree, find point on contour (from centroid in direction of the theta - last point in region
    Pi = math.pi
    pts = np.zeros([N,2])
    for ipt in range(N):
        angle = (ipt/N) * 2 * Pi
        angle_in_degrees = angle * 180 / Pi
        #print('angle ',angle,angle_in_degrees)
        # line from centroid with angle
        # start at centroid, follow line for this angle until find a point not in mask
        step = .5
        for incr in range(5000):
            testy = int ( incr*step* math.cos(angle) + m1_centroid[0] )
            testx = int ( incr*step* math.sin(angle) + m1_centroid[1] )
            #print(testy,testx)
            #if  (m1[testx,testy,1] == 0):
            if (testy >= h) or (testx >= w) or (testy < 0) or (testx < 0):
                print('bad testy,testx ',testy,testx,incr,m1_centroid, angle_in_degrees)
                exit()
            if (label_img[islice,testy, testx] != ilabel):
                    #print('first point not in mask from centroid at this angle',m1_centroid,testx,testy)
                    pts[ipt,0] = testy
                    pts[ipt,1] = testx
                    break
    #print('incr ',incr,testy,testx)
    return pts


# from data import *
from data_new2 import *
from att_lstm import AttLSTM
import tensorflow as tf
import random
import numpy as np
import os
import sys
import time
import datetime
# tensorboard –logdir=./logs
#
# http://localhost:6006
VOCAB_FILENAME = 'vocab.vocab'
tensorboard_path = './tensorboard'

print("loading input")
input_x, total_label, vocab = data_loader_raw()
save_vocab(VOCAB_FILENAME, vocab)
input = data_loader_last(input_x, total_label, vocab)
input_train = input[:32000]
input_test = input[32000:]
# label_train =
print("loading input complete")

with tf.Graph().as_default():
    sess = tf.Session()
    with sess:

        num_class = 3

        cnn = AttLSTM(50, num_class, len(vocab), 128, 100)

        global_step = tf.Variable(0, name='global_step', trainable=False)
        optimizer = tf.train.AdamOptimizer(1e-3)
        grads_and_vars = optimizer.compute_gradients(cnn.loss)
        train_op = optimizer.apply_gradients(grads_and_vars, global_step=global_step)

        # Keep track of gradient values and sparsity (optional)
        grad_summaries = []
        for g, v in grads_and_vars:
            if g is not None:
                grad_hist_summary = tf.summary.histogram("{}/grad/hist".format(v.name), g)
                sparsity_summary = tf.summary.scalar("{}/grad/sparsity".format(v.name), tf.nn.zero_fraction(g))
                # grad_summaries.append(grad_hist_summary)
                grad_summaries.append(sparsity_summary)
        grad_summaries_merged = tf.summary.merge(grad_summaries)

        # Output directory for models and summaries
        timestamp = str(int(time.time()))
        out_dir = os.path.abspath(os.path.join(os.path.curdir, "runs", timestamp))
        print("Writing to {}\n".format(out_dir))

        # Summaries for loss and accuracy
        loss_summary = tf.summary.scalar("loss", cnn.loss)
        acc_summary = tf.summary.scalar("accuracy", cnn.accuracy)

        # Train Summaries
        train_summary_op = tf.summary.merge([loss_summary, acc_summary, grad_summaries_merged])
        train_summary_dir = os.path.join(out_dir, "summaries", "train")
        train_summary_writer = tf.summary.FileWriter(train_summary_dir, sess.graph)

        # Dev summaries
        dev_summary_op = tf.summary.merge([loss_summary, acc_summary])
        dev_summary_dir = os.path.join(out_dir, "summaries", "dev")
        dev_summary_writer = tf.summary.FileWriter(dev_summary_dir, sess.graph)

        # Checkpoint directory. Tensorflow assumes this directory already exists so we need to create it
        checkpoint_dir = os.path.abspath(os.path.join(out_dir, "checkpoints"))
        checkpoint_prefix = os.path.join(checkpoint_dir, "model")
        if not os.path.exists(checkpoint_dir):
            os.makedirs(checkpoint_dir)
        saver = tf.train.Saver(tf.global_variables())

        # Write vocabulary
        # vocab_processor.save(os.path.join(out_dir, "vocab"))

        # Initialize all variables
        sess.run(tf.global_variables_initializer())

        def train_step(x_batch, y_batch, sequence_length):
            """
            A single training step
            """
            feed_dict = {
                cnn.input_x: x_batch,
                cnn.input_y: y_batch,
                cnn.emb_dropout_keep_prob: 0.5,
                cnn.rnn_dropout_keep_prob: 0.5,
                cnn.dropout_keep_prob: 0.5
            }
            _, step, summaries, loss, accuracy = sess.run(
                [train_op, global_step, train_summary_op, cnn.loss, cnn.accuracy],
                feed_dict)
            time_str = datetime.datetime.now().isoformat()
            # print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy))
            train_summary_writer.add_summary(summaries, step)

        def dev_step(x_batch, y_batch, sequence_length, writer=None):
            """
            Evaluates model on a dev set
            """
            feed_dict = {
                cnn.input_x: x_batch,
                cnn.input_y: y_batch,
                cnn.emb_dropout_keep_prob: 1.0,
                cnn.rnn_dropout_keep_prob: 1.0,
                cnn.dropout_keep_prob: 1.0
            }
            step, summaries, loss, accuracy = sess.run(
                [global_step, dev_summary_op, cnn.loss, cnn.accuracy],
                feed_dict)
            time_str = datetime.datetime.now().isoformat()
            if step % 100 == 0:
                print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy))
            if writer:
                writer.add_summary(summaries, step)

        # -----여기서부터 수정

        for i in range(10000):
            try:
                batch = random.sample(input_train, 32)

                x_batch, y_batch, sequence_length = zip(*batch)

                train_step(x_batch, y_batch, sequence_length)
                current_step = tf.train.global_step(sess, global_step)
                # if current_step % 100 == 0:
                batch = random.sample(input_test, 32)
                x_test, y_test, sequence_length = zip(*batch)
                dev_step(x_test, y_test, sequence_length, writer=dev_summary_writer)
                if current_step % 1000 == 0:
                    save_path = saver.save(sess, './textcnn3_last.ckpt')
                    print('model saved : %s' % save_path)

            except:
                print("Unexpected error:", sys.exc_info()[0])
                raise
        # -----------------------
        # Generate batches
        # batches = data_helpers.batch_iter(
        #     list(zip(x_train, y_train)), FLAGS.batch_size, FLAGS.num_epochs)
        # # Training loop. For each batch...
        # for batch in batches:
        #     x_batch, y_batch = zip(*batch)
        #     train_step(x_batch, y_batch)
        #     current_step = tf.train.global_step(sess, global_step)
        #     if current_step % FLAGS.evaluate_every == 0:
        #         print("\nEvaluation:")
                # dev_step(x_dev, y_dev, writer=dev_summary_writer)
        #         print("")
        #     if current_step % FLAGS.checkpoint_every == 0:
        #         path = saver.save(sess, checkpoint_prefix, global_step=current_step)
        #         print("Saved model checkpoint to {}\n".format(path))

# ---------------------------원래꺼
# def train():
#     print("loading input")
#     input_x, total_label, vocab = data_loader_raw()
#     input = data_loader_last(input_x, total_label, vocab)
#     input_train = input[:70]
#     input_test = input[70:100]
#     # label_train =
#     print("loading input complete")
#
#     with tf.Session() as sess:
#
#         # seq_length = np.shape(input[0][0])[0]
#         num_class = 5
#
#         cnn = AttLSTM(50, num_class, len(vocab), 128, 100)
#
#         global_step = tf.Variable(0, name='global_step', trainable=False)
#         optimizer = tf.train.AdamOptimizer(1e-3)
#         grads_and_vars = optimizer.compute_gradients(cnn.loss)
#         train_op = optimizer.apply_gradients(grads_and_vars, global_step=global_step)
#
#         def train_step(x_batch, y_batch, sequence_length):
#             feed_dict = {
#
#                 # cnn.sequence_length: sequence_length,
#                 cnn.input_x: x_batch,
#                 cnn.input_y: y_batch,
#                 cnn.emb_dropout_keep_prob: 0.5,
#                 cnn.rnn_dropout_keep_prob: 0.5,
#                 cnn.dropout_keep_prob: 0.5
#             }
#
#             _, step, loss, accuracy = sess.run([train_op, global_step, cnn.loss, cnn.accuracy], feed_dict)
#
#         def evaluate(x_batch, y_batch, sequence_length):
#             feed_dict = {
#
#                 # cnn.sequence_length: sequence_length,
#                 cnn.input_x: x_batch,
#                 cnn.input_y: y_batch,
#                 cnn.emb_dropout_keep_prob: 1.0,
#                 cnn.rnn_dropout_keep_prob: 1.0,
#                 cnn.dropout_keep_prob: 1.0
#             }
#
#             step, loss, accuracy = sess.run([global_step, cnn.loss, cnn.accuracy], feed_dict)
#
#             print("step %d, loss %f, acc %f" % (step, loss, accuracy))
#             # print(len(box))
#             # print(box)
#
#         saver = tf.train.Saver()
#         sess.run(tf.global_variables_initializer())
#
#         for i in range(10):
#             try:
#                 batch = random.sample(input_train, 3)
#
#                 x_batch, y_batch, sequence_length = zip(*batch)
#
#                 train_step(x_batch, y_batch, sequence_length)
#                 current_step = tf.train.global_step(sess, global_step)
#                 if current_step % 10 == 0:
#                     batch = random.sample(input_test, 3)
#                     x_test, y_test, sequence_length = zip(*batch)
#                     evaluate(x_test, y_test, sequence_length)
#                 if current_step % 10 == 0:
#                     save_path = saver.save(sess, './textcnn.ckpt')
#                     print('model saved : %s' % save_path)
#
#
#             except:
#                 print("Unexpected error:", sys.exc_info()[0])
#                 raise
#
#
# if __name__ == '__main__':
#     train()


class Solution:
    def leastInterval(self, tasks: List[str], n: int) -> int:
        tempset = set(tasks)
        max_count = 0
        max_cmd = ''
        if n == 0:
            return len(tasks)
        while len(tempset) > 0:
            cmd = tempset.pop()
            temp = list(filter(lambda a: a != cmd, tasks))
            if len(tasks) - len(temp) > max_count:
                max_count = len(tasks) - len(temp)
                max_cmd = cmd

        return (max_count + (max_count -1 ) * n) + (len(list(filter(lambda a: a != max_cmd, tasks))) - (max_count - 1))


import sys

def flatten(str):
    # return "".join(str.split())
    new_str = ""
    in_string = False
    in_comment = False
    opening_quote = ''
    for char in str:
        if char == '#' and not in_string:
            in_comment = not in_comment
            continue
        if in_comment:
            continue
        if in_string or not char.isspace():
            new_str += char
            if char in '"\'':
                if in_string:
                    if opening_quote == char:
                        in_string = False
                        opening_quote = ''
                else:
                    in_string = True
                    opening_quote = char
    return new_str

def main():
    if len(sys.argv) <= 1:
        print("Unspecified file")
        return

    file_path = sys.argv[1]
    output_file_path = sys.argv[2] if len(sys.argv) > 2 else file_path
    file_contents = ""
    with open(file_path) as file:
        file_contents = file.read()

    file_contents = flatten(file_contents)
    with open(output_file_path, 'w') as file:
        file.write(file_contents)

main()


#!/usr/bin/python3
""" """
from models.base_model import BaseModel
import unittest
import datetime
from uuid import UUID
import json
import os

class test_basemodel(unittest.TestCase):
    """testing for basemodel"""

    def __init__(self, *args, **kwargs):
        """initializing basemodel tests"""
        super().__init__(*args, **kwargs)
        self.name = 'BaseModel'
        self.value = BaseModel

    def setUp(self):
        """nothing to setup"""
        pass

    def tearDown(self):
        """remove file after each test"""
        try:
            os.remove('file.json')
        except Exception:
            pass

    def test_default(self):
        """test class exits"""
        i = self.value()
        self.assertEqual(type(i), self.value)

    def test_kwargs(self):
        """testing object is different from class"""
        i = self.value()
        copy = i.to_dict()
        new = BaseModel(**copy)
        self.assertFalse(new is i)

    def test_kwargs_int(self):
        """testing creation of object with int key value pairs"""
        i = self.value()
        copy = i.to_dict()
        copy.update({1: 2})
        with self.assertRaises(TypeError):
            new = BaseModel(**copy)

    def test_save(self):
        """ Testing save """
        i = self.value()
        i.save()
        key = self.name + "." + i.id
        with open('file.json', 'r') as f:
            j = json.load(f)
            self.assertEqual(j[key], i.to_dict())

    def test_str(self):
        """test the string representation"""
        i = self.value()
        self.assertEqual(str(i), '[{}] ({}) {}'.format(self.name, i.id,
                         i.__dict__))

    def test_todict(self):
        """testing the to_dict instance method"""
        i = self.value()
        n = i.to_dict()
        self.assertEqual(i.to_dict(), n)

        model = self.value()
        m_dict = model.to_dict()
        m_dict_keys = {"__class__", "id", "created_at", "updated_at"}
        self.assertIsInstance(m_dict, dict)
        self.assertSetEqual(set(m_dict.keys()), m_dict_keys)
        self.assertIsInstance(m_dict["id"], str)
        self.assertIsInstance(m_dict["created_at"], str)
        self.assertIsInstance(m_dict["updated_at"], str)

        model = self.value()
        model.name = "John"
        model.age = 50
        m_dict = model.to_dict()
        m_dict_keys = {
            "__class__", "id", "created_at", "updated_at", "name", "age"}
        self.assertIsInstance(m_dict, dict)
        self.assertSetEqual(set(m_dict.keys()), m_dict_keys)
        self.assertIsInstance(m_dict["name"], str)
        self.assertIsInstance(m_dict["age"], int)

        with self.assertRaises(TypeError):
            m_dict = model.to_dict("argument")

    def test_kwargs_none(self):
        """testing when kwarg has none key value pairs"""
        n = {None: None}
        with self.assertRaises(TypeError):
            new = self.value(**n)

    def test_kwargs_one(self):
        """testing when kwargs has one key value pair"""
        n = {'name': 'test'}
        new = self.value(**n)
        self.assertEqual(n['name'], new.name)

    def test_id(self):
        """testing the id attribute"""
        new = self.value()
        self.assertEqual(type(new.id), str)

    def test_created_at(self):
        """testing the created_at attribute"""
        new = self.value()
        self.assertEqual(type(new.created_at), datetime.datetime)

    def test_updated_at(self):
        """testing the updated_at attribute"""
        new = self.value()
        self.assertEqual(type(new.updated_at), datetime.datetime)
        n = new.to_dict()
        new = BaseModel(**n)
        self.assertFalse(new.created_at == new.updated_at)


import re
from selenium.webdriver.support.select import Select
from model.contact import Contact

class ContactHelper:

    def __init__(self, app):
        self.app = app

    def create(self, contact):
        wd = self.app.wd
        # init contact creation
        wd.find_element_by_link_text("add new").click()
        # entering contact's form
        self.enter_values(contact)
        # click to the button "Enter"
        wd.find_element_by_xpath("//input[21]").click()
        self.app.return_to_home_page()
        self.contact_cache = None

    def delete_first_contact(self):
        self.delete_contact_by_index(0)

    def delete_contact_by_index(self, index):
        wd = self.app.wd
        self.app.return_to_home_page()
        # selecting first contact
        wd.find_elements_by_name("selected[]")[index].click()
        # click to the button "Delete"
        wd.find_element_by_xpath("//input[@value='Delete']").click()
        # accepting with alert on the window
        wd.switch_to.alert.accept()
        wd.find_element_by_css_selector("div.msgbox")
        self.app.return_to_home_page()
        self.contact_cache = None

    def delete_contact_by_id(self, id):
        wd = self.app.wd
        self.app.return_to_home_page()
        self.select_contact_by_id(id)
        wd.find_element_by_xpath("//input[@value='Delete']").click()
        # accepting with alert on the window
        wd.switch_to.alert.accept()
        wd.find_element_by_css_selector("div.msgbox")
        self.app.return_to_home_page()
        self.contact_cache = None

    def select_contact_by_id(self, id):
        wd = self.app.wd
        wd.find_element_by_css_selector("input[value='{0}']".format(id)).click()

    def modify_first_contact(self):
        self.modify_contact_by_index(0)

    def modify_contact_by_index(self, index, new_contact):
        wd = self.app.wd
        self.app.return_to_home_page()
        # init contact editing
        self.open_contact_by_index_for_edit(index)
        self.enter_values(new_contact)
        wd.find_element_by_name("update").click()
        self.app.return_to_home_page()
        self.contact_cache = None

    def modify_contact_by_id(self, id, new_contact):
        wd = self.app.wd
        self.app.return_to_home_page()
        # init contact editing
        self.open_contact_by_id_for_edit(id)
        self.enter_values(new_contact)
        wd.find_element_by_name("update").click()
        self.app.return_to_home_page()
        self.contact_cache = None

    def add_some_contact_to_some_group(self, contact, group):
        wd = self.app.wd
        self.app.return_to_home_page()
        self.select_contact_by_id(contact.id)
        Select(wd.find_element_by_name("to_group")).select_by_visible_text(group.group_name.strip())
        wd.find_element_by_css_selector("input[name=\"add\"]").click()
        self.app.return_to_home_page()

    def delete_some_contact_from_some_group(self, contact, group):
        wd = self.app.wd
        self.app.return_to_home_page()
        Select(wd.find_element_by_name("group")).select_by_visible_text(group.group_name.strip())
        self.select_contact_by_id(contact.id)
        wd.find_element_by_name("remove").click()
        self.app.return_to_home_page()

    #  функция заполнения полей
    def enter_values(self, contact):
        self.change_field_value("firstname", contact.firstname)
        self.change_field_value("middlename", contact.middlename)
        self.change_field_value("lastname", contact.lastname)
        self.change_field_value("nickname", contact.nickname)
        self.change_field_value("title", contact.title)
        self.change_field_value("company", contact.company)
        self.change_field_value("address", contact.address)
        # entering numbers
        self.change_field_value("home", contact.home_number)
        self.change_field_value("mobile", contact.mobile_number)
        self.change_field_value("work", contact.work_number)
        self.change_field_value("fax", contact.fax)
        # entering emails and homepage
        self.change_field_value("email", contact.email)
        self.change_field_value("email2", contact.email2)
        self.change_field_value("email3", contact.email3)
        self.change_field_value("homepage", contact.homepage)
        # entering data fields
        self.change_data_field_value("bday", contact.bday)
        self.change_data_field_value("bmonth", contact.bmonth)
        self.change_field_value("byear", contact.byear)
        self.change_data_field_value("aday", contact.aday)
        self.change_data_field_value("amonth", contact.amonth)
        self.change_field_value("ayear", contact.ayear)
        # entering secondary block
        self.change_field_value("address2", contact.address2)
        self.change_field_value("phone2", contact.phone2)
        self.change_field_value("notes", contact.notes)

    def change_data_field_value(self, field_name, new_value):
        wd = self.app.wd
        # если пришло значение != значению по умолчанию, то меняем значение на новое
        if new_value is not None:
            wd.find_element_by_name(field_name).click()
            Select(wd.find_element_by_name(field_name)).select_by_visible_text(new_value)

    def change_field_value(self, field_name, new_value):
        wd = self.app.wd
        # если пришло значение != значению по умолчанию, то меняем значение на новое
        if new_value is not None:
            wd.find_element_by_name(field_name).click()
            wd.find_element_by_name(field_name).clear()
            wd.find_element_by_name(field_name).send_keys(new_value)

    def count_contacts(self):
        wd = self.app.wd
        self.app.return_to_home_page()
        return len(wd.find_elements_by_name("selected[]"))

    def open_contact_by_index_for_edit(self, index):
        wd = self.app.wd
        # в таблице на главной странице нажимаем на иконку карандаша в 8 столбце
        wd.find_elements_by_css_selector("tr > td:nth-child(8)")[index].click()

    def open_contact_by_id_for_edit(self, id):
        wd = self.app.wd
        for element in wd.find_elements_by_name("entry"):
            contact_id = element.find_element_by_name("selected[]").get_attribute("value")
            if contact_id == id:
                element.find_element_by_css_selector("td:nth-child(8)").click()
                break
        # wd.find_element_by_css_selector("input[value='{0}']".format(id))
        # wd.find_element_by_css_selector("td:nth-child(8)").click()

    def open_contact_by_index_for_view(self, index):
        wd = self.app.wd
        # в таблице на главной странице нажимаем на иконку человечка в 7 столбце
        wd.find_elements_by_css_selector("tr > td:nth-child(7)")[index].click()

    contact_cache = None

    def get_contact_list(self):
        if self.contact_cache is None:
            wd = self.app.wd
            self.app.return_to_home_page()
            self.contact_cache = []
            for element in wd.find_elements_by_name("entry"):
                contact_lastname = element.find_element_by_css_selector("tr > td:nth-child(2)").text
                contact_firstname = element.find_element_by_css_selector("tr > td:nth-child(3)").text
                contact_id = element.find_element_by_name("selected[]").get_attribute("value")
                all_phones = element.find_element_by_css_selector("tr > td:nth-child(6)").text
                all_emails = element.find_element_by_css_selector("tr > td:nth-child(5)").text
                address = element.find_element_by_css_selector("tr > td:nth-child(4)").text
                self.contact_cache += [Contact(contact_id=contact_id, lastname=contact_lastname,
                                               firstname=contact_firstname, address=address, all_phones_from_home_page=all_phones,
                                               all_emails_from_home_page=all_emails)]
        return list(self.contact_cache)  # возвращаем копию этого списка в случае поломки данных

    def get_contact_info_from_edit_page(self, index):
        wd = self.app.wd
        self.app.return_to_home_page()
        self.open_contact_by_index_for_edit(index)
        firstname = wd.find_element_by_name("firstname").get_attribute("value")
        lastname = wd.find_element_by_name("lastname").get_attribute("value")
        middlename = wd.find_element_by_name("middlename").get_attribute("value")
        contact_id = wd.find_element_by_name("id").get_attribute("value")
        home_number = wd.find_element_by_name("home").get_attribute("value")
        work_number = wd.find_element_by_name("work").get_attribute("value")
        mobile_number = wd.find_element_by_name("mobile").get_attribute("value")
        secondary_number = wd.find_element_by_name("phone2").get_attribute("value")
        email = wd.find_element_by_name("email").get_attribute("value")
        email2 = wd.find_element_by_name("email2").get_attribute("value")
        email3 = wd.find_element_by_name("email3").get_attribute("value")
        address = wd.find_element_by_name("address").get_attribute("value")
        return Contact(contact_id=contact_id, firstname=firstname, middlename=middlename,
                       lastname=lastname, home_number=home_number, work_number=work_number,
                       mobile_number=mobile_number, phone2=secondary_number,
                       email=email, email2=email2, email3=email3, address=address)

    def get_contact_info_from_view_page(self, index):
        wd = self.app.wd
        self.app.return_to_home_page()
        self.open_contact_by_index_for_view(index)
        text = wd.find_element_by_id("content").text
        fullname = wd.find_element_by_xpath("//div[@id='content']/b").text
        home_number = self.contact_number_on_view_page('H', text)
        work_number = self.contact_number_on_view_page('W', text)
        mobile_number = self.contact_number_on_view_page('M', text)
        secondary_number = self.contact_number_on_view_page('P', text)
        full_emails = self.get_all_emails_on_view_page(text)
        return Contact(fullname=fullname, home_number=home_number, work_number=work_number,
                       mobile_number=mobile_number, phone2=secondary_number, all_emails_from_view_page=full_emails)

    def contact_number_on_view_page(self, number_template, text):
        wd = self.app.wd
        if re.search("{0}:(.*)".format(number_template), text) is not None:
            number_from_view_page = re.search("{0}: (.*)".format(number_template), text).group(1)
        else:
            number_from_view_page = None
        return number_from_view_page

    def get_all_emails_on_view_page(self, text):
        wd = self.app.wd
        if re.findall("(.*@.+.[ru,com])", text) is not None:
            emails_from_view_page = re.findall("(.*@.+.[ru,com])", text)  # .group(1)
        else:
            emails_from_view_page = None
        return emails_from_view_page


import os
import requests
import time
import json
from dotenv import load_dotenv
from openai import OpenAI
from pathlib import Path

load_dotenv()

# Constants

PROMPT = "You are daily NBA audio recap generator. Given JSON data for a day of NBA games, write a script for a 5 minute podcast summarizing the most interesting things about the day's games. Try to be funny and weird. Give the players (and not the teams) nicknames sometimes. Sometimes insult poor-performing players on the losing team."
MODEL = "gpt-4-1106-preview"
STATS_INFO = 'points = points, min = minutes played, fgm = field goals made, fga = field goals attempted, fgp = field goal percentage, ftm = free throws made, fta = free throws attempted, ftp = free throw percentage, tpm = three pointers made, tpa = three pointers attempted, tpp = three point percentage, offReb = offensive rebounds, defReb = defensive rebounds, totReb = total rebounds, assists = assists, pFouls = personal fouls, steals = steals, turnovers = turnovers, blocks = blocks, plusMinus = plus minus'

DATE="2023-11-17"
NBA_STATS_BASE_URL = "https://api-nba-v1.p.rapidapi.com"

BASE_PATH = str(Path(__file__).parent)

Path(BASE_PATH + '/outputs/stats').mkdir(parents=True, exist_ok=True)
Path(BASE_PATH + '/outputs/scripts').mkdir(parents=True, exist_ok=True)
Path(BASE_PATH + '/outputs/audio').mkdir(parents=True, exist_ok=True)

# Helper functions

def read_local_file(path):
  with open(path, 'r') as file:
    data = file.read().replace('\n', '')
  return data

def write_local_file(path, data):
  with open(path, 'w') as file:
    file.write(data)

def get_nba_data(path, query):
  url = NBA_STATS_BASE_URL + path
  headers = {
    'X-RapidAPI-Host': "api-nba-v1.p.rapidapi.com",
    'x-rapidapi-key': os.getenv('RAPID_API_KEY')
  }
  response = requests.request("GET", url, headers=headers, params=query)
  return response.json()

# Get data

games = get_nba_data('/games', {
  'league': 'standard',
  'date': DATE,
  'season': DATE[:4]
})

write_local_file(BASE_PATH + '/outputs/stats/' + DATE + '_raw.json', json.dumps(games))

gamesSimple = []
for game in games['response']:
  time.sleep(.5)

  stats = get_nba_data('/players/statistics', {
    'game': game['id'],
  })

  write_local_file(BASE_PATH + '/outputs/stats/' + DATE + '_' + str(game['id']) + '_raw.json', json.dumps(stats))

  playerStats = []
  for player in stats['response']:
    playerStats.append({
      'first_name': player['player']['firstname'],
      'last_name': player['player']['lastname'],
      'team': player['team']['name'],
      'position': player['pos'],
      'game_stats': {
        'points': player['points'],
        'minutes': player['min'],
        'fgm': player['fgm'],
        'fga': player['fga'],
        'fgp': player['fgp'],
        'ftm': player['ftm'],
        'fta': player['fta'],
        'ftp': player['ftp'],
        'tpm': player['tpm'],
        'tpa': player['tpa'],
        'tpp': player['tpp'],
        'offReb': player['offReb'],
        'defReb': player['defReb'],
        'totReb': player['totReb'],
        'assists': player['assists'],
        'pFouls': player['pFouls'],
        'steals': player['steals'],
        'turnovers': player['turnovers'],
        'blocks': player['blocks'],
        'plusMinus': player['plusMinus'],
      }
    })

  gamesSimple.append({
    'arena': game['arena']['name'],
    'city': game['arena']['city'] + ', ' + game['arena']['state'],
    'home_team_name': game['teams']['home']['name'],
    'away_team_name': game['teams']['visitors']['name'],
    'home_team_quarter_scores': game['scores']['home']['linescore'],
    'away_team_quarter_scores': game['scores']['visitors']['linescore'],
    'home_team_total_score': game['scores']['home']['points'],
    'away_team_total_score': game['scores']['visitors']['points'],
    'player_stats': playerStats,
  })

write_local_file(BASE_PATH + '/outputs/stats/' + DATE + '_simplified.json', json.dumps(gamesSimple))

# Generate script

client = OpenAI()

response = client.chat.completions.create(
  model=MODEL,
  messages=[
    {"role": "system", "content": PROMPT},
    {"role": "user", "content": "Stats abbreviations: " + STATS_INFO + " Game data: " + json.dumps(gamesSimple)},
  ]
)

script = response.choices[0].message.content

write_local_file(BASE_PATH + '/outputs/scripts/' + DATE + '.txt', script)

# Generate audio

speech_file_path = BASE_PATH + "/outputs/audio/" + DATE + ".mp3"

response = client.audio.speech.create(
  model="tts-1",
  voice="onyx",
  input=script,
)

response.stream_to_file(speech_file_path)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
from unittest.mock import call

import mock
from django.test import TestCase
from elasticsearch_dsl import Search, MultiSearch

from series_tiempo_ar_api.apps.metadata import constants
from series_tiempo_ar_api.apps.metadata.models import CatalogAlias, MetadataConfig
from series_tiempo_ar_api.apps.metadata.queries.query import FieldSearchQuery
from .utils import get_mock_search

SAMPLES_DIR = os.path.join(os.path.dirname(__file__), 'samples')
mock.patch.object = mock.patch.object  # Hack for pylint inspection

class QueryTests(TestCase):

    def test_no_querystring_is_valid(self):
        query = FieldSearchQuery(args={})

        with mock.patch.object(MultiSearch, 'execute', return_value=get_mock_search()):
            result = query.execute()

        self.assertFalse(result.get('errors'))

    def test_bad_limit(self):
        query = FieldSearchQuery(args={'limit': 'invalid'})

        result = query.execute()

        self.assertTrue(result['errors'])

    def test_bad_offset(self):
        query = FieldSearchQuery(args={'start': 'invalid'})

        result = query.execute()

        self.assertTrue(result['errors'])

    def test_bad_sort_by(self):
        query = FieldSearchQuery(args={'sort_by': 'invalid'})

        result = query.execute()

        self.assertTrue(result['errors'])

    def test_bad_sort(self):
        query = FieldSearchQuery(args={'sort': 'invalid'})

        result = query.execute()

        self.assertTrue(result['errors'])

    def test_query_response_size(self):
        query = FieldSearchQuery(args={'q': 'aceite'})

        with mock.patch.object(MultiSearch, 'execute', return_value=get_mock_search()):
            result = query.execute()

        self.assertEqual(len(result['data']), result['count'])

    def test_response_params(self):
        limit = '10'
        offset = '15'
        query = FieldSearchQuery(args={'q': 'aceite',
                                       'limit': limit,
                                       'start': offset})

        with mock.patch.object(MultiSearch, 'execute', return_value=get_mock_search()):
            result = query.execute()

        self.assertEqual(result['limit'], int(limit))
        self.assertEqual(result['start'], int(offset))

    def test_add_filter(self):
        q = FieldSearchQuery(args={'units': 'unit_test'})
        search = q.add_filters(Search(), 'units', 'units').to_dict()

        # Esperado: un filter agregado
        filters = search['query']['bool']['filter']
        self.assertEqual(len(filters), 1)
        self.assertEqual(filters[0]['terms']['units'], ['unit_test'])

    def test_add_filter_no_param(self):
        q = FieldSearchQuery(args={})
        search = Search()
        prev_dict = search.to_dict()
        search = q.add_filters(search, 'units', 'units').to_dict()
        # Esperado: no se modifica la query si no hay parámetros
        self.assertEqual(prev_dict, search)

    def test_enhanced_meta(self):
        q = FieldSearchQuery(args={'q': 'a'})

        mock_search = get_mock_search()
        with mock.patch.object(MultiSearch, 'execute', return_value=get_mock_search()):
            result = q.execute()

        self.assertTrue(result['data'][0]['field']['frequency'], mock_search.periodicity)
        self.assertTrue(result['data'][0]['field']['time_index_start'], mock_search.start_date)
        self.assertTrue(result['data'][0]['field']['time_index_end'], mock_search.end_date)

    def test_catalog_id_filter_with_alias(self):
        alias = CatalogAlias.objects.create(alias='alias_id')
        alias.nodes.create(catalog_id='catalog_1', catalog_url='http://example.com/1', indexable=True)
        alias.nodes.create(catalog_id='catalog_2', catalog_url='http://example.com/2', indexable=True)
        q = FieldSearchQuery(args={'catalog_id': 'alias_id'})

        search = Search()
        filtered_search = q.add_filters(search, 'catalog_id', 'catalog_id')

        filtered_catalogs = filtered_search.to_dict()['query']['bool']['filter'][0]['terms']['catalog_id']
        self.assertEqual(set(filtered_catalogs), {'catalog_1', 'catalog_2'})

    @mock.patch('series_tiempo_ar_api.apps.metadata.queries.query.MultiSearch.execute')
    def test_no_aggregations_if_not_requested(self, execute):
        execute.return_value = [mock.MagicMock()]
        resp = FieldSearchQuery(args={}).execute()

        self.assertNotIn('aggregations', resp)

    def test_min_score(self):
        query = FieldSearchQuery(args={'limit': 0, 'start': 0, 'q': 'hola'})

        search = query.get_search()
        min_score = search.to_dict()['min_score']
        self.assertEqual(min_score, MetadataConfig.get_solo().min_score)

    def test_min_score_not_added_without_querystring(self):
        query = FieldSearchQuery(args={'limit': 0, 'start': 0})

        search = query.get_search()
        self.assertNotIn('min_score', search.to_dict())

    def test_sort_by_not_added_if_relevance_specified(self):
        query = FieldSearchQuery(args={'sort_by': 'relevance'})

        search = query.get_search()
        self.assertNotIn('sort', search.to_dict().keys())

    def test_default_sorting_can_not_be_ascending(self):
        query = FieldSearchQuery(args={'sort': 'asc'})

        result = query.execute()

        self.assertTrue(result['errors'])

    def test_descending_sort_by_hits_90_days_with_default_order(self):
        query = FieldSearchQuery(args={'sort_by': 'hits_90_days'})

        search = query.get_search()
        sort_field = search.to_dict()['sort'][0]

        expected_sort_dict = {'hits': {'order': 'desc'}}
        self.assertDictEqual(expected_sort_dict, sort_field)

    def test_ascending_sort_by_hits_90_days_with_specified_order(self):
        query = FieldSearchQuery(args={'sort_by': 'hits_90_days', 'sort': 'asc'})

        search = query.get_search()
        sort_list = search.to_dict()['sort']
        # Como no es el campo _score, no hace falta especificarle un "order" y puede ser un string

        expected_sort_list = ['hits']
        self.assertListEqual(expected_sort_list, sort_list)

    def test_descending_sort_by_frequency_with_default_order(self):
        query = FieldSearchQuery(args={'sort_by': 'frequency'})

        search = query.get_search()
        sort_field = search.to_dict()['sort'][0]

        expected_sort_dict = {'periodicity_index': {'order': 'desc'}}
        self.assertDictEqual(expected_sort_dict, sort_field)

    def test_ascending_sort_by_frequency_with_specified_order(self):
        query = FieldSearchQuery(args={'sort_by': 'frequency', 'sort': 'asc'})

        search = query.get_search()
        sort_list = search.to_dict()['sort']
        # Como no es el campo _score, no hace falta especificarle un "order" y puede ser un string

        expected_sort_list = ['periodicity_index']
        self.assertListEqual(expected_sort_list, sort_list)


from time import time
from .FileManage import FileManage,Boolean
from ..log.Logging import _log
from ..Gtime import get_time

StartTime = get_time()
"""机器人启动时间 str"""

# 配置相关
config = FileManage("./config/config.json", True)
"""机器人配置文件"""
BotUserDict = FileManage("./log/BotUserLog.json")
"""机器人用户信息记录"""
ApiTokenDict = FileManage("./log/ApiToken.json")
"""API token"""
ColorIdDict = FileManage("./log/color_idsave.json")
"""自动上色的信息保存"""
EmojiDict = FileManage("./config/color_emoji.json", True)
"""自动上色 服务器角色配置"""
SponsorDict = FileManage("./log/sponsor_roles.json")
"""感谢助力者 信息保存"""
AfdWebhook = FileManage("./log/AfdWebhook.json")
"""爱发电的wh请求"""

# valorant资源相关
ValErrDict = FileManage("./log/ValErrCode.json")
"""valorant错误码解决办法"""
ValSkinList = FileManage("./log/ValSkin.json")
"""valorant皮肤"""
ValPriceList = FileManage("./log/ValPrice.json")
"""valorant皮肤价格"""
ValBundleList = FileManage("./log/ValBundle.json")
"""valorant皮肤捆绑包"""
ValItersList = FileManage("./log/ValIters.json")
"""valorant皮肤等级"""
ValMissionDict = FileManage("./log/ValMission.json")
"""valorant任务id和名字对照表（收集自用户）"""
ValAgentDict = FileManage("./log/ValAgent.json")
"""valorant英雄相关信息"""

# valorant功能相关
GameIdDict = FileManage("./log/game_idsave.json")
"""玩家游戏id保存"""
SkinRateDict = FileManage("./log/ValSkinRate.json")
"""valorant皮肤评分信息"""
SkinNotifyDict = FileManage("./log/UserSkinNotify.json")
"""皮肤提醒 用户记录"""
UserAuthID = FileManage("./log/UserAuthID.json")
"""用户游戏id/uuid，账户密码重登记录，api/vip登录用户记录"""
UserPwdReauth = UserAuthID['ap_log']
"""riot账户密码重登记录。如果机器人有使用过账户密码进行重登，会在这里记录"""
ApiAuthLog:dict = UserAuthID['api_auth_log']
"""api 缓存用户的riot_user_uuid记录。格式 `account:uuid`"""
VipAuthLog:dict = UserAuthID["vip_auth_log"]
"""vip 已登录用户的记录。格式 `vip_userid:[uuid1,uuid2]`"""

# vip相关
VipUuidDict = FileManage("./log/VipUuid.json")
"""vip uuid文件"""
VipShopBgDict = FileManage("./log/VipUserShopBg.json")
"""vip 背景图设置；商店图缓存"""
VipUser = FileManage("./log/VipUser.json")
"""vip 用户列表/抽奖记录"""
VipUserDict = VipUser['data']
"""vip 用户列表"""
VipRollDcit = VipUser['roll']
"""vip 抽奖记录"""

# 缓存相关
UserAuthCache = {'api':{},'kook':{},'data':{},'acpw':{},'tfa':{}}
"""api/bot 公用EzAuth对象缓存:
- api  | `用户账户:riot_user_uuid`
- kook | `kook_user_id:[uuid1,uuid2]`  值为list,支持多账户登录
- data | `riot_user_uuid:{"auth": EzAuth Obj, "2fa": EzAuth.is2fa}`
- acpw | `riot_user_uuid:{'a':账户,'p':密码}`  用于bot中的账户密码存储。只存储在全局变量中，不写入磁盘
- tfa  | `用户id:EzAuth Obj`  临时使用的缓存
"""
LoginRateLimit = {'limit': False, 'time': time()}
"""全局的速率限制，如果触发了速率限制的err，则阻止所有用户login
- {'limit': False, 'time': time()}
"""
UserShopCache = { 'clear_time':time(),'data':{}}
"""用来存放用户每天的商店（早八会清空）
- { 'clear_time':time(),'data':{}}
"""
UserRtsDict = {}
"""用户皮肤评分rate选择列表"""
UserStsDict = {}
"""用户商店皮肤提醒notify功能选择列表"""
ValItersEmoji = EmojiDict['val_iters_emoji']
"""valorant皮肤等级对应的kook自定义表情。

对应配置文件`./config/color_emoji.json`中的 `val_iters_emoji` 键值
"""

# 实例化一个khl的bot，方便其他模组调用
from khl import Bot,Cert
bot = Bot(token=config['kook']['bot']['token'])  # websocket
"""main bot"""
if not config['kook']['bot']['ws']: # webhook
    _log.info(f"[BOT] using webhook at port {config['kook']['bot']['webhook_port']}")
    bot = Bot(cert=Cert(token=config['kook']['bot']['token'],
                        verify_token=config['kook']['bot']['verify_token'],
                        encrypt_key=config['kook']['bot']['encrypt']),
              port=config['kook']['bot']['webhook_port'])
# 上传图片测试的机器人
bot_upd_img = Bot(token=config['kook']['img_upload_token'])
"""用来上传图片的bot"""
_log.info(f"Loading all files") # 走到这里代表所有文件都打开了