text:
import os, sys, re
from optparse import OptionParser
import xml.etree.ElementTree as ET

class Gene(list):
    def __init__(self, name, exonCount, chr, start, end):
        self.name = name
        self.exonCount = exonCount
        self.chr = chr
        self.start = start
        self.end = end
    def setStatus(self, status):
        self.status = status
    def setMissedSpecies(self, missedSpecies):
        self.missedSpecies = missedSpecies

class Species(list):
    def __init__(self, name, exonCount):
        self.name = name
        self.exonCount = exonCount
    def setStatus(self, status):
        self.status = status
    def setAlnBases(self, count):
        self.alnBases = count

class Exon:
    def __init__(self, line):
        #self.description = line
        items = line.strip().split('\t')
        if len(items) < 20:
            sys.stderr.write("Wrong format: multizLine has less than 16 fields.\n%s\n" %(line))
        self.id = items[7]
        self.gene = items[0]
        self.chr = items[1]
        self.genestart = items[2]
        self.geneend = items[3]
        self.start = items[8]
        self.end = items[9]
        self.exonCount = int(items[6])
        self.codonBases = int(items[11])
        self.insBases = int(items[13])
        self.delBases = int(items[14])
        self.indelBases = self.insBases - self.delBases
        #self.indelBases = int(items[13]) - int(items[14])
        self.species = items[10]
        self.alnBases = int(items[12]) #number of aligned bases
        self.missingBases = int(items[15]) + int(items[16])
        self.numContigs = int(items[17])
        self.orderCons = items[19]
        maxIndel = self.codonBases*0.1
        #self.gapBases = int(items[16])
        #self.numRanges = int(items[16])
        if self.missingBases > 10:#if has any gap at all, marked it as having 'missing data'
            self.status = "MD" #Missing Data
        elif self.alnBases == 0:
            self.status = "NA" #Not Applicaple
        #elif items[17] == "yes":
        elif self.numContigs > 1 or self.insBases > maxIndel or self.delBases > maxIndel or self.indelBases%3 != 0 :
            self.status = "N" #Incomplete / non-conserved
        else:
            self.status = "C" #Complete/ conserved

def mapId2name(file):
    #mapped refseq id to gene name
    f = open(file, "r")
    id2name = {}
    name2id = {}
    for line in f.readlines():
        items = line.strip().split('\t')
        if len(line) < 2:
            continue
        else:
            id2name[items[1]] = items[0]
            name2id[items[0]] = items[1]
    f.close()
    return (id2name, name2id)

def getGene(genes, name):
    for gene in genes:
        if gene.name == name:
            return gene
    return None

def getSpecies(gene, name):
    for species in gene:
        if species.name == name:
            return species
    return None

def getExon(species, id):
    for exon in species:
        if exon.id == id:
            return exon
    return None

def multizgene_getExon(gene, id):
    for species in gene:
        exon = getExon(species, id)
        if exon:
            return exon
    return None

#==== cactus
def cactus_getGene(genes, name):
    for gene in genes:
        if gene.get("name") == name:
            return gene
    return None

def cactus_getSpecies(gene, name):
    species = gene.findall("species")
    for spc in species:
        if spc.get("name") == name:
            return spc
    return None

def cactus_getSpcExonStatus(spc, id):
    exons = spc.getiterator("exon")
    #spcStatus = spc.get("status")
    mdexons = spc.get("missingdataexons").split(',')

    hasExon = False
    for exon in exons:
        if exon.get("id") == id:
            hasExon = True
            if exon.get("status") == "1":
                return "C"
    if not hasExon: #so NA could include cases where the exons are skipped because of MissingData
        status = "NA"
    elif id in mdexons:
        status = 'MD'
    else:
        status = "N"
    return status

def readMultiz(file, id2name):
    f = open(file, "r")
    genes = []
    for line in f.readlines():
        if re.search('#', line): #comment line
            continue
        exon = Exon(line)
        if exon.gene not in id2name:
            continue

        genename = id2name[exon.gene]
        gene = getGene(genes, genename)
        if not gene:#add gene to list if it is not in the list yet
            gene = Gene(genename, exon.exonCount, exon.chr, exon.genestart, exon.geneend)
            genes.append(gene)

        species = getSpecies(gene, exon.species)
        if not species:#add species to gene if it is not in gene yet
            species = Species(exon.species, exon.exonCount)
            gene.append(species)

        if not getExon(species, exon.id):
            species.append(exon)#add exon to species
    return genes

def setMultizSpeciesStatus(species):
    #A species is marked as having 'complete' homolog when all the exons of the reference present and
    #are conserved (status = yes) and [the order and orientation] of the ref. exons are conserved
    #
    #A species is marked as having 'partial' homolog when exons that have missing data are allowed, and
    #(what about exons that get skipped because of msising data?)
    #
    #A species is marked as having incomplete homolog when it has some Non-conserved exon (status = no)
    #
    #If there is no homolog at all mapped to the gene, the species is marked as 'NA'
    status = "C"
    alnBases = 0
    hasMissingData = False
    for exon in species:
        alnBases += exon.alnBases
        if exon.status == "NA" or exon.status == "N" or exon.orderCons == "no":#species status is no if any of its exon is no
            status = "N"
            break
        #if exon.alnBases == 0 and exon.gapBases == 0: #totally miss the exon
        #    status = "N"
        #    break
        if exon.status == "MD": #has missing data exon
            hasMissingData = True

    if alnBases == 0:
        status = "NA"
    elif status != "N" and hasMissingData: #
        status = "MD"
    species.setStatus(status)
    #sys.stderr.write("Getting spc status: %s\t%s\t%d\n" %(species.name, species.status, species.alnBases))
    return

def setMultizGeneStatus(genes):
    #a gene is OK (yes) if it presents in all species with status Yes
    #return 'no' if it presents in all species but broken in at least one
    #'missed' if it does not aligned in at least one species, but not all
    #'NA' if it does not present in any of the species

    for gene in genes:
        status = "C"
        numNAspecies = 0
        hasMDspc = False
        for species in gene:
            setMultizSpeciesStatus(species)
        for species in gene:
            #sys.stderr.write("%s\t%s\t%s\n" %(gene.name, species.name, species.status))
            if species.status == "NA":#gene is absent in current species
                numNAspecies += 1
                hasMDspc = True #TESTING...
                continue
            elif species.status == "N":#incomplete (non-conserved) homolog
            #if species.status == "N":#incomplete (non-conserved) homolog
                status = "N"
                break
            elif species.status == "MD": #species with partially complete homolog
                hasMDspc = True

        if numNAspecies == len(gene):
            gene.setStatus('NA')
        elif species.status != "N" and hasMDspc:
        #if species.status != "N" and hasMDspc:
            gene.setStatus("MD")
        else:
            gene.setStatus(status)
        #gene.setMissedSpecies(missedSpecies)
        #sys.stderr.write("%s\t%s\n\n" %(gene.name, gene.status))
    return

def cactus_getSpcExonString(species):
    exons = species.getiterator("exon")
    exonStr = ""
    for exon in exons:
        exonStr += "%s_%s_%s," %(exon.get("id"), exon.get("status"), exon.get("strand"))
    return exonStr

def cactus_getSpcStatus2(species, exonCount):
    #assert(exonCount > 0)
    exonStr = cactus_getSpcExonString(species)
    #sys.stderr.write("species: %s\n" % species.get("name"))
    #sys.stderr.write("exonStr: [%s]\n" %exonStr)
    strands = ["\+", "-"]
    for strand in strands:
        forwardStr = "\D*0_1_%s.*" %(strand) #first exon
        for id in range(1, exonCount):
            forwardStr += "\D+%d_1_%s.*" %(id, strand)
        #sys.stderr.write("forwardStr: [%s]\n" %forwardStr)

        backwardStr = "\D*%d_1_%s.*" %(exonCount -1, strand) #last exon
        for id in range(exonCount -2, -1, -1):
            backwardStr += "\D+%d_1_%s.*" %(id, strand)
        #sys.stderr.write("backwardStr: [%s]\n" %backwardStr)

        forwardPattern = re.compile(forwardStr)
        fm = forwardPattern.search(exonStr)
        backwardPattern = re.compile(backwardStr)
        bm = backwardPattern.search(exonStr)
        #if fm:
        #    sys.stderr.write("Match forward String\n")
        #if bm:
        #    sys.stderr.write("Match backward String\n")
        if fm or bm:
            return "C"

    #Missingdata cases:
    mdExonsStr = species.get("missingdataexons")
    mdExons = mdExonsStr.split(',')
    for strand in strands:
        first = "0"
        if first in mdExons:
            forwardStr = "\D*0_[01]_%s.*" %(strand) #first exon
        else:
            forwardStr = "\D*0_1_%s.*" %(strand) #first exon

        for id in range(1, exonCount):
            if str(id) in mdExons:
                forwardStr += "\D+%d_[01]_%s.*" %(id, strand)
            else:
                forwardStr += "\D+%d_1_%s.*" %(id, strand)
        #sys.stderr.write("forwardStr: [%s]\n" %forwardStr)

        if str(exonCount -1) in mdExons:
            backwardStr = "\D*%d_[01]_%s.*" %(exonCount -1, strand) #last exon
        else:
            backwardStr = "\D*%d_1_%s.*" %(exonCount -1, strand) #last exon
        for id in range(exonCount -2, -1, -1):
            if str(id) in mdExons:
                backwardStr += "\D+%d_[01]_%s.*" %(id, strand)
            else:
                backwardStr += "\D+%d_1_%s.*" %(id, strand)
        #sys.stderr.write("backwardStr: [%s]\n" %backwardStr)

        forwardPattern = re.compile(forwardStr)
        fm = forwardPattern.search(exonStr)
        backwardPattern = re.compile(backwardStr)
        bm = backwardPattern.search(exonStr)
        if fm or bm:
            return "MD"

    return "N"

def cactus_getGeneStatus2(gene):
    species = gene.findall("species")
    exonCount = int(gene.get("exonCount"))
    hasMDspecies = False
    for spc in species:
        spcStatus = spc.get("status")
        if spcStatus == "N":
            spcStatus = cactus_getSpcStatus2(spc, exonCount)
        if spcStatus == "MD":
            hasMDspecies = True

        if spcStatus == "N":
            return "N"
    if hasMDspecies:
        return "MD"
    else:
        return 'C'

