## -*- encoding: latin-1 -*-

from numpy import *
from einsum2 import einsum2
from scipy import optimize
import scipy as sc
import pyfftw
import h5py

### Set U, U', J, J' as in parameters file (reduce module dependency)
def Uval_set(u0, JU_ratio):
    J        = JU_ratio*u0
    u0_prime = u0 - 2*J
    J_prime  = J
    return u0, JU_ratio, u0_prime, J, J_prime

##########################################################################
##### Main code: Calculate Greens function within FLEX approximation #####
##########################################################################

class gfunction_calc:
    """
    Self consistency loop for Greens function, using FLEX approximation
    """
    def __init__(self,p,h,b):
        ##### Tag for convergence check
        self.tag = 'calc'

        ##### Set parameters for U convergence
        u0_delta = 0.01 #change this parameter for U convergence if not working
        conv_it  = 2
        self.u0_pval  = p.u0
        u0_store = -1
        u0_it    = 0

        ##### Set static quantities (unit matrix, Hamiltonian in (iw, k)-space)
        self.set_static_quantities(p,h,b)

        ##### Set initial round (bare quantities)
        ## Initial guess for mu, sigma
        if p.round_it == 0:
            print("G convergence from ZERO.", file=open(p.Logstr,'a'))
            self.mu = h.mu
            self.sigma = zeros((len(b.fm), p.nk, p.nwan, p.nwan))
        else:
            print("G convergence from pre converged G.", file=open(p.Logstr,'a'))
            with h5py.File(p.loadpath,'r') as file:
                self.sigma = file['gfunction/sigma'][()]
                self.mu    = file['gfunction/mu'][()]

        ## Set G(iwn, k), G(tau, r), Chi_0(iwn, k)
        self.set_gkio(p,h,b,self.mu)
        gkio_old = self.gkio
        self.set_grit(p,b)
        self.set_ckit(p,b)

        ##### Self consistency loop
        if p.mode == 'FLEX':
            div_check_param = self.Max_eigval_ChiU(p,h)

            while div_check_param >= 1 or p.u0 != self.u0_pval or u0_it == 0:

                ##### Check for 1-max(chi@U) > 0, otherwise decrease U
                ### ONLY eigval_magnetic >= 1 check included, not charge!
                # Safety check for too long running calculations
                u0_store = p.u0
                u0_it += 1
                if u0_it == 100:
                    print("U iteration reached step 100. Everything okay?", file=open(p.Logstr,'a'))
                    print(p.err_str_begin + "U iteration reached step 100", file=open(p.Logerrstr,'a'))
                if u0_it == 150:
                    print("U iteration reached step 150. It will be stopped!", file=open(p.Logstr,'a'))
                    print(p.err_str_begin + "U iteration reached step 150", file=open(p.Logerrstr,'a'))
                    break

                # If it's not good already after one cycle, reset U
                if p.u0 != self.u0_pval or u0_it > 1:
                    p.u0 = min(self.u0_pval, p.u0*1.5)
                    _, _, p.u0_prime, p.J, p.J_prime = Uval_set(p.u0, p.JU_ratio)
                    h.set_interaction(p)
                    div_check_param = self.Max_eigval_ChiU(p,h)
                    conv_it -= 10
                    conv_it  = max(conv_it, 1)

                ##### Setting new U if max(|chi0*U|) >= 1
                print('### Check for renormalization |chi@U_S|: ' + str(div_check_param) + ', U = ' + str(p.u0), file=open(p.Logstr,'a'))

                ckio_max = amax(linalg.eigh(self.ckio.reshape(len(b.bm),p.nk1,p.nk2,p.nk3,p.nwan**2,p.nwan**2))[0])
                while div_check_param >= 1:
                    while div_check_param/(div_check_param + u0_delta*conv_it)*1/ckio_max - self.u0_pval > 0.01:
                        conv_it += 5
                        #print(conv_it, div_check_param/(div_check_param + u0_delta*conv_it)*1/ckio_max)
                    p.u0 = min(self.u0_pval,\
                        div_check_param/(div_check_param + u0_delta*conv_it)*1/ckio_max)
                    #print(ckio_max, div_check_param/(div_check_param + u0_delta*conv_it)*1/ckio_max)

                    print("New U set to " + str(p.u0), conv_it)
                    if p.u0 == self.u0_pval:
                        conv_it += 1
                    else:
                        _, _, p.u0_prime, p.J, p.J_prime = Uval_set(p.u0, p.JU_ratio)
                        h.set_interaction(p)
                        div_check_param = self.Max_eigval_ChiU(p,h)
                        if div_check_param >=1:
                            conv_it += 1

                print('New U value: ' + str(p.u0) + ', with |chi@U_S|: ' + str(div_check_param), file=open(p.Logstr,'a'))

                # Safety check if U is the same value twice -> some error has occured!
                if p.u0 == u0_store and u0_it != 1:
                    print("Same U value as before!", file=open(p.Logstr,'a'))
                    print(p.err_str_begin + "Same U value reached twice, abbortion! No convergence! (U = "+str(p.u0) +")", file=open(p.Logerrstr,'a'))
                    break

                #--------------------------------------------------------------
                #### Convergence cycle of FLEX self-energy for given U
                # Setting of convergence tolerance and iteration number (U ~= U_in -> oneshot calculation)
                if p.u0 == self.u0_pval:
                    conv_tol   = p.g_sfc_tol
                    sfc_it_max = 150
                    mix        = p.mix
                else:
                    conv_tol   = 8e-2
                    sfc_it_max = 1
                    mix        = p.mix

                # Convergence loop
                print('Convergence round for U = ' + str(p.u0) + \
                      ',|chi@U_S|: ' + str(div_check_param),\
                      file=open(p.Logstr,'a'))
                for it_sfc in range(sfc_it_max):
                    self.sigma_old = self.sigma
                    self.set_V(p,h,b)
                    self.set_sigma(p,b)

                    self.set_mu_from_gkio(p,h,b)
                    self.set_gkio(p,h,b,self.mu)
                    self.symmetrize_gkio(p,b)

                    #Mixing: Change values if needed!
                    if p.u0 != 1:
                        self.gkio = mix*self.gkio + (1-mix)*gkio_old

                    gkio_old = self.gkio
                    self.set_grit(p,b)
                    self.set_ckit(p,b)

                    print(it_sfc, sum(abs(self.sigma_old-self.sigma))/sum(abs(self.sigma)),\
                          file=open(p.Logstr,'a'))
                    if sum(abs(self.sigma_old-self.sigma))/sum(abs(self.sigma)) <= conv_tol:
                        break

        ##### Security convergence check
        ### U convergence
        if p.u0 != self.u0_pval and p.mode == 'FLEX':
            print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nU is not initial input. Stopping gfunction."\
                  , file=open(p.Logstr,'a'))
            print(p.err_str_begin + "U != U_init | gfunction stopped."\
                  , file=open(p.Logerrstr,'a'))
            return

        ### Sigma convergence
        if p.mode == 'FLEX' and sum(abs(self.sigma_old-self.sigma))/sum(abs(self.sigma)) > conv_tol:
            print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nSigma not converged. Stopping gfunction."\
                  , file=open(p.Logstr,'a'))
            print(p.err_str_begin + "Sigma not converged (diff = "\
                  + str(sum(abs(self.sigma_old-self.sigma))/sum(abs(self.sigma)))\
                  + ") | gfunction stopped.", file=open(p.Logerrstr,'a'))
            return

        ### Calculate G function of negative k
        gkio_invk  = self.gkio.reshape(len(b.fm),p.nk1,p.nk2,p.nk3,p.nwan**2)
        fft_object = pyfftw.builders.fftn(gkio_invk,axes=(1,2,3))
        gkio_invk  = fft_object()
        fft_object = pyfftw.builders.fftn(gkio_invk,axes=(1,2,3))
        gkio_invk  = fft_object()/p.nk
        self.gkio_invk = gkio_invk.reshape(len(b.fm),p.nk,p.nwan,p.nwan)
        print("Self consistency loop finished!", file=open(p.Logstr,'a'))

        ### Calculate maximal magnetic/charge eigenvalue
        print("Extract largest BSE kernel values.", file=open(p.Logstr,'a'))
        BSE_max_spin   = self.Max_eigval_ChiU(p,h,'S')
        BSE_max_charge = self.Max_eigval_ChiU(p,h,'C')

        with open(p.BSE_EV_path,"a") as file:
            file.write('{} {} {}\n'.format(p.T, BSE_max_spin, BSE_max_charge))

        print("### Maximal BSE kernel value Chi@U_S = " + str(BSE_max_spin)\
              + " | Chi@U_C = " + str(BSE_max_charge), file=open(p.Logstr,'a'))

        ##### Finished loop, save results
        print("Saving all data now...", file=open(p.Logstr,'a'))

        with h5py.File(p.savepath,'a') as file:
            group = file.require_group('gfunction')

            group.require_dataset('gkio' , data=self.gkio , shape=self.gkio.shape, dtype=complex)
            group.require_dataset('sigma', data=self.sigma, shape=self.sigma.shape, dtype=complex)
            group.require_dataset('mu', data=self.mu, shape=(), dtype=float)

            group.require_dataset('BSE_max_spin'  , data = BSE_max_spin  , shape=(), dtype=float)
            group.require_dataset('BSE_max_charge', data = BSE_max_charge, shape=(), dtype=float)

        print("Done! -> Move to SC calculation.", file=open(p.Logstr,'a'))

    ##############
    # Calculate chemical potential via bisection method from G(k, iw_n).
    ##############

    ### Set from Greens function ----------------------------------------------
    def set_mu_from_gkio(self,p,h,basis):
        pass
        """
        Determining iteration mu from bisection method of 1 + sum(gkio)
        """

        ### Set electron number for bisection difference
        # n_0 is per electron orbital!
        n_0 = p.n_fill
        n = self.calc_electron_density_from_gkio
        f = lambda mu : 2*n(p,h,basis,mu) - n_0

        self.mu = sc.optimize.bisect(f, 50, -50)

    #--------------------------------------------------------------------------
    def calc_electron_density_from_gkio(self,p,h,b,mu):
        self.set_gkio(p,h,b,mu)
        gio = sum(self.gkio,axis=1)/p.nk
        gio = trace(gio,0,1,2)/p.norb #offset=0, axis=1,2

        n = 1 + real(dot(b.fermi_iw_to_tau_0, gio))
        return n

    ##############
    ### Set functions for self consistency loop.
    # set_gkio  : p, b | calculates G(k, iw_n)
    # set_grit  : p, b | calculates G(r, tau) via FFT + irbasis on bosonic tau
    # set_ckit  : p, b | calculates chi_0(k, iv_m) via G(r, tau) and FFT + irbasis
    # set_v     : p, b | calculates V(r, tau) on fermionic tau via chi_0, FFT + irbasis
    # set_sigma : p, b | calculates Sigma(k, iw_n) via V and G
    ##############

    ### Set static quantities
    def set_static_quantities(self, p, h, b):
        self.E_  = tensordot(ones(len(b.fm)), array([eye(h.hk.shape[1],h.hk.shape[2]) for it in range(h.hk.shape[0])]), axes=0)
        self.hk_ = tensordot(ones(len(b.fm)), h.hk, axes=0)
        self.io_ = b.fm.reshape(len(b.fm),1,1,1)*self.E_

        #For calculating V
        self.E_int = tensordot(ones(len(b.bm)), array([eye(p.nwan**2,p.nwan**2) for it in range(p.nk)]), axes=0)

    ### Set G(k, iw_n) --------------------------------------------------------
    def set_gkio(self, p, h, b, mu):
        self.gkio = linalg.inv(self.io_ + mu*self.E_ - self.hk_ - self.sigma)

    def symmetrize_gkio(self,p,b):
        # G(k, iwn) = G^T(-k, iwn)
        gkio_invk = roll(self.gkio.reshape(len(b.fm),p.nk1,p.nk2,p.nwan,p.nwan),-1,axis=(1,2))[:,::-1,::-1]
        gkio_invk = gkio_invk.reshape(len(b.fm),p.nk,p.nwan,p.nwan)
        self.gkio = (self.gkio + transpose(gkio_invk,axes=(0,1,3,2)))/2

    ### Set G(r, tau) ---------------------------------------------------------
    def set_grit(self, p, b):
        if not hasattr(self, 'gkio'): exit("Error_set_grit")
        grit = self.gkio.reshape(len(b.fm), p.nk1, p.nk2, p.nk3, p.nwan**2)

        fft_object = pyfftw.builders.fftn(grit, axes=(1,2,3))
        grit = fft_object()

        grit_0 = grit[:,0,0,0].reshape(len(b.fm),p.nwan**2)
        grit = grit.reshape(len(b.fm),p.nk*p.nwan**2)
        self.grit_b = dot(b.fermi_iw_to_tau_boson, grit).reshape(len(b.bt),p.nk,p.nwan,p.nwan)
        self.grit_f = dot(b.fermi_iw_to_tau,       grit).reshape(len(b.ft),p.nk,p.nwan,p.nwan)
        self.grit_f_0 = - dot(b.fermi_iw_to_tau_0, grit_0).reshape(p.nwan,p.nwan)

    ### Set chi_0(k, iv_m) ----------------------------------------------------
    def set_ckit(self, p, b):
        if not hasattr(self, 'grit_b'): exit("Error_set_ckit")
        grit_rev = self.grit_b[::-1,:,:,:]    #G_lm(r,beta-tau)
        ckio = einsum2('ijkm,ijln->ijklmn', self.grit_b, grit_rev).reshape(len(b.bt),p.nk*p.nwan**4)#km ln

        ckio = dot(b.bose_tau_to_iw, ckio)
        ckio = ckio.reshape(len(b.bm),p.nk1,p.nk2,p.nk3,p.nwan**4)

        fft_object = pyfftw.builders.ifftn(ckio, axes=(1,2,3))
        ckio = fft_object()/p.nk

        self.ckio = ckio.reshape(len(b.bm),p.nk,p.nwan**2,p.nwan**2)

    ### V(r, tau) -------------------------------------------------------------
    def set_V(self,p,h,b):
        if p.nspin == 1 and p.nwan >= 2:
            chi_spin   = linalg.inv(self.E_int - self.ckio@h.S_mat)@self.ckio
            chi_charge = linalg.inv(self.E_int + self.ckio@h.C_mat)@self.ckio

            V = 3./2.* h.S_mat@(chi_spin   - 1/2*self.ckio)@h.S_mat \
              + 1./2.* h.C_mat@(chi_charge - 1/2*self.ckio)@h.C_mat
        else:
            print('No multiorbital system detected! Use different script...'\
                  , file=open(p.Logstr,'a'))

        V = V.reshape(len(b.bm),p.nk1,p.nk2,p.nk3,p.nwan**4)
        fft_object = pyfftw.builders.fftn(V, axes=(1,2,3))
        V = fft_object().reshape(len(b.bm),p.nk*p.nwan**4)

        V      = dot(b.bose_iw_to_tau_fermi, V)
        self.V = V.reshape(len(b.ft),p.nk,p.nwan,p.nwan,p.nwan,p.nwan)

        V_DC = 3./2.*h.S_mat - 1./2.*h.C_mat
        self.V_DC = V_DC.reshape(p.nwan,p.nwan,p.nwan,p.nwan)

    ### Sigma(k, iw_n) --------------------------------------------------------
    def set_sigma(self,p,b):
        sigma = einsum('ijklmn,ijln->ijkm',self.V, self.grit_f)
        sigma = sigma.reshape(len(b.ft),p.nk*p.nwan**2)

        sigma = dot(b.fermi_tau_to_iw, sigma)
        sigma = sigma.reshape(len(b.fm),p.nk1,p.nk2,p.nk3,p.nwan**2)

        fft_object = pyfftw.builders.ifftn(sigma, axes=(1,2,3))
        sigma = fft_object()/p.nk
        self.sigma = sigma.reshape(len(b.fm),p.nk,p.nwan,p.nwan)

        sigma_DC   = einsum2('klmn,ln->km',self.V_DC , self.grit_f_0)*ones((len(b.fm),p.nk,p.nwan,p.nwan))/p.nk
        self.sigma = self.sigma + sigma_DC

    ##############
    # Function for calculating max eig(chi@U_S) for diverging check
    ##############

    def Max_eigval_ChiU(self, p, h, channel='S'):
        '''
        Calculate max{eig(ckio@S_mat)} as a measure for divergence check in chi_spin
        '''
        chan_dic = {'S': h.S_mat, 'C': h.C_mat, 'S_ask' : amax, 'C_ask': amin}

        X = self.ckio@chan_dic[channel]
        X = X.reshape(-1, p.nk1, p.nk2, p.nk3, p.nwan**2, p.nwan**2)
        #X_eig, _ = linalg.eigh(X)
        X_eig = linalg.eigvals(X)
        if abs(imag(chan_dic[channel+'_ask'](X_eig))) > 10**(-10):
                    print("!!!!!!! Imaginary part of chi eig_val is very large !!!!!!",file=open(p.Logstr,'a'))
        X_eig = real(X_eig)
        return chan_dic[channel+'_ask'](X_eig)

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

