'''
A pipeline for detecting translation errors from proteomics data

https://github.com/xuebingwu/tfams

Xuebing Wu

'''

# Required: please update the path to MaxQuant binary
MaxQuantCmd="dotnet /home/xw2629/software/MaxQuant/bin/MaxQuantCmd.exe"

### Optional but required if default settings will be used

# default of --standard-xml
template_xml_standard='./template_xml/mqpar-standard.xml'         # Standard MaxQuant search parameters, no dependent peptide search

# default of --substitution-xml
template_xml_substitution='./template_xml/mqpar-substitution.xml' # MaxQuant parameters with dependent peptide search and match between runs

# default of --proteome
proteome='./reference/human.protein.fa'                # amino acid sequences of all proteins

# default of --variant
variant='./reference/human.variant.fa'                 # peptides encoded by SNV

# default of --transcriptome
transcriptome='./reference/human.CDS.fa'               # for substitution, only CDS of mRNAs

# default of --contaminant
contaminant='./reference/contaminant.fa'               # for substitution, from MaxQuant

# default for other transcriptomes used to generate noncanonical peptide databases
transcriptome_frameshift='./reference/human.CDS.fa'    # for frameshift analysis, same as substitution
transcriptome_lncrna='./reference/human.lncRNA.fa'     # for lncRNA analysis, downloaded from GENCODE, lncRNA sequence
transcriptome_mrna='./reference/human.mRNA.fa'         # for UTR analysis, downloaded from GENCODE, protein-coding transcript sequence
transcriptome_intron='./reference/human.intron.fa'     # for intron analysis, downloaded from UCSC Table browser, gencode.v32, +9nt flanking sequence

import argparse
import os
from generate_xml import *
from substitution import *
from Bio import SeqIO
import time
import pandas as pd
import numpy as np
import random

# for plotting
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

# noncanonical translation

def generate_UTR_proteome(transcriptome):
    '''
    input:
        - a fasta file of mRNA sequences, including UTRs.
        - downloaded from GENCODE, sequenes for protein-coding transcripts
        - header format: >ENST00000641515.2|ENSG00000186092.6|OTTHUMG00000001094.4|OTTHUMT00000003223.4|OR4F5-202|OR4F5|2618|UTR5:1-60|CDS:61-1041|UTR3:1042-2618|\
    output:
        - a fasta file of amino acid sequences resulted from translating 5' UTRs or 3' UTRs
        - output file name: *-utr-proteome.fa, in the same folder as input
        - allow translation in all 3 reading frames
        - allow stop codons to remain in the peptide sequences (as *)
        - header format: >en|ENST00000641515.2_OR4F5_UTR5_0|
        - UTR5_0 means translation of 5' UTR in frame 0, same as the coding sequence downstream
        - UTR3_0 means translation of 3' UTR in frame 0, same as the coding sequence upstream
    '''
    if not os.path.isfile(transcriptome):
        return -1 # file not found
    out = open(transcriptome+'-utr-proteome.fa','w')
    for record in SeqIO.parse(open(transcriptome,'r'),'fasta'):
        record.seq = record.seq.upper()
        if '-' in record.seq or 'N' in record.seq:
            continue
        header=record.description.split('|')
        description = '>en|'+header[0]+'_'+header[5]
        txpt_len = int(header[6])
        if header[7][:3] == 'CDS':
            s,e = header[7][4:].split('-')
        elif header[8][:3] == 'CDS':
            s,e = header[8][4:].split('-')
        elif header[9][:3] == 'CDS':
            s,e = header[9][4:].split('-')
        else:
            continue
        s=int(s) # CDS start
        e=int(e) # CDS end
        # 5' UTR
        if s > 9: # at least 9nt 5' UTR
            utr5seq = record.seq[:(s+9)]
            utr5seq = utr5seq[len(utr5seq)%3:] # make it in frame with CDS by skipping the first or the first 2 bases
            out.write(description+'_UTR5_0|\n'+str(utr5seq[0:].translate())+'\n')
            out.write(description+'_UTR5-1|\n'+str(utr5seq[1:].translate())+'\n')
            out.write(description+'_UTR5-2|\n'+str(utr5seq[2:].translate())+'\n')
        if txpt_len - e >= 9: # 3' UTR at least 9 nt
            utr3seq = record.seq[(e-9):]
            out.write(description+'_UTR3_0|\n'+str(utr3seq[0:].translate())+'\n')
            out.write(description+'_UTR3_1|\n'+str(utr3seq[1:].translate())+'\n')
            out.write(description+'_UTR3_2|\n'+str(utr3seq[2:].translate())+'\n')
    out.close()
    return 0

def generate_lncRNA_proteome(transcriptome,analysis):
    '''
    input
        - a fasta file containing sequences of all lncRNAs
        - lncRNA: downloaded from GENCODE, sequences of all lncRNAs
        - lncRNA header: >ENST00000326734.2|ENSG00000177757.2|OTTHUMG00000002471.2|OTTHUMT00000007025.2|FAM87B-201|FAM87B|1947|
    output
        - a fasta files for proteins encoded in each reading frame, regardless of start or stop codons
        - output in the same folder as input, file name: *-lncrna-proteome.fa or *-intron-proteome.fa
        - header for lncRNA: >en|ENST00000326734.2_FAM87B_lncrna_0
    '''
    if not os.path.isfile(transcriptome):
        return -1 # file not found

    out = open(transcriptome+'-'+analysis+'-proteome.fa','w')

    for record in SeqIO.parse(open(transcriptome,'r'),'fasta'):
        record.seq = record.seq.upper()
        if '-' in record.seq or 'N' in record.seq:
            continue
        descriptions = record.description.split('|')
        description = '>en|'+descriptions[0]+'_'+descriptions[5]+'_lncrna_'
        out.write(description+'0|\n'+str(record.seq[0:].translate())+'\n')
        out.write(description+'1|\n'+str(record.seq[1:].translate())+'\n')
        out.write(description+'2|\n'+str(record.seq[2:].translate())+'\n')
    out.close()
    return 0

def generate_intron_proteome(transcriptome,analysis):
    '''
    given introns are huge, stop at the first stop codon for each frame

    input
        - a fasta file containing sequences of all introns
        - intron: downloaded from UCSC Table browser, with 9nt flanking sequence, by chromosome and then merged together
    output
        - a fasta files for proteins encoded in each reading frame, regardless of start or stop codons
        - output in the same folder as input, file name: *-intron-proteome.fa
        - header for itnron: >en|ENST00000326734.2_range=chr1:65565-69045_intron_0
    '''
    if not os.path.isfile(transcriptome):
        return -1 # file not found

    out = open(transcriptome+'-'+analysis+'-proteome.fa','w')

    for record in SeqIO.parse(open(transcriptome,'r'),'fasta'):
        record.seq = record.seq.upper()
        if '-' in record.seq or 'N' in record.seq:
            continue
        # >hg38_wgEncodeGencodeCompV36_ENST00000641515.2_1 range=chr1:65565-69045 5'pad=9 3'pad=9 strand=+ repeatMasking=none
        descriptions = record.description.split(' ')
        description = '>en|'+descriptions[0].split('_')[2]+'_'+descriptions[1]+'_intron_'
        seq = str(record.seq[0:].translate().split('*')[0])
        if len(seq) > 6:
            out.write(description+'0|\n'+seq+'\n')
        seq = str(record.seq[1:].translate().split('*')[0])
        if len(seq) > 6:
            out.write(description+'1|\n'+seq+'\n')
        seq = str(record.seq[2:].translate().split('*')[0])
        if len(seq) > 6:
            out.write(description+'2|\n'+seq+'\n')
    out.close()
    return 0

def shuffle(seq):
    str_var = list(seq)
    random.shuffle(str_var)
    return ''.join(str_var)

def generate_frameshift_proteome(transcriptome):
    '''
    generate protein sequences in three reading frames
    input:
        - a fasta file containing CDS of all transcripts, each starts with start codon and ends with stop codon
        - noncanonical start codon allowed ('GTG','TTG','ATT','CTG')
        - downloaded from emsembl http://ftp.ensembl.org/pub/release-103/fasta/
        - header: >ENST00000632684.1 cds chromosome:GRCh38:7:142786213:142786224:1 gene:ENSG00000282431.1 gene_biotype:TR_D_gene transcript_biotype:TR_D_gene gene_symbol:TRBD1 description:T cell receptor beta diversity 1 [Source:HGNC Symbol;Acc:HGNC:12158]
    output:
        - a fasta file for peptides encoded in shifted reading frame (1 or 2).
        - output in the same folder as input, file name: *-frameshift-proteome.fa
        - header: >en|ENST00000632684.1_TRBD1_frameshift_1
    '''
    # note that this doesn't include 3' UTR
    if not os.path.isfile(transcriptome):
        return -1 # file not found
    out = open(transcriptome+'-frameshift-proteome.fa','w')
    out0 = open(transcriptome+'-proteome.fa','w')
    out1 = open(transcriptome+'-frameshift-shuffle-proteome.fa','w')
    for record in SeqIO.parse(open(transcriptome,'r'),'fasta'):
        record.seq = record.seq.upper()
        if '-' in record.seq or 'N' in record.seq:
            continue
        if len(record.seq)%3 == 0 and record.seq[:3] in {'ATG','GTG','TTG','ATT','CTG'} and record.seq[-3:].translate()=='*':
            descriptions = record.description.split(' ')
            gene_symbol = descriptions[0]+'_'+descriptions[6].split(':')[1]+'_frameshift_1'
            description = 'en|'+gene_symbol+'|'
            seq = str(record.seq[1:].translate())
            out.write('>'+description+'\n'+seq+'\n')

            # shuffled frame 1
            out1.write('>'+description+'\n'+shuffle(seq)+'\n')

            gene_symbol = descriptions[0]+'_'+descriptions[6].split(':')[1]+'_frameshift_2'
            description = 'en|'+gene_symbol+'|'

            seq = str(record.seq[2:].translate())
            out.write('>'+description+'\n'+seq+'\n')
            # shuffled frame 2
            out1.write('>'+description+'\n'+shuffle(seq)+'\n')

            # generate non-frameshifted proteins
            gene_symbol = descriptions[0]+'_'+descriptions[6].split(':')[1]+'_frameshift_0'
            description = 'en|'+gene_symbol+'|'
            out0.write('>'+description+'\n'+str(record.seq.translate())+'\n')
    out.close()
    out0.close()
    out1.close()
    return 0

def generate_custom_proteome(analysis):

    print('Creating custom proteome from transcriptome: ')
    if analysis == 'lncrna':
        path_to_custom_proteome = transcriptome_lncrna+'-lncrna-proteome.fa'
        if not os.path.isfile(path_to_custom_proteome):
            generate_lncRNA_proteome(transcriptome_lncrna,'lncrna')
        else:
            print('Custom proteome already exists. Please delete it to create a new one: '+path_to_custom_proteome)
    elif analysis == 'intron':
        path_to_custom_proteome = transcriptome_intron+'-intron-proteome.fa'
        if not os.path.isfile(path_to_custom_proteome):
            generate_intron_proteome(transcriptome_intron,'intron')
        else:
            print('Custom proteome already exists. Please delete it to create a new one: '+path_to_custom_proteome)
    elif analysis == 'utr':
        path_to_custom_proteome = transcriptome_mrna+'-utr-proteome.fa'
        if not os.path.isfile(path_to_custom_proteome):
            generate_UTR_proteome(transcriptome_mrna)
        else:
            print('Custom proteome already exists. Please delete it to create a new one: '+path_to_custom_proteome)
    elif analysis == 'frameshift':
        path_to_custom_proteome = transcriptome_frameshift+'-frameshift-proteome.fa'
        if not os.path.isfile(path_to_custom_proteome):
            generate_frameshift_proteome(transcriptome_frameshift)
        else:
            print('Custom proteome already exists. Please delete it to create a new one: '+path_to_custom_proteome)
    else:
        print("ERROR: unknown analysis type: "+analysis)
        exit()

    return path_to_custom_proteome