def getCactusExonStatus(exonid, gene):
    #return 'C' if input exon present in all species and perfectly conserved
    #"N" when exon is broken (non-conserved) or absent in at least one species
    #'MD': exon marked as having missing data
    #return 'NA' if exon does not present in any species
    species = gene.findall("species")
    numAlnSpecies = 0
    hasMDspc = 0
    for spc in species:
        spcStatus = spc.get("status")
        mdExonsStr = spc.get("missingdataexons")
        mdExons = mdExonsStr.split(',')
        #sys.stderr.write("*%s*\n" %(mdExonsStr))

        #if spcStatus != "incomplete" and spcStatus != "NA":#species is ok ==> all exon is ok (exon that ovelapped with missing data)
        #    continue
        hasexon = "no"
        exons = spc.getiterator("exon")
        exonstatus = "NA"
        for exon in exons:
            if exon.get("id") == exonid: #found exon in current species!
                hasexon = "yes"
                #if exon.get("status") == "1":
                if exon.get("status") == "1":
                    exonstatus = 'C'
                    break

        if hasexon == "yes": #found exon in current species
            numAlnSpecies += 1
            if exonstatus != 'C':#didn't find any complete exon
                if exonid in mdExons: #but found exon that was marked as having missing data
                    hasMDspc += 1
                else:#exon is non-conserved in current species --> exon is non-conserved in all
                    return "N"
        #elif spcStatus == "MD":#doesn't have the exon, but species status = P
        else:#doesn't have the exon, but species status = P
            hasMDspc += 1

    if numAlnSpecies == 0:#does not present in any species
        return "NA"
    elif numAlnSpecies != len(species): #absent in at least one species
        return "N"
    elif hasMDspc > 0:#only have exon marked missing data in some species or exon absent in some species
        return "MD"
    else:#present in all species
        return "C"

def getMultizExonStatus(exonid, gene):
    #return no if any of the involved species has an exonStatus "no"
    if not gene:
        return "NA"
    numAlnSpecies = 0
    hasMDspc = 0
    for species in gene:
        exon = getExon(species, exonid)
        if exon.alnBases > 0:
        #if exon:
            numAlnSpecies += 1
            #if exon.status == "NA":
            #    continue
            if exon.status == "N":
                return "N"
            elif exon.status == "MD":
                hasMDspc += 1
    if numAlnSpecies == 0:
        return 'NA'
    elif numAlnSpecies < len(gene):
        return 'N'
    elif hasMDspc > 0:
    #elif hasMDspc > 0 or numAlnSpecies < len(gene):
        return 'MD'
    else:
        return "C"

def cactusVSmultiz_perSpecies(multizGenes, cactusTree, name2id, allowDup, fh):
    cactusRoot = cactusTree.getroot()
    cGenes = cactusRoot.findall("gene") #cactus genes

    fh.write("Chr\tStart\tEnd\tSpecies\tGeneName\tGeneAccession\tCactusStatus\tMultizStatus\n")

    for cgene in cGenes:
        species = cgene.findall("species")
        genename = cgene.get("name")
        exonCount = int(cgene.get("exonCount"))
        mgene = getGene(multizGenes, genename) #corresponding multiz gene

        for cspc in species:
            cstatus = cspc.get("status")
            #relax the definition of cactus complete homolog by allowing for duplicated pieces of exons in between exons:
            if allowDup and cstatus == "N":
                cstatus = cactus_getSpcStatus2(cspc, exonCount)

            if not mgene:
                mstatus = "NA"
            else:
                mspc = getSpecies(mgene, cspc.get("name"))
                if not mspc:
                    mstatus = "NA"
                else:
                    mstatus = mspc.status

            fh.write("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" %(mgene.chr, mgene.start, mgene.end, cspc.get("name"), genename, name2id[genename], cstatus, mstatus))

    return

def cactusVSmultiz(multizGenes, cactusTree, name2id, allowDup):
    cactusRoot = cactusTree.getroot()
    cGenes = cactusRoot.findall("gene") #cactus genes
    exonTab = {}#first column is cactus, second is multiz
    geneTab = {}#first column is cactus, second is multiz

    sys.stdout.write("Chr\tStart\tEnd\tExonId\tGeneName\tGeneAccession\tCactusStatus\tMultizStatus\n")
    for cgene in cGenes:
        genename = cgene.get("name")

        mgene = getGene(multizGenes, genename) #corresponding multiz gene
        cgstatus = cgene.find("status").text

        #relax the definition of cactus complete homolog by allowing for duplicated pieces of exons in between exons:
        if allowDup and cgstatus == "N":
            cgstatus = cactus_getGeneStatus2(cgene)

        if not mgene:
            mgstatus = "NA"
        else:
            mgstatus = mgene.status

        #Missing data is consider non-conserved if one of the methods (multiz or cactus) has a conserved homolog
        if cgstatus == "MD" and mgstatus == "C":
            cgstatus = "N"
        if mgstatus == "MD" and cgstatus == "C":
            mgstatus = "N"
        #NA (not-aligned) is considered as non-conserved
        if cgstatus == "NA":
            cgstatus = "N"
        if mgstatus == "NA":
            mgstatus = "N"

        #comparing the gene status
        gStatus = cgstatus + mgstatus
        if gStatus not in geneTab:
            geneTab[gStatus] = 1
        else:
            geneTab[gStatus] += 1

        sys.stdout.write("%s\t%s\t%s\tgene\t%s\t%s\t%s\t%s\n" %(mgene.chr, mgene.start, mgene.end, genename, name2id[genename], cgstatus, mgstatus))

        #comparing exon status:
        exonCount = int(cgene.get("exonCount"))
        for id in range(exonCount):
            cexonStatus = getCactusExonStatus(str(id), cgene)
            mexonStatus = getMultizExonStatus(str(id), mgene)

            #Missing data is consider non-conserved if one of the methods (multiz or cactus) has a conserved homolog
            if cexonStatus == "MD" and mexonStatus == "C":
                cexonStatus = "N"
            if mexonStatus == "MD" and cexonStatus == "C":
                mexonStatus = "N"

            if cexonStatus == "NA":
                cexonStatus = "N"
            if mexonStatus == "NA":
                mexonStatus = "N"

            exonStatus = cexonStatus + mexonStatus

            mexon =  multizgene_getExon(mgene, str(id))
            if mexon:
                sys.stdout.write("%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n" %(mexon.chr, mexon.start, mexon.end, id, genename, name2id[genename], cexonStatus, mexonStatus))
            else:
                sys.stdout.write("\t\t\t%d\t%s\t%s\t%s\t%s\n" %(id, genename, name2id[genename], cexonStatus, mexonStatus))

            if exonStatus not in exonTab:
                exonTab[exonStatus] = 1
            else:
                exonTab[exonStatus] += 1

    return (exonTab, geneTab)

#================ get cactus gene/exon status of species of interest ========
def getMultizGeneSpecies(genes, genename, species):
    for gene in genes:
        if gene.name == genename: #skip genes with missing data if missingData is not allowed
            for spc in gene:
                if spc.name == species:
                    return spc
    return None

def cactusSpcExonStatus(spc):
    mdExonsStr = spc.get("missingdataexons")
    mdExons = mdExonsStr.split(',')

    exon2status = {}
    exons = spc.getiterator("exon")
    for exon in exons:
        exonid = exon.get("id")
        status = exon.get("status")

        if exonid not in exon2status:
            exon2status[exonid] = status
        if (status == "1"):
            exon2status[exonid] = "C"

    for id in exon2status:
        if exon2status[id] == "0":
            if id in mdExons:
                exon2status[id] = "MD"
            else:
                exon2status[id] = "N"
    return exon2status

#================ multiz species to genes info ===========
#def multizSpc2genes(genes, cactusTree, mdgenes, allSpcGenes, strict, allowDup):
#def multizSpc2genes(genes, cactusTree, allSpcGenes, strict, allowDup):
def multizSpc2genes(genes, cactusTree, allowDup):
    spc2total = {} #key = species, val = {total number of genes this species covered}
    spc2cons = {} #key = species, val = {number of conserved genes}
    root = cactusTree.getroot()
    cgenes = root.findall("gene")

    for gene in genes:
        cgene = cactus_getGene(cgenes, gene.name)
        for spc in gene:
            cspc = cactus_getSpecies(cgene, spc.name)
            cstatus = cspc.get("status")
            if allowDup and cstatus == "N":
                #cstatus = cactus_getGeneStatus2(cgene)
                cstatus = cactus_getSpcStatus2(cspc, spc.exonCount)

            status = spc.status
            if (status == "MD" and cstatus == "C") or status == "NA":
                status = "N"

            if status != "C" and cstatus == "MD":
                continue

            if status == "C" or status == "N":
                if spc.name not in spc2total:
                    spc2total[spc.name] = 1
                    spc2cons[spc.name] = 0 #initialize spc2cons
                else:
                    spc2total[spc.name] += 1

                if status == "C":#if conserved, report
                    spc2cons[spc.name] +=1

    return (spc2total, spc2cons)

#def multizSpcExonCount(spc, gene, cactusSpc, allSpcExons, strict):
def multizSpcExonCount(spc, cactusSpc):
    total = 0
    cons = 0

    cactusExon2status = cactusSpcExonStatus(cactusSpc)
    for exon in spc:
        status = exon.status
        if status == "MD" and (exon.id in cactusExon2status) and cactusExon2status[exon.id] == "C":
            status = "N"
        if status == "NA":
            status = "N"
        if status != "C" and (exon.id in cactusExon2status) and cactusExon2status[exon.id] == "MD":
            continue
        if status == "C" or status == "N":
            total +=1
            if status == "C":
                cons +=1
    return (total, cons)