##############
# Load Greens function if already calculated
##############

class gfunction_load:
    """
    Load already calculated and saved quantities
    """
    def __init__(self,p,b):
        ##### Tag for convergence check
        self.tag = 'load'

        ##### Full G already calculated, load results
        print("Self consistency loop already done. Loading data now...", file=open(p.Logstr,'a'))

        # G(iwn_fermi, k)
        with h5py.File(p.loadpath,'r') as file:
            self.gkio = file['gfunction/gkio'][()]
        print('G(io,k) done', end =" ", file=open(p.Logstr,'a'))

        # G(iwn_fermi, -k)
        gkio_invk  = self.gkio.reshape(len(b.fm),p.nk1,p.nk2,p.nk3,p.nwan**2)
        fft_object = pyfftw.builders.fftn(gkio_invk,axes=(1,2,3))
        gkio_invk  = fft_object()
        fft_object = pyfftw.builders.fftn(gkio_invk,axes=(1,2,3))
        gkio_invk  = fft_object()/p.nk
        self.gkio_invk = gkio_invk.reshape(len(b.fm),p.nk,p.nwan,p.nwan)
        print('| G(io,-k) [calc] done', end =" ", file=open(p.Logstr,'a'))

        # G(tau, r)
        grit = self.gkio.reshape(len(b.fm), p.nk1, p.nk2, p.nk3, p.nwan**2)
        fft_object = pyfftw.builders.fftn(grit, axes=(1,2,3))
        grit = fft_object()
        grit = grit.reshape(len(b.fm),p.nk*p.nwan**2)
        self.grit_b = dot(b.fermi_iw_to_tau_boson, grit).reshape(len(b.bt),p.nk,p.nwan,p.nwan)
        print('| G(tau,r) [calc] done', end =" ", file=open(p.Logstr,'a'))

        # chi_0(iwn_bose, k)
        grit_rev = self.grit_b[::-1,:,:,:]    #G_lm(r,beta-tau)
        ckio = einsum2('ijkm,ijln->ijklmn', self.grit_b, grit_rev).reshape(len(b.bt),p.nk*p.nwan**4)#km ln
        ckio = dot(b.bose_tau_to_iw, ckio)
        ckio = ckio.reshape(len(b.bm),p.nk1,p.nk2,p.nk3,p.nwan**4)
        fft_object = pyfftw.builders.ifftn(ckio, axes=(1,2,3))
        ckio = fft_object()/p.nk
        self.ckio = ckio.reshape(len(b.bm),p.nk,p.nwan**2,p.nwan**2)
        print('| Chi_0(iw,k) [calc] done', file=open(p.Logstr,'a'))

        ##### Interaction identity
        self.E_int = tensordot(ones(self.ckio.shape[0]), array([eye(p.nwan**2,p.nwan**2) for it in range(p.nk)]), axes=0)


import json
import string
from time import sleep

import requests

SEARCH_URL = "https://api.chambers.com/api/search/name"
# ORG_PROFILE_URL = "https://api.chambers.com/api/organisations/23254203/profile-basics"
# ORG_PROVIDED_PROFILES_URL = "https://api.chambers.com/api/organisations/23254203/provided-profiles"
# ORG_DEPARTMENTS_URL = "https://api.chambers.com/api/organisations/23254203/ranked-departments"
# ORG_LAWYERS_URL = "https://api.chambers.com/api/organisations/23254203/ranked-lawyers"

SUPPORTED_GUIDES = ["USA"]

# map Description: Id
GUIDE_INFO = {
    "Global": {"id": 2, "description": "Global"},
    "USA": {"id": 5, "description": "USA"},
    "UK": {"id": 1, "description": "UK"},
    "Latin America": {"id": 9, "description": "Latin America"},
    "Asia-Pacific": {"id": 8, "description": "Asia-Pacific"},
    "Greater China Region": {"id": 116, "description": "Greater China Region"},
    "High Net Worth": {"id": 21, "description": "High Net Worth"},
    "FinTech": {"id": 49, "description": "FinTech"},
}

def index_firms():
    """index all of the firm ids (called organization ids) into a file 'firms.json'

    Only index firms from the currently supported guides,
    and save them based on which guide they belong to.

    Response Format:
    {'count': 19667, 'skip': 0, 'take': 5, 'results': [{'facetedSearchId': 11041, 'rowType': 'Firms', 'organisationName': 'Abell Eskew Landau', 'organisationId': 23254203, 'organisationLocation': 'New York', 'town': 'New York', 'country': 'USA', 'profilePictureUrl': 'https://media.chambers.com/organisations/392522/8b600834-87a5-45f3-8ec9-939c440776bb/profile.png', 'hasPaidProfile': True, 'publicationTypeGroups': [{'id': 5, 'description': 'USA'}]}]} # noqa: E501
    """
    PAGE_SIZE = 2000
    # DATA_FILENAME = "firms.json"
    # supported_guide_ids = [GUIDE_INFO[guide]["id"] for guide in SUPPORTED_GUIDES]
    body = {
        "query": "",
        "skip": 0,
        "take": PAGE_SIZE,
        "guideIds": [],
        "locationIds": [],
        "practiceAreaIds": [],
        "entityTypes": [],
    }

    for letter in string.ascii_lowercase[:4]:
        body["query"] = letter  # 'a'

        count = PAGE_SIZE + 9999  # make count larger than PAGE_SIZE
        skip = 0
        results = []

        # next page
        while skip < count:
            sleep(0.2)  # sleep 0.2 seconds
            response = requests.post(SEARCH_URL, json=body)
            data = response.json()
            results += data["results"]
            count = data["count"]
            skip += PAGE_SIZE
            body["skip"] = skip

        with open("data/aug15-2022/firms.json", "r") as firmsjson:
            firms = json.load(firmsjson)

        firms.extend(results)

        with open("data/aug15-2022/firms.json", "w") as firmsjson:
            json.dump(firms, firmsjson, indent=4)
            print(f"appended the letter {letter}")

        sleep(5)

index_firms()


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

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Code starts here
df = pd.read_csv(path)
df["state"] = df["state"].apply(lambda x: x.lower())
df["total"] = df["Jan"] + df["Feb"] + df["Mar"]
sum_row = df[["Jan", "Feb", "Mar", "total"]].sum()
df_final = df.append(sum_row, ignore_index = True)
print(df_final)

# Code ends here

# --------------
import requests

# Code starts here

url = "https://en.wikipedia.org/wiki/List_of_U.S._state_abbreviations"
response = requests.get(url)

df1 = pd.read_html(response.content)[0]

df1 = df1.iloc[11:, :]

df1 = df1.rename(columns = df1.iloc[0, :]).iloc[1:, :]

df1['United States of America'] = df1['United States of America'].apply(lambda x: x.replace(' ', '')).astype(object)

# Code ends here

# --------------
df1['United States of America'] = df1['United States of America'].astype(str).apply(lambda x: x.lower())
df1['US'] = df1['US'].astype(str)

# Code starts here
mapping = dict(zip(df1['United States of America'], df1['US']))

df_final['abbr'] = df_final.index[6]

df_final['abbr'] = df_final['state'].map(mapping)

# Code ends here

# --------------
# Code stars here

df_final.loc[df_final['state'] == 'mississipi', 'abbr'] = 'MS'
df_final.loc[df_final['state'] == 'tenessee', 'abbr'] = 'TN'

# Code ends here

# --------------
# Code starts here

df_sub = df_final.groupby(['abbr'])[['Jan', 'Feb', 'Mar', 'total']].sum()

formatted_df = df_sub.applymap(lambda x: "$" + str(x))

print(formatted_df)

# Code ends here

# --------------
# Code starts here
sum_row = pd.DataFrame(df_final[['Jan', 'Feb', 'Mar', 'total']].sum())

df_sub_sum = sum_row.transpose()

df_sub_sum = df_sub_sum.applymap(lambda x: "$" + str(x))

final_table = formatted_df.append(df_sub_sum)

print(final_table)

# Code ends here

# --------------
# Code starts here

df_sub['total'] = df_sub['Jan'] + df_sub['Feb'] + df_sub['Mar']
plt.pie(df_sub['total'])

# Code ends here


import threading
import time

# 使用函数的方式创建线程

import threading

# 方法一：
# 在创建线程时必须先定义一个继承threading.Thread的类，然后重写子类中的run()方法，使用start()方法启动线程。
class threadTest(threading.Thread):
    # args为传入线程的参数，可根据自己的需求进行定义
    def __init__(self, args) -> None:
        # 初始化super()内的必须和类名一样
        super(threadTest, self).__init__()
        self.args = args

    # 定义run()方法，主要写线程的执行内容
    def run(self) -> None:
        print('test thread running...')
        print('args: ', self.args)
        return super().run()