# maxquant

def maxquant_standard_search(path_to_proteome,input_dir,output_dir,template_xml,thread):
    # standard maxquant analysis

    # check if already done
    path_to_evidence = output_dir+'/combined/txt/evidence.txt'
    if not os.path.isfile(path_to_evidence):
        print("MaxQuant search for peptides")
        print("---------------------------------")
        if not os.path.isdir(output_dir):
            os.mkdir(output_dir)
        generate_xml(template_xml,input_dir,output_dir,path_to_proteome,thread)
        cmd = MaxQuantCmd+ " " + output_dir + "/mqpar.xml "
        print(cmd)
        os.system(cmd)
        print("Deleting intermediate files from MaxQuant run")
        clean_up_after_maxquant_run(input_dir,output_dir)
    else:
        print("MaxQuant result found in the output folder. To run again please delete existing output folder: "+output_dir)

def filter_maxquant_result(output_dir,path_to_proteome,path_to_variant_peptide):
    '''
    filter 1: potential contamiants
    filter 2: peptides found in the normal/canonical proteome

    input:
        - output_dir: a parental folder where 'combined' from a MaxQuant run can be found
        - path_to_proteome: a fasta file with all canonical protein sequences
    output:
        - shown on screen how many peptides remain after each filter
        - filtered peptides saved to output_dir+'/combined/txt/evidence.txt-filtered.txt'
    '''
    path_to_evidence = output_dir+'/combined/txt/evidence.txt'
    try:
        pep = pd.read_csv(path_to_evidence,sep = '\t')
        print(str(len(pep))+" peptides identified")
    except:
        print("0 peptides were identified in the MaxQuant search")

    pep = pep[pep['Potential contaminant'] != '+']
    print(str(len(pep))+" peptides remain after removing potential contaminant")
    pep = pep[pep['Reverse'] != '+']
    print(str(len(pep))+" peptides remain after removing reverse match")

    # remove peptides also found in canonical proteome
    # note that two sequences can be the same, so do not index using sequence
    allpep = open(path_to_proteome).read().replace("\n","")
    for i in pep.index:
        if pep is None:
            print("0 peptides remain after removing canonical peptides")
            return 0
            break
        if pep.at[i,'Sequence'] in allpep:
            pep=pep.drop(i,inplace=True)

    print(str(len(pep))+" peptides remain after removing canonical peptides")

    pep = pep[~pep['Intensity'].isna()]
    pep = pep[pep['Intensity']>0]
    print(str(len(pep))+" peptides remain after removing peptides with no positive intensity values")

    pep = pep[~pep['Proteins'].isna()]
    print(str(len(pep))+" peptides remain after removing peptides with no assigned proteins")

    # SNPs
    pep['SNV'] = 0
    n=0
    if os.path.isfile(path_to_variant_peptide):
        variant_pep = open(path_to_variant_peptide).read().replace("\n","")
        for i in pep.index:
            if pep.at[i,'Sequence'] in variant_pep:
                #pep=pep.drop(i)
                pep.at[i,'SNV'] = 1
                n=n+1
        print(str(n)+" peptides are marked as potential SNP peptides")
    else:
        print("Skip variant filter: variant peptide file not found or not set: "+path_to_variant_peptide)

    pep.to_csv(path_to_evidence+'-filtered.txt')
    print('filtered peptides saved to '+path_to_evidence+'-filtered.txt')
    return len(pep)

'''
def quantification_and_plot(output_dir,canonical_output_dir):
    # count, median, mean intensity of identified peptides
    # count, median, mean intensity of protein groups with identified peptides
    # same for canonical output
    # violin plot for the distribution of peptide/protein intensities

    #output_dir = '/home/xw2629/xuebing/amino-acid-substitution/raw-data/frameshift-test/frameshift/'
    #output_dir = '/home/xw2629/xuebing/amino-acid-substitution/raw-data/frameshift-test/canonical/'

    pep = pd.read_csv(output_dir+'/combined/txt/evidence.txt-filtered.txt')

    pep = pep[~pep['Intensity'].isna() & pep['Intensity']>0]

    print(" peptides identified: "+str(len(pep)))
    print(" peptide intensity, median/1e6: "+str(pep['Intensity'].median()/1e6))
    print(" peptide intensity, mean/1e6: "+str(pep['Intensity'].mean()/1e6))
    #plt.hist(np.log10(pep['Intensity']),bins=100)

    plt.violinplot([np.log10(pep['Intensity'])],showmeans=False,showmedians=True)
    plt.ylabel('log10 (Intensity)')
    plt.xticks([1], ['Pep'])
    plt.show()

    # protein level
    protein_intensity = {}
    for i in pep.index:
        protein = pep.loc[i]['Leading razor protein'].split('_')[1] # ENST00000564104.5_TPPP3_frameshift_2
        if not (protein in protein_intensity):
            protein_intensity[protein] = 0
        protein_intensity[protein] = protein_intensity[protein] + pep.loc[i]['Intensity']
    protein_intensity_df = pd.DataFrame.from_dict(protein_intensity, orient='index',columns=['Intensity'])
    print(" proteins identified: "+str(len(protein_intensity_df)))
    print(" protein intensity, median/1e6: "+str(protein_intensity_df.Intensity.median()/1e6))
    print(" peptide intensity, mean/1e6: "+str(protein_intensity_df.Intensity.mean()/1e6))

    plt.violinplot([np.log10(protein_intensity_df.Intensity)],showmeans=False,showmedians=True)
    plt.ylabel('log10 (Intensity)')
    plt.xticks([1], ['Protein'])
'''

def clean_up_after_maxquant_run(input_dir,output_dir):
    '''
    input_dir: for each X.raw file, remove corresponding X.index and folder X
    output_dir:
    '''

    # make sure output file exists
    if not os.path.isfile(output_dir+'/combined/txt/allPeptides.txt'):
        print("warning: it appears the analysis has not been completed. skip clean up")
        return 0

    # delete everything under 'combined' except 'txt'
    os.system('mv '+output_dir+'/combined/txt '+output_dir+'/')
    os.system('rm -rf '+output_dir+'/combined/*')
    os.system('mv '+output_dir+'/txt '+output_dir+'/combined/')

    # clean up intermediate files in input folder
    if os.path.isdir(input_dir):
        files = os.listdir(input_dir)
        for file in files:
            if file[-4:] == ".raw":
                os.system('rm '+input_dir+'/'+file[:-4]+'.index')
                os.system('rm -rf '+input_dir+'/'+file[:-4])
    else:
        print("warning: input folder not found: "+input_dir)

def substitution_second_pass(path_to_subs,input_dir,output_dir,standard_xml,thread):
    '''
    create a peptide database with only substitutions and their base peptide
    then run maxquant standard search again to get quantifications
    '''

    path_to_2nd_evidence = output_dir+'/second_pass/combined/txt/evidence.txt'

    if not os.path.isfile(path_to_2nd_evidence):

        subs = pd.read_csv(path_to_subs)

        print("- 2nd pass: get unique sequences for each sub and base peptide")
        bp_seqs = {}
        for i in subs.index:
            bp_seqs[subs.at[i,'modified_sequence']] = subs.at[i,'DP Base Sequence']
        print('- 2nd pass: '+str(len(bp_seqs))+' unique peptides with substitutions')
        print("- 2nd pass: write into fasta file: "+path_to_subs+'-uniq-seq.fa')
        out = open(path_to_subs+'-uniq-seq.fa','w')
        for key in bp_seqs:
            out.write('>sub|'+key+'|\n'+key+'\n')
            out.write('>sub|'+bp_seqs[key]+'|\n'+bp_seqs[key]+'\n')
        out.close()

        print("- 2nd pass: maxquant search")
        maxquant_standard_search(path_to_subs+'-uniq-seq.fa',input_dir,output_dir+'/second_pass',standard_xml,thread)
    else:
        print("- 2nd pass already done. To run again, please delete "+path_to_2nd_evidence)

def substitution_quantification_with_2nd_pass(path_to_subs,path_to_2nd_evidence,output_dir):
    subs = pd.read_csv(path_to_subs)
    evidence2 = pd.read_csv(path_to_2nd_evidence,sep='\t')
    intensities = {}
    min_PEP_intensity = {} # min PEP
    min_PEP = {} # min PEP

    # add up the intensity values for the same peptides
    for i in evidence2.index:
        if evidence2.at[i,'Intensity'] > 0:
            seq = evidence2.at[i,'Sequence']
            if not (seq in intensities):
                intensities[seq] = 0
                min_PEP_intensity[seq] = 0
                min_PEP[seq] = 1
            intensities[seq] += evidence2.at[i,'Intensity']
            if evidence2.at[i,'PEP'] < min_PEP[seq]:
                min_PEP[seq] = evidence2.at[i,'PEP']
                min_PEP_intensity[seq] = evidence2.at[i,'Intensity']

    # calculate intensity ratio
    uniq_subs = pd.DataFrame([],columns=['modified_sequence',
                                         'reference_sequence',
                                         'modified_intensity',
                                         'reference_intensity',
                                         'log10_mod_to_ref_intensity_ratio',
                                         'modified_min_PEP',
                                         'reference_min_PEP',
                                         'modified_intensity_min_PEP',
                                         'reference_intensity_min_PEP',
                                         'log10_mod_to_ref_intensity_ratio_min_PEP',
                                         'longest_protein',
                                         'protein_length',
                                         'position',
                                         'position_relative',
                                         'longest_protein_status',
                                         'codon',
                                         'destination',
                                         'origin',
                                         'mispairing',
                                         'positions',
                                         'proteins',
                                         'coding_status',
                                         'Retention time',
                                         'DP Time Difference'])

    computed=[]
    for i in subs.index:
        dpseq = subs.at[i,'modified_sequence']
        bpseq = subs.at[i,'DP Base Sequence']
        if not(dpseq in computed):
            computed.append(dpseq)
            if dpseq in intensities and bpseq in intensities:
                uniq_subs=uniq_subs.append(pd.DataFrame([[dpseq,
                                                          bpseq,
                                                          intensities[dpseq],
                                                          intensities[bpseq],
                                                          np.log10(intensities[dpseq]/intensities[bpseq]),
                                                          min_PEP[dpseq],
                                                          min_PEP[bpseq],
                                                          min_PEP_intensity[dpseq],
                                                          min_PEP_intensity[bpseq],
                                                          np.log10(min_PEP_intensity[dpseq] / min_PEP_intensity[bpseq]),
                                                          subs.at[i,'longest_protein'],
                                                          subs.at[i,'protein_length'],
                                                          subs.at[i,'position'],
                                                          subs.at[i,'position_relative'],
                                                          subs.at[i,'longest_protein_status'],
                                                          subs.at[i,'codon'],
                                                          subs.at[i,'destination'],
                                                          subs.at[i,'origin'],
                                                          subs.at[i,'mispairing'],
                                                          subs.at[i,'positions'],
                                                          subs.at[i,'proteins'],
                                                          subs.at[i,'coding_status'],
                                                          subs.at[i,'Retention time'],
                                                          subs.at[i,'DP Time Difference']
                                                         ]], columns=uniq_subs.columns))
    uniq_subs.to_csv(os.path.join(output_dir,'uniq_subs.csv'))