#def multizSpc2exons(genes, cactusTree, mdgenes, allSpcExons, strict):
def multizSpc2exons(genes, cactusTree):
    spc2total = {}
    spc2cons = {}

    root = cactusTree.getroot()
    cgenes = root.findall("gene")

    for gene in genes:
        #spc2exon2status = {}
        cgene = cactus_getGene(cgenes, gene.name)
        for spc in gene:
            cspc = cactus_getSpecies(cgene, spc.name)
            (total, cons) = multizSpcExonCount(spc, cspc)
            #spc2exon2status[spc.name] = exon2status
            if spc.name not in spc2total:
                spc2total[spc.name] = total
                spc2cons[spc.name] = cons
            else:
                spc2total[spc.name] += total
                spc2cons[spc.name] += cons

        #for i in range(gene.exonCount):
        #    if spc2exon2status["panTro2"][str(i)] != "C" and spc2exon2status["rheMac2"][str(i)] == "C":
        #        spc = getSpecies(gene, "rheMac2")
        #        mexon = getExon(spc, str(i))
        #        sys.stdout.write("%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n" %(mexon.chr, mexon.start, mexon.end, i, gene.name, mexon.gene, spc2exon2status["panTro2"][str(i)], spc2exon2status["rheMac2"][str(i)]))

    return (spc2total, spc2cons)

#================== cactus species to genes info ==============
#def cactusSpc2genes(tree, multizGenes, allowMissingData, allSpcGenes, strict, allowDup):
def cactusSpc2genes(tree, multizgenes, allowDup):
    spc2total = {}
    spc2cons = {}
    root = tree.getroot()
    genes = root.findall("gene")

    if len(genes) <= 0:
        return None

    #initialized the hashes:
    species = genes[0].findall("species")
    for spc in species:
        spc2total[spc.get("name")] = 0
        spc2cons[spc.get("name")] = 0

    for gene in genes:
        mgene = getGene(multizgenes, gene.get("name"))

        species = gene.findall("species")
        for spc in species:
            spcname = spc.get("name")
            status = spc.get("status")
            if allowDup and status == "N":
                status = cactus_getSpcStatus2(spc, mgene.exonCount)

            mspc = getSpecies(mgene, spcname) #multiz species
            if status != "C" and mspc.status == "MD":
                continue

            if (status == "MD" and mspc.status == "C") or status == "NA":
                status = "N"

            if status == "C" or status == "N":
                #if status == "N":
                #    if allowDup:
                #        status = cactus_getSpcStatus2(spc, int(gene.get("exonCount")))

                #if status == "MD" and mspc.status == "C":
                #    status = "N"

                if status == "C" or status == "N":
                    spc2total[spcname] += 1
                if status == "C":
                    spc2cons[spcname] += 1

    return (spc2total, spc2cons)

def cactusSpcExonCount(spc, multizspc):
    total = 0
    cons = 0
    exon2status = {}
    exons = spc.getiterator("exon")

    mdExonsStr = spc.get("missingdataexons")
    mdExons = mdExonsStr.split(',')

    total = 0
    for exon in exons:
        exonid = exon.get("id")
        status = exon.get("status")

        if exonid not in exon2status:
            exon2status[exonid] = status
        if (status == "1"):
            exon2status[exonid] = 'C'

    for id in range(multizspc.exonCount):
        if str(id) not in exon2status:
            exon2status[str(id)] = "N"

    for id in exon2status:
        mexon = getExon(multizspc, id)
        cstatus = exon2status[id]
        if cstatus == "0":
            if (id in mdExons) and mexon.status != "C":
                cstatus = "MD"
            else:
                cstatus = "N"
        if mexon.status == "MD" and cstatus != "C":
            continue
        if cstatus == "C" or cstatus == "N":#exon is complete
            total +=1
            if cstatus == "C":
                cons += 1
    #sys.stderr.write("spc %s, total %d, broken %d\n" %(spc.get("name"), total, broken))
    return (total, cons)

#def cactusSpc2exons(tree, multizGenes, allowMissingData, allSpcExons, strict):
def cactusSpc2exons(tree, multizgenes):
    spc2total = {}
    spc2cons = {}
    root = tree.getroot()
    genes = root.findall("gene")

    if len(genes) <= 0:
        return None

    #initialized the hashes:
    species = genes[0].findall("species")
    for spc in species:
        spc2total[spc.get("name")] = 0
        spc2cons[spc.get("name")] = 0

    for gene in genes:
        species = gene.findall("species")
        mgene = getGene(multizgenes, gene.get("name"))
        for spc in species:
            spcname = spc.get("name")
            mspc = getSpecies(mgene, spcname)
            (total, cons) = cactusSpcExonCount(spc, mspc)
            spc2total[spcname] += total
            spc2cons[spcname] += cons

    return (spc2total, spc2cons)

def printSpc2Genes(f, title, totalM, consM, totalC, consC):
    #f.write("%s\n" %(title))
    for spc in totalM:
        #sys.stderr.write("species: %s\n" %(spc))
        tmultiz = totalM[spc]
        cmultiz = consM[spc]
        if tmultiz == 0:
            sys.stderr.write("species %s, total (%s) of multiz is 0\n" %(spc, title))
        #percentM = float(bmultiz)/tmultiz*100.0
        percentM = float(cmultiz)/tmultiz*100.0
        tcactus = totalC[spc]
        ccactus = consC[spc]
        if tcactus == 0:
            sys.stderr.write("species %s, total (%s) of cactus is 0\n" %(spc, title))
        #percentC = float(bcactus)/tcactus*100
        percentC = float(ccactus)/tcactus*100
        #f.write("%s\t%s\t%d\t%d\t%.2f\t%d\t%d\t%.2f\n" %(title, spc, bcactus, tcactus, percentC, bmultiz, tmultiz, percentM))
        f.write("%s\t%s\t%d\t%d\t%.2f\t%d\t%d\t%.2f\n" %(title, spc, ccactus, tcactus, percentC, cmultiz, tmultiz, percentM))
    f.write("#\n")
    return

#def species2genes(f, multizGenes, cactusTree, allowMissingData, allSpcGenes, allSpcExons, strict, allowDup):
def species2genes(f, multizGenes, cactusTree, allowDup):

    #speciesToGenes:
    (gTotalMultiz, gConsMultiz) = multizSpc2genes(multizGenes, cactusTree, allowDup)
    (gTotalCactus, gConsCactus) = cactusSpc2genes(cactusTree, multizGenes, allowDup)
    printSpc2Genes(f, "spcGeneTab", gTotalMultiz, gConsMultiz, gTotalCactus, gConsCactus)

    (eTotalCactus, eConsCactus) = cactusSpc2exons(cactusTree, multizGenes)
    (eTotalMultiz, eConsMultiz) = multizSpc2exons(multizGenes, cactusTree)
    printSpc2Genes(f, "spcExonTab", eTotalMultiz, eConsMultiz, eTotalCactus, eConsCactus)
    return

def printTab(f, title, tab, strict):
    #f.write("%s\n" %(title))
    totalCount = 0
    selectedKeys = ["CC", "NN", "CN", "NC"]
    for key in tab:
        if not strict or key in selectedKeys:
            totalCount += int(tab[key])

    for key in tab:
        if not strict or key in selectedKeys:
            percent = float(tab[key])/totalCount*100
            f.write("%s\t%s\t%d\t%.2f\n" %(title, key, tab[key], percent))

    f.write("#\n")

def dupStats(tree):
    root = tree.getroot()
    genes = root.findall("gene")
    total = {"gene":0, "geneexon": 0, "partialdupgene":0, "exon":0, "intron":0}
    dup = {"gene":0, "geneexon": 0, "partialdupgene":0, "exon":0, "intron": 0}

    for gene in genes:
        numDupExon = 0
        genedup = False
        geneexondup = False
        total["gene"] += 1
        total["geneexon"] += 1
        total["partialdupgene"] += 1
        exonCount = int(gene.get("exonCount"))
        total["exon"] += exonCount
        total["intron"] += exonCount -1
        intronStr = gene.find("intronDups").text
        if intronStr:
            intronDups = intronStr.split(',')
        else:
            intronDups = []

        exonStr = gene.find("exonDups").text
        if exonStr:
            exonDups = exonStr.strip(',').split(',')
        else:
            exonDups = []

        if len(exonDups) != exonCount:
            sys.stderr.write("ERR\n")
        for i in range(exonCount):
            if exonDups[i] == "1":
                genedup = True
                geneexondup = True
                dup["exon"] += 1
                numDupExon +=1
        for i in range(exonCount -1):
            if intronDups[i] == "1":
                genedup = True
                dup["intron"] +=1
        if genedup:
            dup["gene"] +=1
        if geneexondup:
            dup["geneexon"] +=1
            if numDupExon < exonCount:
                dup["partialdupgene"] +=1

    for key in total:
        t = total[key]
        d = dup[key]
        if t == 0:
            sys.stderr.write("total %s 0\n" %(key))
        percent = float(d)/t*100.0
        sys.stdout.write("%s\t%d/%d\t%.2f%%\n" %(key, d, t, percent))
    return

def usage():
    sys.stderr.write("Usage: cactusVSmultiz.py geneNameToRefseqIdFile multizMarkFile cactusXMLFile outputFile\n")
    sys.exit(2)

def main():
    if len(sys.argv) < 5:
        sys.stderr.write("Too few input arguments.\n")
        usage()
    usg = "usage: %prog [options] txId2nameFile consEvidFile cactusHomolog.xml outputFile"
    parser = OptionParser(usage=usg)
    parser.add_option("-a", "--perSpecies", dest="perSpcOut", \
                      help="Print the status per species", default="perSpeciesCmp")
    #parser.add_option("-m", "--missingData", dest="missingData", action="store_true", \
    #                  help="If specified, will allow for missingData. Default is false.", default=False)
    #parser.add_option("-s", "--strict", dest="strict", action="store_true", \
    #                  help="If specified, only look at genes/exons that present in all species in both multiz and cactus. Default is false.", default=False)
    parser.add_option("-d", "--dup", dest="dup", action="store_true", \
                      help="If specified, relax the definition of cactus gene conservation and allow duplicated pieces of exons in between exons. Default is false.", default=False)
    (options, args) = parser.parse_args()

    (id2name, name2id) = mapId2name(args[0])

    multizGenes = readMultiz(args[1], id2name)
    setMultizGeneStatus(multizGenes)

    cactusTree = ET.parse(args[2])
    (exonTab, geneTab) = cactusVSmultiz(multizGenes, cactusTree, name2id, options.dup)
    f = open(args[3], "w")

    printTab(f, "exonTab", exonTab, True)
    printTab(f, "geneTab", geneTab, True)

    printTab(f, "exonTabSupplement", exonTab, False)
    printTab(f, "geneTabSupplement", geneTab, False)

    species2genes(f, multizGenes, cactusTree, options.dup)
    f.close()

    #====== print out the difference in gene conservation status per species =========
    fh = open(options.perSpcOut, "w")
    cactusVSmultiz_perSpecies(multizGenes, cactusTree, name2id, options.dup, fh)
    fh.close()

    #
    dupStats(cactusTree)

    #TEMP:
    #multizSpc2exons(multizGenes, [], options.strict)