def threadTest(arg):
    print("test thread running...")
    print("args: ", arg)

if __name__ == "__main__":
    # target传入函数名，注意不要写参数
    # args target传入的函数需要传入的参数，注意传入参数以元组的形式
    thread = threading.Thread(target=threadTest, args=('just test',))
    # 启动线程
    thread.start()


import os
import pytz
from uuid import uuid4
from datetime import datetime
import cv2
import numpy as np
from keras.preprocessing import image
from keras.applications.imagenet_utils import preprocess_input
from collections import deque
from PIL import Image, ImageFont, ImageDraw

from .ssd_utils import BBoxUtility
from .image_saver import save_image
from .excel_saver import save_excel
from .color_recognition_module.color_classification_image import color_recognition

current_path = os.getcwd()

class Vehicle:

    def __init__(self, location, Type, n_history=50):
        self._type = Type
        self._location = location
        #self._size = size
        self._detected = True
        self._history = deque([], n_history)

    @property
    def types(self):
        return set(['Car', 'Motorbike', 'Bicycle', 'Bus'])

    @property
    def location(self):
        return self._location

    @location.setter
    def location(self, location):
        self._history.append(self._location)
        self._location = location

    def setLocation(self, location):
        self._location = location
        #self._size = size

    def getLocation(self):
        return self._location

class VehicleDetector:
    voc_classes = ['Aeroplane', 'Bicycle', 'Bird', 'Boat', 'Bottle',
                   'Bus', 'Car', 'Cat', 'Chair', 'Cow', 'Diningtable',
                   'Dog', 'Horse', 'Motorbike', 'Person', 'Pottedplant',
                   'Sheep', 'Sofa', 'Train', 'Tvmonitor']

    NUM_CLASSES = len(voc_classes) + 1
    _threshold = 0.5
    no_of_detected_vehicles = 0
    detected_vehicles = deque([])

    def __init__(self, model, n_history=50):
        self._model = model
        self._bbox_util = BBoxUtility(self.NUM_CLASSES)
        VehicleDetector.no_of_detected_vehicles = 0
        VehicleDetector.detected_vehicles = deque([])

    @classmethod
    def draw_boxes(cls, img, results, ROI):
        draw_img = Image.fromarray(img)
        width, height = draw_img.size
        draw = ImageDraw.Draw(draw_img, mode='RGBA')
        font = ImageFont.truetype("font/GillSans.ttc", 18)
        padding = 2

        for i in range(6):
            draw.line([(0, ROI+ i*10 ), (width, ROI+ i*10)], fill='red',width=0)

        # Parse the outputs.
        det_label = results[:, 0]
        det_conf = results[:, 1]
        det_xmin = results[:, 2]
        det_ymin = results[:, 3]
        det_xmax = results[:, 4]
        det_ymax = results[:, 5]

        # Get detections with confidence higher than threshold
        top_indices = [i for i, conf in enumerate(det_conf) if conf >= cls._threshold]

        top_conf = det_conf[top_indices]
        top_label_indices = det_label[top_indices].tolist()
        top_xmin = det_xmin[top_indices]
        top_ymin = det_ymin[top_indices]
        top_xmax = det_xmax[top_indices]
        top_ymax = det_ymax[top_indices]

        top_indices = [i for i, ymax in enumerate(top_ymax) if (int(round(ymax * img.shape[0])) > ROI and int(round(ymax * img.shape[0])) < ROI+50)]
        top_conf = top_conf[top_indices]
        top_label_indices = det_label[top_indices].tolist()
        top_xmin = top_xmin[top_indices]
        top_ymin = top_ymin[top_indices]
        top_xmax = top_xmax[top_indices]
        top_ymax = top_ymax[top_indices]

        colors = {
            'Car': (255, 128, 0),
            'Multi-axle': (0, 0, 255),
            'Motorbike': (128, 0, 255),
            'Bicycle': (255, 0, 128),
            'Person': (255, 0, 0)
        }

        for i in range(top_conf.shape[0]):
            xmin = int(round(top_xmin[i] * img.shape[1]))
            ymin = int(round(top_ymin[i] * img.shape[0]))
            xmax = int(round(top_xmax[i] * img.shape[1]))
            ymax = int(round(top_ymax[i] * img.shape[0]))
            score = top_conf[i]
            label = int(top_label_indices[i])
            label_name = cls.voc_classes[label - 1]
            if label_name == 'Bus' or label_name == 'bus':
                label_name = 'Multi-axle'
            display_text = '{} [{:0.2f}]'.format(label_name, score)
            if label_name in set(('Car', 'Multi-axle', 'Motorbike', 'Bicycle')):
                '''Counting logic starts here'''
                if ymax > ROI and ymax < ROI+50:
                    color = colors[label_name]
                    size = draw.textsize(display_text, font)
                    #_draw_rectangle(draw, (xmin, ymin, xmax, ymax), color)
                    draw.rectangle((xmin, ymin, xmax, ymax), outline=color)
                    _draw_rectangle(draw, (xmin, ymin, xmin + size[0] + 2*padding, ymin - size[1] - 2*padding), None, fill=(*color, 40))
                    draw.text((xmin + padding, ymin - size[1] - padding - 2), display_text, (255, 255, 255), font=font)

                    if ymax > ROI:
                        filename = current_path + '/detection-report.xlsx'
                        vehicle_name = 'vehicle-' + str(uuid4())
                        current_datetime = datetime.now(pytz.timezone('Asia/Kolkata'))

                        if VehicleDetector.no_of_detected_vehicles == 0:
                            VehicleDetector.detected_vehicles.append(Vehicle([xmin, ymin, xmax, ymax], label_name))
                            VehicleDetector.no_of_detected_vehicles += 1
                            save_image(((Image.fromarray(img)).crop((xmin, ymin, xmax, ymax))), vehicle_name)
                            detected_color = color_recognition(cv2.imread(current_path+'/detected_vehicles/'+vehicle_name+'.jpg'))
                            save_excel(detections=[[vehicle_name, label_name, detected_color, current_datetime.year, current_datetime.month, current_datetime.day, current_datetime.hour, current_datetime.minute, current_datetime.second]], file_name=filename)
                        else:
                            old_vehicle = False
                            for vehicle in VehicleDetector.detected_vehicles:
                                # print(f'{ymax} , {vehicle.location[3]}')
                                if abs(ymax - (vehicle.getLocation())[3]) < 10:
                                    vehicle.setLocation([xmin, ymin, xmax, ymax])
                                    #vehicle.accept([xmin, ymin, xmax, ymax])
                                    old_vehicle = True
                                    break
                            if not old_vehicle:
                                if ymax < ROI+20:
                                    VehicleDetector.detected_vehicles.popleft()
                                    VehicleDetector.detected_vehicles.append(Vehicle([xmin, ymin, xmax, ymax], label_name))
                                    VehicleDetector.no_of_detected_vehicles += 1
                                    #print(VehicleDetector.no_of_detected_vehicles)
                                    save_image(((Image.fromarray(img)).crop((xmin, ymin, xmax, ymax))), vehicle_name)
                                    detected_color = color_recognition(cv2.imread(current_path+'/detected_vehicles/'+vehicle_name+'.jpg'))
                                    save_excel(detections=[[vehicle_name, label_name, detected_color, current_datetime.year, current_datetime.month, current_datetime.day, current_datetime.hour, current_datetime.minute, current_datetime.second]], file_name=filename)
                                else:
                                    VehicleDetector.detected_vehicles[-1].location = [xmin, ymin, xmax, ymax]
                            '''Counting logic ends here'''

        # print(len(VehicleDetector.detected_vehicles))
        count_text = 'Count = {}'.format(VehicleDetector.no_of_detected_vehicles)
        size = draw.textsize(count_text, font)
        draw.rectangle((0, 0, size[0] + 2*padding, size[1] + 2*padding), fill=(255, 128, 0))#, 40))
        _draw_rectangle(draw, (0, 0, size[0] + 2*padding, size[1] + 2*padding), None, fill=(255, 128, 0))#, 40))
        draw.text((padding, 0), count_text, (255, 255, 255), font=font)

        return np.asarray(draw_img)

    def detect(self, input_img):
        inputs = []
        img = cv2.resize(input_img, (300, 300))
        img = image.img_to_array(img)
        inputs.append(img.copy())
        inputs = preprocess_input(np.array(inputs))
        inputs = np.expand_dims(inputs[0], axis=0)

        preds = self._model.predict(inputs, batch_size=1, verbose=0)
        results = self._bbox_util.detection_out(preds)

        final_img = self.draw_boxes(input_img, results[0], ROI=200)

        return final_img

    @property
    def pipeline(self):
        def process_frame(input_img):
            return self.detect(input_img)
        return process_frame

def _draw_rectangle(draw, corners, color, fill=None, thickness=3):
    start = -thickness//2
    end = start + thickness
    for i in range(start, end):
        points = [val + i for val in corners]
        draw.rectangle(points, outline=color, fill=fill)


from queue import Queue
class Stack:
    def __init__(self):
        self.q1 = Queue()
        self.q2 = Queue()
        self.count = 0

    def push(self,ele):
        self.q1.put(ele)
        self.count += 1

    def pop(self):
        while(self.q1.qsize() != 1):
            ele1 = self.q1.get()
            self.q2.put(ele1)

        lastEle = self.q1.get()
        self.count -= 1

        while(self.q2.qsize() != 0):
            ele2 = self.q2.get()
            self.q1.put(ele2)

    def top(self):
        while(self.q1.qsize() != 1):
            ele1 = self.q1.get()
            self.q2.put(ele1)

        top = self.q1.queue[0]
        self.q2.put(ele1)

        while(self.q2.qsize() != 0):
            ele2 = self.q2.get()
            self.q1.put(ele2)

        return top

    def size(self):
        return self.count

    def isEmpty(self):
        return self.size() == 0

s = Stack()
n = int(input())
for i in range(1,n+1):
    s.push(i)

while(s.isEmpty() is False):
    print(s.top())
    s.pop()

# qsize - for calculating size of queue(inbuilt)


import asyncio
import concurrent.futures
import json
import logging
import os
import traceback
from contextlib import AsyncExitStack
from typing import Any, Callable, Dict, List, NoReturn, Optional, Set, Tuple, TypedDict

import aiohttp_session  # type: ignore
import kubernetes_asyncio
import kubernetes_asyncio.client
import kubernetes_asyncio.config
import uvloop  # type: ignore
import yaml
from aiohttp import web
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing as gh_routing
from gidgethub import sansio as gh_sansio
from prometheus_async.aio.web import server_stats  # type: ignore

from gear import (
    AuthServiceAuthenticator,
    Database,
    UserData,
    check_csrf_token,
    json_request,
    json_response,
    monitor_endpoints_middleware,
    setup_aiohttp_session,
)
from gear.profiling import install_profiler_if_requested
from hailtop import aiotools, httpx
from hailtop.auth import hail_credentials
from hailtop.batch_client.aioclient import Batch, BatchClient
from hailtop.config import get_deploy_config
from hailtop.hail_logging import AccessLogger
from hailtop.tls import internal_server_ssl_context
from hailtop.utils import collect_aiter, humanize_timedelta_msecs, periodically_call, retry_transient_errors
from web_common import render_template, set_message, setup_aiohttp_jinja2, setup_common_static_routes

from .constants import AUTHORIZED_USERS, TEAMS
from .environment import CLOUD, DEFAULT_NAMESPACE, STORAGE_URI
from .envoy import create_cds_response, create_rds_response
from .github import PR, WIP, FQBranch, MergeFailureBatch, Repo, UnwatchedBranch, WatchedBranch, select_random_teammate
from .utils import gcp_logging_queries

with open(os.environ.get('HAIL_CI_OAUTH_TOKEN', 'oauth-token/oauth-token'), 'r', encoding='utf-8') as f:
    oauth_token = f.read().strip()

log = logging.getLogger('ci')

uvloop.install()

deploy_config = get_deploy_config()

watched_branches: List[WatchedBranch] = []

routes = web.RouteTableDef()

auth = AuthServiceAuthenticator()

class PRConfig(TypedDict):
    number: int
    title: str
    batch_id: Optional[int]
    build_state: Optional[str]
    gh_statuses: Dict[str, str]
    source_branch_name: str
    review_state: Optional[str]
    author: str
    assignees: Set[str]
    reviewers: Set[str]
    labels: Set[str]
    out_of_date: bool