def substitution_filter(path_to_uniq_subs,path_to_variant_peptide,path_to_proteome,path_to_contaminant):

    '''
    if os.path.isfile(path_to_uniq_subs[:-4]+'-filtered.csv'):
        print("- skip variant filter: results already found at: "+path_to_uniq_subs[:-4]+'-filtered.csv')
        return 0
    '''

    uniq_subs = pd.read_csv(path_to_uniq_subs)
    print("- unique peptides identified: "+str(len(uniq_subs)))

    # remove peptides whose base peptides cannot be mapped to the proteome, mostly trypsin peptides
    uniq_subs = uniq_subs[pd.notnull(uniq_subs['proteins'])]
    print("- after removing those with base peptides cannot be mapped to the proteome : "+str(len(uniq_subs)))

    # remove peptides also found in canonical proteome
    n=0
    if os.path.isfile(path_to_proteome):
        cont = open(path_to_proteome).read().replace("\n","")
        for i in uniq_subs.index:
            if uniq_subs.at[i,'modified_sequence'] in cont:
                uniq_subs.drop(i,inplace=True)
                n=n+1
        print("- peptides discarded for matching canonical proteome: "+str(n))
    else:
        print("- skip proteome filter: file not found or not set: "+path_to_proteome)

    # remove peptides also found in potential contaminant sequence
    #uniq_subs['contaminant'] = 0
    n=0
    if os.path.isfile(path_to_contaminant):
        cont = open(path_to_contaminant).read().replace("\n","")
        for i in uniq_subs.index:
            if uniq_subs.at[i,'modified_sequence'] in cont:
                #uniq_subs.at[i,'contaminant'] = 1
                uniq_subs.drop(i,inplace=True)
                n=n+1
        print("- peptides discarded as potential contaminant: "+str(n))
    else:
        print("- skip contaminant filter: file not found or not set: "+path_to_contaminant)

    print("- likely antibody sequences: "+str(sum(uniq_subs['longest_protein_status'] != 'normal')))

    # mark substitutions that have been observed before, in recombinant proteins (usually CHO cells) or native proteins in mammalian cells
    # https://www.sciencedirect.com/science/article/pii/S073497501730126X?via%3Dihub
    # recomb only: not found in native, but may be found in ecoli
    # ecoli only: not found in recomb or native mammalian proteins, only in ecoli
    known_substitutions  =                ['A to T',
                                           'A to V',
                                           'D to G', # recomb only, # PTM
                                           'D to E',                # PTM
                                           'D to N',                # PTM
                                           'E to K',
                                           'F to I',
                                           'F to L',
                                           'G to D', # recomb only
                                           'G to E',             # ecoli only
                                           'G to R',             # ecoli only
                                           'G to S',             # ecoli only
                                           'H to Q',             # ecoli only
                                           'H to Y',
                                           'K to R', # recomb only
                                           'L to F',
                                           'L to K',              # ecoli only
                                           'L to V',              # ecoli only
                                           'M to I',
                                           'M to L',
                                           'M to T',
                                           'N to K', # recomb only
                                           'N to S', # recomb only
                                           'P to I',            # ecoli only
                                           'P to L',            # ecoli only
                                           'P to S',              # ecoli only
                                           'Q to H',              # ecoli only
                                           'R to G', # recomb only
                                           'R to K',
                                           'R to Q',              # ecoli only
                                           'S to I',
                                           'S to L',
                                           'S to N', # recomb only
                                           'S to R', # recomb only
                                           'S to T',              # ecoli only
                                           'T to S', # recomb only
                                           'T to I',
                                           'T to L',
                                           'V to A',
                                           'V to I',
                                           'V to L',
                                           'V to M',              # ecoli only
                                           'Y to F', # recomb only
                                           'Y to H', # recomb only
                                           'Y to N']              # ecoli]

    recombinant_only_substitutions = [     'D to G', # recomb only
                                           'G to D', # recomb only
                                           'K to R', # recomb only
                                           'N to K', # recomb only
                                           'N to S', # recomb only
                                           'R to G', # recomb only
                                           'S to N', # recomb only
                                           'S to R', # recomb only
                                           'T to S', # recomb only
                                           'Y to F', # recomb only
                                           'Y to H'] # recomb only

    ecoli_only_substitutions = [           'G to E',             # ecoli only
                                           'G to R',             # ecoli only
                                           'G to S',             # ecoli only
                                           'H to Q',             # ecoli only
                                           'L to K',              # ecoli only
                                           'L to V',              # ecoli only
                                           'P to L',            # ecoli only
                                           'P to I',            # ecoli only
                                           'P to S',              # ecoli only
                                           'Q to H',              # ecoli only
                                           'R to Q',              # ecoli only
                                           'S to T',              # ecoli only
                                           'V to M',              # ecoli only
                                           'Y to N']              # ecoli only
    # potential PTMs, ignoring positions
    potential_PTMs = [
        'A to E',
        'A to G',
        'A to Q',
        'A to S',
        'D to A',
        'D to G',
        'D to E',
        'D to H',
        'D to N',
        'E to A',
        'E to D',
        'E to Q',
        'F to E',
        'F to V',
        'F to Y',
        'G to A',
        'G to D',
        'G to N',
        'H to N',
        'I to V',
        'I to N',
        'I to Q',
        'I to R',
        'L to V',
        'L to N',
        'L to Q',
        'L to R',
        'K to R',
        'K to W',
        'M to S',
        'N to G',
        'N to P',
        'P to E',
        'P to Q',
        'P to S',
        'P to T',
        'Q to A',
        'Q to N',
        'R to K',
        'S to G',
        'T to G',
        'T to A',
        'T to D',
        'T to S',
        'V to F',
        'V to M',
        'V to N',
        'V to D',
        'Y to D']
    #
    uniq_subs['known_substitution'] = ''
    uniq_subs['potential_PTM'] = ''
    n_known = 0
    n_ptm = 0
    for i in uniq_subs.index:
        subs = uniq_subs.at[i,'origin']+' to '+uniq_subs.at[i,'destination']
        if subs in known_substitutions:
            uniq_subs.at[i,'known_substitution'] = 'native'
            n_known += 1
            if subs in recombinant_only_substitutions:
                uniq_subs.at[i,'known_substitution'] = 'recombinant_only'
            elif subs in ecoli_only_substitutions:
                uniq_subs.at[i,'known_substitution'] = 'ecoli_only'
        if subs in potential_PTMs:
            uniq_subs.at[i,'potential_PTM'] = 'potential_PTM'
            n_ptm += 1
    print("- marked as known substitution types: "+str(n_known))
    print("- marked as potential PTM without position filter: "+str(n_ptm))

    # SNPs
    uniq_subs['SNV'] = 0
    n=0
    if os.path.isfile(path_to_variant_peptide):
        variant_pep = open(path_to_variant_peptide).read().replace("\n","")
        for i in uniq_subs.index:
            if uniq_subs.at[i,'modified_sequence'] in variant_pep:
                uniq_subs.at[i,'SNV'] = 1
                n=n+1
        print("- peptides marked as potential SNP peptides: "+str(n))
    else:
        print("- skip variant filter: variant peptide file not found or not set: "+path_to_variant_peptide)
    uniq_subs.to_csv(path_to_uniq_subs[:-4]+'-filtered.csv')

def plotting(output_dir):

    uniq_subs = pd.read_csv(output_dir+'/uniq_subs-filtered.csv')

    # histogram of error rate
    nbin = 30

    fig, axs = plt.subplots(2, 1, sharex=True, sharey=True, tight_layout=True)
    d = uniq_subs[uniq_subs.longest_protein_status == 'normal']
    _, bins, _ = axs[0].hist(d.log10_mod_to_ref_intensity_ratio,nbin,alpha=.3,label='Normal,'+str(len(d)))
    axs[0].hist(d.log10_mod_to_ref_intensity_ratio[d.mispairing==1],bins=bins,alpha=.3,label='near-cognate,'+str(sum(d.mispairing==1)))
    axs[0].hist(d.log10_mod_to_ref_intensity_ratio[d.SNV==1],bins=bins,alpha=.3,label='SNV,'+str(sum(d.SNV==1)))
    axs[0].legend()

    # antibody
    d = uniq_subs[uniq_subs.longest_protein_status != 'normal']
    axs[1].hist(d.log10_mod_to_ref_intensity_ratio,bins=bins,alpha=.3,label='Antibody,'+str(len(d)))
    axs[1].hist(d.log10_mod_to_ref_intensity_ratio[d.mispairing==1],bins=bins,alpha=.3,label='near-cognate,'+str(sum(d.mispairing==1)))
    axs[1].hist(d.log10_mod_to_ref_intensity_ratio[d.SNV==1],bins=bins,alpha=.3,label='SNV,'+str(sum(d.SNV==1)))
    axs[1].legend()
    plt.savefig(output_dir+'/uniq-subs-intensity-ratio-hist.pdf')

    # other plots only look at non SNPs, with log10_mod_to_ref_intensity_ratio < -1
    # in aggregate plots, can use SNPs as background to see bias in positions like 3rd codon position GU wobble pair?
    d = uniq_subs[uniq_subs.log10_mod_to_ref_intensity_ratio < -1]

    # plot aa to aa heatmap
    aa2aa = aa_to_aa_count_matrix(d)
    plot_matrix(np.log2(aa2aa+1),output_dir+'/uniq-subs-aa2aa-log-heatmap.pdf',10)
    aa2aa.to_csv(output_dir+'/uniq-subs-aa2aa-matrix.csv', header=True, index=True, float_format='%d')

    # plot codon to aa heatmap
    d = uniq_subs[uniq_subs.log10_mod_to_ref_intensity_ratio < -1]
    codon2aa = codon_to_aa_count_matrix(d)
    #codon2aa = codon_to_aa_count_matrix(uniq_subs,'','') # do not mask stop codons or PTMs
    #codon2aa = codon_to_aa_count_matrix(uniq_subs,'mask stop codons','mask PTM') # do not mask stop codons or PTMs
    #codon2aa = codon_to_aa_count_matrix(uniq_subs,'delete stop codons','mask PTM') # do not mask stop codons or PTMs

    plot_matrix(np.log2(codon2aa+1),output_dir+'/uniq-subs-codon2aa-log-heatmap.pdf')
    codon2aa.to_csv(output_dir+'/uniq-subs-codon2aa-matrix.csv', header=True, index=True, float_format='%d')

    # plot codon to aa heatmap, mispairing only
    d = uniq_subs[uniq_subs.log10_mod_to_ref_intensity_ratio < -1]
    codon2aa = codon_to_aa_count_matrix(d[d['mispairing']==1])
    plot_matrix(np.log2(codon2aa+1),output_dir+'/uniq-subs-codon2aa-mispairing-only-log-heatmap.pdf')
    codon2aa.to_csv(output_dir+'/uniq-subs-codon2aa-mispairing-only-matrix.csv', header=True, index=True, float_format='%d')