if __name__ == "__main__":
    main()

redpajama_set_name: RedPajamaGithub


text:
import userErrorNoFunds from '../usererrors/userErrorNoFunds';

export default function buyClothing(new_state, action)
{

    // assign this to new_state
    const currentCash = new_state.currentGame.currentFinances.cash;

    const price = new_state.game.clothing[action.clothing.id].price;

    // check if we have enough money
    if (currentCash >= price) {

        // get the total space available from game data
        const totalSpace = new_state.game.clothing[action.clothing.id].space;

        // set state of player.space
        new_state.currentGame.currentSpace.clothing = Number(action.clothing.id);
        new_state.currentGame.currentSpace.total = totalSpace;

        // remove cash
        new_state.currentGame.currentFinances.cash = currentCash - price;

        // remove user error in case there was one
        new_state.status.userError.active = false;

    } else {
        new_state = userErrorNoFunds(new_state);
    }

	return new_state
}


text:
from typing import List

l1 = [int]
foo7: List[<error descr="Parameters to generic types must be types">l<caret>1</error>]


text:
package com.bt.pi.app.management;

import java.util.Locale;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import com.bt.pi.app.common.entities.Image;
import com.bt.pi.app.common.entities.ImageIndex;
import com.bt.pi.app.common.entities.ImageState;
import com.bt.pi.app.common.entities.MachineType;
import com.bt.pi.app.common.entities.User;
import com.bt.pi.app.common.images.platform.ImagePlatform;
import com.bt.pi.core.continuation.UpdateResolver;
import com.bt.pi.core.continuation.UpdateResolvingPiContinuation;
import com.bt.pi.core.dht.BlockingDhtWriter;
import com.bt.pi.core.id.PId;

@Component
public class ImageSeeder extends SeederBase {
    private static final Log LOG = LogFactory.getLog(ImageSeeder.class);
    private static final String DASH = "-";
    private static final int EIGHT = 8;

    public ImageSeeder() {
        super();
    }

    public String createImage(String imageId, int regionCode, String kernelId, String ramDiskId, String manifestLocation, String ownerId, String architecture, String platform, Boolean isPublic, String machineType) {
        LOG.debug(String.format("createImage(%s, %s, %s, %s, %s, %s, %s, %s, %s)", imageId, regionCode, kernelId, ramDiskId, manifestLocation, ownerId, architecture, isPublic, machineType));
        MachineType type = MachineType.valueOf(machineType.toUpperCase(Locale.UK));
        ImagePlatform plat = ImagePlatform.valueOf(platform);
        String imageIdToStore = StringUtils.isBlank(imageId) ? type.getImagePrefix() + DASH + RandomStringUtils.random(EIGHT, HEX_ID_SET) : imageId;
        Image image = new Image(imageIdToStore, kernelId, ramDiskId, manifestLocation, ownerId, architecture, plat, isPublic, type);
        image.setState(ImageState.AVAILABLE);

        if (isPublic)
            addImageToImageIndex(imageIdToStore, regionCode);
        else
            addImageToUser(ownerId, imageIdToStore);

        boolean written = storeImage(image);

        if (written) {
            return image.getImageId();
        } else
            return null;
    }

    private void addImageToUser(final String ownerId, final String imageIdToStore) {
        LOG.debug(String.format("addImageToUser(%s, %s)", ownerId, imageIdToStore));
        getDhtClientFactory().createBlockingWriter().update(getPiIdBuilder().getPId(User.getUrl(ownerId)), null, new UpdateResolver<User>() {
            @Override
            public User update(User existingEntity, User requestedEntity) {
                if (null == existingEntity)
                    throw new IllegalArgumentException(String.format("user %s does not exist for private image", ownerId));
                existingEntity.getImageIds().add(imageIdToStore);
                return existingEntity;
            }
        });
    }

    public void updateImagePlatform(final String imageId, final String platform) {
        LOG.debug(String.format("updateImagePlatform(%s, %s)", imageId, platform));

        if (StringUtils.isEmpty(imageId) || StringUtils.isEmpty(platform))
            throw new IllegalArgumentException("ImageId or Platform is null or empty");

        final ImagePlatform imagePlatform = ImagePlatform.valueOf(platform);
        final PId piImageId = getPiIdBuilder().getPId(Image.getUrl(imageId));

        getDhtClientFactory().createBlockingWriter().update(piImageId, null, new UpdateResolvingPiContinuation<Image>() {

            @Override
            public Image update(Image existingEntity, Image requestedEntity) {
                if (existingEntity == null)
                    return null;

                existingEntity.setPlatform(imagePlatform);
                return existingEntity;
            }

            @Override
            public void handleResult(Image result) {
                if (result == null) {
                    throw new IllegalArgumentException("Unable to update image platform for:" + imageId);
                }

                LOG.debug(String.format("Updated image platform for image id: %s to %s", imageId, platform));
            }
        });
    }

    private boolean storeImage(Image image) {
        LOG.debug(String.format("storeImage(%s)", image));
        PId id = getPiIdBuilder().getPId(image);
        BlockingDhtWriter dhtWriter = getDhtClientFactory().createBlockingWriter();
        return dhtWriter.writeIfAbsent(id, image);
    }

    private void addImageToImageIndex(final String imageId, int regionId) {
        LOG.debug(String.format("addImageToImageIndex(%s)", imageId));
        PId imageIdIndexId = getPiIdBuilder().getPId(ImageIndex.URL).forRegion(regionId);
        ImageIndex imageIndex = new ImageIndex();
        imageIndex.getImages().add(imageId);
        BlockingDhtWriter dhtWriter = getDhtClientFactory().createBlockingWriter();
        dhtWriter.update(imageIdIndexId, imageIndex, new UpdateResolver<ImageIndex>() {
            @Override
            public ImageIndex update(ImageIndex existingEntity, ImageIndex requestedEntity) {
                if (null == existingEntity)
                    return requestedEntity;
                existingEntity.getImages().addAll(requestedEntity.getImages());
                return existingEntity;
            }
        });
    }
}


text:
FOUNDATION_EXPORT double Pods_PageCollectionViewLayout_ExampleVersionNumber;
FOUNDATION_EXPORT const unsigned char Pods_PageCollectionViewLayout_ExampleVersionString[];


text:
本教程将会向您展示如何使用AVOS Cloud SDK开发一个简单的图片应用。

# 申请AVOS Cloud帐号

如果您还未拥有AVOS Cloud的帐号,请访问cn.avoscloud.com (中国区)或者us.avoscloud.com(美国区)申请开发人员帐号。

请注意,目前中国区和美国区的数据并不能互通。

![apply account](images/apply-account.png)

# 创建基于AVOS Cloud的移动App

![create app](images/create-app.png)

# 查看app keys

![app keys](images/app-keys.png)

app keys将会在您的代码中使用到,同时请注意保管好您的app keys,以免给您的应用带来损失。

# 下载SDK

```
git clone git@github.com:avos/avoscloud-sdk.git
```

# 使用CocoaPods

您也可以使用CocoaPods添加项目的依赖

````
platform :ios, '5.0'
pod 'AVOSCloud'
pod 'AVOSCloudUI
````

# 创建iOS工程

![create app](images/create-app.png)

# 将AVOS Cloud SDK加入到工程中

### 使用Finder打开sdk所在的位置,如下图所示

![add sdk](images/add-avoscloud-sdk.png)

### 将SDK加入到project中,如下图所示

![avos cloud framework](images/avoscloud-framework.png)

# 初始化AVOS Cloud SDK

## 引用头文件

```objc
#import "AppDelegate.h"
#import <AVOSCloud/AVOSCloud.h>
```

## 初始化Keys

```objc
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Init AVOS Cloud with app id and app key.
    [AVOSCloud setApplicationId:appID
                   clientKey:appKey];
    [AVOSCloud useAVCloudUS];

    // Override point for customization after application launch.
    return YES;
}

```

![init avos cloud](images/init-avos-cloud.png)

# 增加LoginViewController

```objc
-(IBAction)logInPressed:(id)sender
{
    [AVUser logInWithUsernameInBackground:self.userTextField.text password:self.passwordTextField.text block:^(AVUser *user, NSError *error) {
        if (user) {
            //Open the wall
             [self performSegueWithIdentifier:@"LoginSuccesful" sender:self];
        } else {
            //Something bad has ocurred
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
            [errorAlertView show];
        }
    }];
}
```

# 增加RegisterViewController

```objc

////Sign Up Button pressed
-(IBAction)signUpUserPressed:(id)sender
{
    AVUser *user = [AVUser user];
    user.username = self.userRegisterTextField.text;
    user.password = self.passwordRegisterTextField.text;

    [user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
        if (!error) {
            //The registration was succesful, go to the wall
            [self performSegueWithIdentifier:@"SignupSuccesful" sender:self];

        } else {
            //Something bad has ocurred
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
            [errorAlertView show];
        }
    }];
}
```

# 创建UploadImageViewController

