#!/usr/bin/env python

#    Amplicon: software for designing PCR primers on aligned DNA sequences.
#    Copyright (C) 2003  Simon Neil Jarman
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation as version 2.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    A copy of the GNU General Public License is available from the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#    http://www.gnu.org/licenses/gpl


from Tkinter import *
import tkFileDialog,tkSimpleDialog,tkMessageBox,sys,string,math

#Reads an .aln file and returns the data as a list of names and a congruent list of sequences# 
def read_aln(inseq):
    name=''
    names=[]
    sequence=''
    sequences=[]
    flag='no'
    for a in inseq:
        if (a=='\n' or a=='\r') and flag=='no':
            flag='no1'
        if (a=='\n' or a=='\r') and flag=='no1':
            flag='name' 
        if a==' ' and flag=='name':
            names=names+[name]
            name=''
            flag='seq'
        if (a=='\n' or a=='\r') and flag=='seq':
            sequences=sequences+[sequence]
            sequence=''
            flag='name'
        if a<>'\n' and a<>'\r' and flag=='name':
            name=name+a
        if a<>'\n' and a <>'\r' and a <>' ' and flag=='seq':
            sequence=sequence+a
    names2=[]
    for b in names:
        if b=='':
            break
        names2=names2+[b]
    sequences2=[]
    for c in names2:
        sequences2=sequences2+['']
    for d in range(0,len(sequences),len(names2)+1):
        for e in range(0,len(sequences2),1):
            sequences2[e]=str(sequences2[e])+str(sequences[d+e])
    return names2,sequences2

#Reads a .fas file and returns the data as a list of names and a congruent list of sequences# 
def read_fasta(inseq):
    inseq = inseq + '>'
    names = []
    name = ''
    sequences = []
    sequence = ''
    a = 0
    sw = 2
    for a in inseq:
        if a == '>':
            if sequence <> '':
                sequences = sequences + [sequence]
            sequence = ''
            sw = 0
        if (a == '\n' or a == '\r') and sw == 0:
            names = names + [name]
            name = ''
            sw = 1
        if sw == 0 and a <> '>' and a <> '\n' and a <> '\r':
            name = name + a
        if sw == 1 and a <> '\n' and a <> '\r' and sequence <> '\n' and sequence <> '\r':
            sequence = sequence + a
    return names, sequences

#Reads a .meg file and returns the data as a list of names and a congruent list of sequences# 
def read_meg(inseq):
    inseq=inseq+'\n\n'
    names = []
    name = ''
    sequences = []
    sequence = ''
    a = 0
    sw = 3
    while a < len(inseq):
        if inseq[a] == '#':
            sw=sw-1
        if inseq[a]=='\n' or inseq[a]=='\r':
            sw=sw-1
        if sw==0:
            b=a
            a=len(inseq)-1
        a=a+1
    while b < len(inseq):
        if sw==0 and inseq[b]=='#':
            sw=1
        if sw == 1 and inseq[b] <> '#' and inseq[b] <> '\n' and inseq[b] <> '\r' and inseq[b] <>' ':
            name = name + inseq[b]
        if sw==1 and name<>'' and (inseq[b] == '\n' or inseq[b] == '\r'):
            names = names + [name]
            name = ''
            sw = 0
        if sw == 0 and inseq[b] <> '\n'  and inseq[b] <> '\r' and inseq[b]<>'#':
            sequence = sequence + inseq[b]
        if sw==0 and inseq[b:b+2]=='\n\n':
            sequences = sequences + [sequence]
            sequence = ''
            sw = 1
        b = b + 1
    sequences=sequences[1:]
    return names, sequences

#A function to create a degenerate consensus sequence from a list of sequences#
def create_consensus(inseqs):
    aflags =[0]
    cflags =[0]
    gflags =[0]
    tflags =[0]
    xflags =[0]
    for a in range(0,len(inseqs[1]),1):
        aflags = aflags+[0]
        cflags = cflags+[0]
        gflags = gflags+[0]
        tflags = tflags+[0]
        xflags=xflags+[0]
    num = len(inseqs)-1
    while num > -1:
        z=str(inseqs[num])
        a = 0
        for a in range(0,len(inseqs[1]),1):
            if z[a]=='A' or z[a]=='R'or z[a]=='W'or z[a]=='N'or z[a]=='V'or z[a]=='H'or z[a]=='D'or z[a]=='M':
                aflags[a]=1
            if z[a]=='C' or z[a]=='Y'or z[a]=='S'or z[a]=='N'or z[a]=='V'or z[a]=='H'or z[a]=='B'or z[a]=='M':
                cflags[a]=1
            if z[a]=='G' or z[a]=='R'or z[a]=='S'or z[a]=='N'or z[a]=='V'or z[a]=='D'or z[a]=='B'or z[a]=='K':
                gflags[a]=1
            if z[a]=='T' or z[a]=='Y'or z[a]=='W'or z[a]=='N'or z[a]=='D'or z[a]=='H'or z[a]=='B'or z[a]=='K':
                tflags[a]=1
            if z[a]=='-' or z[a]=='*':
                xflags[a]=1
        num=num-1
    consensus =''
    a = 0
    for a in range(0,len(aflags),1):
        if aflags[a]==1 and cflags[a]==0 and gflags[a]==0 and tflags[a]==0:
            consensus =consensus+'A'
        if aflags[a]==0 and cflags[a]==1 and gflags[a]==0 and tflags[a]==0:
            consensus =consensus+'C'
        if aflags[a]==0 and cflags[a]==0 and gflags[a]==1 and tflags[a]==0:
            consensus =consensus+'G'
        if aflags[a]==0 and cflags[a]==0 and gflags[a]==0 and tflags[a]==1:
            consensus =consensus+'T'
        if aflags[a]==1 and cflags[a]==0 and gflags[a]==0 and tflags[a]==1:
            consensus =consensus+'W'
        if aflags[a]==0 and cflags[a]==1 and gflags[a]==1 and tflags[a]==0:
            consensus =consensus+'S'
        if aflags[a]==0 and cflags[a]==1 and gflags[a]==0 and tflags[a]==1:
            consensus =consensus+'Y'
        if aflags[a]==1 and cflags[a]==0 and gflags[a]==1 and tflags[a]==0:
            consensus =consensus+'R'
        if aflags[a]==1 and cflags[a]==1 and gflags[a]==1 and tflags[a]==1:
            consensus =consensus+'N'
        if aflags[a]==1 and cflags[a]==1 and gflags[a]==1 and tflags[a]==0:
            consensus =consensus+'V'
        if aflags[a]==1 and cflags[a]==1 and gflags[a]==0 and tflags[a]==1:
            consensus =consensus+'H'
        if aflags[a]==1 and cflags[a]==0 and gflags[a]==1 and tflags[a]==1:
            consensus =consensus+'D'
        if aflags[a]==0 and cflags[a]==1 and gflags[a]==1 and tflags[a]==1:
            consensus =consensus+'B'
        if aflags[a]==1 and cflags[a]==1 and gflags[a]==0 and tflags[a]==0:
            consensus =consensus+'M'
        if aflags[a]==0 and cflags[a]==0 and gflags[a]==1 and tflags[a]==1:
            consensus =consensus+'K'
        if aflags[a]==0 and cflags[a]==0 and gflags[a]==0 and tflags[a]==0:
            consensus =consensus+'-'
        if xflags[a]==1:
            last=consensus[len(consensus)-1:len(consensus)+1]
            consensus=consensus[:len(consensus)-1]
            last=string.lower(last)
            consensus=consensus+last
    return consensus[:len(consensus)-1]

#A function to find the consistent sites within a sequence and return these in a consensus sequence#
def create_consensus2(inseqs):
    first = inseqs[0]
    for a in range(0,len(inseqs),1):
        consensus=''
        test=inseqs[a]
        for b in range(0,len(first),1):
            if first[b]<>test[b]:
                consensus=consensus+'*'
            if first[b]==test[b]:
                consensus=consensus+first[b]
        first=consensus
    return consensus

#A function that returns the antisense strand of a given sense strand#
def complement(inseq):
    inseq=string.upper(inseq)
    complement =''
    messy = 'ACGTYRMWSKVHDBN-*'
    clean = 'TGCARYKWSMBDHVN-*'
    for a in range(0,len(inseq),1):
        for c in range(0,len(messy),1):
            if inseq[a]==messy[c]:
                complement = complement + clean[c]
    return complement

#A function that returns the reverse of a given sequence#
def reverse(inseq):
    reversed=''
    l=len(inseq)-1
    for a in range(l,-1,-1):
        reversed=reversed+inseq[a]
    return reversed

#A nice function that returns a list of the component sequences from a string for a degenerate sequence#
def regenerate(oligo):
    inp =   'ACGTRYSWKMBDVHN'
    deg = ['A','C','G','T','AG','CT','CG','AT','GT','AC','CGT','AGT','ACG','ACT','ACGT']
    grow = ['']
    newgrow = ['']
    for a in range(0,len(oligo),1):
        for b in range(0,15,1):
            if oligo[a] == inp[b]:
                if b > 3:
                    x = 0
                    newgrow = grow
                    while x < len(deg[b])-1:
                        newgrow = newgrow + grow
                        x = x + 1
                grow = newgrow
                n = 0
                x=0
                for c in range(0,len(grow),1):
                    grow[c] = grow[c]+deg[b][x]
                    n = n + 1
                    if n == len(grow)/len(deg[b]):
                        n = 0
                        x=x+1
    return grow

#A function that scores strong and weak Watson-Crick base pairs as 3 and 2 in perfectly-matched d.s. DNA#
def perfectmatch(inseq):
    score=0
    for a in inseq:
        if a == 'A' or a =='T':
            score=score+2
        if a=='G'or a=='C':
            score=score+3
    return score

#Function that returns degree of degeneracy of a given sequence#
def degeneracy(inseq):
    score=1
    for a in inseq:
        if a=='R' or a=='Y' or a=='S' or a=='W' or a=='M' or a=='K':
            score=score*2
        if a=='V' or a=='H' or a=='D' or a=='B':
            score=score*3
        if a=='N':
            score=score*4
    return score

#Function that returns GC% for a given sequence, allowing degenerate sites and gaps#
def gcper(inseq):
    iub='CGATYRMKWSVBHDN-*'
    gc=0
    gcmin=0
    gcmax=0
    space=0
    length=len(inseq)
    for a in inseq:
        for y in range(0,16,1):
            if a==iub[y]:
                if y<2:
                    gc=gc+1
                if y>3 and y<8:
                    gcmin=gcmin+1
                    gcmax=gcmax+1
                    gc=gc+0.5
                if y==8:
                    gc=gc-1
                if y==9:
                    gc=gc+1
                if y>9 and y<15:
                    gcmin=gcmin+1
                    gcmax=gcmax+1
                if y>14:
                    space=space+1
    length=float(length-space)
    if length<1:
        length=1
    gcp=(float(gc)/length)*100
    gclow=(float(gc-(gcmin/2))/(length))*100
    gchigh=(float(gc+(gcmax/2))/(length))*100
    return gcp,gclow,gchigh

#Calculation of Tm with nearest-neighbor bas stacking parameters#
def CalcTm1(seq):
    cat=float(MW.monovalent)
    NearPairsPlus = ['AA','AC','AG','AT',
                     'CA','CC','CG','CT',
                     'GA','GC','GG','GT',
                     'TA','TC','TG','TT']
    DeltaH =        [7.9,8.4,7.8,7.2,
                     8.5,8.0,10.6,7.8,
                     8.2,9.8,8.0,8.4,
                     7.2,8.2,8.5,7.9]
    DeltaS =        [22.2,22.4,21.0,20.4,
                     22.7,19.9,27.2,21.0,
                     22.2,24.4,19.9,22.4,
                     21.3,22.2,22.7,22,2]
    dH = 0
    dS = 0
    seq = seq+ ' '
    a = 0
    while a < len(seq):
        b = 0
        while b < len(NearPairsPlus):
            if seq[a-2:a] == NearPairsPlus[b]:
                dH = dH + DeltaH[b]
                dS = dS + DeltaS[b]
            b = b + 1
        a = a + 1
    a = a -1
    if seq[0]=='A' or seq[0]=='T' or seq[a] == 'A' or seq[a] == 'T':
        dH = dH + 2.3
        dS = dS + 4.1
    if seq[0]=='C'or seq[0]=='G' or seq[a]=='C'or seq[a]=='G':
        dH = dH + 0.1
        dS = dS - 2.8
    Tm = -dH * 1000 /(10.8-dS+(1.987*(math.log(0.00025)))) - 273.15 + (12*math.log(cat))
    return Tm

#simple Tm calculation#
def CalcTm2(seq):
    t=0
    for a in seq:
        if a=='A' or a=='T':
            t=t+2
        if a=='C' or a=='G':
            t=t+4
    return t

#another Tm calculation method#
def CalcTm3(seq):
    cat=float(MW.monovalent)
    den=float(MW.formamide)
    c=0
    g=0
    for a in seq:
        if a=='C':
            c=c+1
        if a =='G':
            g=g+1
    xc=float(c) / float(len(seq))
    xg=float(g) / float(len(seq))
    cg=xc+xg
    tm = 81.5 + (16.6 * math.log(cat*10)) + (41 * cg) - 500/(len(seq) - (0.62 * den))
    return tm

#A function for identifying complementarity between two sequences and returning lists of complementary pairs above a given threshold#
def complementarity(inseq,inseq2,threshold):
    matches = []
    max=1
    threshold=int(threshold)
    oligo="5' "+ inseq+" 3'"
    oligorev="3' "+reverse(inseq2)+" 5'"
    if inseq2=='':
        oligorev = ''
        a = len(oligo)-4
        while a > 1:
            oligorev = oligorev + oligo[a]
            a = a - 1
        oligorev="3' "+oligorev+" 5'"
    if len(oligo)>len(oligorev):
        d=len(oligo)-len(oligorev)
        while d>0:
            oligorev=oligorev+' '
            d=d-1
    if len(oligo)<len(oligorev):
        d=len(oligorev)-len(oligo)
        while d>0:
            oligo=' '+oligo
            d=d-1
    Toligo = oligo
    mid=u''
    for a in range(len(Toligo),0,-1):
        match = 0
        mid=''
        for b in range(0,len(oligorev)-3,1):
            inmatch=match
            if Toligo[b]=='C' and oligorev[b] =='G' or Toligo[b]=='G' and oligorev[b] =='C':
                match = match + 3
                mid=mid+u'\u2261'
            if Toligo[b]=='A' and oligorev[b] =='T' or Toligo[b]=='T' and oligorev[b] =='A':
                match = match + 2
                mid=mid+'='
            if MW.wobble==1:
                if Toligo[b]=='G' and oligorev[b] =='T' or Toligo[b]=='T' and oligorev[b] =='G':
                    match = match + 2
                    mid=mid+'~'
            if inmatch==match:
                mid=mid+' '
        if match > threshold:
            smatch = str(match)
            matches = matches+[Toligo]+[mid]+[oligorev]+[smatch]
            if int(match)>max:
                max=int(match)
        Toligo = ' '+ Toligo 
    Toligorev = oligorev
    for a in range(len(oligo),0,-1):
        match = 0
        mid=u''
        for b in range(0,len(oligorev)-3,1):
            inmatch=match
            if oligo[b]=='C' and Toligorev[b] =='G' or oligo[b]=='G' and Toligorev[b] =='C':
                match = match + 3
                mid=mid+u'\u2261'
            if oligo[b]=='A' and Toligorev[b] =='T' or oligo[b]=='T' and Toligorev[b] =='A':
                match = match + 2
                mid=mid+'='
            if MW.wobble==1:
                if oligo[b]=='G' and Toligorev[b] =='T' or oligo[b]=='T' and Toligorev[b] =='G':
                    match = match + 2
                    mid=mid+'~'
            if inmatch==match:
                mid=mid+' '
        if match > threshold:
            f=0
            for e in matches:
                if e == mid:
                    f=1
            if f <>1:
                smatch = str(match)
                matches = matches+[oligo]+[mid]+[Toligorev]+[smatch]
                if int(match) > max:
                    max=match
            Toligorev = ' '+ Toligorev 
    newmatches=[]
    while max>0:
        for a in range(3,len(matches)-1,4):
            if max==int(matches[a]):
                one=matches[a-3]
                two=matches[a-2]
                thr=matches[a-1]
                fou=matches[a]
                fou=str(fou)
                newmatches=newmatches+[one]+[two]+[thr]+[fou]
        max=max-1
    return newmatches

#A function to find hairpin loops of a given length that form within a given oligo and are over a set threshold of complementarity#
def hairpin(inseq,loopl,threshold):
    l=len(inseq)
    a=0
    max=1
    tops=[]
    bots=[]
    mids=[]
    matches=[]
    b=l
    while b >1:
        match=0
        mid=''
        top = "5' "+ inseq[:b-1]
        loop=inseq[b-1:b+loopl-1]
        bot=inseq[b+loopl-1:l+1]
        q=len(top)-len(bot)
        if q<0:
            q=q*-1        
        f=' '
        for a in range(1,q,1):
            f=f+' '
        top=top+u'\u2500'+loop
        revbot=''
        for a in range(len(bot)-1,-1,-1):
            revbot=revbot+bot[a]
        if len(top)-len(loop)-1>len(bot):
            bot=f+revbot
        if len(top)-len(loop)-1<len(bot):
            top=f+top
        for a in range(0,loopl,1):
            bot=bot+u'\u2500'
        bot=bot+u'\u2518'
        a=0
        while a <len(bot)-loopl:
            inmatch=match
            if top[a]=='C' and bot[a]=='G' or top[a]=='G' and bot[a]=='C':
                match = match + 3
                mid=mid+u'\u2261'
            if top[a]=='A' and bot[a]=='T' or top[a]=='T' and bot[a]=='A':
                match = match + 2
                mid=mid+u'='
            if MW.wobble==1:
                if top[a]=='T' and bot[a]=='G' or top[a]=='G' and bot[a]=='T':
                    match = match + 2
                    mid=mid+'~'
            if inmatch==match:
                mid=mid+' '
            a=a+1
        for a in range(0,loopl-1,1):
            mid=mid+' '
        mid=mid+u'\u2502'
        if match>threshold:
            tops=tops+[top]
            bots=bots+[bot]
            mids=mids+[mid]
            matches=matches+[match]
            if int(match)>max:
                max=int(match)
        top=''
        bot=''
        b=b-1
    newtops=[]
    newbots=[]
    newmids=[]
    newmatches=[]
    while max>0:
        for a in range(0,len(matches)-1,1):
            if max==int(matches[a]):
                newtops=newtops+[tops[a]]
                newbots=newbots+[bots[a]]
                newmids=newmids+[mids[a]]
                newmatches=newmatches+[matches[a]]
        max=max-1        
    return newtops,newmids,newbots,newmatches