def plot_matrix(m,filename,fontsize=5):
    fig, ax = plt.subplots()
    im = ax.imshow(m,cmap='magma')

    ax.set_facecolor("gray")

    # We want to show all ticks...
    ax.set_xticks(np.arange(len(m.columns)))
    ax.set_yticks(np.arange(len(m.index)))
    # ... and label them with the respective list entries
    ax.set_xticklabels(m.columns,fontsize=fontsize)
    ax.set_yticklabels(m.index,fontsize=fontsize)

    # Rotate the tick labels and set their alignment.
    plt.setp(ax.get_xticklabels(), rotation=0, ha="center",
             rotation_mode="anchor")

    # Loop over data dimensions and create text annotations.
    '''
    for i in range(len(index)):
        for j in range(len(column)):
            text = ax.text(j, i, m[i, j],ha="center", va="center", color="w")
    '''

    #ax.set_title("Title")
    fig.tight_layout()
    #plt.show()
    plt.savefig(filename)

    '''
    # example
    index = ["AAA", "CCC", "UUU", "GGG", "CGA", "GUG", "UGG"]
    columns = list('ABCDEFG')
    d = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                            [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                            [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                            [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                            [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                            [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                            [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])
    m = pd.DataFrame(data = d, index = index, columns=columns,dtype=float)
    plot_matrix(m,'test.pdf')
    '''

def codon_to_aa_count_matrix(uniq_subs):
    # mask_stop_codons: 'mask stop codons' or 'delete stop codons' or else
    # mask_potential_PTMs: 'mask PTM' or else

    uniq_subs = uniq_subs[pd.notnull(uniq_subs['codon'])]
    uniq_subs['codon'] = uniq_subs['codon'].map(lambda x: x.replace('T','U'))
    counts = uniq_subs[['codon','destination','origin']].groupby(['codon','destination']).count()
    #print(counts.index)

    bases = 'UCAG'
    codons = [a+b+c for a in bases for b in bases for c in bases]
    matrix = pd.DataFrame(data = 0, index = codons, columns=list('ACDEFGHKLMNPQRSTVWY'),dtype=float)

    for codon,destination in counts.index:
        matrix.loc[codon,destination] = counts.origin[codon][destination]

    #print(matrix.index)

    # the following code will gray out stop codons or delete them
    for label in matrix.index:
        ## the following code will gray out stop codons
        if label == 'UGA' or label == 'UAG' or label == 'UAA':
            #if mask_stop_codons == 'mask stop codons':
            matrix.loc[label] = 0 #float('NaN')
            #elif mask_stop_codons == 'delete stop codons':
            #    matrix.drop(label)

    amino_acids = 'FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG'
    codon_table = get_codon_table(codons,amino_acids)
    inverted_codon_table = get_inverted_codon_table(codons,amino_acids)
    inverted_codon_table['L'] = inverted_codon_table['L'] + inverted_codon_table['I']

    exact_PTM_spec_list =   ['A to I',
                                 'A to L',
                                 'S to T',
                                 'S to D',
                                 'S to E',
                                 'P to E',
                                 'T to E',
                                 'N to D',
                                 'N to Q',
                                 'N to C',
                                 'D to E',
                                 'Q to E',
                                 'K to C',
                                 'F to C',
                                 'F to Y']

    ## the following code will gray out potential PTM substitutions
    #print(matrix.index)
    for label in matrix.index:
        for col in matrix.columns:
            if (label in inverted_codon_table[col]) or (codon_table[label] +' to '+col in exact_PTM_spec_list):
                matrix.loc[label, col] = 0#float('NaN')

    matrix.rename(columns={"L": "I\nL"},inplace=True)

    # add aa to codons as row name
    for label in matrix.index:
        matrix.at[label,'new-index'] = label+'-'+codon_table[label]
    matrix.set_index('new-index',inplace=True)

    return matrix

def aa_to_aa_count_matrix(uniq_subs):
    exact_PTM_spec_list =   ['A to I',
                             'A to L',
                             'S to T',
                             'S to D',
                             'S to E',
                             'P to E',
                             'T to E',
                             'N to D',
                             'N to Q',
                             'N to C',
                             'D to E',
                             'Q to E',
                             'K to C',
                             'F to C',
                             'F to Y']
    matrix = pd.DataFrame(data = 0, index =list('ACDEFGHKLMNPQRSTVWY'), columns=list('ACDEFGHKLMNPQRSTVWY'),dtype=float)
    for i in uniq_subs.index:
        matrix.loc[uniq_subs.at[i,'origin'].replace('I','L'),uniq_subs.at[i,'destination']] += 1
    matrix.rename(columns={"L": "I\nL"},inplace=True)
    matrix.rename(index={"L": "I/L"},inplace=True)

    for label in matrix.index:
        for col in matrix.columns:
            if label +' to '+col in exact_PTM_spec_list:
                matrix.loc[label, col] = 0#float('NaN')

    return matrix

def merge(folder):
    # merge the uniq_subs file from multiple samples
    data = []
    for f in os.scandir(folder):
        if f.is_dir():
            sample = f.name
            if os.path.isfile(folder+'/'+sample+'/substitution/uniq_subs-filtered.csv'):
                uniq_subs = pd.read_csv(folder+'/'+sample+'/substitution/uniq_subs-filtered.csv')
                uniq_subs['sample'] = sample
                data.append(uniq_subs)
                print(sample)
    alldata = pd.concat(data)
    alldata.to_csv(folder+'/uniq_subs-filtered.csv')
    plotting(folder)

# NOT USED!!! slows the analysis by a lot
def parse_fragments(header,translation,min_pep_len):
    '''
    generate fasta output for a translated peptides containing stop codons:
    header: fasta header to be used
    translation: amino acid sequence containing stop codons, e.g. NNNN*NNNNN*NNNN*NN
    min_pep_len: 7, shortest peptides to consider

    example output:

    >header1
    NNNN
    >header2
    NNNNN
    >header3
    NNNN
    '''
    translations = translation.split('*')
    n = 0
    fasta_block = ''
    for translation in translations:
        if len(translation) >= min_pep_len:
            n = n + 1
            fasta_block = fasta_block + header +str(n) + '\n' + translation + '\n'
    return fasta_block

if __name__ == "__main__":

    parser = argparse.ArgumentParser()

    parser.add_argument('input_dir',help='Required. Path to a folder with raw data (*.raw) (exception: see --merge)')

    parser.add_argument("--analysis", dest='analysis', action='store',default='canonical',
                         help='combination of canonical, frameshift, utr, lncrna, intron, and substitution separated by comma (no space). Default: canonical')

    parser.add_argument("--output-dir",action='store',default='NA',
                         help='Output folder name. Default: same as input')

    parser.add_argument("--transcriptome", action='store',default=transcriptome,
                         help='Path to transcriptome fasta file. See README for details')

    parser.add_argument("--proteome", action='store',default=proteome,
                         help='Path to proteome fasta file')

    parser.add_argument("--contaminant", action='store',default=contaminant,
                         help='Path to contaminant fasta file')

    parser.add_argument("--variant", action='store',default=variant,
                         help='Path to variant peptides created by SNV. To skip, set it NA')

    parser.add_argument("--substitution-xml", dest='template_xml_substitution', action='store',default=template_xml_substitution,
                         help='A template xml file for substitution detection')

    parser.add_argument("--standard-xml", dest='template_xml_standard', action='store',default=template_xml_standard,
                         help='A template xml file for standard MaxQuant search')

    parser.add_argument("--thread", dest='thread', action='store',default=4,type=int,
                         help='Number fo threads for MaxQuant. Default: 4')

    parser.add_argument("--merge", action='store_true',
                         help='merge output from multiple substitution analysis. Each folder under input dir is one sample')

    args = parser.parse_args()

    if args.merge:
        merge(args.input_dir)
        exit(0)

    # check the number of *.raw files in the input folder
    args.input_dir = os.path.abspath(args.input_dir)
    nSample = valid_raw_folder(args.input_dir)
    if nSample < 0: # folder not found
        exit()

    # the default output folder is the input folder
    if args.output_dir == 'NA':
        args.output_dir = args.input_dir
    # create the output folder if not exist
    if not os.path.isdir(args.output_dir):
        os.mkdir(args.output_dir)

    # start the analysis pipeline
    analyses = args.analysis.lower().split(',')

    # for analysis other than 'substitution'
    for analysis in analyses:

        if analysis == 'substitution':
            continue

        # create sub-folder for specific type of analysis (canonical,frameshift, utr, lncrna, intron etc)
        output_dir = args.output_dir +'/'+analysis
        if not os.path.isdir(output_dir):
            os.mkdir(output_dir)

        # generate custom proteome if not aligning to the canonical proteome
        path_to_custom_proteome = args.proteome
        if analysis != 'canonical':
            path_to_custom_proteome = generate_custom_proteome(analysis)

        # print to screen the parameters
        print("=========================================")
        print("analysis         : "+analysis)
        print("=========================================")
        print("- proteome       : "+path_to_custom_proteome)
        print("- variant        : "+args.variant)
        print("- template xml   : "+args.template_xml_standard)
        print("- thread         : "+str(args.thread))
        print("- output         : "+output_dir)
        print("- input          : "+args.input_dir)
        print("                   " + str(nSample) + " raw file(s)")

        # run maxquant
        maxquant_standard_search(path_to_custom_proteome,args.input_dir,output_dir,args.template_xml_standard,args.thread)

        if analysis != 'canonical':
            npep = filter_maxquant_result(output_dir,args.proteome,args.variant)

    # substitution

    if 'substitution' in args.analysis.lower():

        args.output_dir = args.output_dir +'/substitution'

        print("Path to files:")
        print("- proteome          : "+args.proteome)
        print("- variant           : "+args.variant)
        print("- transcriptome     : "+args.transcriptome)
        print("- contaminant       : "+args.contaminant)
        print("- template xml      : "+args.template_xml_substitution)
        print("- thread            : "+str(args.thread))
        print("- output            : "+args.output_dir)
        print("- input             : "+args.input_dir)
        print("                      " + str(nSample) + " raw file(s)")

        # dependent peptide search by MaxQuant
        if os.path.isfile(args.output_dir+'/combined/txt/allPeptides.txt'):
            print("MaxQuant search results detected in the output folder "+args.output_dir)
            print("- to run MaxQuant again, please change output directory")
        else:
            print("Generate MaxQuant parameter file (xml)")
            generate_xml(args.template_xml_substitution,args.input_dir,args.output_dir,args.proteome,args.thread)
            print("MaxQuant search of dependent peptides")
            cmd = MaxQuantCmd+ " " + args.output_dir + "/mqpar.xml"
            print('- '+cmd)
            os.system(cmd)
            print("Deleting intermediate files from MaxQuant run")
            clean_up_after_maxquant_run(args.input_dir,args.output_dir)

        # identify potential substitutions
        if os.path.isfile(args.output_dir+'/subs.csv'):
            print("Substitution detection results found ")
            print("- to run again, please delete the file "+args.output_dir+'/subs.csv')
        else:
            print("Substitution detection and filtering")
            substitution_detection_and_filtering(args.input_dir,args.output_dir,args.transcriptome)
            #import detect
            #import quantify
            #import plot

        # standard maxquant search to get intensity of substitutions
        print("Second pass")
        substitution_second_pass(args.output_dir+'/subs.csv',args.input_dir,args.output_dir,args.template_xml_standard,args.thread)
        print("Substitution quantification")
        substitution_quantification_with_2nd_pass(args.output_dir+'/subs.csv',args.output_dir+'/second_pass/combined/txt/evidence.txt',args.output_dir)
        print("Additional filters")
        substitution_filter(args.output_dir+'/uniq_subs.csv',args.variant,args.proteome,args.contaminant)
        print("Plotting results")
        plotting(args.output_dir)