```objc

-(IBAction)sendPressed:(id)sender
{
    [self.commentTextField resignFirstResponder];

    //Disable the send button until we are ready
    self.navigationItem.rightBarButtonItem.enabled = NO;

    //Place the loading spinner
    UIActivityIndicatorView *loadingSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];

    [loadingSpinner setCenter:CGPointMake(self.view.frame.size.width/2.0, self.view.frame.size.height/2.0)];
    [loadingSpinner startAnimating];
    [self.view addSubview:loadingSpinner];

    //Upload a new picture
    NSData *pictureData = UIImagePNGRepresentation(self.imgToUpload.image);

    AVFile *file = [AVFile fileWithName:@"img" data:pictureData];
    [file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {

        if (succeeded){

            //Add the image to the object, and add the comments, the user, and the geolocation (fake)
            AVObject *imageObject = [AVObject objectWithClassName:WALL_OBJECT];
            [imageObject setObject:file forKey:KEY_IMAGE];
            [imageObject setObject:[PFUser currentUser].username forKey:KEY_USER];
            [imageObject setObject:self.commentTextField.text forKey:KEY_COMMENT];

            AVGeoPoint *point = [AVGeoPoint geoPointWithLatitude:52 longitude:-4];
            [imageObject setObject:point forKey:KEY_GEOLOC];

            [imageObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {

                if (succeeded){
                    //Go back to the wall
                    [self.navigationController popViewControllerAnimated:YES];
                }
                else{
                    NSString *errorString = [[error userInfo] objectForKey:@"error"];
                    [self showErrorView:errorString];
                }
            }];
        }
        else{
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            [self showErrorView:errorString];
        }

        [loadingSpinner stopAnimating];
        [loadingSpinner removeFromSuperview];

    } progressBlock:^(int percentDone) {

    }];
}
```

# 创建ImagesViewController

## 获取所有的图片列表

```objc
//Get the list of images
-(void)getWallImages
{
    //Prepare the query to get all the images in descending order
    AVQuery *query = [AVQuery queryWithClassName:WALL_OBJECT];
    [query orderByDescending:KEY_CREATION_DATE];
    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {

        if (!error) {
            //Everything was correct, put the new objects and load the wall
            self.wallObjectsArray = nil;
            self.wallObjectsArray = [[NSArray alloc] initWithArray:objects];

            [self loadWallViews];

        } else {
            //Remove the activity indicator
            [self.activityIndicator stopAnimating];
            [self.activityIndicator removeFromSuperview];

            //Show the error
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            [self showErrorView:errorString];
        }
    }];

}
```

## 加载图片

```objc
-(void)loadWallViews
{
    //Clean the scroll view
    for (id viewToRemove in [self.wallScroll subviews]){

        if ([viewToRemove isMemberOfClass:[UIView class]])
            [viewToRemove removeFromSuperview];
    }

    //For every wall element, put a view in the scroll
    int originY = 10;

    for (AVObject *wallObject in self.wallObjectsArray){

        //Build the view with the image and the comments
        UIView *wallImageView = [[UIView alloc] initWithFrame:CGRectMake(10, originY, self.view.frame.size.width - 20 , 300)];

        //Add the image
        AVFile *image = (PFFile *)[wallObject objectForKey:KEY_IMAGE];
        UIImageView *userImage = [[UIImageView alloc] initWithImage:[UIImage imageWithData:image.getData]];
        userImage.frame = CGRectMake(0, 0, wallImageView.frame.size.width, 200);
        [wallImageView addSubview:userImage];

        //Add the info label (User and creation date)
        NSDate *creationDate = wallObject.createdAt;
        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        [df setDateFormat:@"HH:mm dd/MM yyyy"];

        UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 210, wallImageView.frame.size.width,15)];
        infoLabel.text = [NSString stringWithFormat:@"Uploaded by: %@, %@", [wallObject objectForKey:KEY_USER], [df stringFromDate:creationDate]];
        infoLabel.font = [UIFont fontWithName:@"Arial-ItalicMT" size:9];
        infoLabel.textColor = [UIColor whiteColor];
        infoLabel.backgroundColor = [UIColor clearColor];
        [wallImageView addSubview:infoLabel];

        //Add the comment
        UILabel *commentLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 240, wallImageView.frame.size.width, 15)];
        commentLabel.text = [wallObject objectForKey:KEY_COMMENT];
        commentLabel.font = [UIFont fontWithName:@"ArialMT" size:13];
        commentLabel.textColor = [UIColor whiteColor];
        commentLabel.backgroundColor = [UIColor clearColor];
        [wallImageView addSubview:commentLabel];

        [self.wallScroll addSubview:wallImageView];

        originY = originY + wallImageView.frame.size.width + 20;

    }

    //Set the bounds of the scroll
    self.wallScroll.contentSize = CGSizeMake(self.wallScroll.frame.size.width, originY);

    //Remove the activity indicator
    [self.activityIndicator stopAnimating];
    [self.activityIndicator removeFromSuperview];
}
```

# 手工添加bundle

为了可以在设备上正常运行app,您需要手工copy bundle

![copy resource bundle](images/avoscloudui-bundle.png)

# 下载完整示例

```
git clone git@github.com:avos/avoscloud-sdk.git
cd avoscloud-sdk.git/iOS/samples
```


text:
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.AspNet.SignalR.Hubs
{
    internal class HubOutgoingInvokerContext : IHubOutgoingInvokerContext
    {
        public HubOutgoingInvokerContext(IConnection connection, string signal, ClientHubInvocation invocation)
        {
            Connection = connection;
            Signal = signal;
            Invocation = invocation;
        }

        public HubOutgoingInvokerContext(IConnection connection, IList<string> signals, ClientHubInvocation invocation)
        {
            Connection = connection;
            Signals = signals;
            Invocation = invocation;
        }

        public IConnection Connection
        {
            get;
            private set;
        }

        public ClientHubInvocation Invocation
        {
            get;
            private set;
        }

        public string Signal
        {
            get;
            private set;
        }

        public IList<string> Signals
        {
            get;
            private set;
        }

        public IList<string> ExcludedSignals
        {
            get;
            set;
        }
    }
}


text:
#include <aws/waf-regional/model/ActivatedRule.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::Utils::Json;
using namespace Aws::Utils;

namespace Aws
{
namespace WAFRegional
{
namespace Model
{

ActivatedRule::ActivatedRule() :
    m_priority(0),
    m_priorityHasBeenSet(false),
    m_ruleIdHasBeenSet(false),
    m_actionHasBeenSet(false),
    m_overrideActionHasBeenSet(false),
    m_type(WafRuleType::NOT_SET),
    m_typeHasBeenSet(false),
    m_excludedRulesHasBeenSet(false)
{
}

ActivatedRule::ActivatedRule(JsonView jsonValue) :
    m_priority(0),
    m_priorityHasBeenSet(false),
    m_ruleIdHasBeenSet(false),
    m_actionHasBeenSet(false),
    m_overrideActionHasBeenSet(false),
    m_type(WafRuleType::NOT_SET),
    m_typeHasBeenSet(false),
    m_excludedRulesHasBeenSet(false)
{
  *this = jsonValue;
}

ActivatedRule& ActivatedRule::operator =(JsonView jsonValue)
{
  if(jsonValue.ValueExists("Priority"))
  {
    m_priority = jsonValue.GetInteger("Priority");

    m_priorityHasBeenSet = true;
  }

  if(jsonValue.ValueExists("RuleId"))
  {
    m_ruleId = jsonValue.GetString("RuleId");

    m_ruleIdHasBeenSet = true;
  }

  if(jsonValue.ValueExists("Action"))
  {
    m_action = jsonValue.GetObject("Action");

    m_actionHasBeenSet = true;
  }

  if(jsonValue.ValueExists("OverrideAction"))
  {
    m_overrideAction = jsonValue.GetObject("OverrideAction");

    m_overrideActionHasBeenSet = true;
  }

  if(jsonValue.ValueExists("Type"))
  {
    m_type = WafRuleTypeMapper::GetWafRuleTypeForName(jsonValue.GetString("Type"));

    m_typeHasBeenSet = true;
  }

  if(jsonValue.ValueExists("ExcludedRules"))
  {
    Aws::Utils::Array<JsonView> excludedRulesJsonList = jsonValue.GetArray("ExcludedRules");
    for(unsigned excludedRulesIndex = 0; excludedRulesIndex < excludedRulesJsonList.GetLength(); ++excludedRulesIndex)
    {
      m_excludedRules.push_back(excludedRulesJsonList[excludedRulesIndex].AsObject());
    }
    m_excludedRulesHasBeenSet = true;
  }

  return *this;
}

JsonValue ActivatedRule::Jsonize() const
{
  JsonValue payload;

  if(m_priorityHasBeenSet)
  {
   payload.WithInteger("Priority", m_priority);

  }

  if(m_ruleIdHasBeenSet)
  {
   payload.WithString("RuleId", m_ruleId);

  }

  if(m_actionHasBeenSet)
  {
   payload.WithObject("Action", m_action.Jsonize());

  }

  if(m_overrideActionHasBeenSet)
  {
   payload.WithObject("OverrideAction", m_overrideAction.Jsonize());

  }

  if(m_typeHasBeenSet)
  {
   payload.WithString("Type", WafRuleTypeMapper::GetNameForWafRuleType(m_type));
  }

  if(m_excludedRulesHasBeenSet)
  {
   Aws::Utils::Array<JsonValue> excludedRulesJsonList(m_excludedRules.size());
   for(unsigned excludedRulesIndex = 0; excludedRulesIndex < excludedRulesJsonList.GetLength(); ++excludedRulesIndex)
   {
     excludedRulesJsonList[excludedRulesIndex].AsObject(m_excludedRules[excludedRulesIndex].Jsonize());
   }
   payload.WithArray("ExcludedRules", std::move(excludedRulesJsonList));

  }

  return payload;
}

} // namespace Model
} // namespace WAFRegional
} // namespace Aws


text:
<!DOCTYPE html>
<html lang="fr">

{% include service/head.html %}

<body id="page-top">
  {% include nav.html %}
  {% include service/header.html %}
  {% include service/service-resume.html %}
  {% include portfolio.html %}

  {% include contact.html %}

  {% include scripts.html %}
</body>

</html>


text:
package com.xeiam.xchange.btcmarkets;

import java.io.IOException;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.xeiam.xchange.btcmarkets.dto.marketdata.BTCMarketsOrderBook;
import com.xeiam.xchange.btcmarkets.dto.marketdata.BTCMarketsTicker;