async def pr_config(app, pr: PR) -> PRConfig:
    batch_id = pr.batch.id if pr.batch and isinstance(pr.batch, Batch) else None
    build_state = pr.build_state if await pr.authorized(app['db']) else 'unauthorized'
    if build_state is None and batch_id is not None:
        build_state = 'building'
    return {
        'number': pr.number,
        'title': pr.title,
        # FIXME generate links to the merge log
        'batch_id': batch_id,
        'build_state': build_state,
        'gh_statuses': {k: v.value for k, v in pr.last_known_github_status.items()},
        'source_branch_name': pr.source_branch.name,
        'review_state': pr.review_state,
        'author': pr.author,
        'assignees': pr.assignees,
        'reviewers': pr.reviewers,
        'labels': pr.labels,
        'out_of_date': pr.build_state in ['failure', 'success', None] and not pr.is_up_to_date(),
    }

class WatchedBranchConfig(TypedDict):
    index: int
    branch: str
    sha: Optional[str]
    deploy_batch_id: Optional[int]
    deploy_state: Optional[str]
    repo: str
    prs: List[PRConfig]
    gh_status_names: Set[str]
    merge_candidate: Optional[str]

async def watched_branch_config(app, wb: WatchedBranch, index: int) -> WatchedBranchConfig:
    if wb.prs:
        pr_configs = [await pr_config(app, pr) for pr in wb.prs.values()]
    else:
        pr_configs = []
    # FIXME recent deploy history
    gh_status_names = {k for pr in pr_configs for k in pr['gh_statuses'].keys()}
    return {
        'index': index,
        'branch': wb.branch.short_str(),
        'sha': wb.sha,
        # FIXME generate links to the merge log
        'deploy_batch_id': wb.deploy_batch.id if wb.deploy_batch and isinstance(wb.deploy_batch, Batch) else None,
        'deploy_state': wb.deploy_state,
        'repo': wb.branch.repo.short_str(),
        'prs': pr_configs,
        'gh_status_names': gh_status_names,
        'merge_candidate': wb.merge_candidate.short_str() if wb.merge_candidate else None,
    }

@routes.get('')
@routes.get('/')
@auth.authenticated_developers_only()
async def index(request: web.Request, userdata: UserData) -> web.Response:
    wb_configs = [await watched_branch_config(request.app, wb, i) for i, wb in enumerate(watched_branches)]
    page_context = {'watched_branches': wb_configs, 'frozen_merge_deploy': request.app['frozen_merge_deploy']}
    return await render_template('ci', request, userdata, 'index.html', page_context)

def wb_and_pr_from_request(request: web.Request) -> Tuple[WatchedBranch, PR]:
    watched_branch_index = int(request.match_info['watched_branch_index'])
    pr_number = int(request.match_info['pr_number'])

    if watched_branch_index < 0 or watched_branch_index >= len(watched_branches):
        raise web.HTTPNotFound()
    wb = watched_branches[watched_branch_index]

    if not wb.prs or pr_number not in wb.prs:
        raise web.HTTPNotFound()
    return wb, wb.prs[pr_number]

def filter_jobs(jobs):
    filtered: Dict[str, list] = {
        state: []
        # the order of this list is the order in which the states will be displayed on the page
        for state in ["failed", "error", "cancelled", "running", "pending", "ready", "creating", "success"]
    }
    for job in jobs:
        filtered[job["state"].lower()].append(job)
    return {"jobs": filtered}

@routes.get('/watched_branches/{watched_branch_index}/pr/{pr_number}')
@auth.authenticated_developers_only()
async def get_pr(request: web.Request, userdata: UserData) -> web.Response:
    wb, pr = wb_and_pr_from_request(request)

    page_context: Dict[str, Any] = {}
    page_context['repo'] = wb.branch.repo.short_str()
    page_context['wb'] = wb
    page_context['pr'] = pr
    # FIXME
    batch = pr.batch
    if batch:
        if isinstance(batch, Batch):
            status = await batch.last_known_status()
            jobs = await collect_aiter(batch.jobs())
            for j in jobs:
                j['duration'] = humanize_timedelta_msecs(j['duration'])
            page_context['batch'] = status
            page_context.update(filter_jobs(jobs))
            artifacts_uri = f'{STORAGE_URI}/build/{batch.attributes["token"]}'
            page_context['artifacts_uri'] = artifacts_uri
            page_context['artifacts_url'] = storage_uri_to_url(artifacts_uri)

            if CLOUD == 'gcp':
                start_time = status['time_created']
                end_time = status['time_completed']
                assert start_time is not None
                page_context['logging_queries'] = gcp_logging_queries(
                    batch.attributes['namespace'], start_time, end_time
                )
            else:
                page_context['logging_queries'] = None
        else:
            page_context['exception'] = '\n'.join(
                traceback.format_exception(None, batch.exception, batch.exception.__traceback__)
            )

    batch_client = request.app['batch_client']
    target_branch = wb.branch.short_str()
    batches = batch_client.list_batches(f'test=1 ' f'pr={pr.number} ' f'target_branch={target_branch} ' f'user:ci')
    batches = sorted([b async for b in batches], key=lambda b: b.id, reverse=True)
    page_context['history'] = [await b.last_known_status() for b in batches]

    return await render_template('ci', request, userdata, 'pr.html', page_context)

def storage_uri_to_url(uri: str) -> str:
    if uri.startswith('gs://'):
        path = uri.removeprefix('gs://')
        return f'https://console.cloud.google.com/storage/browser/{path}'
    return uri

async def retry_pr(wb, pr, request):
    app = request.app
    session = await aiohttp_session.get_session(request)

    if pr.batch is None:
        log.info('retry cannot be requested for PR #{pr.number} because it has no batch')
        set_message(session, f'Retry cannot be requested for PR #{pr.number} because it has no batch.', 'error')
        return

    batch_id = pr.batch.id
    db: Database = app['db']
    await db.execute_insertone('INSERT INTO invalidated_batches (batch_id) VALUES (%s);', batch_id)
    await wb.notify_batch_changed(app)

    log.info(f'retry requested for PR: {pr.number}')
    set_message(session, f'Retry requested for PR #{pr.number}.', 'info')

@routes.post('/watched_branches/{watched_branch_index}/pr/{pr_number}/retry')
@auth.authenticated_developers_only(redirect=False)
async def post_retry_pr(request: web.Request, _) -> NoReturn:
    wb, pr = wb_and_pr_from_request(request)

    await asyncio.shield(retry_pr(wb, pr, request))
    raise web.HTTPFound(deploy_config.external_url('ci', f'/watched_branches/{wb.index}/pr/{pr.number}'))

@routes.get('/batches')
@auth.authenticated_developers_only()
async def get_batches(request, userdata):
    batch_client = request.app['batch_client']
    batches = [b async for b in batch_client.list_batches()]
    statuses = [await b.last_known_status() for b in batches]
    page_context = {'batches': statuses}
    return await render_template('ci', request, userdata, 'batches.html', page_context)

@routes.get('/batches/{batch_id}')
@auth.authenticated_developers_only()
async def get_batch(request, userdata):
    batch_id = int(request.match_info['batch_id'])
    batch_client = request.app['batch_client']
    b = await batch_client.get_batch(batch_id)
    status = await b.last_known_status()
    jobs = await collect_aiter(b.jobs())
    for j in jobs:
        j['duration'] = humanize_timedelta_msecs(j['duration'])
    wb = get_maybe_wb_for_batch(b)
    page_context = {'batch': status, 'wb': wb}
    page_context.update(filter_jobs(jobs))
    return await render_template('ci', request, userdata, 'batch.html', page_context)

def get_maybe_wb_for_batch(b: Batch):
    if 'target_branch' in b.attributes and 'pr' in b.attributes:
        branch = b.attributes['target_branch']
        wbs = [wb for wb in watched_branches if wb.branch.short_str() == branch]
        if len(wbs) == 0:
            pr = b.attributes['pr']
            log.exception(f"Attempted to load PR {pr} for unwatched branch {branch}")
        else:
            assert len(wbs) == 1
            return wbs[0].index
    return None

def filter_wbs(wbs: List[WatchedBranchConfig], pred: Callable[[PRConfig], bool]):
    return [{**wb, 'prs': [pr for pr in wb['prs'] if pred(pr)]} for wb in wbs]

def is_pr_author(gh_username: str, pr_config: PRConfig) -> bool:
    return gh_username == pr_config['author']

def is_pr_reviewer(gh_username: str, pr_config: PRConfig) -> bool:
    return gh_username in pr_config['assignees'] or gh_username in pr_config['reviewers']

def pr_requires_action(gh_username: str, pr_config: PRConfig) -> bool:
    build_state = pr_config['build_state']
    review_state = pr_config['review_state']
    return (
        is_pr_author(gh_username, pr_config)
        and (build_state == 'failure' or review_state == 'changes_requested' or WIP in pr_config['labels'])
    ) or (is_pr_reviewer(gh_username, pr_config) and review_state == 'pending')

@routes.get('/me')
@auth.authenticated_developers_only()
async def get_user(request: web.Request, userdata: UserData) -> web.Response:
    for authorized_user in AUTHORIZED_USERS:
        if authorized_user.hail_username == userdata['username']:
            user = authorized_user
            break
    else:
        raise web.HTTPForbidden()

    wbs = [await watched_branch_config(request.app, wb, i) for i, wb in enumerate(watched_branches)]
    pr_wbs = filter_wbs(wbs, lambda pr: is_pr_author(user.gh_username, pr))
    review_wbs = filter_wbs(wbs, lambda pr: is_pr_reviewer(user.gh_username, pr))
    actionable_wbs = filter_wbs(wbs, lambda pr: pr_requires_action(user.gh_username, pr))

    batch_client = request.app['batch_client']
    dev_deploys = batch_client.list_batches(f'user={user.hail_username} dev_deploy=1', limit=10)
    dev_deploys = sorted([b async for b in dev_deploys], key=lambda b: b.id, reverse=True)

    team_random_member = {team: select_random_teammate(team).gh_username for team in TEAMS}

    page_context = {
        'username': user.hail_username,
        'gh_username': user.gh_username,
        'pr_wbs': pr_wbs,
        'review_wbs': review_wbs,
        'actionable_wbs': actionable_wbs,
        'team_member': team_random_member,
        'dev_deploys': [await b.last_known_status() for b in dev_deploys],
    }
    return await render_template('ci', request, userdata, 'user.html', page_context)

@routes.post('/authorize_source_sha')
@auth.authenticated_developers_only(redirect=False)
async def post_authorized_source_sha(request: web.Request, _) -> NoReturn:
    app = request.app
    db: Database = app['db']
    post = await request.post()
    sha = str(post['sha']).strip()
    await db.execute_insertone('INSERT INTO authorized_shas (sha) VALUES (%s);', sha)
    log.info(f'authorized sha: {sha}')
    session = await aiohttp_session.get_session(request)
    set_message(session, f'SHA {sha} authorized.', 'info')
    raise web.HTTPFound(deploy_config.external_url('ci', '/'))

@routes.get('/healthcheck')
async def healthcheck(_) -> web.Response:
    return web.Response(status=200)

gh_router = gh_routing.Router()

@gh_router.register('pull_request')
async def pull_request_callback(event):
    gh_pr = event.data['pull_request']
    number = gh_pr['number']
    target_branch = FQBranch.from_gh_json(gh_pr['base'])
    for wb in watched_branches:
        if (wb.prs and number in wb.prs) or (wb.branch == target_branch):
            await wb.notify_github_changed(event.app)

@gh_router.register('push')
async def push_callback(event):
    data = event.data
    ref = data['ref']
    if ref.startswith('refs/heads/'):
        branch_name = ref.removeprefix('refs/heads/')
        branch = FQBranch(Repo.from_gh_json(data['repository']), branch_name)
        for wb in watched_branches:
            if wb.branch == branch:
                await wb.notify_github_changed(event.app)

@gh_router.register('pull_request_review')
async def pull_request_review_callback(event):
    gh_pr = event.data['pull_request']
    number = gh_pr['number']
    for wb in watched_branches:
        if number in wb.prs:
            await wb.notify_github_changed(event.app)

async def github_callback_handler(request):
    event = gh_sansio.Event.from_http(request.headers, await request.read())
    event.app = request.app  # type: ignore
    await gh_router.dispatch(event)

@routes.post('/github_callback')
async def github_callback(request):
    await asyncio.shield(github_callback_handler(request))
    return web.Response(status=200)

async def remove_namespace_from_db(db: Database, namespace: str):
    assert namespace != 'default'
    await db.just_execute(
        'DELETE FROM active_namespaces WHERE namespace = %s',
        (namespace,),
    )

async def batch_callback_handler(request):
    app = request.app
    db: Database = app['db']
    params = await json_request(request)
    log.info(f'batch callback {params}')
    attrs = params.get('attributes')
    if attrs:
        target_branch = attrs.get('target_branch')
        if target_branch:
            for wb in watched_branches:
                if wb.branch.short_str() == target_branch:
                    log.info(f'watched_branch {wb.branch.short_str()} notify batch changed')

                    if 'test' in attrs and params['complete']:
                        assert 'deploy' not in attrs
                        assert 'dev' not in attrs
                        namespace = attrs['namespace']
                        if DEFAULT_NAMESPACE == 'default':
                            await remove_namespace_from_db(db, namespace)

                    await wb.notify_batch_changed(app)