from django.conf.urls import url
from .views import *

urlpatterns=[
		url(r'^Add_Inventory/$',Add_Inventory,name="Add_Inventory"),
		url(r'^List_Inventory/$',List_Inventory,name="List_Inventory"),
		url(r'^Add_Category/$',Add_Category,name="Add_Category"),
		url(r'^Edit_Inventory/(\d+)/$',Edit_Inventory,name="Edit_Inventory"),
		url(r'^Delete_Inventario/(\d+)/$',Delete_Inventario,name="Delete_Inventario"),
	]


from django import forms
from django.forms import ModelChoiceField
from .models import Provider

class ProviderForm(forms.ModelForm):

	#region = ModelChoiceField(queryset = Region.objects.all())

	class Meta:
		model = Provider
		fields = ['ruc','businessName','status','region','province','distric','registrationDate','address','phone','postal','email','contactName','contactPhone']

	def __init__(self,*args, **kwargs):
		super(ProviderForm,self).__init__(*args,**kwargs)

		self.fields['ruc'].widget.attrs.update({'class' : 'form-control','id' : 'ruc','name' : 'ruc', 'type' : 'number','min' : '0', 'placeholder' : 'Ingrese el RUC..'})
		self.fields['businessName'].widget.attrs.update({'class' : 'form-control','id' : 'businessName','name' : 'businessName', 'type' : 'text', 'placeholder' : 'Ingrese el nombre de su compañía..'})
		self.fields['status'].widget.attrs.update({'class' : 'form-control','id' : 'status','name' : 'status', 'size' : '1',  'placeholder' : 'Seleccione un estado..'})
		self.fields['region'].widget.attrs.update({'class' : 'form-control','id' : 'region','name' : 'region', 'placeholder' : 'Ingrese la región..'})
		self.fields['province'].widget.attrs.update({'class' : 'form-control','id' : 'province','name' : 'province', 'type' : 'text', 'placeholder' : 'Ingrese la provincia..'})
		self.fields['distric'].widget.attrs.update({'class' : 'form-control','id' : 'distric','name' : 'distric', 'type' : 'text', 'placeholder' : 'Ingrese el distrito..'})
		self.fields['registrationDate'].widget.attrs.update({'class' : 'js-datepicker form-control', 'data-date-format' : 'yyyy-mm-dd', 'id' : 'registrationDate','name' : 'registrationDate', 'placeholder' : 'Ingrese una fecha..'})
		self.fields['registrationDate'].widget.format = '%Y-%m-%d'
		self.fields['registrationDate'].input_formats = ['%Y-%m-%d']
		self.fields['address'].widget.attrs.update({'class' : 'form-control','id' : 'address','name' : 'address', 'type' : 'text', 'placeholder' : 'Ingrese la dirección..'})
		self.fields['phone'].widget.attrs.update({'class' : 'form-control','id' : 'phone','name' : 'phone', 'type' : 'text','min' : '0', 'placeholder' : 'Ingrese el teléfono..'})
		self.fields['postal'].widget.attrs.update({'class' : 'form-control','id' : 'postal','name' : 'postal','min' : '0', 'placeholder' : 'Ingrese el código postal..'})
		#self.fields['effectiveTime'].widget.attrs.update({'class' : 'form-control','id' : 'effectiveTime','name' : 'effectiveTime', 'type' : 'text','min' : '0', 'placeholder' : 'Ingrese el tiempo de vigencia..'})
		self.fields['email'].widget.attrs.update({'class' : 'form-control','id' : 'email','name' : 'email', 'type' : 'text', 'placeholder' : 'Ingrese el email..'})
		self.fields['contactName'].widget.attrs.update({'class' : 'form-control','id' : 'contactName','name' : 'contactName', 'type' : 'text', 'placeholder' : 'Ingrese nombre de contacto..'})
		self.fields['contactPhone'].widget.attrs.update({'class' : 'form-control','id' : 'contactPhone','name' : 'contactPhone', 'type' : 'text','min' : '0', 'placeholder' : 'Ingrese el número de contacto..'})
		#'style':'text-align:right;'


#otviram soubor se seznamem karet, rozdeluji jedotlive karty jako seznam seznamu
soubor = open('karty.txt', 'r', encoding='utf-8')
karty = [radek.strip() for radek in soubor]
karty_split = [radek.split(" ") for radek in karty]
soubor.close()

#nahodne vybiram prvky seznamu a vybrane ze seznamu mazu, aby se v tazich neopakovaly
import random
prvni_tah = random.choice(karty_split)
prvni_index = karty_split.index(prvni_tah)
del karty_split[prvni_index]

druhy_tah = random.choice(karty_split)
druhy_index = karty_split.index(druhy_tah)
del karty_split[druhy_index]

treti_tah = random.choice(karty_split)
treti_index = karty_split.index(treti_tah)
del karty_split[treti_index]

ctvrty_tah = random.choice(karty_split)

#prejmenovavam string hodnoty na cislo, aby se daly secist a scitam hodnoty vybranych karet
hodnoty = [prvni_tah[0], druhy_tah[0], treti_tah[0], ctvrty_tah[0]]
list_pro_soucet = [hodnoty.replace("kluk", "10") for hodnoty in hodnoty]
list_pro_soucet1 = [hodnoty.replace("dáma", "10") for hodnoty in list_pro_soucet]
list_pro_soucet2 = [hodnoty.replace("král", "10") for hodnoty in list_pro_soucet1]
list_pro_soucet3 = [hodnoty.replace("eso", "1") for hodnoty in list_pro_soucet2]
soucet = sum([int(hodnoty) for hodnoty in list_pro_soucet3])
print(f'tahy: {prvni_tah, druhy_tah, treti_tah, ctvrty_tah}, soucet:{soucet}')


import unittest
from typing import Optional

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

    def __str__(self):
        if self.next is None:
            return f'{self.val}'

        return f'{self.val}->{self.next.__str__()}'