@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public interface BTCMarkets {

  @GET
  @Path("/market/{instrument}/{currency}/tick")
  BTCMarketsTicker getTicker(
      @PathParam("instrument") String instrument,
      @PathParam("currency") String currency
  ) throws IOException;

  @GET
  @Path("/market/{instrument}/{currency}/orderbook")
  BTCMarketsOrderBook getOrderBook(
      @PathParam("instrument") String instrument,
      @PathParam("currency") String currency
  ) throws IOException;
}


text:
local M = {}

function M.parse(arg)

  local cmd = torch.CmdLine()
  cmd:text()
  cmd:text('Object detection in torch')
  cmd:text()
  cmd:text('Options:')

  local curr_dir = paths.cwd()
  local defaultDataSetDir = paths.concat(curr_dir,'datasets')
  local defaultDataDir = paths.concat(defaultDataSetDir,'VOCdevkit/')
  local defaultROIDBDir = paths.concat(curr_dir,'data','selective_search_data/')

  cmd:text('Folder parameters')
  cmd:option('-cache',paths.concat(curr_dir,'cachedir'),'Cache dir')
  cmd:option('-datadir',defaultDataDir,'Path to dataset')
  cmd:option('-roidbdir',defaultROIDBDir,'Path to ROIDB')
  cmd:text()
  cmd:text('Model parameters')
  cmd:option('-algo','SPP','Detection framework. Options: RCNN | SPP')
  cmd:option('-netType','zeiler','Options: zeiler | vgg')
  cmd:option('-backend','cudnn','Options: nn | cudnn')
  cmd:text()
  cmd:text('Data parameters')
  cmd:option('-year',2007,'DataSet year (for Pascal)')
  cmd:option('-ipb',500,'iter per batch')
  cmd:option('-ntmd',10,'nTimesMoreData')
  cmd:option('-fg_frac',0.25,'fg_fraction')
  cmd:option('-classes','all','use all classes (all) or given class')
  cmd:text()
  cmd:text('Training parameters')
  cmd:option('-lr',1e-2,'learning rate')
  cmd:option('-num_iter',300,'number of iterations')
  cmd:option('-nsmooth',40,'number of iterations before reducing learning rate')
  cmd:option('-nred',4,'number of divisions by 2 before stopping learning')
  cmd:option('-nildfdx',false,'erase memory of gradients when reducing learning rate')
  cmd:text()
  cmd:text('Others')
  cmd:option('-gpu',1,'gpu device to use')
  cmd:option('-numthreads',6,'number of threads to use')
  cmd:option('-comment','','additional comment to the name')
  cmd:option('-seed',0,'random seed (0 = no fixed seed)')
  cmd:option('-retrain','none','modelpath for finetuning')
  cmd:text()

  local opt = cmd:parse(arg or {})
  -- add commandline specified options
  opt.save = paths.concat(opt.cache,
                          cmd:string(opt.netType, opt,
                                     {retrain=true, optimState=true, cache=true,
                                      data=true, gpu=true, numthread=true,
                                      netType=true}))
  -- add date/time
  opt.save_base = opt.save
  local date_time = os.date():gsub(' ','')
  opt.save = paths.concat(opt.save, date_time)

  return opt

end

return M