@routes.get('/api/v1alpha/deploy_status')
@auth.authenticated_developers_only()
async def deploy_status(request: web.Request, _) -> web.Response:
    batch_client = request.app['batch_client']

    async def get_failure_information(batch):
        if isinstance(batch, MergeFailureBatch):
            exc = batch.exception
            return traceback.format_exception(type(exc), value=exc, tb=exc.__traceback__)
        jobs = await collect_aiter(batch.jobs())

        async def fetch_job_and_log(j):
            full_job = await batch_client.get_job(j['batch_id'], j['job_id'])
            log = await full_job.log()
            return {**full_job._status, 'log': log}

        return await asyncio.gather(*[fetch_job_and_log(j) for j in jobs if j['state'] in ('Error', 'Failed')])

    wb_configs = [
        {
            'branch': wb.branch.short_str(),
            'sha': wb.sha,
            'deploy_batch_id': wb.deploy_batch.id if wb.deploy_batch and isinstance(wb.deploy_batch, Batch) else None,
            'deploy_state': wb.deploy_state,
            'repo': wb.branch.repo.short_str(),
            'failure_information': None
            if wb.deploy_state == 'success'
            else await get_failure_information(wb.deploy_batch),
        }
        for wb in watched_branches
    ]
    return json_response(wb_configs)

@routes.post('/api/v1alpha/update')
@auth.authenticated_developers_only()
async def post_update(request: web.Request, _) -> web.Response:
    log.info('developer triggered update')

    async def update_all():
        for wb in watched_branches:
            await wb.update(request.app)

    request.app['task_manager'].ensure_future(update_all())
    return web.Response(status=200)

@routes.post('/api/v1alpha/dev_deploy_branch')
@auth.authenticated_developers_only()
async def dev_deploy_branch(request: web.Request, userdata: UserData) -> web.Response:
    app = request.app
    try:
        params = await json_request(request)
    except asyncio.CancelledError:
        raise
    except Exception as e:
        message = 'could not read body as JSON'
        log.info('dev deploy failed: ' + message, exc_info=True)
        raise web.HTTPBadRequest(text=message) from e

    try:
        branch = FQBranch.from_short_str(params['branch'])
        steps = params['steps']
        excluded_steps = params['excluded_steps']
        extra_config = params.get('extra_config', {})
    except asyncio.CancelledError:
        raise
    except Exception as e:
        message = f'parameters are wrong; check the branch and steps syntax.\n\n{params}'
        log.info('dev deploy failed: ' + message, exc_info=True)
        raise web.HTTPBadRequest(text=message) from e

    gh = app['github_client']
    request_string = f'/repos/{branch.repo.owner}/{branch.repo.name}/git/refs/heads/{branch.name}'

    try:
        branch_gh_json = await gh.getitem(request_string)
        sha = branch_gh_json['object']['sha']
    except asyncio.CancelledError:
        raise
    except Exception as e:
        message = f'error finding {branch} at GitHub'
        log.info('dev deploy failed: ' + message, exc_info=True)
        raise web.HTTPBadRequest(text=message) from e

    unwatched_branch = UnwatchedBranch(branch, sha, userdata, app['developers'], extra_config=extra_config)

    batch_client = app['batch_client']

    try:
        batch_id = await unwatched_branch.deploy(app['db'], batch_client, steps, excluded_steps=excluded_steps)
    except asyncio.CancelledError:
        raise
    except Exception as e:  # pylint: disable=broad-except
        message = traceback.format_exc()
        raise web.HTTPBadRequest(text=f'starting the deploy failed due to\n{message}') from e
    return json_response({'sha': sha, 'batch_id': batch_id})

@routes.post('/api/v1alpha/batch_callback')
async def batch_callback(request):
    await asyncio.shield(batch_callback_handler(request))
    return web.Response(status=200)

@routes.post('/freeze_merge_deploy')
@auth.authenticated_developers_only()
async def freeze_deploys(request: web.Request, _) -> NoReturn:
    app = request.app
    db: Database = app['db']
    session = await aiohttp_session.get_session(request)

    if app['frozen_merge_deploy']:
        set_message(session, 'CI is already frozen.', 'info')
        raise web.HTTPFound(deploy_config.external_url('ci', '/'))

    await db.execute_update(
        '''
UPDATE globals SET frozen_merge_deploy = 1;
'''
    )

    app['frozen_merge_deploy'] = True

    set_message(session, 'Froze all merges and deploys.', 'info')

    raise web.HTTPFound(deploy_config.external_url('ci', '/'))

@routes.post('/unfreeze_merge_deploy')
@auth.authenticated_developers_only()
async def unfreeze_deploys(request: web.Request, _) -> NoReturn:
    app = request.app
    db: Database = app['db']
    session = await aiohttp_session.get_session(request)

    if not app['frozen_merge_deploy']:
        set_message(session, 'CI is already unfrozen.', 'info')
        raise web.HTTPFound(deploy_config.external_url('ci', '/'))

    await db.execute_update(
        '''
UPDATE globals SET frozen_merge_deploy = 0;
'''
    )

    app['frozen_merge_deploy'] = False

    set_message(session, 'Unfroze all merges and deploys.', 'info')

    raise web.HTTPFound(deploy_config.external_url('ci', '/'))

@routes.get('/namespaces')
@auth.authenticated_developers_only()
async def get_active_namespaces(request: web.Request, userdata: UserData) -> web.Response:
    db: Database = request.app['db']
    namespaces = [
        r
        async for r in db.execute_and_fetchall(
            '''
SELECT active_namespaces.*, JSON_ARRAYAGG(service) as services
FROM active_namespaces
LEFT JOIN deployed_services
ON active_namespaces.namespace = deployed_services.namespace
GROUP BY active_namespaces.namespace'''
        )
    ]
    for ns in namespaces:
        ns['services'] = [s for s in json.loads(ns['services']) if s is not None]
    context = {
        'namespaces': namespaces,
    }
    return await render_template('ci', request, userdata, 'namespaces.html', context)

@routes.post('/namespaces/{namespace}/services/add')
@auth.authenticated_developers_only()
async def add_namespaced_service(request: web.Request, _) -> NoReturn:
    db: Database = request.app['db']
    post = await request.post()
    service = post['service']
    namespace = request.match_info['namespace']

    record = await db.select_and_fetchone(
        '''
SELECT 1 FROM deployed_services
WHERE namespace = %s AND service = %s
''',
        (namespace, service),
    )

    if record:
        session = await aiohttp_session.get_session(request)
        set_message(session, 'Service already registered', 'info')
    else:
        await db.execute_insertone(
            'INSERT INTO deployed_services VALUES (%s, %s)',
            (namespace, service),
        )

    raise web.HTTPFound(deploy_config.external_url('ci', '/namespaces'))

@routes.post('/namespaces/add')
@auth.authenticated_developers_only()
async def add_namespace(request: web.Request, _) -> NoReturn:
    db: Database = request.app['db']
    post = await request.post()
    namespace = post['namespace']

    record = await db.execute_and_fetchone(
        'SELECT 1 FROM active_namespaces where namespace = %s',
        (namespace,),
    )

    if record:
        session = await aiohttp_session.get_session(request)
        set_message(session, 'Namespace already registered', 'info')
    else:
        await db.execute_insertone(
            'INSERT INTO active_namespaces (`namespace`) VALUES (%s)',
            (namespace,),
        )

    raise web.HTTPFound(deploy_config.external_url('ci', '/namespaces'))

async def cleanup_expired_namespaces(db: Database):
    assert DEFAULT_NAMESPACE == 'default'
    expired_namespaces = [
        record['namespace']
        async for record in db.execute_and_fetchall(
            'SELECT namespace FROM active_namespaces WHERE expiration_time < UTC_TIMESTAMP()'
        )
    ]
    for namespace in expired_namespaces:
        assert namespace != 'default'
        log.info(f'Cleaning up expired namespace: {namespace}')
        await remove_namespace_from_db(db, namespace)

async def update_envoy_configs(db: Database, k8s_client):
    assert DEFAULT_NAMESPACE == 'default'

    api_response = await k8s_client.list_namespace()
    live_namespaces = tuple(ns.metadata.name for ns in api_response.items)
    namespace_arg_list = "(" + ",".join('%s' for _ in live_namespaces) + ")"

    services_per_namespace = {
        r['namespace']: [s for s in json.loads(r['services']) if s is not None]
        async for r in db.execute_and_fetchall(
            f'''
SELECT active_namespaces.namespace, JSON_ARRAYAGG(service) as services
FROM active_namespaces
LEFT JOIN deployed_services
ON active_namespaces.namespace = deployed_services.namespace
WHERE active_namespaces.namespace IN {namespace_arg_list}
GROUP BY active_namespaces.namespace''',
            live_namespaces,
        )
    }
    assert 'default' in services_per_namespace
    default_services = services_per_namespace.pop('default')
    assert set(['batch', 'auth', 'batch-driver', 'ci']).issubset(set(default_services)), default_services

    for proxy in ('gateway', 'internal-gateway'):
        configmap_name = f'{proxy}-xds-config'
        configmap = await k8s_client.read_namespaced_config_map(
            name=configmap_name,
            namespace=DEFAULT_NAMESPACE,
        )
        cds = create_cds_response(default_services, services_per_namespace, proxy)
        rds = create_rds_response(default_services, services_per_namespace, proxy)
        configmap.data['cds.yaml'] = yaml.dump(cds)
        configmap.data['rds.yaml'] = yaml.dump(rds)
        await k8s_client.patch_namespaced_config_map(
            name=configmap_name,
            namespace=DEFAULT_NAMESPACE,
            body=configmap,
        )

async def update_loop(app):
    wb: Optional[WatchedBranch] = None
    while True:
        try:
            for wb in watched_branches:
                log.info(f'updating {wb.branch.short_str()}')
                await wb.update(app)
        except concurrent.futures.CancelledError:
            raise
        except Exception:  # pylint: disable=broad-except
            if wb:
                log.exception(f'{wb.branch.short_str()} update failed due to exception')
        await asyncio.sleep(300)

async def on_startup(app):
    client_session = httpx.client_session()
    app['client_session'] = client_session
    app['github_client'] = gh_aiohttp.GitHubAPI(app['client_session'], 'ci', oauth_token=oauth_token)
    app['batch_client'] = await BatchClient.create('ci')

    app['db'] = Database()
    await app['db'].async_init()

    row = await app['db'].select_and_fetchone(
        '''
SELECT frozen_merge_deploy FROM globals;
'''
    )

    app['frozen_merge_deploy'] = row['frozen_merge_deploy']

    app['task_manager'] = aiotools.BackgroundTaskManager()

    if DEFAULT_NAMESPACE == 'default':
        kubernetes_asyncio.config.load_incluster_config()
        k8s_client = kubernetes_asyncio.client.CoreV1Api()
        app['task_manager'].ensure_future(periodically_call(10, update_envoy_configs, app['db'], k8s_client))
        app['task_manager'].ensure_future(periodically_call(10, cleanup_expired_namespaces, app['db']))

    async with hail_credentials() as creds:
        headers = await creds.auth_headers()
    users = await retry_transient_errors(
        client_session.get_read_json,
        deploy_config.url('auth', '/api/v1alpha/users'),
        headers=headers,
    )
    app['developers'] = [u for u in users if u['is_developer'] == 1 and u['state'] == 'active']

    global watched_branches
    watched_branches = [
        WatchedBranch(index, FQBranch.from_short_str(bss), deployable, mergeable, app['developers'])
        for (index, [bss, deployable, mergeable]) in enumerate(
            json.loads(os.environ.get('HAIL_WATCHED_BRANCHES', '[]'))
        )
    ]

    app['task_manager'].ensure_future(update_loop(app))

async def on_cleanup(app):
    async with AsyncExitStack() as cleanup:
        cleanup.push_async_callback(app['db'].async_close)
        cleanup.push_async_callback(app['client_session'].close)
        cleanup.push_async_callback(app['batch_client'].close)
        cleanup.callback(app['task_manager'].shutdown)

def run():
    install_profiler_if_requested('ci')

    app = web.Application(middlewares=[check_csrf_token, monitor_endpoints_middleware])
    setup_aiohttp_jinja2(app, 'ci')
    setup_aiohttp_session(app)

    app.on_startup.append(on_startup)
    app.on_cleanup.append(on_cleanup)

    setup_common_static_routes(routes)
    app.add_routes(routes)
    app.router.add_get("/metrics", server_stats)

    web.run_app(
        deploy_config.prefix_application(app, 'ci'),
        host='0.0.0.0',
        port=5000,
        access_log_class=AccessLogger,
        ssl_context=internal_server_ssl_context(),
    )


## Template for calculator I, II, III