class Solution:
    def reverse(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        prev, curr = None, head

        while curr and k:
            forward = curr.next
            curr.next = prev
            prev = curr
            curr = forward
            k -= 1

        return prev

    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        tmp = head
        for _ in range(k):
            if tmp is None:
                return head

            tmp = tmp.next

        prev = self.reverse(head, k)
        head.next = self.reverseKGroup(tmp, k)

        return prev

class TestListNode(unittest.TestCase):
    def testCase1(self):
        head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
        self.assertEqual(Solution().reverseKGroup(head, 3).__str__(), '3->2->1->4->5', '3->2->1->4->5')
    def testCase2(self):
        head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
        self.assertEqual(Solution().reverseKGroup(head, 2).__str__(), '2->1->4->3->5', '2->1->4->3->5')

if __name__ == '__main__':
    unittest.main()


#!/usr/bin/env python3

'''
Author: Daniel Del Hoyo Gomez
Script that creates a file with LOCALIZER outnput that classifies the
proteins in compartments. To use by location_filter.py

Input: python3 ids_location.py <Localizer_results_folder> cytoplasm(T|[F])
'''

from sys import argv,exit
import subprocess as sbp
import os

def all_prots(res_file):
    '''Return a list with all proteins identifiers
    '''
    prots=[]
    with open(res_file) as filex:
        for line in filex:
            if not line.startswith('#'):
                if len(line.split())>0 and line.split()[0]!='Identifier':
                    prots+=[line.split()[0]]
    return prots

def write_id_location(loc_file,outname,class_prots):
    loca_file=loc_file.split('/')[-1]
    if loca_file.startswith('chloroplast'):
        loc='ch'
    elif loca_file.startswith('mitochondria'):
        loc='mt'
    elif loca_file.startswith('nucleus'):
        loc='nc'
    else:
        return class_prots

    f=open(outname,'a')
    with open(loc_file) as filex:
        for line in filex:
            if line.startswith(">"):
                idi=line.split()[0].replace(">","")
                class_prots+=[idi]
                f.write('{}\t{}\n'.format(idi,loc))

    f.close()
    return class_prots

def add_cyto(prots,class_prots,outname):
    '''Add cytoplasm location for not classified proteins
    '''

    with open(outname,'a') as f:
        for p in prots:
            if not p in class_prots:
                f.write('{}\tct\n'.format(p))

if __name__=="__main__":
    locali_folder=argv[1]
    if len(argv)>2:
        cyto=argv[2]
        outname=locali_folder+'ids_location_cyto.txt'
    else:
        cyto=False
        outname=locali_folder+'ids_location.txt'

    locali_files=os.listdir(locali_folder)

    with open(outname,'w'):
        pass
    class_prots=[]
    for resu in locali_files:
        class_prots=write_id_location(locali_folder+resu,outname,class_prots)

    if cyto in ['t','T','true','True']:
        prots=all_prots(locali_folder+'Results.txt')
        add_cyto(prots,class_prots,outname)


import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from utils import mulaw_decode
from tqdm import tqdm

def get_gru_cell(gru):
    gru_cell = nn.GRUCell(gru.input_size, gru.hidden_size)
    gru_cell.weight_hh.data = gru.weight_hh_l0.data
    gru_cell.weight_ih.data = gru.weight_ih_l0.data
    gru_cell.bias_hh.data = gru.bias_hh_l0.data
    gru_cell.bias_ih.data = gru.bias_ih_l0.data
    return gru_cell

class Vocoder(nn.Module):
    def __init__(self, mel_channels, conditioning_channels, embedding_dim,
                 rnn_channels, fc_channels, bits, hop_length):
        super().__init__()
        self.rnn_channels = rnn_channels
        self.quantization_channels = 2**bits
        self.hop_length = hop_length

        self.rnn1 = nn.GRU(mel_channels, conditioning_channels, num_layers=2, batch_first=True, bidirectional=True)
        self.embedding = nn.Embedding(self.quantization_channels, embedding_dim)
        self.rnn2 = nn.GRU(embedding_dim + 2 * conditioning_channels, rnn_channels, batch_first=True)
        self.fc1 = nn.Linear(rnn_channels, fc_channels)
        self.fc2 = nn.Linear(fc_channels, self.quantization_channels)

    def forward(self, x, mels):
        sample_frames = mels.size(1)
        audio_slice_frames = x.size(1) // self.hop_length
        pad = (sample_frames - audio_slice_frames) // 2

        mels, _ = self.rnn1(mels)
        mels = mels[:, pad:pad + audio_slice_frames, :]

        mels = F.interpolate(mels.transpose(1, 2), scale_factor=self.hop_length)
        mels = mels.transpose(1, 2)

        x = self.embedding(x)

        x, _ = self.rnn2(torch.cat((x, mels), dim=2))

        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

    def generate(self, mel):
        self.eval()

        output = []
        cell = get_gru_cell(self.rnn2)

        with torch.no_grad():
            mel, _ = self.rnn1(mel)

            mel = F.interpolate(mel.transpose(1, 2), scale_factor=self.hop_length)
            mel = mel.transpose(1, 2)

            batch_size, sample_size, _ = mel.size()

            h = torch.zeros(batch_size, self.rnn_channels, device=mel.device)
            x = torch.zeros(batch_size, device=mel.device).fill_(self.quantization_channels // 2).long()

            for m in tqdm(torch.unbind(mel, dim=1), leave=False):
                x = self.embedding(x)
                h = cell(torch.cat((x, m), dim=1), h)

                x = F.relu(self.fc1(h))
                logits = self.fc2(x)

                posterior = F.softmax(logits, dim=1)
                dist = torch.distributions.Categorical(posterior)

                x = dist.sample()
                output.append(2 * x.float().item() / (self.quantization_channels - 1.) - 1.)

        output = np.asarray(output, dtype=np.float64)
        output = mulaw_decode(output, self.quantization_channels)

        self.train()
        return output


import hmac
import traceback
from datetime import datetime
from datetime import timezone

from flask import request
from flask_restful import Resource
from flask_jwt_extended import (
    create_access_token,
    create_refresh_token,
    jwt_required,
    get_jwt_identity,
    get_jwt
)
from libs.mailgun import MailGunException
from schemas.user import UserSchema
from models.user import UserModel, TokenBlocklist
from models.confirmation import ConfirmationModel
from libs.strings import get_text

user_schema = UserSchema()

class UserRegister(Resource):
    @classmethod
    def post(cls):
        user_json = request.get_json()
        user = user_schema.load(user_json)

        if UserModel.find_by_username(user.username):
            return {'message': get_text("user_already_exists")}, 400

        if UserModel.find_by_email(user.email):
            return {'message': get_text("user_email_already_exists")}, 400

        try:
            user.save_to_db()
            confirmation = ConfirmationModel(user.id)
            confirmation.save_to_db()
            user.send_confirmation_email()
            return {"message": get_text("user_created_successfully")}, 201
        except MailGunException as e:
            user.delete_from_db()
            return {"message", str(e)}, 500
        except:
            traceback.print_exc()
            user.delete_from_db()
            return {"message": get_text("user_failed_to_create")}, 500

class User(Resource):
    @classmethod
    def get(cls, user_id: int):
        user = UserModel.find_by_id(user_id)
        if not user:
            return {'message': get_text("user_not_found")}, 404

        return user_schema.dump(user), 200

    @classmethod
    def delete(cls, user_id: int):
        user = UserModel.find_by_id(user_id)
        if not user:
            return {'message': get_text("user_not_found")}, 404

        user.delete_from_db()
        return {'message': get_text("user_deleted")}, 200

class UserLogin(Resource):
    @classmethod
    def post(cls):
        user_json = request.get_json()
        user_data = user_schema.load(user_json, partial=("email",))

        user = UserModel.find_by_username(user_data.username)

        if user and hmac.compare_digest(user.password, user_data.password):
            confirmation = user.most_recent_confirmation
            if confirmation and confirmation.confirmed:
                access_token = create_access_token(identity=user.id, fresh=True)
                refresh_token = create_refresh_token(user.id)
                return {
                           'access_token': access_token,
                           'refresh_token': refresh_token
                       }, 200
            return {'message:': get_text("user_not_confirmed_error").format(user.username)}, 400

        return {'message': get_text("user_invalid_credentials")}, 401

class UserLogout(Resource):
    @classmethod
    @jwt_required()
    def post(cls):
        jti = get_jwt()["jti"]
        now = datetime.now(timezone.utc)
        token_blocklist = TokenBlocklist(jti, now)
        token_blocklist.save_to_db()
        return {'message': get_text("user_logged_out")}, 200

class TokenRefresh(Resource):
    @classmethod
    @jwt_required(refresh=True)
    def post(cls):
        current_user = get_jwt_identity()
        new_token = create_access_token(identity=current_user, fresh=False)
        return {'access_token': new_token}, 200


import pytest

from typing import Union, Optional

from fractions import Fraction

from recipe_grid.scaled_value_string import ScaledValueString as SVS

from recipe_grid.renderer.table import Table, Cell, BorderType

from recipe_grid.recipe import (
    Quantity,
    Proportion,
    Ingredient,
    SubRecipe,
    Reference,
    Step,
)

from recipe_grid.renderer.html import (
    t,
    render_number,
    render_quantity,
    render_proportion,
    render_scaled_value_string,
    render_ingredient,
    generate_subrecipe_output_id,
    render_reference,
    render_step,
    render_sub_recipe_header,
    render_sub_recipe_outputs,
    render_cell,
    render_table,
    render_recipe_tree,
)

class TestT:
    def test_minimal_tag(self) -> None:
        assert t("foo") == "<foo />"

    def test_no_child_with_attrs(self) -> None:
        assert t("foo", bar="baz") == '<foo bar="baz"/>'
        assert t("foo", bar="baz", quo="qux") == '<foo bar="baz" quo="qux"/>'

    def test_underscore_postfix_removal(self) -> None:
        assert t("foo", class_="baz") == '<foo class="baz"/>'

    def test_dunderscore_to_hyphen_substitution(self) -> None:
        assert t("foo", data__foo="bar") == '<foo data-foo="bar"/>'

    def test_empty_body(self) -> None:
        assert t("foo", "") == "<foo></foo>"

    def test_with_body_and_attrs(self) -> None:
        assert t("foo", "", bar="baz") == '<foo bar="baz"></foo>'
        assert t("foo", "", bar="baz", quo="qux") == '<foo bar="baz" quo="qux"></foo>'

    def test_single_line_body(self) -> None:
        assert t("foo", "bar") == "<foo>bar</foo>"

    def test_single_line_body_with_trailing_newline(self) -> None:
        assert t("foo", "bar\n") == "<foo>\n  bar\n</foo>"

    def test_multi_line_body(self) -> None:
        assert t("foo", "bar\nbaz") == "<foo>\n  bar\n  baz\n</foo>"

    def test_escape_attr_values(self) -> None:
        assert (
            t("foo", bar="in 'quotes\" here") == '<foo bar="in \'quotes" here"/>'
        )

@pytest.mark.parametrize(
    "number, exp",
    [
        # Integer
        (123, "123"),
        # Float
        (1.23456, "1.23"),
        # Fraction
        (Fraction(2, 3), "2⁄3"),
        # Improper fraction
        (Fraction(5, 3), "1 2⁄3"),
    ],
)
def test_render_number(number: Union[float, int, Fraction], exp: str) -> None:
    assert render_number(number) == exp

@pytest.mark.parametrize(
    "quantity, exp",
    [
        # Unitless
        (
            Quantity(123),
            '123',
        ),
        # Unitless with preposition
        (
            Quantity(123, preposition=" of>"),
            '123 of>',
        ),
        # Custom (unknown) unit with HTML char in
        (
            Quantity(123, "<foo>"),
            '123<foo>',
        ),
        # Custom unit with spacing and preposition
        (
            Quantity(123, "<foo>", value_unit_spacing=" < ", preposition=" of>"),
            (
                ''
                "123 < <foo> of>"
            ),
        ),
        # Known unit (with non normative name given and with fractional and
        # floating point conversions).
        (
            Quantity(Fraction(1, 2), "Kilos"),
            (
                '\n'
                '  1⁄2Kilos
\n'
                "
500g
\n"
                "
1.1lb
\n"
                "
17.6oz
\n"
                "
\n"
                ""
            ),
        ),
        # Again but with custom spacing
        (
            Quantity(Fraction(1, 2), "Kilos", value_unit_spacing=" "),
            (
                '\n'
                '  1⁄2 Kilos
\n'
                "
500 g
\n"
                "
1.1 lb
\n"
                "
17.6 oz
\n"
                "
\n"
                ""
            ),
        ),
    ],
)
def test_render_quantity(quantity: Quantity, exp: str) -> None:
    assert render_quantity(quantity) == exp

@pytest.mark.parametrize(
    "proportion, exp",
    [
        # Remainder
        (
            Proportion(None, remainder_wording="left over"),
            'left over',
        ),
        # Remainder with preposition
        (
            Proportion(None, remainder_wording="rest>", preposition=" of>"),
            'rest> of>',
        ),
        # Quantity (float)
        (
            Proportion(0.2, preposition="*>"),
            '0.2×>',
        ),
        # Quantity (percentage)
        (
            Proportion(0.5, preposition="% of", percentage=True),
            '50% of',
        ),
    ],
)
def test_render_proportion(proportion: Proportion, exp: str) -> None:
    assert render_proportion(proportion) == exp

@pytest.mark.parametrize(
    "string, exp",
    [
        # Pure string
        (SVS("Hello"), "Hello"),
        # HTML special chars in string
        (SVS("<Hello>"), "<Hello>"),
        # Scaled values formatted and spanned
        (
            SVS([1.2345, " < ", Fraction(5, 3)]),
            (
                '1.23'
                " < "
                '1 2⁄3'
            ),
        ),
    ],
)
def test_render_scaled_value_string(string: SVS, exp: str) -> None:
    assert render_scaled_value_string(string) == exp

@pytest.mark.parametrize(
    "ingredient, exp",
    [
        # Quantity-less
        (Ingredient(SVS("Air")), "Air"),
        # With quantity
        (
            Ingredient(SVS("apples"), Quantity(2)),
            '2 apples',
        ),
    ],
)
def test_render_ingredient(ingredient: Ingredient, exp: str) -> None:
    assert render_ingredient(ingredient) == exp

def test_generate_subrecipe_output_id() -> None:
    sub_recipe = SubRecipe(
        Ingredient(SVS("spam")),
        (SVS("foo"), SVS(["foo bar ", 123, " baz?"])),
    )
    assert generate_subrecipe_output_id(sub_recipe, 0, "qux-") == "qux-foo"
    assert generate_subrecipe_output_id(sub_recipe, 1, "qux-") == "qux-foo-bar-123-baz"

@pytest.mark.parametrize(
    "reference, exp",
    [
        # No amount (consumes whole thing)
        (
            Reference(
                SubRecipe(Ingredient(SVS("spam")), (SVS("foo"),)), 0, Proportion(1)
            ),
            'foo',
        ),
        # Non-whole proportion
        (
            Reference(
                SubRecipe(Ingredient(SVS("spam")), (SVS("foo"),)), 0, Proportion(None)
            ),
            (
                ''
                'remaining foo'
                ""
            ),
        ),
        (
            Reference(
                SubRecipe(Ingredient(SVS("spam")), (SVS("foo"),)),
                0,
                Proportion(0.5, preposition=" *"),
            ),
            '0.5 × foo',
        ),
        # Quantity
        (
            Reference(
                SubRecipe(Ingredient(SVS("spam")), (SVS("foo"),)), 0, Quantity(2)
            ),
            (
                ''
                '2 foo'
                ""
            ),
        ),
    ],
)
def test_render_reference(reference: Reference, exp: str) -> None:
    assert render_reference(reference, "sub-recipe-") == exp

def test_render_step() -> None:
    assert render_step(Step(SVS("fry"), (Ingredient(SVS("spam")),))) == "fry"

def test_render_sub_recipe_header() -> None:
    assert (
        render_sub_recipe_header(SubRecipe(Ingredient(SVS("spam")), (SVS("foo"),)))
        == "foo"
    )

def test_render_sub_recipe_outputs() -> None:
    assert render_sub_recipe_outputs(
        SubRecipe(Ingredient(SVS("spam")), (SVS("foo"), SVS("bar"), SVS("baz"))),
        "sub-recipe-",
    ) == (
        '
\n'
        '
foo
\n'
        '
bar
\n'
        '
baz
\n'
        "
"
    )

class TestRenderCell:
    def test_ingredient(self) -> None:
        assert (
            render_cell(Cell(Ingredient(SVS("spam"))))
            == 'spam	'
        )

    def test_reference(self) -> None:
        assert (
            render_cell(
                Cell(Reference(SubRecipe(Ingredient(SVS("spam")), (SVS("foo"),)), 0))
            )
            == 'foo	'
        )

    def test_step(self) -> None:
        assert (
            render_cell(Cell(Step(SVS("fry"), (Ingredient(SVS("spam")),))))
            == 'fry	'
        )

    def test_subrecipe_header(self) -> None:
        assert (
            render_cell(Cell(SubRecipe(Ingredient(SVS("spam")), (SVS("foo"),))))
            == 'foo	'
        )

    def test_subrecipe_outputs(self) -> None:
        assert render_cell(
            Cell(SubRecipe(Ingredient(SVS("spam")), (SVS("foo"), SVS("bar"))))
        ) == (
            '\n'
            '
\n'
            '
foo
\n'
            '
bar
\n'
            "
\n"
            "	"
        )

    def test_colspan(self) -> None:
        assert (
            render_cell(
                Cell(
                    Ingredient(SVS("spam")),
                    columns=3,
                ),
            )
            == 'spam	'
        )

    def test_rowspan(self) -> None:
        assert (
            render_cell(
                Cell(
                    Step(SVS("fry"), (Ingredient(SVS("spam")),)),
                    rows=3,
                ),
            )
            == 'fry	'
        )

    def test_edges(self) -> None:
        assert render_cell(
            Cell(
                Ingredient(SVS("spam")),
                border_top=BorderType.sub_recipe,
                border_left=BorderType.none,
                border_bottom=BorderType.sub_recipe,
                border_right=BorderType.none,
            ),
        ) == (
            'spam	'
        )

@pytest.mark.parametrize(
    "id, exp_attrs",
    [(None, ""), ("foo-bar", ' id="foo-bar"')],
)
def test_render_table(id: Optional[str], exp_attrs: str) -> None:
    assert render_table(
        Table.from_dict(
            {
                (0, 0): Cell(Ingredient(SVS("spam"))),
                (1, 0): Cell(Ingredient(SVS("eggs"))),
                (0, 1): Cell(
                    Step(
                        SVS("fry"), (Ingredient(SVS("spam")), Ingredient(SVS("eggs")))
                    ),
                    rows=2,
                ),
            }
        ),
        id=id,
    ) == (
        f'
\n'
        "
\n"
        '    spam	\n'
        '    fry	\n'
        "
\n"
        '
eggs
\n'
        "
"
    )

class TestRenderRecipeTree:
    def test_non_subrecipe(self) -> None:
        assert render_recipe_tree(Ingredient(SVS("spam"))) == (
            '
'
            "
"
            'spam	'
            "
"
            "
"
        )

    def test_single_output_hidden_subrecipe(self) -> None:
        assert render_recipe_tree(
            SubRecipe(Ingredient(SVS("spam")), (SVS("spam"),), show_output_names=False),
            "qux-",
        ) == (
            '
'
            "
"
            'spam	'
            "
"
            "
"
        )

    def test_multiple_output_hidden_subrecipe(self) -> None:
        assert render_recipe_tree(
            SubRecipe(
                Ingredient(SVS("spam")),
                (SVS("spam"), SVS("tin")),
                show_output_names=False,
            ),
            "qux-",
        ) == (
            ""
            '
\n'
            "
\n"
            '    spam	\n'
            '    \n'
            '
\n'
            '
spam
\n'
            '
tin
\n'
            "
\n"
            "    	\n"
            "
\n"
            "
"
        )


# import math
class Solution:
    def nthMagicalNumber(self, N, A, B):
        """
        :type N: int
        :type A: int
        :type B: int
        :rtype: int
        """
        # how many numbers are in A*B
        # counter = 0
        # for i in range(min(A,B),A*B+1):
        #     if i % A == 0 or i % B == 0:
        #         counter += 1
        #         if counter == N:
        #             return i
        # n_common = self.nCommonFactors(A, B)
        # if A%B == 0:
        #     counter = A
        # elif B%A == 0:
        #     counter = B
        # else:
        #     counter = A+B-math.factorial(n_common)
        lcm = self.lcm(A,B)
        counter = lcm//A+lcm//B-1
        n_AB = N // counter
        ret_val = n_AB * lcm
        # print(N, A, B)
        # print(lcm, counter, n_AB, ret_val)
        counter = counter * n_AB
        # print(N, counter)
        # N = N%counter
        n_a = 0
        n_b = 0
        # print(lcm, n_AB, ret_val, counter, N)
        while counter < N:
            if n_a * A == n_b * B:
                n_a += 1
                n_b += 1
            elif n_a * A < n_b * B:
                n_a += 1
            else:
                n_b += 1
            counter += 1
        return (ret_val+min(n_a*A, n_b*B))%1000000007

    def gcd(self, a, b):
        if b == 0:
            return a
        return self.gcd(b, a % b)

    def lcm(self, a, b):
        return (a * b) // self.gcd(a, b)

sol = Solution()

# print(sol.nCommonFactors(33333, 34919))
# print(sol.nCommonFactors(4, 6))
# print(sol.nCommonFactors(4, 8))
# 4, 8, 12, 16, 20, 24, 28, 32 = 8 = 32/4 + 32/8 - 4 = 8
# 4, 6, 8, 12, 16, 18, 20, 24 = 8 = 24/4 + 24/6 - 2
# 3, 6, 8, 9, 12, 15, 16, 18, 21, 24 = 10 = 24/3 + 24/8 - 1

print(sol.nthMagicalNumber(1, 2, 3), 2)
print(sol.nthMagicalNumber(4, 2, 3), 6)
print(sol.nthMagicalNumber(5, 2, 4), 10) # 2, 4, 6, 8
print(sol.nthMagicalNumber(3, 6, 4), 8)
# a, b, l = 39999, 40000, sol.lcm(39999, 40000)
# print(sol.lcm(39999, 40000), l/a+l/b-1)
print(sol.nthMagicalNumber(1000000000, 39999, 40000), 499900006)
# print(sol.nthMagicalNumber(99999999, 33333, 34919))


#!/usr/bin/env python3

import unittest

import torch
from captum.attr._core.saliency import Saliency
from captum.attr._core.neuron_gradient import NeuronGradient
from captum.attr._utils.gradient import _forward_layer_eval

from .helpers.basic_models import (
    BasicModel_ConvNet,
    BasicModel_MultiLayer,
    BasicModel_MultiLayer_MultiInput,
)
from .helpers.utils import assertArraysAlmostEqual, BaseTest

class Test(BaseTest):
    def test_simple_gradient_input_linear2(self):
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[0.0, 100.0, 0.0]], requires_grad=True)
        self._gradient_input_test_assert(net, net.linear2, inp, (0,), [4.0, 4.0, 4.0])

    def test_simple_gradient_input_linear1(self):
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[0.0, 100.0, 0.0]])
        self._gradient_input_test_assert(net, net.linear1, inp, (0,), [1.0, 1.0, 1.0])

    def test_simple_gradient_input_relu(self):
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[0.0, 5.0, 4.0]], requires_grad=True)
        self._gradient_input_test_assert(net, net.relu, inp, 0, [0.0, 0.0, 0.0])

    def test_simple_gradient_input_relu2(self):
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[0.0, 5.0, 4.0]])
        self._gradient_input_test_assert(net, net.relu, inp, 1, [1.0, 1.0, 1.0])

    def test_simple_gradient_multi_input_linear2(self):
        net = BasicModel_MultiLayer_MultiInput()
        inp1 = torch.tensor([[0.0, 100.0, 0.0]])
        inp2 = torch.tensor([[0.0, 100.0, 0.0]])
        inp3 = torch.tensor([[0.0, 100.0, 0.0]])
        self._gradient_input_test_assert(
            net,
            net.model.linear2,
            (inp1, inp2, inp3),
            (0,),
            ([12.0, 12.0, 12.0], [12.0, 12.0, 12.0], [12.0, 12.0, 12.0]),
            (3,),
        )

    def test_simple_gradient_multi_input_linear1(self):
        net = BasicModel_MultiLayer_MultiInput()
        inp1 = torch.tensor([[0.0, 100.0, 0.0]])
        inp2 = torch.tensor([[0.0, 100.0, 0.0]])
        inp3 = torch.tensor([[0.0, 100.0, 0.0]])
        self._gradient_input_test_assert(
            net,
            net.model.linear1,
            (inp1, inp2),
            (0,),
            ([5.0, 5.0, 5.0], [5.0, 5.0, 5.0]),
            (inp3, 5),
        )

    def test_matching_output_gradient(self):
        net = BasicModel_ConvNet()
        inp = torch.randn(2, 1, 10, 10, requires_grad=True)
        self._gradient_matching_test_assert(net, net.softmax, inp)

    def test_matching_intermediate_gradient(self):
        net = BasicModel_ConvNet()
        inp = torch.randn(3, 1, 10, 10)
        self._gradient_matching_test_assert(net, net.relu2, inp)

    def _gradient_input_test_assert(
        self,
        model,
        target_layer,
        test_input,
        test_neuron,
        expected_input_gradient,
        additional_input=None,
    ):
        grad = NeuronGradient(model, target_layer)
        attributions = grad.attribute(
            test_input, test_neuron, additional_forward_args=additional_input
        )
        if isinstance(expected_input_gradient, tuple):
            for i in range(len(expected_input_gradient)):
                assertArraysAlmostEqual(
                    attributions[i].squeeze(0).tolist(),
                    expected_input_gradient[i],
                    delta=0.1,
                )
        else:
            assertArraysAlmostEqual(
                attributions.squeeze(0).tolist(), expected_input_gradient, delta=0.1
            )

    def _gradient_matching_test_assert(self, model, output_layer, test_input):
        out = _forward_layer_eval(model, test_input, output_layer)
        gradient_attrib = NeuronGradient(model, output_layer)
        for i in range(out.shape[1]):
            neuron = (i,)
            while len(neuron) < len(out.shape) - 1:
                neuron = neuron + (0,)
            input_attrib = Saliency(
                lambda x: _forward_layer_eval(model, x, output_layer)[
                    (slice(None), *neuron)
                ]
            )
            sal_vals = input_attrib.attribute(test_input, abs=False)
            grad_vals = gradient_attrib.attribute(test_input, neuron)
            # Verify matching sizes
            self.assertEqual(grad_vals.shape, sal_vals.shape)
            self.assertEqual(grad_vals.shape, test_input.shape)
            assertArraysAlmostEqual(
                sal_vals.reshape(-1).tolist(),
                grad_vals.reshape(-1).tolist(),
                delta=0.001,
            )