#A function to find false priming sites for forward primers#
def falsepriming(inseq,inseq2):
    oligo="5' "+ inseq+" 3'"
    site="3' "+inseq2+" 5'"
    match = 0
    matches=[]
    mid=''
    for b in range(0,len(oligo)):
        mt=match
        if oligo[b]=='C' and site[b] =='G' or oligo[b]=='G' and site[b] =='C':
            match = match + 3
            mid=mid+u'\u2261'
        if oligo[b]=='A' and site[b] =='T' or oligo[b]=='T' and site[b] =='A':
            match = match + 2
            mid=mid+'='
        if MW.wobble==1:
            if oligo[b]=='G' and site[b] =='T' or oligo[b]=='T' and site[b] =='G':
                match = match + 2
                mid=mid+'~'
        if mt==match:
            mid=mid+' '
    matches = [oligo]+[mid]+[site]+[match]
    return matches

#A function to find false priming sites for reverse primers#
def revfalsepriming(inseq,inseq2):
    oligo="3' "+ inseq+" 5'"
    site="5' "+inseq2+" 3'"
    match = 0
    matches=[]
    mid=''
    for b in range(0,len(oligo)):
        mt=match
        if oligo[b]=='C' and site[b] =='G' or oligo[b]=='G' and site[b] =='C':
            match = match + 3
            mid=mid+u'\u2261'
        if oligo[b]=='A' and site[b] =='T' or oligo[b]=='T' and site[b] =='A':
            match = match + 2
            mid=mid+'='
        if MW.wobble==1:
            if oligo[b]=='G' and site[b] =='T' or oligo[b]=='T' and site[b] =='G':
                match = match + 2
                mid=mid+'~'
        if mt==match:
            mid=mid+' '
    matches = [oligo]+[mid]+[site]+[match]
    return matches

# shortcut key functions and bindings#
def openSC(event):
    MW.OpenFile()

def saveSC(event):
    MW.SaveAnal()

def quitSC(event):
    sys.exit()

def cutSC(event):
    MW.CutSeq()

def pasteSC(event):
    MW.PasteSeq()

def consensus1SC(event):
    MW.buttoncon()

def consensus2SC(event):
    MW.buttoncon2()

def fsearchSC(event):
    MW.fsearch()

def rsearchSC(event):
    MW.rsearch()

def searchparaSC(event):
    MW.setsearch()

def IUBSC(event):
    MW.IUB()

def primerselect1(event):
    x1=MW.alignment.canvasx(event.x)
    x1=int(x1/7)*7
    MW.primerline1(x1)
    MW.primerregion(x1,0)
    return

def primerselect2(event):
    x2=MW.alignment.canvasx(event.x)
    x2=int(x2/7)*7
    MW.primerregion(0,x2)
    return