# One template for calculator I, II, III
"""
https://leetcode.com/problems/basic-calculator-ii/discuss/658480/Python-Basic-Calculator-I-II-III-easy-solution-detailed-explanation

"""
"""
Stack

this solution works for basic calculator (add, substract, parenthesis, space), basic calculator II (add, substract, multiple, divide), basic calculator III (add, substract, multiply, divide, parenthesis)

iterating each char (ignore space), and keep track of last sign (operator), and last number found

c=(: recursively process remaining string
c=): return processed result and index of last processed
c is digit: update variable num
c is operator: update stack by doing
  +: add num into stack
  -: add -num into stack
  *: pop stack top, multiply with num, push result back into stack
  /: pop stack top, divide by num, push result back into stack

"""

class Solution:
    def update(self, stack, op, val):
        if op == '+':
            stack.append(val)
        elif op == '-':
            stack.append(-val)
        elif op == '*':
            stack.append(stack.pop() * val)
        elif op == '/':
            stack.append(int(stack.pop() / val))

    def calc(self, s, i):

        stack = []
        lastsign = '+'
        num = 0
        while i < len(s):
            c = s[i]
            # print(f'{i = } {c = } {num = }')
            if c.isdigit():
                num = num * 10 + int(c)
            elif c == '(':
                # recursive process from here
                num, j = self.calc(s, i + 1)
                i = j - 1  # there is i +=1 at end of loop
            elif c == ')':
                self.update(stack, lastsign, num)
                return sum(stack), i + 1
            elif c in '+-*/':
                self.update(stack, lastsign, num)
                lastsign = c
                num = 0
            # elif c == ' ':
            #     pass
            i += 1
            # print(f'{i = } {c = } {stack = } {num = }')

        self.update(stack, lastsign, num)

        return sum(stack), i

    def calculate(self, s: str) -> int:
        return self.calc(s, 0)[0]