if __name__ == "__main__":
    unittest.main()


#!/usr/bin/env python
#
#  Pan Tilt Servo Control
#  Execute with parameter ==> sudo python3 servoCtrl.py <pan_angle> <tilt_angle>
#
#  MJRoBot.org 01Feb18

from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

pan = 27
tilt = 17

GPIO.setup(tilt, GPIO.OUT) # white => TILT
GPIO.setup(pan, GPIO.OUT) # gray ==> PAN

def setServoAngle(servo, angle):
	assert angle >=30 and angle <= 150
	pwm = GPIO.PWM(servo, 50)
	pwm.start(8)
	dutyCycle = angle / 18. + 3.
	pwm.ChangeDutyCycle(dutyCycle)
	sleep(0.3)
	pwm.stop()

if __name__ == '__main__':
    for i in range (30, 160, 15):
        setServoAngle(pan, i)
        setServoAngle(tilt, i)

    for i in range (150, 30, -15):
        setServoAngle(pan, i)
        setServoAngle(tilt, i)

    setServoAngle(pan, 100)
    setServoAngle(tilt, 90)
    GPIO.cleanup()


from flask import Flask, render_template, request, redirect, session
import random

app = Flask(__name__)
app.secret_key = 'claveSecreta'

@app.route('/')
def index():
    numero = random.randint(1, 100)
    session.pop("numero")
    session.pop("TotalIntentos")
    session.pop("contador")
    session["numero"] = numero
    session["TotalIntentos"] = 5
    session["contador"] = 0
    print(session["numero"])
    return render_template("index.html", cantIntentos = session["TotalIntentos"])