#The class that contains the GUI widgets and many of the operations of the program#
class MainWin:
    def __init__(self,Tk):
        self.createWidgets()     
        self.outseq=0
        self.sense=0

    def createWidgets(self):
        self.menubar = Menu(root)
        self.filemenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='File   ', menu=self.filemenu)
        self.filemenu.add_command(label='Open Alignment File     [Ctrl-o]', command = self.OpenFile)
        self.filemenu.add_separator()
        self.filemenu.add_command(label='Save Open Primer Analyses    [Ctrl-s]', command = self.SaveAnal,state=DISABLED)
        self.filemenu.add_command(label='Save Alignment', command = self.SaveAln1,state=DISABLED)
        self.filemenu.add_separator()
        self.filemenu.add_command(label='Quit Amplicon    [Ctrl-q]', command = sys.exit)
        self.editmenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='Sequences ', menu=self.editmenu)
        self.editmenu.add_command(label='Cut Sequences    [F1]',command=self.CutSeq,state=DISABLED)
        self.editmenu.add_command(label='Paste Sequences    [F2]',command=self.PasteSeq,state=DISABLED)
        self.editmenu.add_command(label='Create Degenerate Sequence    [F3]', command = self.buttoncon,state=DISABLED)
        self.editmenu.add_command(label='Create Consistencies Sequence    [F4]', command = self.buttoncon2,state=DISABLED)
        self.editmenu.add_separator()
        self.editmenu.add_command(label='Tm Plot', command = self.PlotTm,state=DISABLED)
        self.editmenu.add_command(label='GC% Plot', command = self.PlotGC,state=DISABLED)
        self.editmenu.add_command(label='Return to Alignment', command = self.redrawalign,state=DISABLED)
        self.searchmenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='Search', menu=self.searchmenu)
        self.searchmenu.add_command(label='Search For Forward Primer Binding Sites   [F5]',command=self.fsearch,state=DISABLED)
        self.searchmenu.add_command(label='Search For Reverse Primer Binding Sites   [F6]',command=self.rsearch,state=DISABLED)
        self.analysemenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='Primers', menu=self.analysemenu)
        self.analysemenu.add_command(label='Forward Primer Tm', command = self.analysefp,state=DISABLED)
        self.analysemenu2= Menu(self.analysemenu, tearoff=0)
        self.analysemenu.add_cascade(label='Forward Primer False Priming',menu=self.analysemenu2,state=DISABLED)
        self.analysemenu2.add_command(label='in Excluded Group',command = self.forexb,state=DISABLED)
        self.analysemenu2.add_command(label='in Target Group',command = self.forfp,state=DISABLED)
        self.analysemenu.add_command(label='Forward Primer Self Complementarity', command = self.forselfcomp,state=DISABLED)
        self.analysemenu.add_command(label='Forward Primer Hairpins', command = self.forhp,state=DISABLED)
        self.analysemenu.add_separator()
        self.analysemenu.add_command(label='Reverse Primer Tm', command = self.analyserp,state=DISABLED)
        self.analysemenu3= Menu(self.analysemenu, tearoff=0)
        self.analysemenu.add_cascade(label='Reverse Primer False Priming',menu=self.analysemenu3,state=DISABLED)
        self.analysemenu3.add_command(label='in Excluded Group',command=self.revexb,state=DISABLED)
        self.analysemenu3.add_command(label='in Target Group',command=self.revfp,state=DISABLED)
        self.analysemenu.add_command(label='Reverse Primer Self Complementarity', command = self.revselfcomp,state=DISABLED)
        self.analysemenu.add_command(label='Reverse Primer Hairpins', command = self.revhp,state=DISABLED)
        self.analysemenu.add_separator()
        self.analysemenu.add_command(label='Amplified Fragment', command = self.analyseamp,state=DISABLED)
        self.analysemenu.add_command(label='Forward-Reverse Complementarity', command = self.bothcomp,state=DISABLED)
        self.settingsmenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='Settings', menu=self.settingsmenu)
        self.settingsmenu.add_command(label='Search Parameters   [F7]', command = self.setsearch)
        self.settingsmenu.add_command(label='Plots', command = self.setplot)
        self.settingsmenu.add_command(label='Tm Calculation', command = self.settm)
        self.settingsmenu.add_command(label='Hairpin Tests', command = self.sethairpin)
        self.settingsmenu.add_command(label='Primer Binding and Complementarity Tests',command = self.setcomplement)
        self.infomenu = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='Information', menu=self.infomenu)
        self.infomenu.add_command(label='About Amplicon', command = self.about)
        self.infomenu.add_command(label='Degenerate Codes for Nucleotides   [F8]', command = self.IUB)
        self.infomenu.add_command(label='Quick Tutorial', command = self.tutorial)
        root.config(menu=self.menubar)

        #Default Settings #
        self.names=[]
        self.sequences=[]
        self.searchlen=20
        self.searchdeg=16
        self.searchtm=60
        self.searchtmmax=70
        self.searchgclow=40
        self.searchgchigh=60
        self.search3set=1
        self.tmRad=1
        self.tmMeth=1
        self.monovalent=0.05
        self.formamide=0.0
        self.numcomp=4
        self.propcomp=40
        self.maxdegeneracy=64
        self.numhp=4
        self.minhplen=2
        self.maxhplenprop=40
        self.hpthresh=35
        self.ft=1
        self.scanlength=20
        self.scanMeth=1
        self.scandegeneracy=256
        self.wobble=1
        self.outseq=''
        self.fpbind5=0
        self.fpbind3=0
        self.rpbind5=0
        self.rpbind3=0
        self.primerx1=0
        self.primerx2=0
        self.alreadysearchedf=0
        self.alreadysearchedr=0
        self.threeprimetick=1

        # Blank widgets that are displayed upon command#
        self.pgcgraph=Canvas(root)
        self.ptmgraph=Canvas(root)
        self.gctitle=Text(root)
        self.tmtitle=Text(root)
        
        # Create Widgets #
        self.logotext=root.title()
        self.logo=Label(root,text=self.logotext)
        self.logo.config(font=('Arial',16),foreground='Dark Green')
        self.logo.grid(column=0,row=7,rowspan=2,sticky=W)

        dirs=sys.argv[0]
        for a in range(len(dirs)-1,1,-1):
            if dirs[a]=='/':
                break
        directory=dirs[:a+1]
        self.IconPath=directory+'AmpliconIconII.xbm'
        self.img=BitmapImage(self.IconPath)
        root.iconname(self.IconPath)

        self.sourcefiletitle=Label(root,font=('Arial',10),text=' Alignment source file:')
        self.sourcefiletitle.grid(row=4,sticky=SW)      

        self.sourcefile=Text(root, background='light yellow',font=('Arial',7),width=42,height=3)
        self.sourcefile.grid(column=0,row=5,sticky=SW,rowspan=2)
        self.sourcefile.insert(1.0,'None')
        self.sourcefile.config(state=DISABLED)
        
        self.titles=Listbox(root)
        self.titles.config(selectmode=EXTENDED,font=('courier',12),background = 'light yellow', height=20, width=30)
        self.titles.grid(column=0, row=0, sticky = E)
        self.selection=self.titles.curselection()

        self.alignment=Canvas(root)
        self.alignment.config(width = 704, height = 321, background = 'light yellow',wrap=None,scrollregion=(0,0,704,321),relief=SUNKEN,borderwidth=2)
        self.alignment.grid(column=2, row=0, columnspan=4)
        self.alignment.bind('<Button-1>',primerselect1)
        self.alignment.bind('<ButtonRelease-1>',primerselect2)

        self.outwin=Canvas(root)
        self.outwin.config(width=704,height=40,background='lightsteelblue',wrap=None,scrollregion=(0,0,704,30),borderwidth=2,relief=SUNKEN)
        self.outwin.grid(column=2,row=2,columnspan=4,sticky=S)
        self.outwin.bind('<Button-1>',primerselect1)
        self.outwin.bind('<ButtonRelease-1>',primerselect2)

        self.inwin=Canvas(root)
        self.inwin.config(width=704,height=40,background='light yellow',wrap=None,scrollregion=(0,0,704,40),borderwidth=2,relief=SUNKEN)
        self.inwin.grid(column=2,row=3,columnspan=4,rowspan=2,sticky=N)
        self.inwin.bind('<Button-1>',primerselect1)
        self.inwin.bind('<ButtonRelease-1>',primerselect2)

        self.o5label=Label(root,text="5'").grid(column=1, row=2,sticky=SE)
        self.i5label=Label(root,text="5'").grid(column=1, row=3,sticky=SE)
        self.i3label=Label(root,text="3'").grid(column=1, row=4,sticky=E)
        self.b5label=Label(root,text="5'").grid(column=1, row=6,sticky=E,pady=2)
        self.b3label=Label(root,text="  3'").grid(column=2, row=6,sticky=E,pady=2)
        self.b52label=Label(root,text="5'  ").grid(column=4, row=6,sticky=E,pady=2)
        self.b53label=Label(root,text="3'").grid(column=5, row=6,sticky=E,pady=2)

        self.vsb=Scrollbar(orient="vertical")
        self.vsb.grid(column=1, row=0,sticky = NS)
        self.vsb['command']=self.YscrollTwo
        self.alignment['yscrollcommand']=self.vsb.set

        self.xsb=Scrollbar(orient="horizontal")

        self.xsb.grid(column=2, row=1,columnspan = 4, sticky = EW)
        self.xsb['command']=self.XscrollTwo
        self.inwin['xscrollcommand']=self.xsb.set
        self.outwin['xscrollcommand']=self.xsb.set

        self.fentry=Entry(root)
        self.fentry.config(font=('courier',11),background = 'light green',width=44)
        self.fentry.grid(column=2, row=6, pady=0,sticky=W)
        self.fentry.bind('<Key>',self.fpres)

        self.flabel=Label(root,text=u'    \u2502    \u2502    \u2502    \u2502    \u2502    \u2502    \u2502    \u2502\n    5   10   15   20   25   30   35   40')
        self.flabel.config(font=('courier',11))
        self.flabel.grid(column=2,row=7,sticky=W)

        self.fbutton=Button(root, text=u'Primer for Forward Site \u21E9', font=('Arial',10),background = 'light green', command = self.buttonf)
        self.fbutton.grid(column=2, row=5,padx=5, pady=2,sticky=W)
        self.fbutton.bind('<Button-1>',self.fpres)

        self.rentry=Entry(root)
        self.rentry.config(font=('courier',11),background = 'light coral',width=44)
        self.rentry.grid(column=5, row=6,pady=0, sticky = W)
        self.rentry.bind('<Key>',self.rpres)

        self.rlabel=Label(root,text=u'    \u2502    \u2502    \u2502    \u2502    \u2502    \u2502    \u2502    \u2502\n    5   10   15   20   25   30   35   40')
        self.rlabel.config(font=('courier',11))
        self.rlabel.grid(column=5,row=7,sticky=W)

        self.rbutton=Button(root, text=u'Primer for Reverse Site \u21E9', font=('Arial',10), background = 'light coral', command = self.buttonr)
        self.rbutton.grid(column=5, row=5,padx=5,pady=2,sticky=W)
        self.rbutton.bind('<Button-1>',self.rpres)

        self.outbutton=Button(root, text=u'Excluded Group \u21E9', font=('Arial',10),background='lightsteelblue', command = self.buttonout)
        self.outbutton.grid(column=0, row=1,padx=3, sticky = NE,rowspan=2,pady=6)

        self.outname=Text(root,height=1, width=30,font=('courier',12),background = 'lightsteelblue')
        self.outname.grid(column=0,row=2,sticky=SW,pady=2)

        self.inbutton=Button(root, text=u' Target Group \u21E9    ', font=('Arial',10),background='light yellow', command = self.buttonin)
        self.inbutton.grid(column=0, row=1, sticky = NW,rowspan=2,pady=6)

        self.inname=Text(root,height=1, width=30,font=('courier',12),background='light yellow')
        self.inname.grid(column=0,row=3,sticky=NW,pady=2)

        a = self.place_names_sequences()

        #Displays the GNU GPL message upon startup#
        license=tkMessageBox.Message(icon='info', type='ok', message=self.logotext+' Copyright (C) 2003 by Simon Neil Jarman\n\n'+
                 "Amplicon comes with ABSOLUTELY NO WARRANTY.  This is free software and you are welcome "+
                 "to copy and redistribute it under the terms and conditions of the GNU General Public Licence,\n"+
                 "Copyright (C) 1989, 1991  http://www.gnu.org/licenses/gpl.txt",title='Amplicon License').show()

    #Allows the y-axis scrollbar to control multiple windows#
    def YscrollTwo(self,*args):
        apply(self.titles.yview,args)
        apply(self.alignment.yview,args)
        return None

    #Allows the x-axis scrollbar to control multiple windows#
    def XscrollTwo(self,*args):
        apply(self.alignment.xview,args)
        apply(self.inwin.xview,args)
        apply(self.outwin.xview,args)
        apply(self.ptmgraph.xview,args)
        apply(self.pgcgraph.xview,args)

    #Draws the alignment#
    def place_names_sequences(self):
        if self.names:
            self.editmenu.entryconfig(0,state=NORMAL)
            self.editmenu.entryconfig(1,state=NORMAL)
            self.editmenu.entryconfig(2,state=NORMAL)
            self.editmenu.entryconfig(3,state=NORMAL)
            self.editmenu.entryconfig(5,state=NORMAL)
            self.editmenu.entryconfig(6,state=NORMAL)
            self.filemenu.entryconfig(2,state=NORMAL)
            self.filemenu.entryconfig(3,state=NORMAL)
            self.alignment.delete(ALL)
        self.titles.delete('0',END)
        a=0
        while a < len(self.names):
            self.titles.insert(END,str(a+1)+'_'+self.names[a])
            a=a+1
        l=-9
        c=4
        for sequence in self.sequences:
            al=sequence
            l=l+16
            c=4
            for x in al:
                if x=='A':
                    self.alignment.create_text(c,l,text='A',fill='Red',font=('courier',11))
                if x=='C':
                    self.alignment.create_text(c,l,text='C',fill='Blue',font=('courier',11))
                if x=='T':
                    self.alignment.create_text(c,l,text='T',fill='Dark Green',font=('courier',11))
                if x=='G':
                    self.alignment.create_text(c,l,text='G',fill='Black',font=('courier',11))
                if x <> 'A' and x <>'C' and x<>'T' and x<>'G' and x <>'\n' and x <>'\r':
                    self.alignment.create_text(c,l,text=x,fill='Orange',font=('courier',11))
                if ((c-4)/7.0/5.0)==((c-4)/7/5):
                    n=str(c/7)
                    self.outwin.create_text(c-5-len(n)*3,12,text=n,fill='Dark Green',font=('courier',11))
                    self.outwin.create_line(c-7,0,c-7,8)
                    self.outwin.create_line(c-7,18,c-7,26)
                c=c+7
            a = len(al)
        if len(self.sequences)<18:
            for x in range(0,a,5):
                n=str(x)
                self.alignment.create_text(x*7-len(n)*3,(len(self.sequences)+1)*16,text=n,fill='Dark Green',font=('courier',11))
                self.alignment.create_line(x*7-3,len(self.sequences)*16,x*7-3,len(self.sequences)*16+7)
        self.alignment.config(scrollregion=(0,0,4+a*7,len(self.sequences)*16))
        self.inwin.config(scrollregion=(0,0,4+a*7,40))
        self.outwin.config(scrollregion=(0,0,4+a*7,40))

    #Draws the target group#
    def place_ingroup(self):
        self.inwin.delete(ALL)
        l=8
        c=4
        for x in self.sense:
            if x=='A':
                self.inwin.create_text(c,l,text='A',fill='Red',font=('courier',11))
            if x=='C':
                self.inwin.create_text(c,l,text='C',fill='Blue',font=('courier',11))
            if x=='T':
                self.inwin.create_text(c,l,text='T',fill='Dark Green',font=('courier',11))
            if x=='G':
                self.inwin.create_text(c,l,text='G',fill='Black',font=('courier',11))
            if x <> 'A' and x <>'C' and x<>'T' and x<>'G' and x <>'\n' and x <>'\r':
                self.inwin.create_text(c,l,text=x,fill='Orange',font=('courier',11))
            if x <> '-':
                self.inwin.create_line(c,18,c,22,fill='black')
            c=c+7
        l=30
        c=4
        for x in self.antisense:
            if x=='A':
                self.inwin.create_text(c,l,text='A',fill='Red',font=('courier',11))
            if x=='C':
                self.inwin.create_text(c,l,text='C',fill='Blue',font=('courier',11))
            if x=='T':
                self.inwin.create_text(c,l,text='T',fill='Dark Green',font=('courier',11))
            if x=='G':
                self.inwin.create_text(c,l,text='G',fill='Black',font=('courier',11))
            if x <> 'A' and x <>'C' and x<>'T' and x<>'G' and x <>'\n' and x <>'\r':
                self.inwin.create_text(c,l,text=x,fill='Orange',font=('courier',11))
            c=c+7
        self.inwin.config(scrollregion=(0,0,4+len(self.sense)*7,40))
        return

    #Draws the exluded group#
    def place_outgroup(self):
        self.outwin.delete(ALL)
        l=30
        c=4
        for x in self.outseq:
            if x=='A':
                self.outwin.create_text(c,l,text='A',fill='Red',font=('courier',11))
            if x=='C':
                self.outwin.create_text(c,l,text='C',fill='Blue',font=('courier',11))
            if x=='T':
                self.outwin.create_text(c,l,text='T',fill='Dark Green',font=('courier',11))
            if x=='G':
                self.outwin.create_text(c,l,text='G',fill='Black',font=('courier',11))
            if x <> 'A' and x <>'C' and x<>'T' and x<>'G' and x <>'\n' and x <>'\r':
                self.outwin.create_text(c,l,text=x,fill='Orange',font=('courier',11))
            c=c+7
            if ((c-4)/7.0/5.0)==((c-4)/7/5):
                n=str(c/7)
                self.outwin.create_text(c-5-len(n)*3,12,text=n,fill='Dark Green',font=('courier',11))
                self.outwin.create_line(c-7,2,c-7,8)
                self.outwin.create_line(c-7,19,c-7,25)
        self.outwin.config(scrollregion=(0,0,4+len(self.outseq)*7,40))

    #Places a vertical line on three windows when the left mouse button is pressed and the mouse pointer is within the windows#
    def primerline1(self,x):
        self.inwin.create_line(x,4,x,36,fill='black',tag='sel1')
        self.outwin.create_line(x,25,x,36,fill='black',tag='sel1')
        self.alignment.create_line(x,2,x,16*len(self.sequences),fill='black',tag='sel1')
        self.ptmgraph.create_line(x,307,x,318,fill='black',tag='sel1')
        self.pgcgraph.create_line(x,313,x,324,fill='black',tag='sel1')
        
    #Places a rectangle in three windows when the left mouse button is released and the mouse pointer is within the windows#
    def primerregion(self,x,x2):
        if self.primerx1 and self.primerx2:
            self.inwin.delete('sel2')
            self.outwin.delete('sel2')
            self.alignment.delete('sel2')
            self.ptmgraph.delete('sel2')
            self.pgcgraph.delete('sel2')
        if x:
            self.primerx1=x
        if x2:
            self.primerx2=x2
            self.inwin.delete('sel1')
            self.outwin.delete('sel1')
            self.alignment.delete('sel1')
            self.ptmgraph.delete('sel1')
            self.pgcgraph.delete('sel1')
            self.inwin.create_rectangle(self.primerx1,36,self.primerx2,4,tag='sel2')
            self.outwin.create_rectangle(self.primerx1,25,self.primerx2,36,tag='sel2')
            self.alignment.create_rectangle(self.primerx1,2,self.primerx2,16*len(self.sequences),tag='sel2')
            self.ptmgraph.create_rectangle(self.primerx1,307,self.primerx2,318,tag='sel2')
            self.pgcgraph.create_rectangle(self.primerx1,313,self.primerx2,324,tag='sel2')

    #Finds and marks differences between target and excluded group sequences#
    def differences(self):
        self.inwin.delete('diffs')
        self.outwin.delete('diffs')
        amatch='RWNVHDMarwnvhdm'
        cmatch='YSNVHBMcysnvhbm'
        gmatch='RSNVDBKgrsnvdbk'
        tmatch='YWNDHBKtywndhbk'
        gapmatch='acgtrymwksvhdbn'
        for a in range(0,len(self.sense)):
            if self.sense[a]<>self.outseq[a]:
                self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='yellow',outline='black',tag='diffs')
                self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='yellow',outline='black',tag='diffs')
                if self.sense[a]=='A':
                    for b in amatch:
                        if self.outseq[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.sense[a]=='C':
                    for b in cmatch:
                        if self.outseq[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.sense[a]=='G':
                    for b in gmatch:
                        if self.outseq[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.sense[a]=='T':
                    for b in tmatch:
                        if self.outseq[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.sense[a]=='-':
                    for b in gapmatch:
                        if self.outseq[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.outseq[a]=='A':
                    for b in amatch:
                        if self.sense[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.outseq[a]=='C':
                    for b in cmatch:
                        if self.sense[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.outseq[a]=='G':
                    for b in gmatch:
                        if self.sense[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.outseq[a]=='T':
                    for b in tmatch:
                        if self.sense[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
                if self.outseq[a]=='-':
                    for b in gapmatch:
                        if self.sense[a]==b:
                            self.inwin.create_rectangle(a*7+1,0,a*7+6,3,fill='orange',outline='black',tag='diffs')
                            self.outwin.create_rectangle(a*7+1,36,a*7+6,39,fill='orange',outline='black',tag='diffs')
        return

        
#Functions called from buttons on the screen#
    #Selects the excluded group sequence/es#
    def buttonout(self):
        root.config(cursor='watch')
        root.update()
        self.out=self.titles.curselection()
        self.out=self.out[0]
        self.out=int(self.out)
        title=self.names[self.out]
        self.outseq=self.sequences[self.out]
        self.outname.delete(1.0,END)
        self.outname.insert(1.0,title)
        self.filemenu.entryconfig(3,state=NORMAL)
        self.place_outgroup()
        if self.sense:
            self.place_names_sequences()
            self.place_ingroup()
            self.place_outgroup()
            self.differences()
        root.config(cursor='arrow')
        root.update()
        return

    #Selects the target group sequence/es#
    def buttonin(self):
        root.config(cursor='watch')
        root.update()
        self.ing=self.titles.curselection()
        self.ing=self.ing[0]
        self.ing=int(self.ing)
        self.sense=self.sequences[self.ing]
        title=self.names[self.ing]
        self.antisense = complement(self.sense)
        self.inname.delete(1.0,END)
        self.inname.insert(1.0,title)
        self.searchmenu.entryconfig(0,state=NORMAL)
        self.searchmenu.entryconfig(1,state=NORMAL)
        self.filemenu.entryconfig(3,state=NORMAL)
        self.place_ingroup()
        if self.outseq:
            self.place_names_sequences()
            self.place_ingroup()
            self.place_outgroup()
            self.differences()
        root.config(cursor='arrow')
        root.update()
        return

    #selects the forward primer#
    def buttonf(self):
        if self.primerx1>self.primerx2:
            self.primerx1,self.primerx2=self.primerx2,self.primerx1
        self.fpbind5=int(self.primerx1/7)
        self.fpbind3=int(self.primerx2/7)
        forw=self.sense[self.fpbind5:self.fpbind3]
        self.inwin.delete('sel2')
        self.outwin.delete('sel2')
        self.alignment.delete('sel2')
        self.ptmgraph.delete('sel2')
        self.pgcgraph.delete('sel2')
        forw2=''
        for a in forw:
            if a<>'-':
                forw2=forw2+a
        forw2=self.primerin(forw2)
        if not forw2:
            return
        self.fentry.delete(0,END)
        self.fentry.insert(0,forw2)
        self.inwin.delete('forward')
        self.outwin.delete('forward')
        self.alignment.delete('forward')
        self.ptmgraph.delete('forward')
        self.inwin.create_rectangle(self.primerx1,14,self.primerx2,4,outline='dark green',fill='dark green',stipple='gray12',tag='forward')
        self.inwin.create_rectangle(self.primerx1,16,self.primerx2,36,outline='dark green',tag='forward')
        self.inwin.create_rectangle(self.primerx1,16,self.primerx2+14,26,outline='light yellow',fill='light yellow',tag='forward')
        self.inwin.create_rectangle(self.primerx1,16,self.primerx2,36,outline='dark green',tag='forward')
        x=self.primerx1+4
        for a in forw:
            self.inwin.create_text(x,21,text=a,fill='dark green',font=('courier',11),tag='forward')
            x=x+7            
        self.inwin.create_polygon(self.primerx2+2,17,self.primerx2+2,25,self.primerx2+14,21,outline='dark green',fill='dark green',tag='forward')        
        self.outwin.create_rectangle(self.primerx1,36,self.primerx2,25,outline='dark green',fill='dark green',stipple='gray12',tag='forward')
        self.alignment.create_rectangle(self.primerx1,len(self.sequences)*16,self.primerx2,2,outline='dark green',fill='dark green',stipple='gray12',tag='forward')
        self.ptmgraph.create_rectangle(self.primerx1,307,self.primerx2,318,outline='dark green',fill='dark green',stipple='gray12',tag='forward')
        self.pgcgraph.create_rectangle(self.primerx1,313,self.primerx2,324,outline='dark green',fill='dark green',stipple='gray12',tag='forward')
        self.primerx1=0
        self.primerx2=0
        return

    #Adjusts menus when the forward primer is selected#
    def fpres(self,event):
        self.analysemenu.entryconfig(0,state=NORMAL)
        self.analysemenu.entryconfig(1,state=NORMAL)
        self.analysemenu.entryconfig(2,state=NORMAL)
        self.analysemenu.entryconfig(3,state=NORMAL)
        self.analysemenu2.entryconfig(0,state=NORMAL)
        self.analysemenu2.entryconfig(1,state=NORMAL)
        rev=self.rentry.get()
        if rev <> '':
            self.analysemenu.entryconfig(10,state=NORMAL)
            self.analysemenu.entryconfig(11,state=NORMAL)
        return
    
    #Selects the reverse primer#
    def buttonr(self):
        if self.primerx1>self.primerx2:
            self.primerx1,self.primerx2=self.primerx2,self.primerx1
        self.rpbind5=int(self.primerx1/7)
        self.rpbind3=int(self.primerx2/7)
        self.inwin.delete('sel2')
        self.outwin.delete('sel2')
        self.alignment.delete('sel2')
        self.ptmgraph.delete('sel2')
        self.pgcgraph.delete('sel2')
        reve=self.antisense[self.rpbind5:self.rpbind3]
        reve2=''
        for a in reve:
            if a<>'-':
                reve2=reve2+a
        reve2=reverse(reve2)
        reve2=self.primerin(reve2)
        if not reve2:            
            return
        self.rentry.delete(0,END)
        self.rentry.insert(0,reve2)
        self.inwin.delete('reverse')
        self.outwin.delete('reverse')
        self.alignment.delete('reverse')
        self.ptmgraph.delete('reverse')
        self.pgcgraph.delete('reverse')
        self.inwin.create_rectangle(self.primerx1-14,16,self.primerx2,26,outline='light yellow',fill='light yellow',tag='reverse')
        self.inwin.create_rectangle(self.primerx1,24,self.primerx2,4,outline='light coral',tag='reverse')
        self.inwin.create_rectangle(self.primerx1,36,self.primerx2,26,outline='light coral',fill='light coral',stipple='gray12',tag='reverse')
    
        x=self.primerx1+4
        for a in reve:
            self.inwin.create_text(x,17,text=a,fill='light coral',font=('courier',11),tag='reverse')
            x=x+7   
        self.inwin.create_polygon(self.primerx1-2,15,self.primerx1-2,23,self.primerx1-14,19,outline='light coral',fill='light coral',tag='reverse')        
        self.outwin.create_rectangle(self.primerx1,36,self.primerx2,25,outline='light coral',fill='light coral',stipple='gray12',tag='reverse')
        self.alignment.create_rectangle(self.primerx1,len(self.sequences)*16,self.primerx2,2,outline='light coral',fill='light coral',stipple='gray12',tag='reverse')
        self.ptmgraph.create_rectangle(self.primerx1,307,self.primerx2,318,outline='light coral',fill='light coral',stipple='gray12',tag='reverse')

        self.pgcgraph.create_rectangle(self.primerx1,313,self.primerx2,324,outline='light coral',fill='light coral',stipple='gray12',tag='reverse')


        self.primerx1=0
        self.primerx2=0
        return

    #Adjusts menus when the reverse primer is selected#
    def rpres(self,event):
        self.analysemenu.entryconfig(5,state=NORMAL)
        self.analysemenu.entryconfig(6,state=NORMAL)
        self.analysemenu.entryconfig(7,state=NORMAL)
        self.analysemenu.entryconfig(8,state=NORMAL)
        self.analysemenu3.entryconfig(0,state=NORMAL)
        self.analysemenu3.entryconfig(1,state=NORMAL)
        forw=self.fentry.get()
        if forw <> '':
            self.analysemenu.entryconfig(10,state=NORMAL)
            self.analysemenu.entryconfig(11,state=NORMAL)

    #Checks that primers are appropriate# 
    def primerin(self,oligoin):
        oligoin=string.upper(oligoin)
        if len(oligoin)<9:
            x=tkMessageBox.Message(icon='error', type='ok',
         message='Oligo(s) too short (< 9 nucleotides)', title='Amplicon: Error').show()
            return ''
        if len(oligoin)>42:
            x=tkMessageBox.Message(icon='error', type='ok',
         message='Oligo(s) too long (> 42 nucleotides)', title='Amplicon: Error').show()
            return ''
        degen=degeneracy(oligoin)
        if degen > self.maxdegeneracy:
            x=tkMessageBox.Message(icon='error', type='ok',
         message='Oligo(s) too degenerate (> '+str(self.maxdegeneracy)+'-fold degenerate)', title='Amplicon: Error').show()
            return ''
        return oligoin

# File Menu Functions #
    #Opens an alignment file#
    def OpenFile(self):
        self.openfilename=tkFileDialog.askopenfilename(title='Select a file containing aligned DNA sequences',
                                                  filetypes=[('Clustal','*.aln'),('FASTA','*.fas'),('Text,','*.txt'),
                                                             ('MEGA','*.meg'),('All files','*.*')])
        if not self.openfilename:
            return
        self.titles.delete(0,END)
        self.fentry.delete(0,END)
        self.rentry.delete(0,END)
        self.inname.delete(1.0,END)
        self.outname.delete(1.0,END)
        self.outseq=''
        self.sourcefile.config(state=NORMAL)
        self.sourcefile.delete(1.0,END)
        self.sourcefile.insert(END,'Loading... please wait...')
        self.sourcefile.config(background='light green')
        if self.sequences:
            self.alignment.delete(ALL)
            self.inwin.delete(ALL)
            self.outwin.delete(ALL)
        root.bell()
        root.config(cursor='watch')
        root.update()
        xten=''
        xt=len(self.openfilename)-1
        while self.openfilename[xt]<>'.':
            xten=xten+self.openfilename[xt]
            xt=xt-1
        openedfile = open(self.openfilename,'r')
        openedcontents = openedfile.read()
        if xten=='nla':
            self.names,self.sequences=read_aln(openedcontents)
        if xten=='saf' or xten=='txt':
            self.names,self.sequences=read_fasta(openedcontents)
        if xten=='gem':
            self.names,self.sequences=read_meg(openedcontents)
        if xten=='xen':
            self.names,self.sequences=read_nex(openedcontents)
        if not self.names:
            x=tkMessageBox.Message(icon='error', type='ok', message="Could not read file.  Please try another.", title='Amplicon: Error').show()
            return
        self.sourcefile.config(state=NORMAL)
        self.sourcefile.delete(1.0,END)
        self.sourcefile.insert(1.0,self.openfilename)
        self.searchmenu.entryconfig(0,state=DISABLED)
        self.searchmenu.entryconfig(1,state=DISABLED)
        self.analysemenu.entryconfig(0,state=DISABLED)
        self.analysemenu.entryconfig(1,state=DISABLED)
        self.analysemenu.entryconfig(2,state=DISABLED)
        self.analysemenu.entryconfig(3,state=DISABLED)
        self.analysemenu.entryconfig(5,state=DISABLED)
        self.analysemenu.entryconfig(6,state=DISABLED)
        self.analysemenu.entryconfig(7,state=DISABLED)
        self.analysemenu.entryconfig(8,state=DISABLED)
        self.analysemenu.entryconfig(10,state=DISABLED)
        self.analysemenu.entryconfig(11,state=DISABLED)
        self.analysemenu2.entryconfig(0,state=DISABLED)
        self.analysemenu2.entryconfig(1,state=DISABLED)
        self.analysemenu3.entryconfig(0,state=DISABLED)
        self.analysemenu3.entryconfig(1,state=DISABLED)
        self.analysemenu.entryconfig(10,state=DISABLED)
        self.analysemenu.entryconfig(11,state=DISABLED)
        self.place_names_sequences()
        self.sourcefile.config(background='light yellow')
        self.outseq=''
        self.primerx1=0
        self.primerx2=0
        self.fpbind5=0
        self.fpbind3=0
        self.rpbind5=0
        self.rpbind3=0
        self.alreadysearchedf=0
        self.alreadysearchedr=0
        root.config(cursor='arrow')

    #Saves open analysis windows as a .txt file#
    def SaveAnal(self):
        text='Amplicon Analysis \n\nGenerated from alignment file: '+self.openfilename+'\n\n'
        try:
            text=text+'\n'+self.amptext.get(1.0,END)
        except:
            text=text+'No Amplification Analysis\n\n'
        try:
            text=text+'\n'+self.fptext.get(1.0,END)
        except:
            text=text+'No Forward Primer Tm Analysis\n\n'
        try:
            text=text+'\n'+self.fexbwtext.get(1.0,END)
        except:
            text=text+'No Forward Primer / Excluded Group Binding Analysis\n\n'
        try:
            text=text+'\n'+self.fcptext.get(1.0,END)
        except:
            text=text+'No Forward Primer Self Complementarity Analysis\n\n'
        try:
            text=text+'\n'+self.fhptext.get(1.0,END)
        except:
            text=text+'No Forward Hairpin Analysis\n\n'
        try:
            text=text+'\n'+self.rptext.get(1.0,END)
        except:
            text=text+'No Reverse Primer Tm Analysis\n\n'
        try:
            text=text+'\n'+self.rexbwtext.get(1.0,END)
        except:
            text=text+'No Reverse Primer / Excluded Group Binding Analysis\n\n'
        try:
            text=text+'\n'+self.rcptext.get(1.0,END)
        except:
            text=text+'No Reverse Primer Self Complementarity Analysis\n\n'
        try:
            text=text+'\n'+self.rhptext.get(1.0,END)
        except:
            text=text+'No Reverse Hairpin Analysis\n\n'
        try:
            text=text+'\n'+self.bcptext.get(1.0,END)
        except:
            text=text+'No Forward / Reverse Primer Complementarity Analysis\n\n'
        savefilename=tkFileDialog.asksaveasfilename(title='Save analyses to a text file',
                                                  filetypes=[('Text','*.txt'),('All files','*.*')])
        savefile = open(savefilename,'w')
        text=text.encode('utf-8')
        savefile.write(text)
        return
    
    #Saves alignments#
    def SaveAln(self):
        alnseqs=[]
        space='                  '
        first=self.E1.get()
        if first=='':
            first=0
        first=int(first)
        last=self.E2.get()
        if last=='':
            last=len(self.sequences[0])
        last=int(last)
        seqs=self.sequences
        names=self.names
        seqs2=[]
        for s in seqs:
            seqs2=seqs2+[s[first:last]]
        seqs=seqs2
        if seqs==[]:
            x=tkMessageBox.Message(icon='error', type='ok', message="No alignment to save.  Please get one.", title='Amplicon: Error').show()
            return
        self.ftt=self.ft.get()
        if self.ftt==1:
            text='CLUSTAL multiple sequence alignment (generated by Amplicon)\n\n\n'
            length=len(seqs[0])
            for a in range(0,length,60):
                for b in seqs:
                    alnseqs=alnseqs+[b[a:a+60]]
            nnames=[]
            for n in names:
                nnames=nnames+[n+space[0:18-len(n)]]
            c=0
            for d in alnseqs:
                text=text+nnames[c]+d+'\n'
                c=c+1
                if c==len(nnames):
                    c=0
                    text=text+'                                                         \n\n'
        if self.ftt==2:
            text=''
            for a in range(0,len(names),1):
                text=text+"\n\n#"+names[a]+'\n'+seqs[a]
        if self.ftt==3:
            length=len(seqs[0])
            ntax=str(len(names))
            b=[]
            for a in names:
                b=b+[a+'                   ']
            names=b
            text='#NEXUS\n\nbegin data;\ndimensions ntax='+ntax +' nchar='+str(length)+';\nformat missing=? gap=- matchchar=. interleave datatype=dna;\noptions gapmode=missing;\nmatrix\n\n'
            for a in range(0,length,60):
                for b in range(0,len(names),1):
                    text=text+names[b][:18]+' '+seqs[b][a:a+60]+'\n'
                text=text+'\n'
            text=text+';\nEnd;'
        if self.ftt==4:
            b=[]
            for a in names:
                b=b+[a+'         ']
            names=b
            length=len(seqs[0])
            text='   '+str(len(names))+'   '+str(length)+'\n'
            for n in range(0,len(names),1):
                text=text+names[n][:10]+' '+seqs[n][0:50]+'\n'
            text=text+'\n'
            for a in range(50,len(seqs[0]),50):
                for b in seqs:
                    text=text+b[a:a+50]+'\n'
                text=text+'\n'
        if self.ftt==5:
            text=''
            for a in range(0,len(names),1):
                text=text+"\n\n>"+names[a]+'\n'+seqs[a]
        if self.ftt==1:
            savefilename=tkFileDialog.asksaveasfilename(title='Save alignment as Clustal (.aln) file',
                                                      filetypes=[('Clustal','*.aln'),('All files','*.*')]\
                                                        ,initialfile='.aln')
        if self.ftt==2:
            savefilename=tkFileDialog.asksaveasfilename(title='Save alignment as MEGA (.meg) file',
                                                      filetypes=[('MEGA','*.meg'),('All files','*.*')]\
                                                        ,initialfile='.meg')
            text='#MEGA\n\nTitle:'+savefilename+'\n'+text
        if self.ftt==3:
            savefilename=tkFileDialog.asksaveasfilename(title='Save alignment as NEXUS (.nex) file',
                                                      filetypes=[('NEXUS','*.nex'),('All files','*.*')]\
                                                        ,initialfile='.nex')
        if self.ftt==4:
            savefilename=tkFileDialog.asksaveasfilename(title='Save alignment as PHYLIP (.phy) file',
                                                      filetypes=[('PHYLIP','*.phy'),('All files','*.*')]\
                                                        ,initialfile='.phy')
        if self.ftt==5:
            savefilename=tkFileDialog.asksaveasfilename(title='Save alignment as FASTA (.fas) file',
                                                      filetypes=[('FASTA','*.fas'),('All files','*.*')]\
                                                        ,initialfile='.fas')
        savefile = open(savefilename,'w')
        savefile.write(text)
        self.SA.destroy()
        return

    #Options dialog for saving alignments#
    def SaveAln1(self):
        self.SA=Toplevel(root)
        self.SA.title('Options for saving alignment')
        self.SA.resizable(0,0)
        #self.SA.iconbitmap(self.IconPath)
        self.SA.transient(root)
        self.E1=Entry(self.SA,width=5)
        self.E1.grid(row=2,column=0)
        self.E1.config(state=DISABLED)
        self.E2=Entry(self.SA,width=5)
        self.E2.grid(row=3,column=0)
        self.E2.config(state=DISABLED)
        l1=Label(self.SA,text="5' end of alignment section to save",font=('Arial',10)).grid(row=2,column=1)
        l2=Label(self.SA,text="3' end of alignment section to save",font=('Arial',10)).grid(row=3,column=1)
        B=Button(self.SA,text='Enter',command=self.SaveAln)
        B.grid(row=10)
        self.ms=IntVar()
        self.R1=Radiobutton(self.SA,variable=self.ms,value=1,text='1. Save whole alignment',font=('Arial',10),command=self.SAwhole)
        self.R1.grid(column=0,row=0,sticky=W, columnspan=2)
        self.R2=Radiobutton(self.SA,variable=self.ms,value=2,text='2. Save part of alignment',font=('Arial',10),command=self.SApart)
        self.R2.grid(column=0,row=1,sticky=W, columnspan=2)
        self.R1.select()
        self.E1.insert(0,'0')
        self.E2.insert(0,len(self.sequences[0]))
        self.ft=IntVar()
        self.F1=Radiobutton(self.SA,variable=self.ft,value=1,text='1. Save as Clustal (.aln) file',font=('Arial',10))
        self.F1.grid(column=0,row=5,sticky=W, columnspan=2)
        self.F2=Radiobutton(self.SA,variable=self.ft,value=2,text='2. Save as MEGA (.meg) file',font=('Arial',10))
        self.F2.grid(column=0,row=6,sticky=W, columnspan=2)
        self.F3=Radiobutton(self.SA,variable=self.ft,value=3,text='3. Save as NEXUS (.nex) file',font=('Arial',10))
        self.F3.grid(column=0,row=7,sticky=W, columnspan=2)
        self.F4=Radiobutton(self.SA,variable=self.ft,value=4,text='4. Save as PHYLIP (.phy) file',font=('Arial',10))
        self.F4.grid(column=0,row=8,sticky=W, columnspan=2)
        self.F5=Radiobutton(self.SA,variable=self.ft,value=5,text='5. Save as FASTA (.fas) file',font=('Arial',10))
        self.F5.grid(column=0,row=9,sticky=W, columnspan=2)
        self.F1.select()
        return

    #For saving whole alignments#
    def SAwhole(self):
        self.E1.config(state=NORMAL)
        self.E2.config(state=NORMAL)
        self.E1.delete(0,END)
        self.E2.delete(0,END)
        self.E1.insert(0,'0')
        self.E2.insert(0,len(self.sequences[0]))
        self.E1.config(state=DISABLED)
        self.E2.config(state=DISABLED)
        return

    #For saving partial alignments#
    def SApart(self):
        self.E1.config(state=NORMAL)
        self.E2.config(state=NORMAL)
        self.E1.delete(0,END)
        self.E2.delete(0,END)
        first=self.fpbind5
        if not first:
            first='0'
        last=self.rpbind3
        if not last:
            last=len(self.sequences[0])
        self.E1.insert(0,first)
        self.E2.insert(0,last)
        return

# Sequences Menu Functions #
    #Cuts a sequence from the alignment#
    def CutSeq(self):
        root.bell()
        if self.sequences:
            self.alignment.create_rectangle(0,0,4+len(self.sequences[0])*7,len(self.sequences)*16,fill='Light Yellow', outline='Light Yellow')
        else:
            return
        self.remnames=[]
        self.remseq=[]
        togo=self.titles.curselection()
        togo=map(int,togo)
        a = len(togo)-1
        while a >-1:
            b=togo[a]
            x=self.names.pop(b)
            y=self.sequences.pop(b)
            self.remnames=self.remnames+[x]
            self.remseq=self.remseq+[y]
            a=a-1
        self.place_names_sequences()

    #Pastes a sequence into the alignment#
    def PasteSeq(self):
        root.bell()
        place=self.titles.curselection()
        if not place:
            for a in self.remnames:
                newnames=self.names+[a]
            for a in self.remseq:
                newseq=self.sequences+[a]
        if place:
            place=int(place[0])+1
            a=0
            newnames=[]
            newseq=[]
            endnames=[]
            endseq=[]
            while a<place:
                newnames=newnames+[self.names[a]]
                newseq=newseq+[self.sequences[a]]
                a=a+1
            a=place
            endnames=[]
            endseq=[]
            while a<len(self.names):
                endnames=endnames+[self.names[a]]
                endseq=endseq+[self.sequences[a]]
                a=a+1
            newnames=newnames+self.remnames+endnames
            newseq=newseq+self.remseq+endseq
        self.names=newnames
        self.sequences=newseq
        self.place_names_sequences()
        return

    #Generates a degenerate sequence from several sequences and inserts it into the alignment#
    def buttoncon(self):
        root.config(cursor='watch')
        root.bell()
        root.update()
        self.all=[]
        self.con=self.titles.curselection()
        for a in self.con:
            self.all=self.all+[self.sequences[int(a)]]
        self.consensus=create_consensus(self.all)
        self.sequences=self.sequences+[self.consensus]
        consnums='Poss:'
        for a in range(0,len(self.con),1):
            con=int(self.con[a])+1
            con=str(con)
            consnums=consnums+con+','
        consnums=consnums[:len(consnums)-1]+' '
        self.names=self.names+[consnums]
        self.place_names_sequences()
        self.titles.see(END)
        root.config(cursor='arrow')
        return

    #Generates a sequence representing consistent sites from several sequences and inserts it into the alignment#
    def buttoncon2(self):
        root.config(cursor='watch')
        root.bell()
        root.update()
        self.all=[]
        self.con=self.titles.curselection()
        for a in self.con:
            self.all=self.all+[self.sequences[int(a)]]
        self.consensus=create_consensus2(self.all)
        self.sequences=self.sequences+[self.consensus]
        consnums='Cons:'
        a=0
        while a <len(self.con):
            con=int(self.con[a])+1
            con=str(con)
            consnums=consnums+con+','
            a=a+1
        consnums=consnums[:len(consnums)-1]+' '
        self.names=self.names+[consnums]
        self.place_names_sequences()
        self.titles.see(END)
        root.config(cursor='arrow')
        return

    #Plots a Tm graph for a selected sequence#
    def PlotTm(self):
        root.config(cursor='watch')
        root.bell()
        root.update()
        title=self.titles.curselection()
        if not title:
            x=tkMessageBox.Message(icon='error', type='ok', message="No sequence selected.  Please select one.", title='Amplicon: Error').show()
            return
        self.alignment.grid_forget()
        self.titles.grid_forget()
        self.tmtitle=Text(root, font=('Arial',10),background='light yellow',height=18,width=36)
        if self.scanMeth==2:
            direct="Right to left, result plotted at 5' end"
        else:
            direct="Left to right, result plotted at 3' end"
        self.tmtitle.delete(1.0,END)
        self.tmtitle.insert(1.0,'Sliding Tm plot for sequence: \n'+self.names[int(title[0])]+'\n\nLength of sliding window: '+str(self.scanlength)+
                            '\n\nScan drection: \n'+direct+'\n\nGapped regions are skipped.  Regions more degenerate than'+
                            ' the current limit of '+str(self.scandegeneracy)+' are \nnot analysed\n\nMinima and maxima are shown'+
                            ' for \ndegenerate sequences')
        self.tmtitle.grid(column=0,row=0,sticky=N)
        a=int(title[0])
        seq=self.sequences[a]
        seq=string.upper(seq)
        self.alignment.grid_forget()
        self.ptmgraph.delete(ALL)
        self.ptmgraph.config(width = 706, height = 321, background = 'light yellow',xscrollcommand=self.xsb,relief=SUNKEN,borderwidth=2)
        self.ptmgraph.bind('<Button-1>',primerselect1)
        self.ptmgraph.bind('<ButtonRelease-1>',primerselect2)
        self.ptmgraph['xscrollcommand']=self.xsb.set
        self.ptmgraph.config(scrollregion=(0,0,(len(seq)*7),321))
        length=self.scanlength
        i=7
        bits=[]
        pos=[]
        for a in range(0,len(seq)-length,1):
            if seq[a]<>'-':
                bit=seq[a]
                z=1
                while len(bit)<length:
                    if seq[a+z]<>'-':
                        bit=bit+seq[a+z]
                    z=z+1
                    if a+z==len(seq):
                        break
                deg=degeneracy(bit)
                if deg<self.scandegeneracy:
                    bits=bits+[bit]
                    bit=''
                    if self.scanMeth==2:
                        z=1
                    pos=pos+[a+z]
        for x in range(0,len(pos)):            
            lots=regenerate(bits[x])
            tr=[]
            for m in lots:
                n=self.CalcTm(m)
                tr=tr+[n]
            tr.sort()
            trmin=tr[0]
            trmax=tr[len(tr)-1]
            self.ptmgraph.create_line(pos[x]*7-3,470-trmin*5,pos[x]*7-3,307,fill='green')
            self.ptmgraph.create_line(pos[x]*7-3,470-trmin*5,pos[x]*7-3,470-trmax*5,fill='blue')
            self.ptmgraph.create_oval(pos[x]*7-3,470-trmin*5,pos[x]*7-3,470-trmin*5,width=3)
            self.ptmgraph.create_oval(pos[x]*7-3,470-trmax*5,pos[x]*7-3,470-trmax*5,width=3)
        for m in range(35,95,5):
            for n in range(10,len(seq)*7,500):
                self.ptmgraph.create_text(n,470-(m*5)-6,text=str(m), font=('Arial',8))
            self.ptmgraph.create_line(0,470-(m*5),(len(seq)*7),470-(m*5),fill='red')
        l=312
        c=4
        for x in seq:
            if x=='A':
                self.ptmgraph.create_text(c,l,text='A',fill='Red',font=('courier',11))
            if x=='C':
                self.ptmgraph.create_text(c,l,text='C',fill='Blue',font=('courier',11))
            if x=='T':
                self.ptmgraph.create_text(c,l,text='T',fill='Dark Green',font=('courier',11))
            if x=='G':
                self.ptmgraph.create_text(c,l,text='G',fill='Black',font=('courier',11))
            if x <> 'A' and x <>'C' and x<>'T' and x<>'G' and x <>'\n'  and x <>'\r':
                self.ptmgraph.create_text(c,l,text=x,fill='Orange',font=('courier',11))
            c=c+7
#        if self.fpbind5:
#            self.ptmgraph.create_rectangle(self.primerx1,307,self.primerx2,318,outline='dark green',fill='dark green',stipple='gray12',tag='forward')
        self.ptmgraph.grid(column=2, row=0, columnspan = 4)
        self.editmenu.entryconfig(7,state=NORMAL)
        self.editmenu.entryconfig(0,state=DISABLED)
        self.editmenu.entryconfig(1,state=DISABLED)
        self.editmenu.entryconfig(2,state=DISABLED)
        self.editmenu.entryconfig(3,state=DISABLED)
        self.editmenu.entryconfig(5,state=DISABLED)
        self.editmenu.entryconfig(6,state=DISABLED)
        root.config(cursor='arrow')

    #Plots a GC% graph for a selected sequence#
    def PlotGC(self):
        root.bell()
        root.config(cursor='watch')
        root.update()
        title=self.titles.curselection()
        if not title:
            x=tkMessageBox.Message(icon='error', type='ok', message="No sequence selected.  Please select one.", title='Amplicon: Error').show()
            return
        self.alignment.grid_forget()
        self.titles.grid_forget()
        self.gctitle=Text(root, font=('Arial',10),background='light yellow',height=18,width=36)
        if self.scanMeth==2:
            direct="Right to left, result plotted at 5' end"
        else:
            direct="Left to right, result plotted at 3' end"
        self.gctitle.delete(1.0,END)
        self.gctitle.insert(1.0,'Sliding GC% plot for sequence: \n'+self.names[int(title[0])]+'\n\nLength of sliding window: '+str(self.scanlength)+
                            '\n\nScan drection: \n'+direct+'\n\nGapped regions are skipped.  Regions more degenerate than'+
                            ' the current limit of '+str(self.scandegeneracy)+' are \nnot analysed\n\nMinima and maxima are shown'+
                            ' for \ndegenerate sequences')
        self.gctitle.grid(column=0,row=0,sticky=N)
        a=int(title[0])
        seq=self.sequences[a]
        self.pgcgraph=Canvas(root)
        self.pgcgraph.config(width = 706, height = 321, background = 'light yellow',xscrollcommand=self.xsb,relief=SUNKEN,borderwidth=2)
        self.pgcgraph.bind('<Button-1>',primerselect1)
        self.pgcgraph.bind('<ButtonRelease-1>',primerselect2)
        self.pgcgraph['xscrollcommand']=self.xsb.set
        self.pgcgraph.config(scrollregion=(0,0,(len(seq)*7),360))
        length=self.scanlength
        bits=[]
        pos=[]
        for a in range(0,len(seq)-length,1):
            if seq[a]<>'-':
                bit=seq[a]
                z=1
                while len(bit)<length:
                    if seq[a+z]<>'-':
                        bit=bit+seq[a+z]
                    z=z+1
                    if a+z==len(seq):
                        break
                deg=degeneracy(bit)
                if deg<self.scandegeneracy:
                    bits=bits+[bit]
                    bit=''
                    if self.scanMeth==2:
                        z=1
                    pos=pos+[a+z]
        for x in range(0,len(pos),1):           
            q,trmin,trmax=gcper(bits[x])
            self.pgcgraph.create_line(pos[x]*7-3,312-trmin*3,pos[x]*7-3,312,fill='green')
            self.pgcgraph.create_line(pos[x]*7-3,312-trmin*3,pos[x]*7-3,312-trmax*3,fill='blue')
            self.pgcgraph.create_oval(pos[x]*7-3,312-trmin*3,pos[x]*7-3,312-trmin*3,width=3)
            self.pgcgraph.create_oval(pos[x]*7-3,312-trmax*3,pos[x]*7-3,312-trmax*3,width=3)
        for m in range(0,101,10):
            for n in range(10,len(seq)*7,500):
                self.pgcgraph.create_text(n,312-(m*3)-6,text=str(m), font=('Arial',8))
            self.pgcgraph.create_line(0,312-(m*3),(len(seq)*7),312-(m*3),fill='red')
        l=318
        c=4
        for x in seq:
            if x=='A':
                self.pgcgraph.create_text(c,l,text='A',fill='Red',font=('courier',11))
            if x=='C':
                self.pgcgraph.create_text(c,l,text='C',fill='Blue',font=('courier',11))
            if x=='T':
                self.pgcgraph.create_text(c,l,text='T',fill='Dark Green',font=('courier',11))
            if x=='G':
                self.pgcgraph.create_text(c,l,text='G',fill='Black',font=('courier',11))
            if x <> 'A' and x <>'C' and x<>'T' and x<>'G' and x <>'\n'  and x <>'\r':
                self.pgcgraph.create_text(c,l,text=x,fill='Orange',font=('courier',11))
            c=c+7
        self.pgcgraph.grid(column=2, row=0, columnspan = 4)
        self.editmenu.entryconfig(7,state=NORMAL)
        self.editmenu.entryconfig(0,state=DISABLED)
        self.editmenu.entryconfig(1,state=DISABLED)
        self.editmenu.entryconfig(2,state=DISABLED)
        self.editmenu.entryconfig(3,state=DISABLED)
        self.editmenu.entryconfig(5,state=DISABLED)
        self.editmenu.entryconfig(6,state=DISABLED)
        root.config(cursor='arrow')

    def redrawalign(self):
        self.pgcgraph.grid_forget()
        self.gctitle.grid_forget()
        self.ptmgraph.grid_forget()
        self.tmtitle.grid_forget()
        self.alignment.grid(column=2, row=0, columnspan = 4)
        self.titles.grid(column=0, row=0,sticky=E)
        self.editmenu.entryconfig(7,state=DISABLED)
        self.editmenu.entryconfig(0,state=ACTIVE)
        self.editmenu.entryconfig(1,state=ACTIVE)
        self.editmenu.entryconfig(2,state=ACTIVE)
        self.editmenu.entryconfig(3,state=ACTIVE)
        self.editmenu.entryconfig(5,state=ACTIVE)
        self.editmenu.entryconfig(6,state=ACTIVE)
        return

# Search Menu Functions #

    #Searches for forward primer binding sites#
    def fsearch(self):
        root.config(cursor='watch')
        root.update()
        self.alreadysearchedf=1
        self.inwin.delete('forsearch')
        for c in range(4,len(self.sense)*7,7):
            if self.sense[int(c-4)/7]<>'-':
                self.inwin.create_line(c,18,c,22,fill='black')
        find=0
        length=int(self.searchlen)
        for a in range(0,len(self.sense)-length,1):
            if self.sense[a]<>'-':
                scanbit=''
                b=a
                while len(scanbit)<length and b < len(self.antisense)-1:
                    if self.sense[b]<>'-':  
                        scanbit=scanbit+self.sense[b]
                    b=b+1
                tryit=self.searchit(scanbit)
                if tryit==1:
                    if self.search3set==2 or self.search3set==4:
                        if scanbit[len(scanbit)-1] =='A' or scanbit[len(scanbit)-1]=='C' or scanbit[len(scanbit)-1]=='G' or scanbit[len(scanbit)-1]=='T':
                            tryit = 1
                        else:
                            tryit = 0
                    if self.search3set==3 or self.search3set==4:
                        if self.sense[b-1]==self.outseq[b-1]:
                            tryit=0
                if tryit==1:
                    self.inwin.create_polygon((b-1)*7,20,(b-1)*7,24,(b)*7,24,outline='black',fill='light green',tag='forsearch')
                    find=1
        root.config(cursor='arrow')
        root.update()
        if find==0:
            x=tkMessageBox.Message(icon='info', type='ok', message="No forward primer binding sites matching current parameters were found.", title='Amplicon: search result').show()
        return

    #Searches for reverse primer binding sites#
    def rsearch(self):
        root.config(cursor='watch')
        root.update()
        self.alreadysearchedr=1
        self.inwin.delete('rsearch')
        for c in range(4,len(self.sense)*7,7):
            if self.sense[int(c-4)/7]<>'-':
                self.inwin.create_line(c,18,c,22,fill='black')
        find=0
        length=int(self.searchlen)
        for a in range(0,len(self.antisense)-length,1):
            if self.antisense[a]<>'-':
                scanbit=''
                b=a
                while len(scanbit)<length and b < len(self.antisense)-1:
                    if self.sense[b]<>'-':  
                        scanbit=scanbit+self.sense[b]
                    b=b+1
                scanbit=reverse(scanbit)
                tryit=self.searchit(scanbit)
                if tryit==1:
                    if self.search3set==2 or self.search3set==4:
                        if scanbit[0] =='A' or scanbit[0] =='C' or scanbit[0] =='G' or scanbit[0] =='T':
                            tryit=1
                        else:
                            tryit=0
                    if self.search3set==3 or self.search3set==4:
                        if self.sense[a]==self.outseq[a]:
                            tryit=0
                if tryit==1:
                    self.inwin.create_polygon((a+1)*7,15,(a)*7,15,(a+1)*7,19,outline='black',fill='light coral',tag='rsearch')
                    find=1
        root.config(cursor='arrow')
        root.update()
        if find==0:
            x=tkMessageBox.Message(icon='info', type='ok', message="No reverse primer binding sites matching current parameters were found.", title='Amplicon: search result').show()
        return

    #Accessory function for primer binding site searches#
    def searchit(self,frag):
        newfrag=''
        for a in frag:
            if a <>'-':
                newfrag=newfrag+a
        x = degeneracy(frag)
        if x > self.searchdeg:
            return 0
        lots=regenerate(newfrag)
        minmin=0
        maxmax=0
        for z in lots:
            mid,min,max=gcper(z)
            if min<float(self.searchgclow):
                minmin=1
            if max>float(self.searchgchigh):
                maxmax=1
        if maxmax or minmin:
            return 0
        for x in lots:
            Tm=self.CalcTm(x)
            if Tm<float(self.searchtm) or Tm>float(self.searchtmmax):
                return 0
        return 1

# Analysis Menu Functions #

    #Gets Tm for forward primers and displays it in a toplevel window#
    def analysefp(self):
        lowtemp=100
        hightemp=0
        self.oligo=self.fentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        self.grow=regenerate(self.oligo)
        self.fp=Toplevel(root)
        self.fp.title('Amplicon: Forward Primer Tm and Position')
        #self.fp.iconbitmap(self.IconPath)
        self.fp.maxsize(390,205)
        self.fpscroll=Scrollbar(self.fp)
        self.fpscroll.pack(side=RIGHT,fill=Y)
        if self.fpbind5:
            st=str(self.fpbind5+1)
        else:
            st=' none '
        if self.fpbind3:
            en=str(self.fpbind3)
        else:
            en=' none '
        self.fptext=Text(self.fp,font=('courier new',10), background='light green', height=20, width=60,yscrollcommand=self.fpscroll.set)
        self.fptext.insert(1.0,'Forward primer: '+self.oligo+', '+str(len(self.oligo))+' mer'+'\nBinding site position in alignment: '+st+' to '+en+'\n\n'+\
                           '\n\nA mixture of '+str(len(self.grow))+' oligo sequences:\n\n')
        self.fptext.insert(3.0,'Tm calculation method: ')
        if self.tmMeth==1:
            self.fptext.insert(3.23,'Nearest Neighbour\n')
        if self.tmMeth==2:
            self.fptext.insert(3.23,'GC%\n')
        if self.tmMeth==3:
            self.fptext.insert(3.23,'GC% + salt + formamide\n')
        for a in self.grow:
            self.tm=self.CalcTm(a)
            if self.tm<lowtemp:
                lowtemp=self.tm
            if self.tm>hightemp:
                hightemp=self.tm
            self.oligo=a
            self.tm=str(self.tm)
            self.fptext.insert(END,a+'  Tm: '+self.tm[:5]+u' \u00BAC\n')
        self.fptext.insert(5.0,'Lowest Tm: '+str(lowtemp)[:5]+u' \u00BAC'+'\nHighest Tm: '+str(hightemp)[:5]+u' \u00BAC')
        self.fpscroll.config(command=self.fptext.yview)
        self.fptext.pack()
        self.oligo=''
        return
    
    #Gets Tm for reverse primers and displays it in a toplevel window#
    def analyserp(self):
        lowtemp=100
        hightemp=0
        self.oligo=self.rentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        self.grow=regenerate(self.oligo)
        self.rp=Toplevel(root)
        self.rp.title('Amplicon: Reverse Primer Tm and Position')
        self.rp.resizable(0,0)
        ##self.rp.iconbitmap(self.IconPath)
        self.rpscroll=Scrollbar(self.rp)
        self.rpscroll.pack(side=RIGHT,fill=Y)
        if self.rpbind5:
            st=str(self.rpbind5+1)
        else:
            st=' none '
        if self.rpbind3:
            en=str(self.rpbind3)
        else:
            en=' none '
        self.rptext=Text(self.rp,font=('courier',10), background='light coral', height=20, width=60,yscrollcommand=self.rpscroll.set)
        self.rptext.insert(1.0,'Reverse primer: '+self.oligo+', '+str(len(self.oligo))+' mer'+'\nBinding site position in alignment: '+st+' to '+en+'\n\n'+\
                           '\n\nA mixture of '+str(len(self.grow))+' oligo sequences:\n\n')
        self.rptext.insert(3.0,'Tm calculation method: ')
        if self.tmMeth==1:
            self.rptext.insert(3.23,'Nearest Neighbour\n')
        if self.tmMeth==2:
            self.rptext.insert(3.23,'GC%\n')
        if self.tmMeth==3:
            self.rptext.insert(3.23,'GC% + salt + formamide\n')
        for a in self.grow:
            self.tm=self.CalcTm(a)
            if self.tm<lowtemp:
                lowtemp=self.tm
            if self.tm>hightemp:
                hightemp=self.tm
            self.oligo=a
            self.tm=str(self.tm)
            self.rptext.insert(END,a+'  Tm: '+self.tm[:5]+u' \u00BAC\n')
        self.rptext.insert(5.0,'Lowest Tm: '+str(lowtemp)[:5]+u' \u00BAC'+'\nHighest Tm: '+str(hightemp)[:5]+u' \u00BAC')
        self.rpscroll.config(command=self.rptext.yview)
        self.rptext.pack()
        self.oligo=''
        return

    #Gets the setting for Tm calculation and selects the appropriate Tm calculating function#
    def CalcTm(self,seq):
        if self.tmMeth==1:
            Tm=CalcTm1(seq)
        if self.tmMeth==2:
            Tm=CalcTm2(seq)
        if self.tmMeth==3:
            Tm=CalcTm3(seq)
        return Tm

    #Assesses forward primers for hairpin loop formation#
    def forhp(self):
        self.oligo=self.fentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        self.grow=regenerate(self.oligo)
        self.fhp=Toplevel(root)
        self.fhp.title('Amplicon: Forward Primer Hairpin Formation')
        self.fhp.resizable(0,0)
        #self.fhp.iconbitmap(self.IconPath)
        self.fhpscroll=Scrollbar(self.fhp)
        self.fhpscroll.pack(side=RIGHT,fill=Y)
        self.fhptext=Text(self.fhp,font=('courier',10), background='light green', height=20, width=60,yscrollcommand=self.fhpscroll.set)
        num = str(len(self.grow))
        self.fhptext.insert(1.0,'Hairpins for forward primer: '+self.oligo+'\nA mixture of '+num+' sequences\n\nHairpins above current threshold:\n\n')
        max=len(self.oligo)*(int(self.maxhplenprop)/100.0)
        n=1
        for seq in self.grow:
            self.fhptext.insert(END,'For oligo number '+str(n)+': '+seq+'\n\n')
            n=n+1
            high=perfectmatch(seq)
            thresh=(self.hpthresh/200.0)*high
            l=self.minhplen
            topcheck=0
            while l<max:
                tops,mids,bots,matches=hairpin(seq,l,thresh)
                tops=tops[:self.numhp+1]
                mids=mids[:self.numhp+1]
                bots=bots[:self.numhp+1]
                matches=matches[:self.numhp+1]
                a=0
                while a < len(tops)-1:
                    self.fhptext.insert(END,tops[a]+'\n')
                    self.fhptext.insert(END,mids[a]+'\n')
                    self.fhptext.insert(END,bots[a]+'\n\n')
                    self.fhptext.insert(END,str(matches[a])+' / '+str(high/2-l)+ ' Potential H-Bonds\n\n')
                    if tops[a]<>[]:
                        topcheck=1
                    a=a+1
                l=l+1
            if topcheck==0:
                self.fhptext.insert(END,'  None\n\n')
        self.fhpscroll.config(command=self.fhptext.yview)
        self.fhptext.pack()
        return

    #Assesses reverse primers for hairpin loop formation#
    def revhp(self):
        self.oligo=self.rentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        self.grow=regenerate(self.oligo)
        self.rhp=Toplevel(root)
        self.rhp.title('Amplicon: Reverse Primer Hairpin Formation')
        self.rhp.resizable(0,0)
        #self.rhp.iconbitmap(self.IconPath)
        self.rhpscroll=Scrollbar(self.rhp)
        self.rhpscroll.pack(side=RIGHT,fill=Y)
        self.rhptext=Text(self.rhp,font=('courier',10), background='light coral', height=20, width=60,yscrollcommand=self.rhpscroll.set)
        num = str(len(self.grow))
        self.rhptext.insert(1.0,'Hairpins for reverse primer: '+self.oligo+'\nA mixture of '+num+' sequences\n\nHairpins above current threshold:\n\n')
        max=len(self.oligo)*(int(self.maxhplenprop)/100.0)
        n=1
        for seq in self.grow:
            self.rhptext.insert(END,'For oligo number '+str(n)+': '+seq+'\n\n')
            n=n+1
            high=perfectmatch(seq)
            thresh=(self.hpthresh/200.0)*high
            l=self.minhplen
            topcheck=0
            while l<max:
                tops,mids,bots,matches=hairpin(seq,l,thresh)
                tops=tops[:self.numhp+1]
                mids=mids[:self.numhp+1]
                bots=bots[:self.numhp+1]
                matches=matches[:self.numhp+1]
                a=0
                while a < len(tops)-1:
                    self.rhptext.insert(END,tops[a]+'\n')
                    self.rhptext.insert(END,mids[a]+'\n')
                    self.rhptext.insert(END,bots[a]+'\n')
                    self.rhptext.insert(END,str(matches[a])+' / '+str(high/2-l)+ ' Potential H-Bonds\n\n')
                    if tops[a]<>[]:
                        topcheck=1
                    a=a+1
                l=l+1
            if topcheck==0:
                self.rhptext.insert(END,'  None\n\n')
        self.rhpscroll.config(command=self.rhptext.yview)
        self.rhptext.pack()
        return

    #Assesses forward primers for self complementarity#
    def forselfcomp(self):
        self.oligo=self.fentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        perfect=perfectmatch(self.oligo)
        threshold=self.propcomp*perfect*0.01
        self.grow=regenerate(self.oligo)
        self.fcp=Toplevel(root)
        self.fcp.title('Amplicon: Forward Primer Self Complementarity')
        self.fcp.resizable(0,0)
        #self.fcp.iconbitmap(self.IconPath)
        self.fcpscroll=Scrollbar(self.fcp)
        self.fcpscroll.pack(side=RIGHT,fill=Y)
        self.fcptext=Text(self.fcp,font=('courier',10), background='light green', height=20, width=60,yscrollcommand=self.fcpscroll.set)
        self.fcptext.tag_config('plus',foreground='blue')
        self.fcptext.tag_config('mid',foreground='black')
        self.fcptext.tag_config('minus',foreground='red')
        self.fcptext.insert(1.0,'Forward primer self complementarity analysis:\n\n')
        n=1
        for a in self.grow:
            self.comps=complementarity(a,'',threshold)
            self.comps=self.comps[:(self.numcomp*4)]
            self.fcptext.insert(END,'oligo number '+str(n)+': '+a)
            if self.comps==[]:
                self.fcptext.insert(END,"\n\nNo self complementarity above current threshold")
            n=n+1
            b=0
            while b<len(self.comps):
                self.fcptext.insert(END,"\n\n"+self.comps[b])
                self.fcptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                self.fcptext.insert(END,'\n'+self.comps[b+1])
                self.fcptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                self.fcptext.insert(END,'\n'+self.comps[b+2])
                self.fcptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                per=perfectmatch(self.comps[b])
                self.fcptext.insert(END,'\n '+self.comps[b+3]+' / '+str(per)+' Potential H-bonds')
                b=b+4
            self.fcptext.insert(END,'\n\n\n')
        if len(self.grow)>1:
            self.fcptext.insert(END,"forward primer multiple sequence complementarities \n\n")
            n=1
            dmin=1
            for a in self.grow:
                d=dmin
                while d < len(self.grow):
                    self.comps=complementarity(a,self.grow[d],threshold)
                    self.comps=self.comps[:(self.numcomp*4)]
                    self.fcptext.insert(END,'oligo combination '+str(n)+': '+a+' + '+self.grow[d])
                    if self.comps==[]:
                        self.fcptext.insert(END,"\n\nNo self complementarity above current threshold\n")
                    n=n+1
                    b=0
                    while b<len(self.comps):
                        self.fcptext.insert(END,"\n\n"+self.comps[b])
                        self.fcptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                        self.fcptext.insert(END,'\n'+self.comps[b+1])
                        self.fcptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                        self.fcptext.insert(END,'\n'+self.comps[b+2])
                        self.fcptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                        per=perfectmatch(self.comps[b])
                        self.fcptext.insert(END,'\n '+self.comps[b+3]+' / '+str(per)+' Potential H-bonds')
                        b=b+4
                    self.fcptext.insert(END,'\n\n\n')     
                    d=d+1
                dmin=dmin+1
        self.fcpscroll.config(command=self.fcptext.yview)
        self.fcptext.pack()
        return
    
    #Assesses reverse primers for self complementarity#
    def revselfcomp(self):
        self.oligo=self.rentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        perfect=perfectmatch(self.oligo)
        threshold=self.propcomp*perfect*0.01
        self.grow=regenerate(self.oligo)
        self.rcp=Toplevel(root)
        self.rcp.title('Amplicon: Reverse Primer Self Complementarity')
        self.rcp.resizable(0,0)
        #self.rcp.iconbitmap(self.IconPath)
        self.rcpscroll=Scrollbar(self.rcp)
        self.rcpscroll.pack(side=RIGHT,fill=Y)
        self.rcptext=Text(self.rcp,font=('courier',10), background='light coral', height=20, width=60,yscrollcommand=self.rcpscroll.set)
        self.rcptext.tag_config('plus',foreground='blue')
        self.rcptext.tag_config('mid',foreground='black')
        self.rcptext.tag_config('minus',foreground='red')
        self.rcptext.insert(1.0,'Reverse primer self complementarity analysis:\n\n')
        n=1
        for a in self.grow:
            self.comps=complementarity(a,'',threshold)
            self.comps=self.comps[:(self.numcomp*4)]
            self.rcptext.insert(END,'oligo number '+str(n)+': '+a)
            if self.comps==[]:
                self.rcptext.insert(END,"\n\nNo self complementarity above current threshold")
            n=n+1
            b=0
            while b<len(self.comps):
                self.rcptext.insert(END,"\n\n"+self.comps[b])
                self.rcptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                self.rcptext.insert(END,'\n'+self.comps[b+1])
                self.rcptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                self.rcptext.insert(END,'\n'+self.comps[b+2])
                self.rcptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                per=perfectmatch(self.comps[b])
                self.rcptext.insert(END,'\n '+self.comps[b+3]+' / '+str(per)+' Potential H-bonds')
                b=b+4
            self.rcptext.insert(END,'\n\n\n')
        if len(self.grow)>1:
            self.rcptext.insert(END,"forward primer multiple sequence complementarities \n\n")
            n=1
            dmin=1
            for a in self.grow:
                d=dmin
                while d < len(self.grow):
                    self.comps=complementarity(a,self.grow[d],threshold)
                    self.comps=self.comps[:(self.numcomp*4)]
                    self.rcptext.insert(END,'oligo combination '+str(n)+': '+a+' + '+self.grow[d])
                    if self.comps==[]:
                        self.rcptext.insert(END,"\n\nNo self complementarity above current threshold\n")
                    n=n+1
                    b=0
                    while b<len(self.comps):
                        self.rcptext.insert(END,"\n\n"+self.comps[b])
                        self.rcptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                        self.rcptext.insert(END,'\n'+self.comps[b+1])
                        self.rcptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                        self.rcptext.insert(END,'\n'+self.comps[b+2])
                        self.rcptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                        per=perfectmatch(self.comps[b])
                        self.rcptext.insert(END,'\n '+self.comps[b+3]+' / '+str(per)+' Potential H-bonds')
                        b=b+4
                    self.rcptext.insert(END,'\n\n\n')     
                    d=d+1
                dmin=dmin+1
        self.rcpscroll.config(command=self.rcptext.yview)
        self.rcptext.pack()
        return

    #Finds false priming sites in the excluded group for the forward primer#
    def forexb(self):
        self.oligo=self.fentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        self.grow=regenerate(self.oligo)
        self.ffp=Toplevel(root)
        self.ffp.title('Amplicon: Forward Primer Excluded Group False Priming Site Search')
        self.ffp.resizable(0,0)
        #self.ffp.iconbitmap(self.IconPath)
        self.ffpscroll=Scrollbar(self.ffp)
        self.ffpscroll.pack(side=RIGHT,fill=Y)
        self.ffptext=Text(self.ffp,font=('courier',10), background='light green', height=20, width=60,yscrollcommand=self.ffpscroll.set)
        self.ffptext.tag_config('plus',foreground='blue')
        self.ffptext.tag_config('mid',foreground='black')
        self.ffptext.tag_config('minus',foreground='red')
        self.ffptext.insert(1.0,'False priming for forward primer in excluded group sequences:\n')
        revout=complement(self.outseq)
        length=len(self.oligo)
        scanbit=''
        scanbits=[]
        positions=[]
        for a in range(0,len(revout)-length-1,1):
            if self.sense[a]<>'-':
                scanbit=''
                b=a
                while len(scanbit)<length and b < len(revout)-1:
                    if revout[b]<>'-':  
                        scanbit=scanbit+revout[b]
                    b=b+1
            if len(scanbit)==len(self.oligo):
                degscanbit=regenerate(scanbit)
                for d in range(0,len(degscanbit)):
                    scanbits=scanbits+[degscanbit[d]]
                    positions=positions+[b]
        perfect=perfectmatch(self.oligo)
        threshold=self.propcomp*perfect*0.01
        n=1
        for x in self.grow:
            self.ffptext.insert(END,'\nOligo number: '+str(n)+ '\nSequence: '+x+'\n')
            n=n+1
            matchlist0=[]
            matchlist1=[]
            matchlist2=[]
            matchlist3=[]
            matchlist4=[]
            for y in range(0,len(scanbits)-1,1):
                self.comps=falsepriming(x,scanbits[y])
                if self.comps[3]>threshold:
                    if self.threeprimetick==1 and self.comps[1][len(self.comps[1])-4]<>' ' or self.threeprimetick==0:
                        matchlist0=[self.comps[0]]+matchlist0
                        matchlist1=[self.comps[1]]+matchlist1      
                        matchlist2=[self.comps[2]]+matchlist2
                        matchlist3=[self.comps[3]]+matchlist3
                        matchlist4=[positions[y]]+matchlist4
            max=perfect
            nmatchlist0=[]
            nmatchlist1=[]
            nmatchlist2=[]
            nmatchlist3=[]
            nmatchlist4=[]
            while max>0:
                for r in range(0,len(matchlist3)):
                    if int(matchlist3[r])==max:
                        nmatchlist0=nmatchlist0+[matchlist0[r]]
                        nmatchlist1=nmatchlist1+[matchlist1[r]]
                        nmatchlist2=nmatchlist2+[matchlist2[r]]
                        nmatchlist3=nmatchlist3+[matchlist3[r]]
                        nmatchlist4=nmatchlist4+[matchlist4[r]]
                max=max-1
            nmatchlist0=nmatchlist0[:self.numcomp+1]
            nmatchlist1=nmatchlist1[:self.numcomp+1]
            nmatchlist2=nmatchlist2[:self.numcomp+1]
            nmatchlist3=nmatchlist3[:self.numcomp+1]
            nmatchlist4=nmatchlist4[:self.numcomp+1]
            if len(nmatchlist0)<2:
                self.ffptext.insert(END,"No false priming above current threshold\n")   
            for z in range(0,len(nmatchlist0)-1):
                self.ffptext.insert(END,"\nPosition in alignment where 3' end of oligo binds: "+str(nmatchlist4[z]-len(self.oligo)+1)+' - '+str(nmatchlist4[z]))
                self.ffptext.insert(END,"\n"+nmatchlist0[z]+' (oligo)')
                self.ffptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                self.ffptext.insert(END,'\n'+nmatchlist1[z])
                self.ffptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                self.ffptext.insert(END,'\n'+nmatchlist2[z]+' (excluded)')
                self.ffptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                per=perfectmatch(nmatchlist0[z])
                self.ffptext.insert(END,'\n '+str(nmatchlist3[z])+' / '+str(per)+' Potential H-bonds\n')
        self.ffpscroll.config(command=self.ffptext.yview)
        self.ffptext.pack()
        return

    #Finds false priming sites in the target group for the forward primer#
    def forfp(self):
        self.oligo=self.fentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        self.grow=regenerate(self.oligo)
        self.ffp=Toplevel(root)
        self.ffp.title('Amplicon: Forward Primer Target Group False Priming Site Search')
        self.ffp.resizable(0,0)
        #self.ffp.iconbitmap(self.IconPath)
        self.ffpscroll=Scrollbar(self.ffp)
        self.ffpscroll.pack(side=RIGHT,fill=Y)
        self.ffptext=Text(self.ffp,font=('courier',10), background='light green', height=20, width=60,yscrollcommand=self.ffpscroll.set)
        self.ffptext.tag_config('plus',foreground='blue')
        self.ffptext.tag_config('mid',foreground='black')
        self.ffptext.tag_config('minus',foreground='red')
        self.ffptext.insert(1.0,'False priming for forward primer in target sequences:\n')
        length=len(self.oligo)
        scanbit=''
        scanbits=[]
        positions=[]
        for a in range(0,len(self.antisense)-length-1,1):
            if self.sense[a]<>'-':
                scanbit=''
                b=a
                while len(scanbit)<length and b < len(self.antisense)-1:
                    if self.antisense[b]<>'-':  
                        scanbit=scanbit+self.antisense[b]
                    b=b+1
            if len(scanbit)==len(self.oligo):
                degscanbit=regenerate(scanbit)
                for d in range(0,len(degscanbit)):
                    scanbits=scanbits+[degscanbit[d]]
                    positions=positions+[b]
        perfect=perfectmatch(self.oligo)
        threshold=self.propcomp*perfect*0.01
        n=1
        for x in self.grow:
            self.ffptext.insert(END,'\nOligo number: '+str(n)+ '\nSequence: '+x+'\n')
            n=n+1
            matchlist0=[]
            matchlist1=[]
            matchlist2=[]
            matchlist3=[]
            matchlist4=[]
            for y in range(0,len(scanbits)-1,1):
                self.comps=falsepriming(x,scanbits[y])
                if self.comps[3]>threshold:
                    if self.threeprimetick==1 and self.comps[1][len(self.comps[1])-4]<>' ' or self.threeprimetick==0:
                        matchlist0=[self.comps[0]]+matchlist0
                        matchlist1=[self.comps[1]]+matchlist1      
                        matchlist2=[self.comps[2]]+matchlist2
                        matchlist3=[self.comps[3]]+matchlist3
                        matchlist4=[positions[y]]+matchlist4
            max=perfect-1
            nmatchlist0=[]
            nmatchlist1=[]
            nmatchlist2=[]
            nmatchlist3=[]
            nmatchlist4=[]
            while max>0:
                for r in range(0,len(matchlist3)):
                    if int(matchlist3[r])==max:
                        nmatchlist0=nmatchlist0+[matchlist0[r]]
                        nmatchlist1=nmatchlist1+[matchlist1[r]]
                        nmatchlist2=nmatchlist2+[matchlist2[r]]
                        nmatchlist3=nmatchlist3+[matchlist3[r]]
                        nmatchlist4=nmatchlist4+[matchlist4[r]]
                max=max-1
            nmatchlist0=nmatchlist0[:self.numcomp+1]
            nmatchlist1=nmatchlist1[:self.numcomp+1]
            nmatchlist2=nmatchlist2[:self.numcomp+1]
            nmatchlist3=nmatchlist3[:self.numcomp+1]
            nmatchlist4=nmatchlist4[:self.numcomp+1]
            if len(nmatchlist0)<2:
                self.ffptext.insert(END,"No false priming above current threshold\n")   
            for z in range(0,len(nmatchlist0)-1):
                self.ffptext.insert(END,"\nPosition in target sequence where oligo binds: "+str(nmatchlist4[z]-len(self.oligo)+1)+' - '+str(nmatchlist4[z]))
                self.ffptext.insert(END,"\n"+nmatchlist0[z]+' (oligo)')
                self.ffptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                self.ffptext.insert(END,'\n'+nmatchlist1[z])
                self.ffptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                self.ffptext.insert(END,'\n'+nmatchlist2[z]+' (target)')
                self.ffptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                per=perfectmatch(nmatchlist0[z])
                self.ffptext.insert(END,'\n '+str(nmatchlist3[z])+' / '+str(per)+' Potential H-bonds\n')
        self.ffpscroll.config(command=self.ffptext.yview)
        self.ffptext.pack()
        return

    #Finds false priming sites in the target group for the reverse primer#
    def revfp(self):
        self.oligo=self.rentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        self.oligo=reverse(self.oligo)
        self.grow=regenerate(self.oligo)
        self.rfp=Toplevel(root)
        self.rfp.title('Amplicon: Reverse Primer Target Group False Priming Site Search')
        self.rfp.resizable(0,0)
        #self.rfp.iconbitmap(self.IconPath)
        self.rfpscroll=Scrollbar(self.rfp)
        self.rfpscroll.pack(side=RIGHT,fill=Y)
        self.rfptext=Text(self.rfp,font=('courier',10), background='light coral', height=20, width=60,yscrollcommand=self.rfpscroll.set)
        self.rfptext.tag_config('plus',foreground='blue')
        self.rfptext.tag_config('mid',foreground='black')
        self.rfptext.tag_config('minus',foreground='red')
        self.rfptext.insert(1.0,'False target group priming for reverse primer:\n')
        length=len(self.oligo)
        scanbit=''
        scanbits=[]
        positions=[]
        for a in range(0,len(self.antisense)-length-1,1):
            if self.sense[a]<>'-':
                scanbit=''
                b=a
                while len(scanbit)<length and b < len(self.sense)-1:
                    if self.sense[b]<>'-':  
                        scanbit=scanbit+self.sense[b]
                    b=b+1
            if len(scanbit)==len(self.oligo):
                degscanbit=regenerate(scanbit)
                for d in range(0,len(degscanbit)):
                    scanbits=scanbits+[degscanbit[d]]
                    positions=positions+[(b-len(self.oligo))-2]
        perfect=perfectmatch(self.oligo)
        threshold=self.propcomp*perfect*0.01
        n=1
        for x in self.grow:
            self.rfptext.insert(END,'\nOligo number: '+str(n)+ '\nSequence: '+x+'\n')
            n=n+1
            matchlist0=[]
            matchlist1=[]
            matchlist2=[]
            matchlist3=[]
            matchlist4=[]
            for y in range(0,len(scanbits)-1,1):
                self.comps=revfalsepriming(x,scanbits[y])
                if self.comps[3]>threshold:
                    if self.threeprimetick==1 and self.comps[1][3]<>' ' or self.threeprimetick==0:
                        matchlist0=[self.comps[0]]+matchlist0
                        matchlist1=[self.comps[1]]+matchlist1      
                        matchlist2=[self.comps[2]]+matchlist2
                        matchlist3=[self.comps[3]]+matchlist3
                        matchlist4=[positions[y]]+matchlist4
            max=perfect-1
            nmatchlist0=[]
            nmatchlist1=[]
            nmatchlist2=[]
            nmatchlist3=[]
            nmatchlist4=[]
            while max>0:
                for r in range(0,len(matchlist3)):
                    if int(matchlist3[r])==max:
                        nmatchlist0=nmatchlist0+[matchlist0[r]]
                        nmatchlist1=nmatchlist1+[matchlist1[r]]
                        nmatchlist2=nmatchlist2+[matchlist2[r]]
                        nmatchlist3=nmatchlist3+[matchlist3[r]]
                        nmatchlist4=nmatchlist4+[matchlist4[r]]
                max=max-1
            nmatchlist0=nmatchlist0[:self.numcomp+1]
            nmatchlist1=nmatchlist1[:self.numcomp+1]
            nmatchlist2=nmatchlist2[:self.numcomp+1]
            nmatchlist3=nmatchlist3[:self.numcomp+1]
            nmatchlist4=nmatchlist4[:self.numcomp+1]
            if len(nmatchlist0)<2:
                self.ffptext.insert(END,"No false priming above current threshold\n")   
            for z in range(0,len(nmatchlist0)-1):
                self.rfptext.insert(END,"\nPosition where oligo binds: "+str(nmatchlist4[z]+3)+' - '+str(nmatchlist4[z]+len(self.oligo)+2))
                self.rfptext.insert(END,"\n"+nmatchlist0[z]+' (oligo)')
                self.rfptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                self.rfptext.insert(END,'\n'+nmatchlist1[z])
                self.rfptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                self.rfptext.insert(END,'\n'+nmatchlist2[z]+' (target)')
                self.rfptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                per=perfectmatch(nmatchlist0[z])
                self.rfptext.insert(END,'\n '+str(nmatchlist3[z])+' / '+str(per)+' Potential H-bonds\n')
        self.rfpscroll.config(command=self.rfptext.yview)
        self.rfptext.pack()
        return

    #Finds false priming sites in the excluded group for the reverse primer#
    def revexb(self):
        self.oligo=self.rentry.get()
        self.oligo=self.primerin(self.oligo)
        if self.oligo=='':
            return
        self.oligo=reverse(self.oligo)
        self.grow=regenerate(self.oligo)
        self.rfp=Toplevel(root)
        self.rfp.title('Amplicon: Reverse Primer Excluded Group False Priming Site Search')
        self.rfp.resizable(0,0)
        #self.rfp.iconbitmap(self.IconPath)
        self.rfpscroll=Scrollbar(self.rfp)
        self.rfpscroll.pack(side=RIGHT,fill=Y)
        self.rfptext=Text(self.rfp,font=('courier',10), background='light coral', height=20, width=60,yscrollcommand=self.rfpscroll.set)
        self.rfptext.tag_config('plus',foreground='blue')
        self.rfptext.tag_config('mid',foreground='black')
        self.rfptext.tag_config('minus',foreground='red')
        self.rfptext.insert(1.0,'False excluded group priming for reverse primer:\n')
        length=len(self.oligo)
        scanbit=''
        scanbits=[]
        positions=[]
        for a in range(0,len(self.outseq)-length-1,1):
            if self.outseq[a]<>'-':
                scanbit=''
                b=a
                while len(scanbit)<length and b < len(self.outseq)-1:
                    if self.outseq[b]<>'-':  
                        scanbit=scanbit+self.outseq[b]
                    b=b+1
            if len(scanbit)==len(self.oligo):
                degscanbit=regenerate(scanbit)
                for d in range(0,len(degscanbit)):
                    scanbits=scanbits+[degscanbit[d]]
                    positions=positions+[(b-len(self.oligo))-2]
        perfect=perfectmatch(self.oligo)
        threshold=self.propcomp*perfect*0.01
        n=1
        for x in self.grow:
            self.rfptext.insert(END,'\nOligo number: '+str(n)+ '\nSequence: '+x+'\n')
            n=n+1
            matchlist0=[]
            matchlist1=[]
            matchlist2=[]
            matchlist3=[]
            matchlist4=[]
            for y in range(0,len(scanbits)-1,1):
                self.comps=revfalsepriming(x,scanbits[y])
                if self.comps[3]>threshold:
                    if self.threeprimetick==1 and self.comps[1][3]<>' ' or self.threeprimetick==0:
                        matchlist0=[self.comps[0]]+matchlist0
                        matchlist1=[self.comps[1]]+matchlist1      
                        matchlist2=[self.comps[2]]+matchlist2
                        matchlist3=[self.comps[3]]+matchlist3
                        matchlist4=[positions[y]]+matchlist4
            max=perfect+1
            nmatchlist0=[]
            nmatchlist1=[]
            nmatchlist2=[]
            nmatchlist3=[]
            nmatchlist4=[]
            while max>0:
                for r in range(0,len(matchlist3)):
                    if int(matchlist3[r])==max:
                        nmatchlist0=nmatchlist0+[matchlist0[r]]
                        nmatchlist1=nmatchlist1+[matchlist1[r]]
                        nmatchlist2=nmatchlist2+[matchlist2[r]]
                        nmatchlist3=nmatchlist3+[matchlist3[r]]
                        nmatchlist4=nmatchlist4+[matchlist4[r]]
                max=max-1
            nmatchlist0=nmatchlist0[:self.numcomp+1]
            nmatchlist1=nmatchlist1[:self.numcomp+1]
            nmatchlist2=nmatchlist2[:self.numcomp+1]
            nmatchlist3=nmatchlist3[:self.numcomp+1]
            nmatchlist4=nmatchlist4[:self.numcomp+1]
            if len(nmatchlist0)<2:
                self.ffptext.insert(END,"No false priming above current threshold\n")   
            for z in range(0,len(nmatchlist0)-1):
                self.rfptext.insert(END,"\nPosition in excluded group where oligo binds: "+str(nmatchlist4[z]+3)+' - '+str(nmatchlist4[z]+len(self.oligo)+2))
                self.rfptext.insert(END,"\n"+nmatchlist0[z]+' (oligo)')
                self.rfptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                self.rfptext.insert(END,'\n'+nmatchlist1[z])
                self.rfptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                self.rfptext.insert(END,'\n'+nmatchlist2[z]+' (excluded)')
                self.rfptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                per=perfectmatch(nmatchlist0[z])
                self.rfptext.insert(END,'\n '+str(nmatchlist3[z])+' / '+str(per)+' Potential H-bonds\n')
        self.rfpscroll.config(command=self.rfptext.yview)
        self.rfptext.pack()
        return

    #Checks forward and reverse primers for complementarity with each other#
    def bothcomp(self):
        self.oligoF=self.fentry.get()
        self.oligoF=self.primerin(self.oligoF)
        if self.oligoF=='':
            return
        self.oligoR=self.rentry.get()
        self.oligoR=self.primerin(self.oligoR)
        if self.oligoR=='':
            return
        self.growF=regenerate(self.oligoF)
        self.growR=regenerate(self.oligoR)
        perfect1=perfectmatch(self.oligoF)
        perfect2=perfectmatch(self.oligoR)
        if perfect2<perfect1:
            perfect1=perfect2
        threshold=self.propcomp*perfect1*0.01
        self.bcp=Toplevel(root)
        self.bcp.title('Amplicon: Forward - Reverse Primer Complementarity')
        self.bcp.resizable(0,0)
        #self.bcp.iconbitmap(self.IconPath)
        self.bcpscroll=Scrollbar(self.bcp)
        self.bcpscroll.pack(side=RIGHT,fill=Y)
        self.bcptext=Text(self.bcp,font=('courier',10), background='light yellow', height=20, width=60,yscrollcommand=self.bcpscroll.set)
        self.bcptext.tag_config('plus',foreground='blue')
        self.bcptext.tag_config('mid',foreground='black')
        self.bcptext.tag_config('minus',foreground='red')
        self.bcptext.insert(1.0,'Forward - reverse primer complementarity analysis:\n\n')
        n=1
        q=0
        while q <len(self.growR):
            for a in self.growF:
                self.comps=complementarity(a,self.growR[q],threshold)
                self.comps=self.comps[:(self.numcomp*4)]
                self.bcptext.insert(END,'Oligo Combination Number '+str(n)+'\nForward Primer: '+a+'\nReverse Primer: '+self.growR[q])
                if self.comps==[]:
                    self.bcptext.insert(END,"\n\nNo complementarity above current threshold\n")
                n=n+1
                b=0
                while b<len(self.comps):
                    self.bcptext.insert(END,"\n\n"+self.comps[b])
                    self.bcptext.tag_add('plus',END+'- 1 lines',END+'- 1 c')
                    self.bcptext.insert(END,'\n'+self.comps[b+1])
                    self.bcptext.tag_add('mid',END+'- 1 lines',END+'- 1 c')
                    self.bcptext.insert(END,'\n'+self.comps[b+2])
                    self.bcptext.tag_add('minus',END+'- 1 lines',END+'- 1 c')
                    per=perfectmatch(self.comps[b])
                    self.bcptext.insert(END,'\n '+self.comps[b+3]+' / '+str(per)+' Potential H-bonds')
                    b=b+4
                self.bcptext.insert(END,'\n\n')
            q=q+1
        self.bcpscroll.config(command=self.bcptext.yview)
        self.bcptext.pack()
        return

    #Generates information on the fragment of DNA to be amplified#
    def analyseamp(self):
        sense=self.sense
        sp=0
        startrange=self.fpbind5
        endrange=self.rpbind3
        if startrange==0 or endrange==0:
            x=tkMessageBox.Message(icon='error', type='ok', message='Primer binding sites must be selected', title='Amplicon: Error').show()
            return
        if startrange>endrange:
            x=tkMessageBox.Message(icon='error', type='ok', message="3' end of forward primer binding site must be \n 5' of 3' end of reverse primer binding site", title='Amplicon: Error').show()
            return
        frag=sense[startrange:endrange]
        newfrag=''
        for a in frag:
            if a <>'-':
                newfrag=newfrag+a
        frag=string.upper(newfrag)
        fraglength=len(frag)
        gc,gcmin,gcmax=gcper(frag)
        gc=str(gc)
        gcmin=str(gcmin)
        gcmax=str(gcmax)
        fo=self.fentry.get()
        forw=self.primerin(fo)
        if forw=='':
            return
        forw=str(len(forw))
        re=self.rentry.get()
        rev=self.primerin(re)
        if rev=='':
            return
        length=len(rev)
        internal=int(len(frag))-int(forw)-length
        self.amp=Toplevel(root)
        self.amp.title('Amplicon: Amplified Fragment Analysis')
        self.amp.resizable(0,0)
        #self.amp.iconbitmap(self.IconPath)
        self.ampscroll=Scrollbar(self.amp)
        self.ampscroll.pack(side=RIGHT,fill=Y)
        self.amptext=Text(self.amp,font=('courier',10), background='light yellow',height=20, width=60,yscrollcommand=self.ampscroll.set)
        self.amptext.tag_config('forward',foreground ='green')
        self.amptext.tag_config('reverse',foreground ='light coral')
        self.amptext.insert(1.0,'Forward Primer: '+fo+', '+forw+' mer'+'\nReverse Primer: '+re+', '+str(length)+
                            ' mer\n\nFragment sequence: \n'+frag+'\n\nOverall Length: '+str(len(frag))+' bp\nInter-Primer Length: '+
                            str(internal)+' bp\n\nMean Fragment GC% '+gc[:5]+'\nLowest Possible Fragment GC% '+
                            gcmin[:5]+'\nHighest Possible Fragment GC% '+gcmax[:5])
        fo=self.fentry.get()
        if fo[len(fo)-1]<>'A' and fo[len(fo)-1]<>'C' and fo[len(fo)-1]<>'T' and fo[len(fo)-1]<>'G':
            self.amptext.insert(END,"\n\nWARNING! 3' end of forward primer is degenerate")
        fo=self.rentry.get()
        if fo[len(fo)-1]<>'A' and fo[len(fo)-1]<>'C' and fo[len(fo)-1]<>'T' and fo[len(fo)-1]<>'G':
            self.amptext.insert(END,"\n\nWARNING! 3' end of reverse primer is degenerate")
        self.amptext.insert(END,'\n\nBase Counts:')
        counts=[0]
        iub='ACGTYRMKWSVBHDN-*'
        for r in iub:
            counts=counts+[0]
        for a in frag:
            for b in range(0,len(iub)-1,1):
                if iub[b]==a:
                    counts[b]=counts[b]+1
        for x in range(0,len(iub)):
            self.amptext.insert(END,'\n'+str(iub[x])+': '+str(counts[x]))
        rev=int(fraglength)-length
        rev=str(rev)
        length=str(length)
        first='5.0+'+forw+'c'
        second='5.0+'+rev+'c'
        third=second+'+'+length+'c'
        self.amptext.tag_add('forward','5.0',first)
        self.amptext.tag_add('reverse',second,third)
        self.ampscroll.config(command=self.amptext.yview)
        self.amptext.pack()
        return

# Settings Menu Functions #

    #Dialog for altering parameters for primer binding site searches#
    def setsearch(self):
        try:
            self.se1.insert(0,'')
            return
        except:
            sets=Toplevel(root)
            sets.title('Parameters for oligo binding site searches')
            sets.resizable(0,0)
            #sets.iconbitmap(self.IconPath)
            sets.transient(root)
            self.se1=Entry(sets,width=4)
            self.se1.grid(row=0)
            self.se2=Entry(sets,width=4)
            self.se2.grid(row=1)
            self.se3=Entry(sets,width=4)
            self.se3.grid(row=2)
            self.se4=Entry(sets,width=4)
            self.se4.grid(row=3)
            self.se5=Entry(sets,width=4)
            self.se5.grid(row=4)
            self.se6=Entry(sets,width=4)
            self.se6.grid(row=5)
            self.l1=Label(sets,font=('Arial',10),text='Length of primer binding site (10-42)').grid(row=0,column=1,sticky=W)
            self.l2=Label(sets,font=('Arial',10),text='Degeneracy allowed in primer binding site (1-64)').grid(row=1,column=1,sticky=W)
            self.l3=Label(sets,font=('Arial',10),text='Minimum Tm for oligo perfectly matched to primer binding site (30-80)').grid(row=2,column=1,sticky=W)
            self.l4=Label(sets,font=('Arial',10),text='Maximum Tm for oligo perfectly matched to primer binding site (30-80)').grid(row=3,column=1,sticky=W)
            self.l5=Label(sets,font=('Arial',10),text='Minimum GC% for primer binding site (1-99)').grid(row=4,column=1,sticky=W)
            self.l6=Label(sets,font=('Arial',10),text='Maximum GC% for primer binding site (1-99)').grid(row=5,column=1,sticky=W)
            self.se1.insert(0,self.searchlen)
            self.se2.insert(0,self.searchdeg)
            self.se3.insert(0,self.searchtm)
            self.se4.insert(0,self.searchtmmax)
            self.se5.insert(0,self.searchgclow)
            self.se6.insert(0,self.searchgchigh)
            self.svrad=IntVar()
            self.sr1=Radiobutton(sets,variable=self.svrad,value=1,font=('Arial',10),text="1. All 3' ends allowed")
            self.sr1.grid(row=6,columnspan=2,sticky=W)
            self.sr2=Radiobutton(sets,variable=self.svrad,value=2,font=('Arial',10),text="2. No degenerate sites in terminal 3' position")
            self.sr2.grid(row=7,columnspan=2,sticky=W)
            self.sr3=Radiobutton(sets,variable=self.svrad,value=3,font=('Arial',10),text="3. Terminal 3' position must differ between target and excluded group")
            self.sr3.grid(row=8,columnspan=2,sticky=W)
            self.sr4=Radiobutton(sets,variable=self.svrad,value=4,font=('Arial',10),text="4. Terminal 3' position must not be degenerate and \nmust differ between target and excluded group")
            self.sr4.grid(row=9,columnspan=2,sticky=W)
            self.butt=Button(sets,text='Enter',command=self.setsin)
            self.butt.grid(row=10)
            self.sr1.select()
            return

    #Changes parameters for primer binding site searches#
    def setsin(self):
        self.searchlen1=self.se1.get()
        self.searchlen1=int(self.searchlen1)
        if self.searchlen1>9 and self.searchlen1<43:
            self.searchlen=self.searchlen1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Primer binding site length out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.searchdeg1=self.se2.get()
        self.searchdeg1=int(self.searchdeg1)
        if self.searchdeg1 >0 and self.searchdeg1<65:
            self.searchdeg=self.searchdeg1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Primer binding site degeneracy out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.searchtm1=self.se3.get()
        self.searchtm1=int(self.searchtm1)
        if self.searchtm1 >29 and self.searchtm1<81:
            self.searchtm=self.searchtm1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Primer binding site / oligo Tm minimum out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.searchtmmax1=self.se4.get()
        self.searchtmmax1=int(self.searchtmmax1)
        if self.searchtmmax1>0 and self.searchtmmax1<100:
            self.searchtmmax=self.searchtmmax1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Primer binding site / oligo Tm maximum out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.searchgclow1=self.se5.get()
        self.searchgclow1=int(self.searchgclow1)
        if self.searchgclow1>0 and self.searchgclow1<100:
            self.searchgclow=self.searchgclow1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Minimum primer binding site GC% out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.searchgchigh1=self.se6.get()
        self.searchgchigh1=int(self.searchgchigh1)
        if self.searchgchigh>1 and self.searchgchigh1<100:
            self.searchgchigh=self.searchgchigh1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Maximum primer binding site GC% out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.search3set=self.svrad.get()
        root.bell()
        return

    #Dialog for altering parameters for GC% and Tm plotting#
    def setplot(self):
        try:
            self.spentry1.insert(0,'')
            return
        except:
            sp=Toplevel(root)
            sp.title('Settings for Tm and GC% plots')
            sp.resizable(0,0)
            #sp.iconbitmap(self.IconPath)
            sp.transient(root)
            self.dir=IntVar()
            self.setd=Radiobutton(sp,variable=self.dir,value=1,text="Foward scan, results plotted at 3' end of window",font=('Arial',10))
            self.setd.grid(column=0,row=0,sticky=W,columnspan=2)
            self.setd1=Radiobutton(sp,variable=self.dir,value=2,text="Reverse scan, results plotted at 5' end of window",font=('Arial',10))
            self.setd1.grid(column=0,row=1,sticky=W,columnspan=2)
            self.spentry1=Entry(sp,width=4)
            self.spentry1.insert(0,self.scanlength)
            self.spentry1.grid(column=0,row=2)
            self.spentry2=Entry(sp,width=4)
            self.spentry2.insert(0,self.scandegeneracy)
            self.spentry2.grid(column=0,row=3)
            self.splabel1=Label(sp,font=('Arial',10),text='Length of scan window (10-50)').grid(column=1,row=2,sticky=W,columnspan=2)
            self.splabel1=Label(sp,font=('Arial',10),text='Maximum degeneracy for sites in scan window (1-1024)').grid(column=1,row=3,sticky=W,columnspan=2)
            self.spbutton=Button(sp,text='Enter',command=self.setsp)
            self.spbutton.grid(column=0,row=4,sticky=W)
            self.setd.select()
        return

    #Alters parameters for GC% and Tm plotting#
    def setsp(self):
        self.scanlength1=self.spentry1.get()
        self.scanlength1=int(self.scanlength1)
        if self.scanlength1 >9 and self.scanlength1 < 51:
            self.scanlength=self.scanlength1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Search window size out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.scandegeneracy1=self.spentry2.get()
        self.scandegeneracy1=int(self.scandegeneracy1)
        if self.scandegeneracy1 >0 and self.scandegeneracy1<1025:
            self.scandegeneracy=self.scandegeneracy1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Maximum degeneracy for scan window out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.scanMeth=self.dir.get()
        root.bell()
        return

    #Dialog for selecting Tm calculation method#
    def settm(self):
        try:
            self.tmentry1.insert(0,'')
            return
        except:
            settm=Toplevel(root)
            settm.title('Settings for Tm calculation')
            settm.resizable(0,0)
            #settm.iconbitmap(self.IconPath)
            settm.transient(root)
            self.tmRad=IntVar()
            self.settmRadB1=Radiobutton(settm,variable=self.tmRad,value=1,text='1. Nearest neighbour (Allawi and SantaLucia, 1997)',font=('Arial',10))
            self.settmRadB1.grid(column=0,row=0,sticky=W, columnspan=2)
            self.settmRadB2=Radiobutton(settm,variable=self.tmRad,value=2,text='3. GC% (Wallace et al., 1979)',font=('Arial',10))
            self.settmRadB2.grid(column=0,row=2,sticky=W, columnspan=2)
            self.settmRadB3=Radiobutton(settm,variable=self.tmRad,value=3,text='2. GC% + Salt + Formamide (Howley et al., 1979)',font=('Arial',10))
            self.settmRadB3.grid(column=0,row=1,sticky=W, columnspan=2)
            self.tmentry1=Entry(settm,width=4)
            self.tmentry1.grid(column=0,row=3,sticky=W)
            self.tmentry2=Entry(settm,width=4)
            self.tmentry2.grid(column=0,row=4,sticky=W)
            self.tmlabel=Label(settm,font=('Arial',10),text='(1,2 only) Molar concentration of monovalent cations (0-1)').grid(column=1,row=3, sticky=W)
            self.tmlabel=Label(settm,font=('Arial',10),text='(2 only) Molar concentration of formamide (0-5)').grid(column=1,row=4, sticky=W)
            self.settmbutton = Button(settm,text='Enter',command=self.settmin)
            self.settmbutton.grid(column=0,row=5, sticky=W)
            self.tmentry1.insert(0,self.monovalent)
            self.tmentry2.insert(0,self.formamide)
            self.settmRadB1.select()
            return

    #Alters Tm calculation method#
    def settmin(self):
        self.tmMeth=self.tmRad.get()
        self.monovalent1=self.tmentry1.get()
        self.monovalent1=float(self.monovalent1)
        if self.monovalent1>0 and self.monovalent1<1:
            self.monovalent=self.monovalent1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Monovalent cation concentration of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.formamide1=self.tmentry2.get()
        self.formamide1=float(self.formamide1)
        if self.formamide1>-0.01 and self.formamide1<5:
            self.formamide=self.formamide1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Formamide concentration of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        root.bell()
        return

    #Dialog for selecting paramters used in testing for hairpin loop formation#
    def sethairpin(self):
        try:
            self.setHentry.insert(0,'')
            return
        except:
            setH=Toplevel(root)
            setH.title('Settings for Primer Hairpin Tests')
            setH.resizable(0,0)
            #setH.iconbitmap(self.IconPath)
            setH.transient(root)
            self.setHentry = Entry(setH,width=3)
            self.setHentry.insert(1,self.numhp)
            self.setHbutton = Button(setH,text='Enter',command=self.setHin)
            self.setHentry2 = Entry(setH,width=3)
            self.setHentry2.insert(1,self.minhplen)
            self.setHentry3 = Entry(setH,width=3)
            self.setHentry3.insert(1,self.maxhplenprop)
            self.setHentry4 = Entry(setH,width=3)
            self.setHentry4.insert(1,self.hpthresh)
            self.Hl1=Label(setH,font=('Arial',10),text='Number of strongest matches over threshold to return (1-20)').grid(row=0,column=1, sticky=W)
            self.Hl2=Label(setH,font=('Arial',10),text='Minimum length of hairpin loop in base pairs (1-5)').grid(row=1,column=1, sticky=W)
            self.Hl3=Label(setH,font=('Arial',10),text='Maximum length of hairpin loop as percentage of oligo length (1-50%)').grid(row=2,column=1, sticky=W)
            self.Hl4=Label(setH,font=('Arial',10),text='Threshold: percentage proportion of mathces compared to a perfect hairpin oligo (1-99%)').grid(row=3,column=1, sticky=W)
            self.setHentry.grid(row=0, column=0)
            self.setHbutton.grid(row=4, column=0, sticky=W)
            self.setHentry2.grid(row=1, column=0)
            self.setHentry3.grid(row=2, column=0)
            self.setHentry4.grid(row=3, column=0)
            return

    #Sets parameters for hairpin loop formation tests#
    def setHin(self):
        self.numhp1=self.setHentry.get()
        self.numhp1=int(self.numhp1)
        if self.numhp1>0 and self.numhp1<20:
            self.numhp=self.numhp1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Threshold value out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.minhplen1=self.setHentry2.get()
        self.minhplen1=int(self.minhplen1)
        if self.minhplen1>0 and self.minhplen1<6:
            self.minhplen=self.minhplen1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Minimum hairpin loops value out of range.  Please re-enter.", title='Amplicon: Error').show()
            return            
        self.maxhplenprop1=self.setHentry3.get()
        self.maxhplenprop1=int(self.maxhplenprop1)
        if self.maxhplenprop1>0 and self.maxhplenprop1<51:
            self.maxhplenprop=self.maxhplenprop1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Maximum hairpin loops percentage out of range.  Please re-enter.", title='Amplicon: Error').show()
            return            
        self.hpthresh1=self.setHentry4.get()
        self.hpthresh1=int(self.hpthresh1)
        if self.hpthresh1>0 and self.hpthresh1<100:
            self.hpthresh=self.hpthresh1
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Threshold percentage out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        root.bell()
        return

    #Dialog for selecting parameters for complementarity tests#
    def setcomplement(self):
        try:
            self.setcentry.insert(0,'')
            return
        except:
            setC=Toplevel(root)
            setC.title('Settings for Complementarity, Binding and False Priming Tests')
            setC.resizable(0,0)
            #setC.iconbitmap(self.IconPath)
            setC.transient(root)
            self.setcentry = Entry(setC,width=3)
            self.setcentry.insert(1,self.numcomp)
            self.setcbutton = Button(setC,text='Enter',command=self.setCin)
            self.setcentry2 = Entry(setC,width=3)
            self.setcentry2.insert(1,self.propcomp)
            self.setcentry3 = Entry(setC,width=3)
            self.setcentry3.insert(1,self.maxdegeneracy)
            self.l1=Label(setC,font=('Arial',10),text='Number of strongest matches over threshold to return (1-20)').grid(row=2,column=1, sticky=W)
            self.l2=Label(setC,font=('Arial',10),text='Threshold for recognition as percentage of H-bonds compared to perfect match (1-99%)').grid(row=3,column=1, sticky=W)
            self.l3=Label(setC,font=('Arial',10),text='Maximum degeneracy (number of component sequences in any oligo) (1-256)').grid(row=4,column=1, sticky=W)
            self.wobvar=IntVar()
            self.wob1=Radiobutton(setC,variable=self.wobvar,value=1,font=('Arial',10),text='Allow wobble G:T pairings of two H-bonds')
            self.wob2=Radiobutton(setC,variable=self.wobvar,value=2,font=('Arial',10),text='Disalow wobble G:T pairings')
            self.wob1.grid(row=0,columnspan=2,sticky=W)
            self.wob2.grid(row=1,columnspan=2,sticky=W)
            self.tptickvar=IntVar()
            self.tpt1=Radiobutton(setC,variable=self.tptickvar,value=0,font=('Arial',10),text='Consider all oligo false priming')
            self.tpt2=Radiobutton(setC,variable=self.tptickvar,value=1,font=('Arial',10),text="Only consider false priming positions with binding of 3' end of oligo")
            self.tpt1.grid(row=5,columnspan=2,sticky=W)
            self.tpt2.grid(row=6,columnspan=2,sticky=W)
            self.setcentry.grid(row=2, column=0)
            self.setcbutton.grid(row=7, column=0, sticky=W)
            self.setcentry2.grid(row=3, column=0)
            self.setcentry3.grid(row=4, column=0)
            self.wob1.select()
            self.tpt2.select()
            return

    #Alters parameters for complementarity tests#
    def setCin(self):
        self.numcomp=self.setcentry.get()
        if int(self.numcomp)>1 and int(self.numcomp)<20: 
            self.numcomp=int(self.numcomp)
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Number of complementary pairs to return out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.propcomp=self.setcentry2.get()
        if int(self.propcomp)>0 and int(self.propcomp)<100:
            self.propcomp=int(self.propcomp)
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Threshold for H-bond percentage of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        self.propcomp=int(self.propcomp)
        self.maxdegeneracy=self.setcentry3.get()
        if int(self.maxdegeneracy)>0 and int(self.maxdegeneracy)<257:
            self.maxdegeneracy=int(self.maxdegeneracy)
        else:
            x=tkMessageBox.Message(icon='error', type='ok', message="Maximum degeneracy out of range.  Please re-enter.", title='Amplicon: Error').show()
            return
        if self.maxdegeneracy>64:
            self.setcentry3.config(foreground='red')
        wob=self.wobvar.get()
        if wob==1:
            self.wobble=1
        else:
            self.wobble=2
        tpt=self.tptickvar.get()
        self.threeprimetick=tpt
        root.bell()
        return

# Information Menu Functions #

    #Displays IUB codes for degenerate sites#
    def IUB(self):
        IUB = Toplevel(root)
        IUB.resizable(0,0)
        IUB.iconbitmap(self.IconPath)
        IUB.transient(root)
        IUBlabel = Label(IUB,justify = LEFT, font = ('Arial',10), background = 'light yellow',
                         text='Degenerate (IUB) codes for nucleotides\n\nA = adenosine\nC = cytidine\nG = guanine\nT = thymidine\n'+
                         '\n'+ 'R = A,G (purines)\nY = C,T (pyrimidines)\nM = A,C (amino)\nW = A,T (weak)\nK = G,T (keto)\n'+'S = C,G (strong)'+ '\n'+
              'V = A,C,G\nH = A,C,T\nD = A,G,T\nB = C,G,T \nN = A,C,G,T\n\n- = alignment gap\n\nlower case character = gap also possible \n                                     (Amplicon only)').pack(side=LEFT)

    #Displays information about Amplicon#
    def about(self):
        about=Toplevel(root)
        about.resizable(0,0)
        #about.iconbitmap(self.IconPath)
        about.transient(root)
        aboutlabel=Label(about,justify = LEFT, font = ('Arial',10), background = 'light yellow',\
                         text=self.logotext+' software for designing group-specific PCR primers on aligned DNA sequences.\n\nby Simon Jarman 2003\n'+
                         '\nWritten in Python 2.3 (http://www.python.org/)\n\nBug reports,comments,suggestions: simon.jarman@aad.gov.au\n\n'+
                         'Citation: Jarman SN (2004) Amplicon: software for designing PCR primers on aligned DNA sequences.\n'+
                         'Bioinformatics 20:1644-1645.\n\n'+
                         'Disclaimer: This software is provided free of charge and without any warranty whatsoever.  \nThe author accepts'+
                         ' no responsibility for anything you do with it.\n\n'+
                         'This release September 2004.  Changes since version b09:'+
                         '\nWindows and Unix-style line endings in .aln format recognised (thanks to Nell Gwyn).'+
                         '\nThis version tested on SuSE Linux 9.1 and Knoppix'+
                         '\nFonts fixed for Linux version of Tkinter.').grid()
        return

    #Provides a very quick tutorial for using Amplicon#
    def tutorial(self):
        self.help=Toplevel(root)
        self.help.title('Amplicon Quick Tutorial')
        self.help.resizable(0,0)
        #self.help.iconbitmap(self.IconPath)
        self.help.transient(root)
        self.helpscroll=Scrollbar(self.help)
        self.helpscroll.pack(side=RIGHT,fill=Y)
        self.helptext=Text(self.help,font = ('Arial',10),background='light yellow',height=24, width=60,yscrollcommand=self.helpscroll.set)
        self.helptext.insert(1.0,'For a full description, please read the Amplicon manual.  The following\n'+
                             'is a brief synopsis for people who do not like reading instructions.\n\n'+
                             'Amplicon is a program for designing PCR primer pairs.  It may be useful\n'+
                             'for designing PCRs that will amplify an orthologous DNA region from a\n'+
                             '"target" group of taxa, but not from an "excluded" group of taxa. To allow\n'+
                             'this type of design, Amplicon supports the use of degenerate (IUB) \n'+
                             'codes for nucleotides.  When calculating features of oligonucleotides or \n'+
                             'sequences that include degenerate sites, each possible real sequence  \n'+
                             'in the degenerate sequence is determined and analysed separately.\n\n'+
                             'Amplicon reads files containing aligned sequences.  Currently supported \n'+
                             'alignment formats are Clustal (.aln), MEGA (.meg) and FASTA (.fas).\n'+
                             'Aligned sequences can be grouped and the consistencies within the\n'+
                             'group or possible sequences within the group calculated.  These\n'+
                             '"consensus" sequences can then be compared to identify differences \n'+
                             'between groups.  The differences highlight possible positions for PCR\n'+
                             'primers to bind.  Oligonucleotides designed to bind these sites can then\n'+
                             'be checked for Tm, hairpin formation, self and primer-primer\n'+
                             'complementarity.\n\n'+
                             ' Step 1. Open a file of aligned sequences from <Open Alignment File>'+
                             '\nin the <File> menu.\n\n'+
                             ' Step 2. Use the pointer and mouse select key (left on PCs) to select  \n'+
                             '"target" group sequences from their titles listed in the top left box.  To\n'+
                             'select multiple sequences for group-specific primer design, hold down\n'+
                             '<Shift> for a continuous range or <Control> for sequences not adjacent.\n'+
                             'Once the range is selected, create a "possibilities" sequence by \n'+
                             'choosing this option in the <Sequences> menu.\n\n'+
                             ' Step 3. Repeat Step 2 for the "excluded" group of sequences if an\n'+
                             'excluded group is required.\n\n'+
                             ' Step 4. Select the target group sequence and enter it to the target\n'+
                             'analysis box with the <Target Group> button.\n\n'+
                             ' Step 5. Repeat Step 4 for the "excluded" group Possibilities Sequence,\n'+
                             'using the <Excluded Group> button if an excluded group is desired.\n'+
                             'Differences between the "target" and "excluded" sequences are \n'+
                             'highlighted.  Consistent differences are back-highlighted in orange.\n'+
                             'Possible matches or differences for IUB characters are back-highlighted\n'+
                             'with pink.\n\n'+
                             ' Step 6. Use the mouse and pointer to select a region from either strand\n'+
                             'of the "target" group sequence which you want to be the binding site for\n'+
                             'the Forward Primer.  Press the <Primer for Forward Site> button, which \n'+
                             'highlights the binding site for the primer and enters the appropriate \n'+
                             'primer into the Forward Primer entry box.  Primer binding sites may be\n'+
                             'found using the options in the <Search> menu or by referring to graphs\n'+
                             'drawn from options in the <Sequences> menu.  The primer may be  \n'+
                             'edited manually in the entry box before analysis.\n\n'+
                             ' Step 7. Repeat Step 6 for the Reverse Primer.\n\n'+
                             ' Step 8. The <Primers> menu functions are now available.  Use them to \n'+
                             'assess your primer combination.  The settings in the <Settings> menu \n'+
                             'can be altered and re-entered with the <Enter> key on each <Setting>\n'+
                             'window.\n\n'+
                             ' Step 9.  Analyses can be saved with options in the <File> menu.\n'+
                             'The files will be .txt files (add this suffix for ease of use).  The\n'+
                             'The file is then readable by any text editor or word processor.\n\n'+
                             ' Step 10.  Buy the primers and amplify your target.  Good luck.\n\n')
        self.helpscroll.config(command=self.helptext.yview)
        self.helptext.pack(side=LEFT)
        return

root = Tk()
root.title('Amplicon b09.1')
root.maxsize(1400,800)
root.config(borderwidth=5)
MW=MainWin(Tk)
root.bind('<Control-o>',openSC)
root.bind('<Control-s>',saveSC)
root.bind('<Control-q>',quitSC)
root.bind('<F1>',cutSC)
root.bind('<F2>',pasteSC)
root.bind('<F3>',consensus1SC)
root.bind('<F4>',consensus2SC)
root.bind('<F5>',fsearchSC)
root.bind('<F6>',rsearchSC)
root.bind('<F7>',searchparaSC)
root.bind('<F8>',IUBSC)
root.mainloop()