"""
Two Stack approach
https://blog.csdn.net/shenjian58/article/details/89849281

输入长度为n的字符串，例如：1+2+3*4*5

输出表达式的值，即：63

“表达式求值”问题，两个核心关键点：

（1）双栈，一个操作数栈，一个运算符栈；

（2）运算符优先级，栈顶运算符，和，即将入栈的运算符的优先级比较：

如果栈顶的运算符优先级低，新运算符直接入栈

如果栈顶的运算符优先级高，先出栈计算，计算结果入栈，新运算符再入栈

如果新运算符和栈顶运算符同级别，栈顶级别算高，先出栈计算，计算结果入栈，新运算符再入栈

这个方法的时间复杂度为O(n)，整个字符串只需要扫描一遍。
————————————————
版权声明：本文为CSDN博主「58沈剑」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/shenjian58/article/details/89849281

"""
""""
Recursive with Stack
"""
class Solution:
    def calculate(self, s: str) -> int:
        i = 0

        def calc():
            nonlocal i, s
            stack = []
            operator = '+'
            num = 0
            while i < len(s):
                c = s[i]
                i += 1
                if c in '0123456789':
                    num = num * 10 + int(c)
                elif c == '(':
                    num = calc()
                if c in '+-*/)' or i >= len(s):  # operator, closing paren or end of string
                    if operator == '+':
                        stack.append(num)
                        print('after + %s' % str(stack))
                    elif operator == '-':
                        stack.append(-num)
                        print('after - %s' % str(stack))
                    elif operator == '*':
                        t = stack.pop()
                        stack.append(t * num)
                        print('after * %s' % str(stack))
                    elif operator == '/':
                        numerate = stack.pop()
                        print('numerate=%s num=%s' % (numerate, num))
                        stack.append(-(-numerate // num) if numerate < 0 else numerate // num)  # round towards zero
                        print('after / %s' % str(stack))
                    operator = c
                    if c == ')':
                        break
                    num = 0
                print(stack)

            return sum(stack)

        return calc()

"""
Stack with recursive call

Note in this approach most expression are evaluated on-the-go, operands and signs are pushed to stack when sub-expression needs to be evaled first
"""

class Solution:

    def calculate(self, s: str) -> int:
        n = len(s)
        stack = []
        i = 0
        operand = 0
        sign = 1
        res = 0  # on-going result
        while i < n:
            c = s[i]
            # print('i=%s c=%s sign=%s operand=%s stack=%s res=%s' % (i, c, sign, operand, stack, res))
            # skip whitespace
            if c == ' ':
                i += 1
                continue
            if c.isdigit():
                # get the entire number
                j = i
                while j < n and s[j].isdigit():
                    j += 1
                # now s[i:j] is the entire number
                operand = int(s[i:j])
                i = j
            elif c == '+':
                # evaludate expression to the left, with result, sign operand
                res += sign * operand
                sign = 1  # save sign for next
                operand = 0  # reset operand
                i += 1
            elif c == '-':
                # evaludate expression to the left, with result, sign operand
                res += sign * operand
                sign = -1  # save sign for next
                operand = 0  # reset operand
                i += 1
            elif c == '(':
                # push result and sign onto stack, for later
                # push result first, then sign
                stack.append(res)
                stack.append(sign)

                # then reset sign and result, as if new evaluation begins for the new sub-expression
                sign = 1
                res = 0
                i += 1
            elif c == ')':
                # evaluate expression to left, with result, sign and operand
                res += sign * operand

                # ')' marks end of expression within a set of paren
                # its result is multiplied with sign on top of stack
                res *= stack.pop()  # stack pop 1, which is the sign to apply to the result of this paren

                # then add the result to next operand on top of stack
                res += stack.pop()  # stack pop 2, operand to add with result

                # reset operand
                sign = 1
                operand = 0
                i += 1

            # print('*** i=%s c=%s sign=%s operand=%s stack=%s res=%s' % (i, c, sign, operand, stack, res))

        return res + sign * operand


from django.test import TestCase

from apps.colecoes.forms import ColecaoModelForm
from apps.usuarios.models import Usuario

# Rodar o teste com o seguinte comando:
# python manage.py test apps.colecoes.tests.tests_forms

class ColecaoFormTestCase(TestCase):

    def test_colecao_form_valido(self):
        form = ColecaoModelForm(data={
            'nome': 'Sega', 'descricao': 'colecao de portáteis', 'data_inicio': '2021-01-01', 'valor_estimado': '10.000'
        })
        self.assertTrue(form.is_valid())

    def test_colecao_form_invalido(self):
        form = ColecaoModelForm(data={})
        self.assertFalse(form.is_valid())


import numpy as np
from pathlib import Path

def collaps_synonyms(network_T_full,nn_full,all_KW_full):
    synonym_list = Path('3CollapsNetwork/SynonymList.lst')
    all_syn=[[]]
    syn_count=0
    with open(synonym_list) as fp:
        line = fp.readline()
        while line:
            if line[0:-1]=='---':
                all_syn.append([])
                syn_count+=1
            else:
                all_syn[syn_count].append(line[0:-1])
            line = fp.readline()

    synonym_indices=[]
    for ii in range(len(all_syn)): # all classes of synonyms (e.g., ['bb84','bb84 protocol'])
        KW_idx=[]
        for jj in range(len(all_KW_full)): # all KWs
            for kk in range(len(all_syn[ii])): # over all synonym members, 'bb84','bb84 protocol'
                if all_syn[ii][kk]==all_KW_full[jj]: # is any of the synonym members the KW?
                    KW_idx.append(jj)
        KW_idx.sort()
        synonym_indices.append(KW_idx)

    all_removed_kws=[]
    for ii in range(len(synonym_indices)):
        if len(synonym_indices[ii])>1:
            curr_syn_idx=synonym_indices[ii]
            prime_idx=curr_syn_idx[0]
            for jj in range(1,len(curr_syn_idx)):
                all_removed_kws.append(curr_syn_idx[jj])
                for kk in range(len(network_T_full)):
                    network_T_full[prime_idx,kk]+=network_T_full[curr_syn_idx[jj],kk]
                    network_T_full[kk,prime_idx]+=network_T_full[curr_syn_idx[jj],kk]

                    nn_full[prime_idx,kk]+=nn_full[curr_syn_idx[jj],kk]
                    nn_full[kk,prime_idx]+=nn_full[kk,curr_syn_idx[jj]]

    all_removed_kws.sort(reverse=True)

    # all_removed_kws are KWs that we will delete, because they are
    # synonyms with other words, and we store their information
    network_T_full=np.delete(network_T_full,all_removed_kws,axis=0)
    network_T_full=np.delete(network_T_full,all_removed_kws,axis=1)
    nn_full=np.delete(nn_full,all_removed_kws,axis=0)
    nn_full=np.delete(nn_full,all_removed_kws,axis=1)

    for ii in all_removed_kws:
        del all_KW_full[ii]

    return network_T_full,nn_full,all_KW_full

def collaps_network(network_T_full,nn_full,all_KW_full):
    # Remove keywords that are synonyms, but keep their information
    network_T_full,nn_full,all_KW_full=collaps_synonyms(network_T_full,nn_full,all_KW_full)
    print('collaps_network - Finished collapsing synonyms')

    degree=sum(np.heaviside(nn_full,0))
    orig_size=len(network_T_full)

    # Remove keywords that have never been used
    ii=0
    network_T_s1=network_T_full[0,:]
    nn_s1=nn_full[0,:]
    while ii<orig_size:
        if ii%500==0:
            print('collaps_network: Progress (vertical): ',ii, '/', orig_size,'(', len(network_T_s1),')')
        if degree[ii]>0:
            network_T_s1=np.vstack([network_T_s1, network_T_full[ii,:]])
            nn_s1=np.vstack([nn_s1, nn_full[ii,:]])
        ii+=1
    network_T_s1=network_T_s1[1:,:]
    nn_s1=nn_s1[1:,:]

    network_T_s1=network_T_s1.transpose()
    nn_s1=nn_s1.transpose()

    ii=0
    network_T_s2=network_T_s1[0,:]
    nn_s2=nn_s1[0,:]
    all_KW_s2=[]
    while ii<orig_size:
        if ii%500==0:
            print('collaps_network: Progress (horizontal): ',ii, '/', orig_size,'(', len(network_T_s2),')')
        if degree[ii]>0:
            network_T_s2=np.vstack([network_T_s2, network_T_s1[ii,:]])
            nn_s2=np.vstack([nn_s2, nn_s1[ii,:]])
            all_KW_s2.append(all_KW_full[ii])
        ii+=1
    network_T_s2=network_T_s2[1:,:]
    nn_s2=nn_s2[1:,:]

    return network_T_s2, nn_s2, all_KW_s2


class Solution:
    def addBinary(self, a: str, b: str) -> str:
        res_len = max(len(a),len(b)) + 1
        res = ["0"] * res_len
        res = deque(res)
        rem = 0
        for i in range(1, res_len + 1):
            A = 0 if i > len(a) else int(a[-i])
            B = 0 if i > len(b) else int(b[-i])
            if (A + B + rem) % 2 == 1:
                res[-i] = "1"
            rem = (A + B + rem) // 2
        if res[0] == "0":
            res.popleft()
        return "".join(res)


import discord
from discord_slash import SlashCommand
import os
from discord.ext import commands
import requests
from bs4 import BeautifulSoup

client = commands.Bot(command_prefix=[' '])
client.remove_command('help')
slash = SlashCommand(client, sync_commands=True) # Declares slash commands through the client.
token = os.environ.get('token')
guild_ids = [945418074121715782, 814607316107395093, 704482683857928222,961863482867847188, 962033686046466070]
roboteventskey = os.environ.get('robotevents_key')
def get_current_season():
	iq_seasons = 'https://www.robotevents.com/api/v2/seasons?program%5B%5D=41'
	headers = {"Authorization": f"Bearer {roboteventskey}"}
	seasondata = requests.get(iq_seasons, headers=headers).json()
	currentseasonid = seasondata['data'][1]['id']
	currentseasonname = seasondata['data'][1]['name']
	return currentseasonid, currentseasonname

currentseasonid, currentseasonname = get_current_season()

async def get_ranking(team):
	url = f'https://www.robotevents.com/teams/VIQC/{team.upper()}'
	res = requests.get(url)
	html_page = res.content
	soup = BeautifulSoup(html_page, 'html.parser')
	text = soup.find_all(text=True)

	output = ''
	blacklist = [
		'[document]',
		'noscript',
		'header',
		'html',
		'meta',
		'head',
		'input',
		'script',
	]

	for t in text:
		if t.parent.name not in blacklist:
			output += '{} '.format(t)
	index = output.find("World Skills Rank:")
	rank = ''
	for x in range(0, 4):
		if output[index+21+x].isnumeric():
			rank+=output[index+21+x]
	return rank
@client.event
async def on_ready():
	print("Ready!")
	# channel = client.get_guild(945418074121715782).get_channel(992529252652158977)
	# e = await channel.create_webhook(name='counting').url
	# print(e)
	game = discord.Game("a skills run")
	await client.change_presence(activity=game)
 # Put your server ID in this array.
guild_ids = [945418074121715782, 814607316107395093, 704482683857928222,961863482867847188, 962033686046466070]
# This command is used to get the ranking of a VIQC team.

@slash.slash(name='skills', description='World Skills Rank')
async def skills(ctx, team):

	team = team.upper()
	await ctx.defer()
	rank = await get_ranking(team)
	teaminfo = f'https://www.robotevents.com/api/v2/teams?number={team}'
	headers = {"Authorization": f"Bearer {roboteventskey}"}
	teamdata = requests.get(teaminfo, headers=headers).json()

	try:
		for allteam in teamdata['data']:
			if allteam['program']['code'] == 'VIQC':
				id = allteam['id']
				teamname = allteam['team_name']
		teaminfo = f'https://www.robotevents.com/api/v2/teams/{id}/skills'
	except:
		await ctx.send(f"Sorry, we couldn't find team {team}.")
		return

	driverlist = []
	autonlist = []
	events = {}

	def eventdata(teaminfo, driverlist, autonlist, events):
		teamdata = requests.get(teaminfo, headers=headers).json()
		for event in teamdata['data']:
			if event['season']['id'] == currentseasonid:
				if event['event']['name'] not in events:
					events[event['event']['name']] = {}
					events[event['event']['name']]['total'] = 0
					events[event['event']['name']]['driver'] = 0
					events[event['event']['name']]['auton'] = 0
				if event['type'] == 'driver':
					driverlist.append(event['score'])
					events[event['event']['name']]['total'] += event['score']
					events[event['event']['name']]['driver'] = event['score']
				elif event['type'] == 'programming':
					autonlist.append(event['score'])
					events[event['event']['name']]['total'] += event['score']
					events[event['event']['name']]['auton'] = event['score']
		if isinstance(teamdata['meta']['next_page_url'], str):
			teaminfo=teamdata['meta']['next_page_url']
			eventdata(teaminfo, driverlist, autonlist, events)
		return driverlist, autonlist, events

	eventdata(teaminfo, driverlist, autonlist, events)

	if driverlist:
		driverHigh = max(driverlist)
	else:
		driverHigh=0
	if autonlist:
		autonomousHigh = max(autonlist)
	else:
		autonomousHigh=0
	score = 0

	for total in events:
		if events[total]['total'] > score:
			score = events[total]['total']
			event = total
	try:
		autonomous = events[event]['auton']
	except:
		autonomous = 0
	try:
		driver = events[event]['driver']
	except:
		driver = 0

	embed=discord.Embed(title="Current VIQC Event", url="https://www.vexrobotics.com/iq/competition/viqc-current-game", color=0x24c9ff)
	embed.set_author(name=f"VIQC {team} ({teamname})", url=f"https://www.robotevents.com/teams/VIQC/{team}")
	embed.add_field(name="Rank", value=rank, inline=True)
	embed.add_field(name="Score", value=score, inline=True)
	embed.add_field(name="Programming", value=autonomous, inline=True)
	embed.add_field(name="Driver", value=driver, inline=True)
	embed.add_field(name="Highest Programming", value=autonomousHigh, inline=True)
	embed.add_field(name="Highest Driver", value=driverHigh, inline=True)
	print(embed)
	try:
		await ctx.send(embed=embed)
	except:
		await ctx.send(f"Hmm, we couldn't fetch your skills rank. Check https://www.robotevents.com/robot-competitions/vex-iq-challenge/standings/skills to see if {team} ({teamname}) is on there.")

@slash.slash(name='about', description='Bot credits')
async def credits(ctx):
	await ctx.send('''Made by VIQC 84C in 2022:
<@!697535361315766322>
<@!697913907528073296>
<@!475315771086602241>

Special thanks to makers of <@!329389228398215179>

If you would like to add the slash commands to your server, click on my profile and press "Add to Server"!''',
	allowed_mentions=discord.AllowedMentions(
	users=False,		 # Whether to ping individual user @mentions
	everyone=False,	  # Whether to ping @everyone or @here mentions
	roles=False,		 # Whether to ping role @mentions
	replied_user=False,  # Whether to ping on replies to messages
), hidden = True)

# This command is used to get the awards of a VIQC team.

@slash.slash(name='awards', description='Specified Team\'s awards')
async def awards(ctx, team):

	team = team.upper()
	await ctx.defer()
	teaminfo = f'https://www.robotevents.com/api/v2/teams?number={team}'
	headers = {"Authorization": f"Bearer {roboteventskey}"}
	teamdata = requests.get(teaminfo, headers=headers).json()

	try:
		for allteam in teamdata['data']:
			if allteam['program']['code'] == 'VIQC':
				id = allteam['id']
				teamname = allteam['team_name']
		awardsUrl = f'https://www.robotevents.com/api/v2/teams/{id}/awards?season={currentseasonid}'
	except:
		await ctx.send(f"Sorry, we couldn't find team {team}.")
		return

	headers = {"Authorization": f"Bearer {roboteventskey}"}

	# Award Data Loop for Next Page

	awardsDict = {}
	def awardData(awardsUrl, awardsDict):

		teamAwards = requests.get(awardsUrl, headers=headers).json()
		print(awardsUrl)

		for event in teamAwards['data']:
			if event['event']['name'] not in awardsDict:
				awardsDict[event['event']['name']] = []
			awardsDict[event['event']['name']].append(event['title'])
		if isinstance(teamAwards['meta']['next_page_url'], str):
			print('sus')
			awardsUrl=teamAwards['meta']['next_page_url']
			awardData(awardsUrl, awardsDict)
		return awardsDict

	awardData(awardsUrl, awardsDict)
	orderedAwards = ''

	for event in awardsDict:
		orderedAwards+=f'\n\n**{event}**\n'
		for award in awardsDict[event]:
			orderedAwards+=f"{award}\n"

	if not orderedAwards:
		orderedAwards = "\n\nCouldn't find any awards this season!"

	await ctx.send(f"**{team.upper()} ({teamname})'s Awards**{orderedAwards}")

@slash.slash(name='compare', description="Compare two teams by skills ranking")
async def compare(ctx, team1, team2):

	team1 = team1.upper()
	team2 = team2.upper()
	await ctx.defer()
	rank1 = await get_ranking(team1)
	rank2 = await get_ranking(team2)
	team1info = f'https://www.robotevents.com/api/v2/teams?number={team1}'
	team2info = f'https://www.robotevents.com/api/v2/teams?number={team2}'
	headers = {"Authorization": f"Bearer {roboteventskey}"}
	team1data = requests.get(team1info, headers=headers).json()
	team2data = requests.get(team2info, headers=headers).json()

	try:
		for allteam in team1data['data']:
			if allteam['program']['code'] == 'VIQC':
				id1 = allteam['id']
				team1name = allteam['team_name']
		for allteam2 in team2data['data']:
			if allteam['program']['code'] == 'VIQC':
				id2 = allteam2['id']
				team2name = allteam2['team_name']
	except:
		await ctx.send("Sorry, we couldn't find a team specified.")
		return

	team1info = f'https://www.robotevents.com/api/v2/teams/{id1}/skills'
	driverlist1 = []
	autonlist1 = []
	events1 = {}
	team2info = f'https://www.robotevents.com/api/v2/teams/{id2}/skills'
	driverlist2 = []
	autonlist2 = []
	events2 = {}

	def eventdata(teaminfo, driverlist, autonlist, events):
		teamdata = requests.get(teaminfo, headers=headers).json()
		for event in teamdata['data']:
			if event['season']['id'] == currentseasonid:
				if event['event']['name'] not in events:
					events[event['event']['name']] = {}
					events[event['event']['name']]['total'] = 0
					events[event['event']['name']]['driver'] = 0
					events[event['event']['name']]['auton'] = 0
				if event['type'] == 'driver':
					driverlist.append(event['score'])
					events[event['event']['name']]['total'] += event['score']
					events[event['event']['name']]['driver'] = event['score']
				elif event['type'] == 'programming':
					autonlist.append(event['score'])
					events[event['event']['name']]['total'] += event['score']
					events[event['event']['name']]['auton'] = event['score']
		if isinstance(teamdata['meta']['next_page_url'], str):
			teaminfo=teamdata['meta']['next_page_url']
			eventdata(teaminfo, driverlist, autonlist, events)
		return driverlist, autonlist, events

	eventdata(team1info, driverlist1, autonlist1, events1)
	eventdata(team2info, driverlist2, autonlist2, events2)

	if driverlist1:
		driverHigh1 = max(driverlist1)
	else:
		driverHigh1=0
	if autonlist1:
		autonomousHigh1 = max(autonlist1)
	else:
		autonomousHigh1=0
	score1 = 0

	for total in events1:
		if events1[total]['total'] > score1:
			score1 = events1[total]['total']
			event = total
	try:
		autonomous1 = events1[event]['auton']
	except:
		autonomous1 = 0
	try:
		driver1 = events1[event]['driver']
	except:
		driver1 = 0

	if driverlist2:
		driverHigh2 = max(driverlist2)
	else:
		driverHigh2=0
	if autonlist2:
		autonomousHigh2 = max(autonlist2)
	else:
		autonomousHigh2=0
	score2 = 0

	for total in events2:
		if events2[total]['total'] > score2:
			score2 = events2[total]['total']
			event = total
	try:
		autonomous2 = events2[event]['auton']
	except:
		autonomous2 = 0
	try:
		driver2 = events2[event]['driver']
	except:
		driver2 = 0

	rank1 = int(rank1)
	rank2 = int(rank2)
	if rank1 < rank2:
		rankdif = rank2-rank1
		r1 = f"{rankdif} ⬆🟩"
		r2 = f"{rankdif} ⬇🟥"
	else:
		rankdif = rank1-rank2
		r2 = f"{rankdif} ⬆🟩"
		r1 = f"{rankdif} ⬇🟥"
	if driver1 > driver2:
		driverdif = driver1-driver2
		d1 = f"{driverdif} ⬆🟩"
		d2 = f"{driverdif} ⬇🟥"
	elif driver2 > driver1:
		driverdif = driver2-driver1
		d2 = f"{driverdif} ⬆🟩"
		d1 = f"{driverdif} ⬇🟥"
	else:
		d1 = "↔⏺"
		d2 = "↔⏺"
	if autonomous1 > autonomous2:
		autonomousdif = autonomous1-autonomous2
		a1 = f"{autonomousdif} ⬆🟩"
		a2 = f"{autonomousdif} ⬇🟥"
	elif autonomous2 > autonomous1:
		autonomousdif = autonomous2-autonomous1
		a2 = f"{autonomousdif} ⬆🟩"
		a1 = f"{autonomousdif} ⬇🟥"
	else:
		a1 = "↔⏺"
		a2 = "↔⏺"

	if score1 > score2:
		scoredif = score1-score2
		s1 = f"{scoredif} ⬆🟩"
		s2 = f"{scoredif} ⬇🟥"
	elif score2 > score1:
		scoredif = score2-score1
		s2 = f"{scoredif} ⬆🟩"
		s1 = f"{scoredif} ⬇🟥"
	else:
		s1 = "↔⏺"
		s2 = "↔⏺"
	if autonomousHigh1 > autonomousHigh2:
		ahdif = autonomousHigh1-autonomousHigh2
		ah1 = f"{ahdif} ⬆🟩"
		ah2 = f"{ahdif} ⬇🟥"
	elif autonomousHigh2 > autonomousHigh1:
		ahdif = autonomousHigh2-autonomousHigh1
		ah2 = f"{ahdif} ⬆🟩"
		ah1 = f"{ahdif} ⬇🟥"
	else:
		ah1 = "↔⏺"
		ah2 = "↔⏺"
	if driverHigh1 > driverHigh2:
		addif = driverHigh1-driverHigh2
		ad1 = f"{addif} ⬆🟩"
		ad2 = f"{addif} ⬇🟥"
	elif driverHigh2 > driverHigh1:
		addif = driverHigh2-driverHigh1
		ad2 = f"{addif} ⬆🟩"
		ad1 = f"{addif} ⬇🟥"
	else:
		ad1 = "↔⏺"
		ad2 = "↔⏺"

	embed=discord.Embed(title="Current VIQC Event", url="https://www.vexrobotics.com/iq/competition/viqc-current-game", color=0x24c9ff)
	embed.set_author(name=f"Comparing VIQC {team1} vs. {team2}")
	embed.add_field(name=f"{team1} ({team1name}):", value=f"Rank: {rank1} ({r1})\nScore: {score1} ({s1})\nProgramming: {autonomous1} ({a1})\nDriver: {driver1} ({d1})\nHighest Programming: {autonomousHigh1} ({ah1})\nHighest Driver: {driverHigh1} ({ad1})")
	embed.add_field(name=f"{team2} ({team2name}):", value=f"Rank: {rank2} ({r2})\nScore: {score2} ({s2})\nProgramming: {autonomous2} ({a2})\nDriver: {driver2} ({d2})\nHighest Programming: {autonomousHigh2} ({ah2})\nHighest Driver: {driverHigh2} ({ad2})")
	await ctx.send(embed=embed)
# keep_alive.keep_alive()
client.run(token)


from setuptools import setup, find_packages
from pathlib import Path
from distutils.util import convert_path

this_directory = Path(__file__).parent
long_description = (this_directory / "README.md").read_text()

version = {}
with open(convert_path('pyerrors/version.py')) as ver_file:
    exec(ver_file.read(), version)

setup(name='pyerrors',
      version=version['__version__'],
      description='Error propagation and statistical analysis for Monte Carlo simulations',
      long_description=long_description,
      long_description_content_type='text/markdown',
      url="https://github.com/fjosw/pyerrors",
      project_urls= {
        'Documentation': 'https://fjosw.github.io/pyerrors/pyerrors.html',
        'Bug Tracker':   'https://github.com/fjosw/pyerrors/issues',
        'Changelog' :    'https://github.com/fjosw/pyerrors/blob/master/CHANGELOG.md'
      },
      author='Fabian Joswig',
      author_email='fabian.joswig@ed.ac.uk',
      license="MIT",
      packages=find_packages(),
      python_requires='>=3.8.0',
      install_requires=['numpy>=1.24', 'autograd>=1.6.2', 'numdifftools>=0.9.41', 'matplotlib>=3.7', 'scipy>=1.10', 'iminuit>=2.21', 'h5py>=3.8', 'lxml>=4.9', 'python-rapidjson>=1.10', 'pandas>=2.0'],
      extras_require={'test': ['pytest', 'pytest-cov', 'pytest-benchmark', 'hypothesis', 'nbmake', 'flake8']},
      classifiers=[
          'Development Status :: 5 - Production/Stable',
          'Intended Audience :: Science/Research',
          'License :: OSI Approved :: MIT License',
          'Programming Language :: Python :: 3',
          'Programming Language :: Python :: 3.8',
          'Programming Language :: Python :: 3.9',
          'Programming Language :: Python :: 3.10',
          'Programming Language :: Python :: 3.11',
          'Topic :: Scientific/Engineering :: Physics'
      ],
     )


import os
import re
from pathlib import Path

import numpy as np
import pandas as pd

def read_csv(filepath: str | Path) -> tuple[int, np.ndarray, np.ndarray]:
    match_result = re.fullmatch(
        pattern=r"(?P<id>\d+).*", string=os.path.basename(filepath)
    )
    assert match_result
    id = int(match_result.group("id"))
    df = pd.read_csv(filepath)
    x = df["flowTime"].to_numpy()
    y = df["frequency"].to_numpy()
    return id, x, y

def prepare_y(x: np.ndarray, y: np.ndarray, func: str = "cdf") -> np.ndarray:
    if func == "cdf":
        return y.cumsum()
    elif func == "pdf":
        return y / (x[1] - x[0])
    else:
        raise NotImplementedError()


#!/bin/python3
# author: Jan Hybs
from processing import ExecutorStatus
from utils.crypto import sha1
from utils.strings import ensure_iterable

class ExecutorResult(object):
    def __init__(self, cmd=None, status=ExecutorStatus.IN_QUEUE, returncode=None, error=None):
        self.cmd = cmd
        self.status = status
        self.returncode = returncode
        self.error = error
        self.uuid = None
        self.id = None

        self.duration = 0

        self.stdinn = None
        self.stdout = None
        self.stderr = None
        self.message = None
        self.message_details = None
        self.console = None
        self.attachments = list()

    def register(self, id):
        self.id = id
        self.uuid = sha1(id)
        return self

    def add_attachment(self, *attachment: dict):
        self.attachments.extend(attachment)

    def __call__(self, status=None, returncode=None, error=None, duration=None):
        if status is not None:
            self.status = status

        if returncode is not None:
            self.returncode = returncode

        if error is not None:
            self.error = error

        if duration is not None:
            self.duration = duration

        return self

    def __repr__(self):
        return 'Result([%s] => %s (%s) in %1.3f sec)' % (
            ' '.join(self.cmd),
            str(self.returncode),
            self.status.name,
            self.duration
        )

    def failed(self):
        return self.returncode != 0

    def peek(self, full=True):
        if full:
            return dict(
                uuid=self.uuid,
                id=self.id,
                status=self.status.str,
                cmd=self.cmd,
                duration=self.duration,
                returncode=self.returncode,
                stdin=ensure_iterable(self.stdinn)[:100],
                stdout=ensure_iterable(self.stdout)[:100],
                stderr=ensure_iterable(self.stderr)[:100],
                console=ensure_iterable(self.console)[:100],
                message=self.message,
                message_details=ensure_iterable(self.message_details)[:100],
                attachments=ensure_iterable(self.attachments),
            )

        doc = dict(
            id=self.id,
            status=self.status.str,
            cmd=' '.join(ensure_iterable(self.cmd)),
            duration=self.duration,
            returncode=self.returncode,
            message=self.message,
            message_details=ensure_iterable(self.message_details),
        )
        for p in ('cmd', 'message', 'message_details'):
            if p in doc and not doc[p]:
                doc.pop(p)
        return doc

    @classmethod
    def empty_result(cls, id, status=ExecutorStatus.IN_QUEUE):
        return ExecutorResult([], status).register(id)

    @classmethod
    def _showcase(cls):
        for status in ExecutorStatus:
            result = cls.empty_result(str(status), status)
            result.message = str(status)
            yield result


# Desafio 044 - Elabore um programa que calcule o valor a ser pago por um produto,
#               considerando o seu preço normal e condição de pagamento:
#               - À vista dinheiro/cheque: 10% de desconto
#               - À vista no cartão: 5% de desconto
#               - Em até 2x no cartão: preço normal
#               - 3x ou mais no cartão: 20% de juros

preco = float(input('Digite o preço do produto:\n>> R$'))
switch = int(input("""FORMAS DE PAGAMENTO
[ 1 ] à vista dinheiro/cheque
[ 2 ] à vista cartão
[ 3 ] 2x no cartão
[ 4 ] 3x ou mais no cartão
Digite uma opção:
>> """))

if switch == 1:
    desconto = preco - preco*0.10
    print('Você recebeu um desconto de 10%.')
    print('Valor com desconto: R${:.2f}'.format(desconto))

elif switch == 2:
    desconto = preco - preco*0.05
    print('Você recebeu um desconto de 5%.')
    print('Valor com desconto: R%{:.2f}'.format(desconto))

elif switch == 3:
    parcela = preco / 2
    print('Sua compra será parcelada em 2x de R${:.2f} SEM JUROS.'.format(parcela))
    print('Valor total: R${:.2f}'.format(preco))

elif switch == 4:
    parcelas = int(input('Digite o número de parcelas:\n>> '))
    if parcelas <=2:
        print('Para parcelar em 2x ou pagar a vista, selecione as outras opções!')
    else:
        juros = preco + preco*0.20
        parcela = juros / parcelas
        print('Sua compra será parcelada em {}x de R${:.2f} COM JUROS.'.format(parcelas,parcela))
        print('Valor com juros: R${:.2f}'.format(juros))

else:
    print('[ - ] Opção Inválida! Digite apenas 1, 2, 3 ou 4.')


from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
import uvicorn
import json

import torch
from transformers import BertForSequenceClassification, BertTokenizer

app = FastAPI()

@app.get('/')
def show():
    return {"text": "Hello World"}

@app.get('/generate/')
def show():
    return {"Page": "show page"}

@app.post('/generate/')
def generate(input):
    tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
    device = torch.device('cpu')
    model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
    model.load_state_dict(torch.load('./models/bert_statedict', map_location=device))
    model.eval()
    test_encoding = tokenizer([json.loads(input)['passage']], return_tensors='pt', padding=True, truncation=True)
    test_input_ids = test_encoding['input_ids']
    test_attention_mask = test_encoding['attention_mask']
    prob = torch.nn.functional.softmax(model(test_input_ids, test_attention_mask).logits, dim=1)[0][1]
    return {"prob": float(prob)}


# BEGIN coreml_styleclassifier
import coremltools

coreml_model = coremltools.converters.caffe.convert(
    ('./finetune_flickr_style.caffemodel', './deploy.prototxt'),
    image_input_names = 'data',
    class_labels = './styles.txt'
)

coreml_model.author = 'Paris BA'

coreml_model.license = 'None'

coreml_model.short_description = 'Flickr Style'

coreml_model.input_description['data'] = 'An image.'

coreml_model.output_description['prob'] = (
    'Probabilities for style type, for a given input.'
)

coreml_model.output_description['classLabel'] = (
    'The most likely style type for the given input.'
)

coreml_model.save('Style.mlmodel')
# END coreml_styleclassifier

Chapter 4 - Vision/StyleClassifier/Python/convert_styleclassifier.py


import numpy as np
import matplotlib.pyplot as plt
from aeons.utils import *
from aeons.regress import GaussianRegress
from aeons.likelihoods import full

def plot_lx(samples):
    logL = samples.logL
    logX_mean = samples.logX()
    fig, ax1 = plt.subplots(figsize=(6.7,2))
    ax2 = plt.twinx(ax1)
    logL_norm = logL - logL.max()
    L_norm = np.exp(logL_norm)
    ax1.plot(logX_mean, L_norm, lw=1, color='black')
    ax2.plot(logX_mean, L_norm*np.exp(logX_mean), lw=1, color='navy')
    ax1.set_title(f'$\\log\\mathcal{{L}}_\\mathrm{{max}}$ = {logL.max():.2f}')

def plot_logLx(samples, ndead=0, lives=True, ax=None, N_points=50, ms=2):
    points = points_at_iteration(samples, ndead)
    nk, logL = np.array(points.nlive), np.array(points.logL)
    X_mean = X_mu(nk)
    N = len(points)
    if lives:
        index = np.linspace(ndead, N, N_points, endpoint=False).astype(int)
    else:
        index = np.linspace(0, N, N_points, endpoint=False).astype(int)

    if ax is None:
        fig, ax = plt.subplots(figsize=(4,2))
        ax.plot(X_mean[index], logL[index], '+', ms=ms, color='navy')
        return fig, ax
    else:
        ax.plot(X_mean[index], logL[index], '+', ms=ms, color='navy')
    ax.ticklabel_format(style='sci')

def plot_std(xvals, y_means, y_stds, true=None, ylim=None, ax=None, color='deepskyblue', label=None):
    # plt.plot(xvals, y_means, lw=1, color='navy')
    if ax is None:
        fig, ax = plt.subplots(figsize=(4,2))
    ax.fill_between(xvals, y_means - y_stds, y_means + y_stds, alpha=1, color=color, label=label)
    ax.fill_between(xvals, y_means - 2*y_stds, y_means + 2*y_stds, alpha=.2, color=color)
    if true is not None:
        ax.axhline(y=true, lw=.5, color='red', ls='--')
        if isinstance(ylim, float):
            ax.set_ylim(0, true*ylim)
        elif isinstance(ylim, tuple):
            ax.set_ylim(ylim[0]*true, ylim[1]*true)

def plot_split(model, ndead, nlive, splits=2, trunc=None):
    logLlive, Xlive, nk, logZdead = model.data(ndead, live=True)
    regress = GaussianRegress(logLlive, Xlive)
    logXf = logXf_formula(regress.theta, logZdead, Xlive[0])
    endpoint = calc_endpoints(ndead, np.log(Xlive[0]), logXf, 0.01, nlive=nlive)[0]

    logL_split, X_split = data_split(logLlive, Xlive, splits, trunc)
    regress_split = GaussianRegress(logL_split, X_split)
    logXf_split = logXf_formula(regress_split.theta, logZdead, Xlive[0])
    endpoint_split = calc_endpoints(ndead, np.log(Xlive[0]), logXf_split, 0.01, nlive=nlive)[0]

    fig, axs = plt.subplots(1, 2, figsize=(8, 3))
    axs[0].plot(Xlive, logLlive, '+', ms=3)
    axs[0].plot(Xlive, full.func(Xlive, regress.theta), lw=2, label=f"{endpoint:.0f}")
    axs[0].set_title(f"{formatt(regress.theta)} logZ = {regress.logZ():.1f}")
    axs[0].legend()
    axs[1].plot(Xlive, logLlive, '+', ms=3)
    axs[1].plot(X_split, full.func(X_split, regress_split.theta), lw=2, label=f"{endpoint_split:.0f}")
    axs[1].set_title(f"{formatt(regress_split.theta)} logZ = {regress_split.logZ():.1f}")
    axs[1].set_yticks([])
    axs[1].legend()
    fig.suptitle(f"ndead = {ndead}, true = {model.true_endpoint():.0f}, {model.true_logXf():.1f}", y=0.95)
    fig.tight_layout()