@app.route('/guess',methods=['POST'])
def guess():
    num_buscar =  int(session["numero"])
    num_ingresado = int(request.form['num_ingresado'])

    if 'TotalIntentos' in session:
        session["contador"] += 1
        session["TotalIntentos"] -= 1

    if(int(session["TotalIntentos"]==0)):
        return render_template("endIntentos.html")
    else:
        if(num_buscar == num_ingresado):
            return redirect("/YouWin")
        elif (num_ingresado>num_buscar):
            return render_template("low.html", cantIntentos = session["TotalIntentos"])
        else:
            return render_template("high.html", cantIntentos = session["TotalIntentos"])

@app.route('/YouWin')
def NewWinner():
    return render_template("winner.html",numero=session["numero"],intentos=session["contador"])

@app.route('/winners',methods=['POST'])
def winner():
    User = []
    auxUser  = []
    if 'winner' in session:
        for i in session["winner"]:
            auxUser.append(i)
        newWinner = {'user': request.form['txt_winner'], 'oportunidades':session["contador"]}
        auxUser.append(newWinner)
        session["winner"] = auxUser
    else:
        newWinner = {'user': request.form['txt_winner'], 'oportunidades':session["contador"]}
        User.append(newWinner)
        session["winner"] = User
    return render_template("winners.html",students = session["winner"])

if __name__=="__main__":
    app.run(debug=True)


# Created by Zoltan Szeman
# 2020-05-28

import pygame

class Settings():
    """An object for the basic game settings."""
    def __init__(self):
        # screen settings
        self.size = (700, 600)
        self.color = 0, 0, 0
        # ball movement settings
        self.jump_speed = 1200.0
        self.gravity = 2000.0
        self.x_speed = 3
        self.fps = 120
        self.bounc_factor = 0.3

        #platform size, movement and color settings
        self.plat_w_min = 30
        self.plat_w_max = 150
        self.plat_h = 10
        self.plat_no = 10
        self.plat_vel = 1.0
        self.brown = (255, 255, 0)


from datetime import datetime as datetime
from discord.ext import commands
import discord, asyncio
from _cache import *
from _sql import *

class Linking(commands.Cog):
    def __init__(self, client):
        self.client = client

    # // Link their account
    @commands.command()
    async def link(self, ctx, user_hash:str):
        await ctx.message.delete()
        await ctx.send(embed=discord.Embed(description=f"{ctx.author.mention} required verification sent to your dm's", color=4669430), delete_after=3)

        try:
            await ctx.author.send(embed=discord.Embed(
                title="Confirmation  [15 Seconds]",
                description=f"{ctx.author.mention} enter the confirmation code from the **Rapid Review** app", color=4669430
            ))
            _confirmation = await self.client.wait_for(
                "message",
                check=lambda m: isinstance(m.channel, discord.channel.DMChannel) and m.author == ctx.author,
                timeout=15
            )

        # // If the user doesn't respond, return with an error embed
        except asyncio.TimeoutError:
            return await ctx.author.send(embed=discord.Embed(description=f"{ctx.author.mention} you did not respond in time", color=15158588))

        # // Check if the code is valid and update database
        _temp = await Cache().fetch_user_from_database("confirmations", user_hash)
        if _confirmation.content == _temp["codes"][1].split("   |   ")[1]:
            if not await SQL_CLASS().exists(f"SELECT * FROM connections WHERE user_id = {ctx.author.id}"):
                await SQL_CLASS().execute(f"INSERT INTO connections (user_hash, user_id, user_name) VALUES ('{user_hash}', {ctx.author.id}, '{ctx.author}')")
            else:
                await SQL_CLASS().execute(f"UPDATE connections SET user_hash = '{user_hash}' WHERE user_id = {ctx.author.id}")
            return await ctx.author.send(embed=discord.Embed(description=f"{ctx.author.mention} successfully linked your discord account", color=4669430))
        return await ctx.author.send(embed=discord.Embed(description=f"{ctx.author.mention} invalid code", color=15158588))

    # // Unlink their account
    @commands.command()
    async def unlink(self, ctx, user_hash:str):
        await ctx.message.delete()
        if await SQL_CLASS().exists(f"SELECT * FROM connections WHERE user_id = {ctx.author.id} AND user_hash = '{user_hash}'"):
            await SQL_CLASS().execute(f"DELETE FROM connections WHERE user_id = {ctx.author.id} AND user_hash = '{user_hash}'")
            return await ctx.author.send(embed=discord.Embed(description=f"{ctx.author.mention} successfully unlinked your discord account", color=4669430))
        return await ctx.author.send(embed=discord.Embed(description=f"{ctx.author.mention} that rapid user id is not linked to your account", color=15158588))

def setup(client):
    client.add_cog(Linking(client))

Rapid Review Discord Bot/cogs/linking.py


""":mod:`news.reporters.abstract` --- Abstract reporter base classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Provide abstract base classes for reporters.

"""
import copy
import functools
import aiohttp

class Reporter(object):
    """Abstract base class for all reporters."""

    def __init__(self, meta, backend, url=None,
                 dispatch_middlewares=None,
                 fetch_middlewares=None, **kwargs):
        self.url = url or meta.schedule.url
        self.meta = meta
        self.backend = backend

        self._fetch_middlewares = fetch_middlewares or []
        self._fetch_middlewares_applied = []
        self._dispatch_middlewares = dispatch_middlewares or []
        self._dispatch_middlewares_applied= []

    @classmethod
    def create_instance(
            cls, meta, backend, url=None,
            dispatch_middlewares=None,
            fetch_middlewares=None, **kwargs):
        """Create an reporter.

        :param url: A url to assign to a reporter.
        :type url: :class:`str`
        :param meta: Meta information of a reporter.
        :type meta: :class:`ReporterMeta`
        :param backend: A news backend to be used.
        :type backend: :class:`~news.backends.AbstractBackend` implementation
        :param dispatch_middlewares: Dispatch middlewares to apply.
        :type dispatch_middlewares: :class:`list`
        :param fetch_middlewares: Fetch middlewares to apply.
        :type fetch_middlewares: :class:`list`

        :returns: An instance of a `Reporter` implementation.
        :rtype: `Reporter` implementation.

        """
        return cls(meta=meta, backend=backend, url=url,
                   dispatch_middlewares=dispatch_middlewares,
                   fetch_middlewares=fetch_middlewares, **kwargs)

    @property
    def schedule(self):
        """(:class:`~news.models.AbstractSchedule` implementation) Schedule of
        the reporter."""
        return self.meta.schedule

    @property
    def options(self):
        """(:class:`dict`) Reporter options."""
        return self.schedule.options

    @property
    def owner(self):
        """(:class:`~news.models.AbstractModel` implementation)Owner of the
        reporter."""
        return self.meta.owner

    def report_news(self, *news):
        """Report news to the backend.

        :param *news: News to report to backend of the reporter.
        :type *news: Arbirtrary number of (:class:`~news.models.AbstractNews`)
            implementation.
        """
        self.backend.save_news(*news)

    async def fetch(self):
        """Fetches url of the reporter and returns news.

        :returns: Either a list of news or a news.
        :rtype: :class:`list` or `~news.models.AbstractNews` implemnetation.

        """
        async with aiohttp.get(self.url) as response:
            # return nothing if status code is not OK
            if response.status != 200:
                return None

            # make news from the response
            items = self.parse(await response.text())

            # return a single news if we have only one. return a list of news
            # if we have more than a single news.
            try:
                return (self.make_news(item) for item in items)
            except TypeError:
                item = items
                news = self.make_news(item)
                return news

    async def dispatch(self):
        """Dispatches the reporter to it's url and returns a list of news.

        Should be implemented by all reporter subclasses.  Defaults to rasing
        `NotImplementedError`.

        :returns: A list of news.
        :rtype: :class:`list`

        """
        raise NotImplementedError

    def parse(self, content):
        """Parses fetched response body into a list of items.

        Should be implemented by all reporter subclasses. Defaults to rasing
        `NotImplementedError`.

        :returns: A list of items each to be passed to `make_news` method.
        :rtype: :class:`list`

        """
        raise NotImplementedError

    def make_news(self, item):
        """Make a news instance from the passed item.

        Should be implemented by all reporter subclasses. Defaults to rasing
        `NotImplementedError`.

        :returns: An instance of `~news.models.AbstractNews` implementation.
        :rtype: :class:`~news.models.AbstractNews` implementation.

        """
        raise NotImplementedError

    def enhance(self):
        """Enhance the reporter with it's middlewares.

        Note that middlewares will be exhausted after the enhancement, leaving
        an empty lists.

        :returns: Ehanced reporter itself.
        :rtype: :class:`~news.reporters.Reporter`

        """
        self.enhance_fetch(*self._fetch_middlewares)
        self.enhance_dispatch(*self._dispatch_middlewares)
        self._fetch_middlewares = []
        self._dispatch_middlewares = []
        return self

    def enhance_dispatch(self, *middlewares):
        """Enhance the reporter's `dispatch()` method with middlewares.

        :param *middlewares: An arbitrary number of dispatch method enhancers.
        :type *middlewares: A function that takes a reporter and dispatch
            method as arguments and returns enhanced dispatch method.
        :returns: Enhanced reporter itself.
        :rtype: :class:`~news.reporters.Reporter`

        """
        for middleware in middlewares:
            self.dispatch = middleware(self, self.dispatch)
            self._dispatch_middlewares_applied.append(middleware)
        return self

    def enhance_fetch(self, *middlewares):
        """Enhance the reporter's `fetch()` method with middlewares.

        :param *middlewares: An arbitrary number of fetch method enhancers.
        :type *middlewares: A function that takes a reporter and fetch method
            as arguments and returns enhanced fetch method.

        """
        for middleware in middlewares:
            self.fetch = middleware(self, self.fetch)
            self._fetch_middlewares_applied.append(middleware)
        return self

    async def worth_to_report(self, news):
        """Decides whether the reporter should report the news to it's backend
        or not. The default implementation always returns `True`.

        :param news: A news to test it's worthiness.
        :type news: :class:`~news.models.AbstractNews` implementation.
        :returns: `True` if the news is expected to be worthy to report.
        :rtype: :class:`bool`

        """
        return True

    async def worth_to_visit(self, news, url):
        """Decides whether the reporter should visit the link of the news.
        The default implementation always returns `True`.

        :param news: A news that contains the link.
        :type news: :class:`~news.models.AbstractNews` implementation.
        :param url: A URL to test it's worthiness.
        :type url: :class:`str`
        :returns: `True` if the url of the news is expected to be worthy to
        visit.
        :rtype: :class:`bool`

        """
        return True