text:
{-# LANGUAGE TypeFamilies, GeneralizedNewtypeDeriving #-}
-----------------------------------------------------------------------------
-- Copyright 2019, Ideas project team. This file is distributed under the
-- terms of the Apache License 2.0. For more information, see the files
-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-----------------------------------------------------------------------------

module Ideas.Common.Traversal.Navigator
   ( -- * Location information
     Location, toLocation, fromLocation
     -- * Navigator type class
   , Navigator(..)
   , isTop, isLeaf
   , hasLeft, hasRight, hasUp, hasDown
   , top, leftMost, rightMost, leftMostLeaf, rightMostLeaf
   , depth, level, levelNext, levelPrevious, leftMostAt, rightMostAt
   , downs, downTo, arity, navigateTo, navigateTowards
     -- * Tree walks
   , PreOrder, makePreOrder
   , PostOrder, makePostOrder
   , LevelOrder, makeLevelOrder
   , Horizontal, makeHorizontal
   , Leafs, makeLeafs
     -- * Uniplate navigator
   , UniplateNavigator
   ) where

import Control.Monad
import Data.Function
import Data.Generics.Str
import Data.Maybe
import Data.Semigroup as Sem
import Ideas.Common.Traversal.Iterator
import Ideas.Common.Traversal.Utils
import Ideas.Utils.Uniplate
import Test.QuickCheck

---------------------------------------------------------------
-- Navigator type class

newtype Location = L { fromLocation :: [Int] }
 deriving (Eq, Ord)

instance Show Location where
   show = show . fromLocation

instance Sem.Semigroup Location where
   L xs <> L ys = L (xs ++ ys)

instance Monoid Location where
   mempty  = L []
   mappend = (<>)

toLocation :: [Int] -> Location
toLocation = L

-- | For a minimal complete definition, provide an implemention for downs or
-- allDowns. All other functions need an implementation as well, except for
-- change. Note that a constructor (a -> f a) is not included in the type class
-- to allow additional type class constraints on type a.
class Navigator a where
   up       :: a -> Maybe a
   down     :: a -> Maybe a
   downLast :: a -> Maybe a
   left     :: a -> Maybe a
   right    :: a -> Maybe a
   childnr  :: a -> Int
   location :: a -> Location
   -- default definitions
   downLast = fmap (fixp right) . down
   childnr  = pred . length . fixpl left
   location = toLocation . map childnr . drop 1 . reverse . fixpl up

instance Navigator a => Navigator (Mirror a) where
   up       = liftWrapper up
   down     = liftWrapper downLast
   downLast = liftWrapper down
   left     = liftWrapper right
   right    = liftWrapper left

isTop, isLeaf :: Navigator a => a -> Bool
isTop  = not . hasUp
isLeaf = not . hasDown

hasLeft, hasRight, hasUp, hasDown :: Navigator a => a -> Bool
hasLeft  = isJust . left
hasRight = isJust . right
hasUp    = isJust . up
hasDown  = isJust . down

top, leftMost, rightMost :: Navigator a => a -> a
top       = fixp up
leftMost  = fixp left
rightMost = fixp right

leftMostLeaf, rightMostLeaf :: Navigator a => a -> a
leftMostLeaf  = fixp down
rightMostLeaf = fixp downLast

downs :: Navigator a => a -> [a]
downs = maybe [] (fixpl right) . down

downTo :: Navigator a => Int -> a -> Maybe a
downTo n
   | n < 0     = const Nothing
   | otherwise = listToMaybe . drop n . downs

arity :: Navigator a => a -> Int
arity = length . downs

depth :: Navigator a => a -> Int
depth a | null xs   = 0
        | otherwise = maximum (map depth xs) + 1
 where
   xs = downs a

level :: Navigator a => a -> Int
level = pred . length . fixpl up

levelNext :: Navigator a => a -> Maybe a
levelNext = right >|< f 1
 where
   f n = up >=> (g n >|< f (n+1))
   g n = right >=> (leftMostAt n >|< g n)

levelPrevious :: Navigator a => a -> Maybe a
levelPrevious = fmap unwrap . levelNext . makeMirror

leftMostAt :: Navigator a => Int -> a -> Maybe a
leftMostAt n
   | n == 0    = Just
   | n <  0    = const Nothing
   | otherwise = (down >=> leftMostAt (n-1)) >|< (right >=> leftMostAt n)

rightMostAt :: Navigator a => Int -> a -> Maybe a
rightMostAt n = fmap unwrap . leftMostAt n . makeMirror

navigateTo :: Navigator a => Location -> a -> Maybe a
navigateTo is a = go (navigation (location a) is) a
 where
   go = foldr (>=>) Just

navigateTowards :: Navigator a => Location -> a -> a
navigateTowards is a = go (navigation (location a) is) a
 where
   go = foldr (\f g -> safe (fmap g . f)) id

navigation :: Navigator a => Location -> Location -> [a -> Maybe a]
navigation old new = replicate upnr up ++ map downTo ds
 where
   os   = fromLocation old
   ns   = fromLocation new
   same = length (takeWhile id (zipWith (==) os ns))
   upnr = length os - same
   ds   = drop same ns

----------------------------------------------------------------
-- Tree walks

newtype PreOrder a = Pre { fromPre :: a }
   deriving (Show, Eq)

makePreOrder :: a -> PreOrder a
makePreOrder = wrap

instance Wrapper PreOrder where
   wrap   = Pre
   unwrap = fromPre

instance Update PreOrder where
   update a = (unwrap a, wrap)

instance Navigator a => Iterator (PreOrder a) where
   previous = liftWrapper ((fmap rightMostLeaf . left) >|< up)
   next     = let rec = right >|< (up >=> rec)
              in liftWrapper (down >|< rec)
   first    = mapWrapper top
   final    = mapWrapper (rightMostLeaf . top)

newtype PostOrder a = Post { fromPost :: Mirror (PreOrder (Mirror a))}
   deriving (Show, Eq, Iterator)

instance Wrapper PostOrder where
   wrap   = Post . wrap . wrap . wrap
   unwrap = unwrap . unwrap . unwrap . fromPost

instance Update PostOrder where
   update a = (unwrap a, wrap)

makePostOrder :: a -> PostOrder a
makePostOrder = wrap

newtype LevelOrder a = Level { fromLevel :: a } -- breadth-first
   deriving (Show, Eq)

instance Wrapper LevelOrder where
   wrap   = Level
   unwrap = fromLevel

instance Update LevelOrder where
   update a = (unwrap a, wrap)

instance Navigator a => Iterator (LevelOrder a) where
   previous = let f a = rightMostAt (level a-1) (top a)
              in liftWrapper (levelPrevious >|< f)
   next     = let f a = leftMostAt (level a+1) (top a)
              in liftWrapper (levelNext >|< f)
   first    = mapWrapper top
   final    = mapWrapper $ \a -> safe (rightMostAt (depth (top a))) (top a)

makeLevelOrder :: a -> LevelOrder a
makeLevelOrder = wrap

newtype Horizontal a = Hor { fromHor :: a }
   deriving (Show, Eq)

instance Wrapper Horizontal where
   wrap   = Hor
   unwrap = fromHor

instance Update Horizontal where
   update a = (unwrap a, wrap)

instance Navigator a => Iterator (Horizontal a) where
   previous = liftWrapper left
   next     = liftWrapper right
   first    = mapWrapper leftMost
   final    = mapWrapper rightMost
   position = childnr . unwrap

makeHorizontal :: a -> Horizontal a
makeHorizontal = wrap

newtype Leafs a = Leafs { fromLeafs :: a }
   deriving (Show, Eq)

makeLeafs :: Navigator a => a -> Leafs a
makeLeafs = first . wrap

instance Wrapper Leafs where
   wrap   = Leafs
   unwrap = fromLeafs

instance Update Leafs where
   update a = (unwrap a, wrap)

instance Navigator a => Iterator (Leafs a) where
   previous = liftWrapper $
      let rec = left >|< (up >=> rec)
      in fmap rightMostLeaf . rec
   next = liftWrapper $
      let rec = right >|< (up >=> rec)
      in fmap leftMostLeaf . rec
   first = mapWrapper (leftMostLeaf . top)
   final = mapWrapper (rightMostLeaf . top)

---------------------------------------------------------------
-- Str navigator (private)

data StrNavigator a = SN
   { currentStr :: Str a
   , strContext :: [Either (Str a) (Str a)]
   }

instance Navigator (StrNavigator a) where
   up (SN a (x:xs)) = Just (SN (either (flip Two) Two x a) xs)
   up _ = Nothing
   down (SN (Two a b) xs) = Just (SN a (Left b:xs))
   down _ = Nothing
   downLast (SN (Two a b) xs) = Just (SN b (Right a:xs))
   downLast _ = Nothing
   left (SN a (Right b:xs)) = Just (SN b (Left a:xs))
   left _ = Nothing
   right (SN a (Left b:xs)) = Just (SN b (Right a:xs))
   right _ = Nothing
   childnr  = maybe 0 (either (const 0) (const 1)) . listToMaybe . strContext

instance Focus (StrNavigator a) where
   type Unfocus (StrNavigator a) = Str a
   focus   = flip SN []
   unfocus = currentStr . top

sizeStrNavigator :: StrNavigator a -> Int
sizeStrNavigator (SN a xs) =
   sum (countStr a : map (either countStr countStr) xs)

countStr :: Str a -> Int
countStr Zero      = 0
countStr (One _)   = 1
countStr (Two a b) = countStr a + countStr b

---------------------------------------------------------------
-- Str iterator (private)

data StrIterator a = SI
   { posSI  :: !Int
   , fromSI :: Leafs (StrNavigator a)
   }

instance Iterator (StrIterator a) where
   next     (SI n a) = SI (n+1) <$> searchNext ok a
   previous (SI n a) = SI (n-1) <$> searchPrevious ok a
   first    (SI _ a) = SI 0 $ safe (searchForward ok) (first a)
   final    (SI _ a) = finalSI $ safe (searchBackward ok) (final a)
   position          = posSI

instance Focus (StrIterator a) where
   type Unfocus (StrIterator a) = Str a
   focusM  = firstStrIterator
   unfocus = unfocus . unwrap . fromSI

instance Update StrIterator where
   update (SI n (Leafs a)) =
      case currentStr a of
         One b -> (b, \c -> SI n $ wrap $ a {currentStr = One c})
         _     -> error "unsafe update"

firstStrIterator :: Str a -> Maybe (StrIterator a)
firstStrIterator = fmap (SI 0) . searchForward ok . first . wrap . focus

lastStrIterator :: Str a -> Maybe (StrIterator a)
lastStrIterator = fmap finalSI . searchBackward ok . final . wrap . focus

finalSI :: Leafs (StrNavigator a) -> StrIterator a
finalSI a = SI (sizeStrNavigator (unwrap a) - 1) a

ok :: Wrapper f => f (StrNavigator a) -> Bool
ok = isOne . currentStr . unwrap
 where
   isOne (One _) = True
   isOne _       = False

---------------------------------------------------------------
-- Uniplate navigator

data UniplateNavigator a = U [StrIterator a -> StrIterator a] (StrIterator a)

instance (Show a, Uniplate a) => Show (UniplateNavigator a) where
   show a = show (current a) ++ " @ " ++ show (location a)

instance (Eq a, Uniplate a) => Eq (UniplateNavigator a) where
   (==) = on (==) $ \a -> (current a, unfocus a, location a)

instance Uniplate a => Navigator (UniplateNavigator a) where
   up (U [] _)     = Nothing
   up (U (f:fs) a) = Just (U fs (f a))

   down     = downWith focusM
   downLast = downWith lastStrIterator

   left  (U fs a) = U fs <$> previous a
   right (U fs a) = U fs <$> next a

   childnr (U _ a) = position a

instance Update UniplateNavigator where
   update (U xs a) = (current a, U xs . flip replace a)

instance Uniplate a => Focus (UniplateNavigator a) where
   type Unfocus (UniplateNavigator a) = a
   focus   = U [] . focus . One
   unfocus = current . top

instance (Arbitrary a, Uniplate a) => Arbitrary (UniplateNavigator a) where
   arbitrary = fmap focus arbitrary >>= genNav
    where
      genNav a =
         case map genNav (downs a) of
            [] -> return a
            xs -> frequency [(1, return a), (4, oneof xs)]

downWith :: Uniplate a => (Str a -> Maybe (StrIterator a))
                       -> UniplateNavigator a -> Maybe (UniplateNavigator a)
downWith make (U fs a) = U (f:fs) <$> make cs
 where
   (cs, g) = uniplate (current a)
   f = (`replace` a) . g . unfocus


text:
package org.apache.flink.streaming.api.windowing.assigners;

import org.apache.flink.annotation.PublicEvolving;

import java.io.Serializable;

/**
 * A {@code SessionWindowTimeGapExtractor} extracts session time gaps for Dynamic Session Window Assigners.
 *
 * @param <T> The type of elements that this {@code SessionWindowTimeGapExtractor} can extract session time gaps from.
 */
@PublicEvolving
public interface SessionWindowTimeGapExtractor<T> extends Serializable {
	/**
	 * Extracts the session time gap.
	 * @param element The input element.
	 * @return The session time gap in milliseconds.
	 */
	long extract(T element);
}


text:
package com.google.api.ads.dfp.jaxws.v201511;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlType;

/**
 *
Java class for GrpGender.
 *
 *
The following schema fragment specifies the expected content contained within this class.
 *

 *

 * <simpleType name="GrpGender">
 *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
 *     <enumeration value="UNKNOWN"/>
 *     <enumeration value="GENDER_UNKNOWN"/>
 *     <enumeration value="GENDER_FEMALE"/>
 *     <enumeration value="GENDER_MALE"/>
 *   </restriction>
 * </simpleType>
 *

 *
 */
@XmlType(name = "GrpGender")
@XmlEnum
public enum GrpGender {

    /**
     *
     *                 The value returned if the actual value is not exposed by the requested API version.
     *
     *
     */
    UNKNOWN,

    /**
     *
     *                 When gender is not available due to low impression levels, GRP privacy thresholds are activated
     *                 and prevent us from specifying gender.
     *
     *
     */
    GENDER_UNKNOWN,
    GENDER_FEMALE,
    GENDER_MALE;

    public String value() {
        return name();
    }

    public static GrpGender fromValue(String v) {
        return valueOf(v);
    }

}


text:
(NTS: Is that a good designation? A "node" is often used to designate a host in a network, it could conflict with _flon worker_)

A node is a live piece of flon execution.

Abbreviated to FEN or fen.

In ruote an "execution node" was called a "flow expression". With flon, we want to move way from this designation. Ruote has an emphasis on executing messages on independent expressions, while flon deals with executions instead of excution nodes.

## flon execution node id (fenid)

TODO: explain exid vs id, and id { nodeid, subid }

## when stored

A node, when stored, is a JSON document.

```javascript
// (using javascript notation)
{
  exid: "",
  id: { nodeid: "x", subid: "y" },
  tree: [ ... ],
  applied_workitem: { ... },
  on: {
    reply: [],
    cancel: [],
    error: []
  }
}
```

## _thought dump_

* have primitives like reply_to_parent or remove_self, spec them, build upon them


text:
namespace OpenApi.UnitTests
{
    using Crest.OpenApi;
    using FluentAssertions;
    using NSubstitute;
    using Xunit;

    public class SpecificationFileLocatorTests
    {
        private const string Docs = Root + "\\" + SpecificationFileLocator.DocsDirectory;
        private const string Root = @"C:\AssemblyDirectory";
        private readonly IOAdapter io = Substitute.For<IOAdapter>();

        public SpecificationFileLocatorTests()
        {
            this.io.GetBaseDirectory().Returns(Root);
        }

        public sealed class RelativePaths : SpecificationFileLocatorTests
        {
            [Fact]
            public void ShouldReturnAllThePaths()
            {
                this.io.EnumerateFiles(Docs, "openapi.json")
                    .Returns(new[]
                    {
                        Docs + @"\v1\openapi.json",
                        Docs + @"\v2\openapi.json"
                    });

                var locator = new SpecificationFileLocator(this.io);

                locator.RelativePaths.Should().BeEquivalentTo("v1/openapi.json", "v2/openapi.json");
            }

            [Fact]
            public void ShouldReturnGzVersionsIfAvailable()
            {
                this.io.EnumerateFiles(Docs, "openapi.json")
                    .Returns(new[]
                    {
                        Docs + @"\v1\openapi.json",
                        Docs + @"\v2\openapi.json"
                    });
                this.io.EnumerateFiles(Docs, "openapi.json.gz")
                    .Returns(new[]
                    {
                        Docs + @"\v1\openapi.json.gz",
                    });

                var locator = new SpecificationFileLocator(this.io);

                locator.RelativePaths.Should().BeEquivalentTo("v1/openapi.json.gz", "v2/openapi.json");
            }
        }
    }
}


text:
package loon.font;

import loon.LSysException;
import loon.LSystem;
import loon.canvas.Canvas;
import loon.canvas.Image;
import loon.canvas.LColor;
import loon.font.Font.Style;
import loon.geom.PointF;
import loon.geom.PointI;
import loon.geom.Vector2f;
import loon.opengl.GLEx;
import loon.opengl.LSTRDictionary;
import loon.opengl.LTexturePack;
import loon.opengl.LTexturePack.PackEntry;
import loon.utils.IntMap;
import loon.utils.MathUtils;
import loon.utils.StringKeyValue;
import loon.utils.StringUtils;

/**
 * Loon内置的Font实现,当用户无自定义IFont时,默认使用此类实现文字渲染
 */
public class LFont implements IFont {

	public static LFont getDefaultFont() {
		return newFont();
	}

	public static LFont newFont() {
		return newFont(20);
	}

	public static LFont newFont(int size) {
		return LFont.getFont(LSystem.getSystemGameFontName(), Style.PLAIN, size);
	}

	/*
	 * 获得一个默认的LFont.
	 *
	 * 比如:
	 *
	 * 游戏全局使用默认LFont(除log字体外,log字体需要设置setSystemLogFont)
	 *
	 * LSystem.setSystemGameFont(LFont.getDefaultFont());
	 *
	 */

	private IntMap<Vector2f> fontSizes = new IntMap<Vector2f>(50);

	private final static String tmp = "H";

	private String lastText = tmp;

	private PointI _offset = new PointI();

	private TextFormat textFormat = null;

	private TextLayout textLayout = null;

	private int _size = -1;

	private float _ascent = -1;

	private boolean useCache, closed;

	public boolean isUseCache() {
		return useCache;
	}

	public void setUseCache(boolean u) {
		this.useCache = u;
	}

	LFont() {
		this(LSystem.getSystemGameFontName(), Style.PLAIN, 20, true);
	}

	LFont(String name, Style style, int size, boolean antialias) {
		if (StringUtils.isEmpty(name)) {
			throw new LSysException("Font name is null !");
		}
		this.textFormat = new TextFormat(new Font(name, style, MathUtils.max(1, size)), antialias);
		LSystem.pushFontPool(this);
	}

	public static LFont getFont(int size) {
		return LFont.getFont(LSystem.getSystemGameFontName(), size);
	}

	public static LFont getFont(String familyName, int size) {
		return new LFont(familyName, Style.PLAIN, size, true);
	}

	public static LFont getFont(String familyName, int styleType, int size) {
		Style style = Style.PLAIN;
		switch (styleType) {
		default:
		case 0:
			style = Style.PLAIN;
			break;
		case 1:
			style = Style.BOLD;
			break;
		case 2:
			style = Style.ITALIC;
			break;
		case 3:
			style = Style.BOLD_ITALIC;
			break;
		}
		return new LFont(familyName, style, size, true);
	}

	public static LFont getFont(String familyName, Style style, int size) {
		return new LFont(familyName, style, size, true);
	}

	public static LFont getFont(String familyName, Style style, int size, boolean antialias) {
		return new LFont(familyName, style, size, antialias);
	}

	public TextFormat getFormat() {
		return textFormat;
	}

	public TextLayout getTextLayout() {
		return textLayout;
	}

	@Override
	public void drawString(GLEx g, String chars, float tx, float ty) {
		drawString(g, chars, tx, ty, LColor.white);
	}

	@Override
	public void drawString(GLEx g, String chars, float tx, float ty, LColor c) {
		drawString(g, chars, tx, ty, 0, c);
	}

	@Override
	public void drawString(GLEx g, String chars, float tx, float ty, float angle, LColor c) {
		if (c == null || c.a <= 0.01) {
			return;
		}
		if (StringUtils.isEmpty(chars)) {
			return;
		}
		if (useCache) {
			LSTRDictionary.get().drawString(this, chars, _offset.x + tx, _offset.y + ty, angle, c);
		} else {
			LSTRDictionary.get().drawString(g, this, chars, _offset.x + tx, _offset.y + ty, angle, c);
		}
	}

	@Override
	public void drawString(GLEx g, String chars, float tx, float ty, float sx, float sy, float ax, float ay,
			float angle, LColor c) {
		if (c == null || c.a <= 0.01) {
			return;
		}
		if (StringUtils.isEmpty(chars)) {
			return;
		}
		if (useCache) {
			LSTRDictionary.get().drawString(this, chars, _offset.x + tx, _offset.y + ty, sx, sy, ax, ay, angle, c);
		} else {

			LSTRDictionary.get().drawString(g, this, chars, _offset.x + tx, _offset.y + ty, sx, sy, ax, ay, angle, c);
		}
	}

	private void initLayout(String text) {
		if (LSystem.base() == null) {
			return;
		}
		if (text == null || textLayout == null || !text.equals(lastText)) {
			textLayout = LSystem.base().graphics().layoutText(tmp, this.textFormat);
		}
	}

	@Override
	public int charWidth(char ch) {
		if (LSystem.base() == null) {
			return 0;
		}
		initLayout(String.valueOf(ch));
		return textLayout.bounds.width;
	}

	@Override
	public int stringWidth(String message) {
		if (LSystem.base() == null || StringUtils.isEmpty(message)) {
			return 0;
		}
		initLayout(message);
		if (message.indexOf('\n') == -1) {
			return textLayout.stringWidth(message);
		} else {
			StringBuffer sbr = new StringBuffer();
			int width = 0;
			for (int i = 0, size = message.length(); i < size; i++) {
				char ch = message.charAt(i);
				if (ch == '\n') {
					width = MathUtils.max(textLayout.stringWidth(sbr.toString()), width);
					sbr.delete(0, sbr.length());
				} else {
					sbr.append(ch);
				}
			}

			return width;
		}
	}

	public int charHeight(char ch) {
		if (LSystem.base() == null) {
			return 0;
		}
		initLayout(String.valueOf(ch));
		return getHeight();
	}

	@Override
	public int stringHeight(String message) {
		if (LSystem.base() == null || StringUtils.isEmpty(message)) {
			return 0;
		}
		initLayout(message);
		if (message.indexOf('\n') == -1) {
			return getHeight();
		} else {
			String[] list = StringUtils.split(message, '\n');
			return list.length * getHeight();
		}
	}

	public boolean isBold() {
		return textFormat.font.style == Style.BOLD;
	}

	public boolean isItalic() {
		return textFormat.font.style == Style.ITALIC;
	}

	public boolean isPlain() {
		return textFormat.font.style == Style.PLAIN;
	}

	@Override
	public int getSize() {
		return this._size == -1 ? (int) textFormat.font.size : this._size;
	}

	public int getStyle() {
		return textFormat.font.style.ordinal();
	}

	public String getFontName() {
		return textFormat.font.name;
	}

	@Override
	public int getHeight() {
		initLayout(tmp);
		return MathUtils.max(getSize(), textLayout.bounds.height);
	}

	@Override
	public float getAscent() {
		initLayout(tmp);
		return this._ascent == -1 ? textLayout.ascent() : this._ascent;
	}

	public float getDescent() {
		initLayout(tmp);
		return textLayout.descent();
	}

	public float getLeading() {
		initLayout(tmp);
		return textLayout.leading();
	}

	private int fontHash = 1;

	@Override
	public int hashCode() {
		if (fontHash == 1) {
			fontHash = LSystem.unite(textFormat.font.name.charAt(0), fontHash);
			fontHash = LSystem.unite(textFormat.font.name.length(), fontHash);
			fontHash = LSystem.unite(textFormat.font.name.hashCode(), fontHash);
			fontHash = LSystem.unite(textFormat.font.style.ordinal(), fontHash);
			fontHash = LSystem.unite((int) textFormat.font.size, fontHash);
		}
		return fontHash;
	}

	@Override
	public boolean equals(Object o) {
		if (o == null) {
			return false;
		}
		if (!(o instanceof LFont)) {
			return false;
		}
		LFont font = (LFont) o;
		if (this == font) {
			return true;
		}
		if (hashCode() == font.hashCode()) {
			return true;
		}
		if (font.textFormat == textFormat) {
			return true;
		}
		if (font.textFormat.font.name.equals(textFormat.font.name) && font.textFormat.font.size == textFormat.font.size
				&& font.textFormat.font.style.equals(textFormat.font.style)) {
			return true;
		}
		return false;
	}

	public Vector2f getOrigin(String text) {
		Vector2f result = fontSizes.get(text);
		if (result == null) {
			result = new Vector2f(stringWidth(text) / 2f, getHeight() / 2f);
			fontSizes.put(text, result);
		}
		return result;
	}

	public TextLayout getLayoutText(String text) {
		return LSystem.base().graphics().layoutText(text, this.textFormat);
	}

	@Override
	public String confineLength(String s, int width) {
		int length = 0;
		for (int i = 0; i < s.length(); i++) {
			length += stringWidth(String.valueOf(s.charAt(i)));
			if (length >= width) {
				int pLength = stringWidth("...");
				while (length + pLength >= width && i >= 0) {
					length -= stringWidth(String.valueOf(s.charAt(i)));
					i--;
				}
				s = s.substring(0, ++i) + "...";
				break;
			}
		}
		return s;
	}

	@Override
	public PointI getOffset() {
		return _offset;
	}

	@Override
	public void setOffset(PointI val) {
		_offset.set(val);
	}

	@Override
	public void setOffsetX(int x) {
		_offset.x = x;
	}

	@Override
	public void setOffsetY(int y) {
		_offset.y = y;
	}

	@Override
	public void setAssent(float assent) {
		this._ascent = assent;
	}

	@Override
	public void setSize(int size) {
		this._size = size;
	}

	@Override
	public String toString() {
		StringKeyValue builder = new StringKeyValue("LFont");
		builder.addValue(textFormat.toString());
		return builder.toString();
	}

	public boolean isClosed() {
		return closed;
	}

	@Override
	public void close() {
		closed = true;
		LSystem.popFontPool(this);
	}

}


text:
REGION=$(shell /usr/bin/curl -s http://169.254.169.254/latest/dynamic/instance-identity/document/ | jq -r .region)
template:
	/usr/bin/ruby flask-signup-datasources.rb expand > flask-signup-datasources.template
validate:
	/usr/bin/aws cloudformation validate-template --template-body file://flask-signup-datasources.template --region ${REGION}
clean:
	rm -f flask-signup-datasources.template