#!/usr/local/bin/python
# The previous line (which must be the first one to work) makes the script self-executing,
# assuming that the system has the Python interpreter at path /usr/local/bin/python.

# This wants to be run in Python 3.

# Reference Pre-Processor
# Given: A reference file
#        An integer horizon, which tells us how far to look ahead if we do look ahead
# Return: A suffix array (either with short strings, or with the BWT)
#
# by Moyaccercchi, 17th of June 2015
#
# version 11:
# added hash support

import collections

fo = open('in.txt', 'r')

referencepath = fo.readline().strip()
horizon = int(fo.readline().strip())
useBWT = int(fo.readline().strip())

fo.close()

def loadTextFromFile(filepath):

    fhandle = open(filepath, 'r')

    lastread = fhandle.readline().strip()

    if (filepath[-6:].lower() == '.fasta'):

        # We ignore the first read, as it is a comment line.
        res = ''
        origres = lastread

        while (lastread != ""):
            lastread = fhandle.readline().strip()
            res += lastread
            origres += '\n' + lastread

    else:

        # STPU files
        res = lastread
        origres = lastread

    fhandle.close()

    return (res, origres)

# we flatten a given reference string by choosing the first option from each bubble;
# however, we could instead also choose the second (or in fact a random) option,
# or ideally put N characters to indicate that there is a character,
# but it is unknown, so that the later steps do NOT count it as an error
# to align against it either way
# (of course, completely ideal would be to keep track of the graph itself,
# or in this case the bubbles, and use ALL the information later on in the chain,
# not ever discarding any of it)

# also, we are now having nested graphs, so we need to check if we are
# in fact encountering a nested one here, and do this recursively, which is
# why this is a function now rather than just a while iteration

def flattenreference(flat_reference):

    # find the first "(", so e.g. GA(GC(T|C)A|CAGG)T(G|A)C
    #                               ^

    i = flat_reference.find("(");

    if i > -1:

        # find what is before the first "(", so e.g. GA(GC(T|C)A|CAGG)T(G|A)C
        #                                            ^^

        flat_before = flat_reference[:i];

        # we would like to find what is the first alternative, so e.g.
        # GA(GC(T|C)A|CAGG)T(G|A)C
        #    ^^^^^^^^
        #
        # to do so, in version 8 of this script, we simply used
        # flat_first = flat_reference[i+1:flat_reference.find("|")];
        #
        # however, this is not sufficient anymore, as it would find the very first "|",
        # and in our example give us GA(GC(T|C)A|CAGG)T(G|A)C (where we are missing all ° chars)
        #                               ^^^^°°°°
        # so instead we first make a recursive call to this function itself, which will give us:
        # GC(T|C)A|CAGG)T(G|A)C => GCTA|CAGG)T(G|A)C => GCTA|CAGG)TGC

        flatter_reference = flattenreference(flat_reference[i+1:]);

        # flat_first is now the the start of the returned value, e.g.
        #
        # GCTA|CAGG)TGC = GA(GC(T|C)A|CAGG)T(G|A)C
        # ^^^^               ^^ ^   ^

        flat_first = flatter_reference[:flatter_reference.find("|")];

        # find what is after the ")" closing the first "(", so e.g.
        # GCTA|CAGG)TGC = GA(GC(T|C)A|CAGG)T(G|A)C
        #           ^^^                    ^ ^   ^

        flat_after = flatter_reference[flatter_reference.find(")")+1:];

        # take all the parts together to flatten one layer, so e.g.
        # (left is what is actually happening, right is what is conceptually happening)
        #
        # GA(GC(T|C)A|CAGG)T(G|A)C + GCTA|CAGG)TGC = GA(GC(T|C)A|CAGG)T(G|A)C
        # ^^                         ^^^^      ^^^   ^^ ^^ ^   ^      ^ ^   ^
        # GA                         GCTA      TGC = GA GC T   A      T G   C
        # =>                                         =>
        # GAGCTATGC                                = GAGCTATGC

        flat_reference = flat_before + flat_first + flat_after;

    return flat_reference;

def getbubblemidlen(reference, offset):

    # in v9, snipmidlen is more involved (it is the length of any path through the graph,
    # so we go for the first option always and keep track of that)

    curpos = offset + 1;
    nestedness = 0;

    snipmidlen = 0;

    addtomidlen = [];

    # A(GT(CT|TA)G|CAA(A|G)A)T
    #   ^^ ^^ xx ^ xxx x x x
    #
    # 0 11 22 22 1 111 2 2 1 0 nestedness
    #
    #   11 11 11 1 000 0 0 0   addtomidlen[0 = nestedness-1]
    #      11 00       1 0     addtomidlen[1 = nestedness-1]
    #   11 11 00 1 000 0 0 0   prod(addtomidlen) = addtomidlen[0] * .. * addtomidlen[nestedness - 1]

    while (nestedness > 0) or (reference[curpos] != '|'):

        if (reference[curpos] == '('):

            nestedness += 1
            addtomidlen.append(1)

        elif (reference[curpos] == ')'):

            nestedness -= 1
            del addtomidlen[-1]

        elif (reference[curpos] == '|'):

            addtomidlen[nestedness-1] = 0

        else:

            doadd = True;

            for atm in addtomidlen:
                if atm == 0:
                    doadd = False
                    break

            if doadd:
                snipmidlen += 1

        curpos += 1

    return snipmidlen

def getbubbleend(reference, offset):

    lr = len(reference)

    # in v9, snipend also is more involved (it is the end of the bubble,
    # but as bubbles can now be nested, it actually needs to keep track of
    # nesting levels while searching for the ending ")" that belongs to the opening "(",
    # where previously it could just be assumed that the first ")" belongs to the first "(")
    snipstarts = 1
    curloc = offset + 1

    while snipstarts > 0:
        nextstart = reference.find("(", curloc)
        nextend = reference.find(")", curloc)

        if nextstart == -1:
            nextstart = lr
        if nextstart < nextend:
            snipstarts += 1
            curloc = nextstart + 1
        else:
            snipstarts -= 1
            curloc = nextend + 1

    return curloc - 1

def generate_suffix_array(referencepath, horizon):

    orighorizon = horizon

    ret = collections.defaultdict(lambda: '')

    reference, out_reference = loadTextFromFile(referencepath)

    if (referencepath[-6:].lower() == '.fasta'):

        # string reference in FASTA

        for i in range(0, len(reference)):
            ret[reference[i:i+horizon]] += str(i) + ","

    else:

        if '(' in reference:

            # (multi-bubble, nested) graph reference in STPU

            # first, start by generating a changed out_reference in which we
            # replace bubbles by characters of equal length to keep a unified index system
            # (based on i_absolute)

            out_reference = flattenreference(out_reference);

            # actually do the preprocessing of the reference

            i = 0;
            i_absolute = 0;
            lr = len(reference)

            # keeps track of the sniplengths we have encountered, to be able to counteract them later
            sniplens = []
            snipmidlens = []

            # initiate the horizon by adding the length of the SNIP - 1 to it for each '(' before
            # the last character of the first read

            rf = reference[0:horizon-1]
            jumpedover = 0

            while '(' in rf:

                snipbeg = rf.find("(")

                # version 8: for non-nested bubbles only
                # snipmidlen = reference.find('|', snipbeg + jumpedover) - (1 + snipbeg + jumpedover)
                # snipend = reference.find(")", snipbeg + jumpedover) - jumpedover

                # version 9: for nested bubbles too
                snipmidlen = getbubblemidlen(reference, snipbeg + jumpedover)
                snipend = getbubbleend(reference, snipbeg + jumpedover) - jumpedover

                # this is not the real length of the snip, but rather the length - 1
                sniplen = snipend - snipbeg

                sniplens.append(sniplen)
                snipmidlens.append(snipmidlen)

                if (snipend+1 > len(rf)):
                    rf = reference[snipend+horizon-len(rf):horizon+sniplen-1]
                else:
                    rf = rf[snipend+1:] + reference[horizon-1:horizon+sniplen-1]

                jumpedover += snipend+1

                horizon += sniplen

            # to get virtual reads all the way to the end, go for:
            # while i < lr:

            # to only get virtual reads of the full specified length, go for:
            while i < lr-horizon+1:

                # imagine the following reads as [ ] and the following reference:
                #
                # ...AGAGA(T|C)AGAGA...
                #    [   ] <- read AGAGA without graph
                #
                # ...AGAGA(T|C)AGAGA...
                #     [   ] <- read GAGA(, find '(' in last position, expand by 4
                #     [       ] <- read GAGAT and GAGAC
                #
                # ...AGAGA(T|C)AGAGA...
                #      [       ] <- read AGATA and AGACA
                #
                # ...AGAGA(T|C)AGAGA...
                #       [       ] <- read GATAG and GACAG
                #
                # ...AGAGA(T|C)AGAGA...
                #        [       ] <- read ATAGA and ACAGA
                #
                # ...AGAGA(T|C)AGAGA...
                #         [       ] <- read TAGAG and CAGAG
                #
                # instead of i+1, do i+5 (or i+4 and then i+1 due to the loop)
                # also, unexpand
                #
                # ...AGAGA(T|C)AGAGA...
                #              [   ] <- read AGAGA, unexpanded

                # now let us have a look at reads containing several two-SNIPs:
                #
                # ...AGAGA(T|C)A(T|C)GAGA...
                #    [   ] <- read AGAGA without graph
                #
                # ...AGAGA(T|C)A(T|C)GAGA...
                #     [   ] <- read GAGA(, find '(' in last position, expand by 4
                #     [       ] <- read GAGAT and GAGAC
                #
                # ...AGAGA(T|C)A(T|C)GAGA...
                #      [       ] <- read AGATA and AGACA
                #
                # ...AGAGA(T|C)A(T|C)GAGA...
                #       [       ] <- read GATA( and GACA(, find '(' in last position, expand by 4 more
                #       [           ] <- read GATAT, GATAC, GACAT and GACAC
                #
                # ...AGAGA(T|C)A(T|C)GAGA...
                #        [           ] <- read ATATG, ATACG, ACATG and ACACG
                #
                # ...AGAGA(T|C)A(T|C)GAGA...
                #         [           ] <- read TATGA, TACGA, CATGA and CACGA
                #
                # instead of i+1, do i+5 (or i+4 and then i+1 due to the loop)
                # also, unexpand
                #
                # ...AGAGA(T|C)A(T|C)GAGA...
                #              [       ] <- read ATGAG and ACGAG

                # And what about nested bubbles?
                #
                # ...AGAGA(T(T|C)|CG)AGAGA...
                #    [   ] <- read AGAGA without graph
                #
                # ...AGAGA(T(T|C)|CG)AGAGA...
                #     [   ] <- read GAGA(, find '(' in last position, expand until the ')' that closes it
                #     [             ] <- read GAGATT, GAGATC and GAGACG,
                #                        reduce to GAGAT, GAGAT and GAGAC,
                #                        remove multiples to find GAGAT and GAGAC
                #
                # ...AGAGA(T(T|C)|CG)AGAGA...
                #      [             ] <- read AGATTA, AGATCA and AGACGA,
                #                         reduce to AGATT, AGATC and AGACG, remove nothing
                #
                # ...AGAGA(T(T|C)|CG)AGAGA...
                #       [             ] <- read GATTAG, GATCAG and GACGAG,
                #                          reduce to GATTA, GATCA and GACGA, remove nothing
                #
                # ...AGAGA(T(T|C)|CG)AGAGA...
                #        [             ] <- read ATTAGA, ATCAGA and ACGAGA,
                #                           reduce to ATTAG, ATCAG and ACGAG, remove nothing
                #
                # ...AGAGA(T(T|C)|CG)AGAGA...
                #         [             ] <- read TTAGAG, TCAGAG and CGAGAG,
                #                            reduce to TTAGA, TCAGA and CGAGA, remove nothing
                #
                # find '(' in first read pos => jump over entire read,
                # fast-adding all reduced variants, that is
                # TTAGAG, TCAGAG and CGAGAG were given
                # TTAGA , TCAGA  and CGAGA  were already added
                #  TAGAG,  CAGAG and  GAGAG are added in the fast-adding round
                #
                #
                # ...AGAGA(T(T|C)|CG)AGAGA...
                #                    [   ] <- read AGAGA

                rf = reference[i:i+horizon]

                if rf[len(rf)-1] == '(':

                    # the last character of the read, which is where we encountered the '(' character
                    snipbeg = i+horizon-1

                    # in version 8, it was enough to do the following:
                    # snipmidlen = reference.find("|", snipbeg) - (1 + snipbeg);
                    # snipend = reference.find(")", snipbeg)

                    # however, now we have to also consider nested bubbles, so instead we do:
                    snipmidlen = getbubblemidlen(reference, snipbeg)
                    snipend = getbubbleend(reference, snipbeg)

                    # again, this is the length of the snip - 1
                    sniplen = snipend - snipbeg
                    sniplens.append(sniplen)
                    snipmidlens.append(snipmidlen)

                    # (analysis) print ("\nnext:")
                    # (analysis) print ("snipbeg:")
                    # (analysis) print (snipbeg)
                    # (analysis) print ("snipmidlen:")
                    # (analysis) print (snipmidlen)
                    # (analysis) print ("snipend:")
                    # (analysis) print (snipend)
                    # (analysis) print ("sniplen:")
                    # (analysis) print (sniplen)
                    # (analysis) print ("rf old:")
                    # (analysis) print (rf)
                    # (analysis) print ("horizon old:")
                    # (analysis) print (horizon)

                    horizon += sniplen
                    rf = reference[i:i+horizon]

                    # (analysis) print ("rf new:")
                    # (analysis) print (rf)
                    # (analysis) print ("horizon new:")
                    # (analysis) print (horizon)

                if '(' in rf:

                    # this virtual read contains at least one SNIP
                    rfs = [rf]

                    while len(rfs) > 0:

                        rfsnew = []

                        for rfl in rfs:

                            # in version 8 it was enough to do
                            # snipbeg = rfl.find("(");

                            # however, we now have to consider nested bubbles as well

                            # we don't go for the first '(' that we encounter,
                            # but instead for the first '(' that belongs to an inner bubble,
                            # where an "inner bubble" is any bubble that contains no nested bubbles
                            #
                            # e.g. AG(CTAG|G(C(G|T)T|TAA))C(G|T), which represents
                            #      AG CTAG                C G
                            #      AG      G C G   T      C G
                            #      AG      G C   T T      C G
                            #      AG      G         TAA  C G
                            #      AG CTAG                C   T
                            #      AG      G C G   T      C   T
                            #      AG      G C   T T      C   T
                            #      AG      G         TAA  C   T
                            #
                            # in this example, there are two inner bubbles:
                            #      AG(CTAG|G(C(G|T)T|TAA))C(G|T)
                            #                 °°°°°        °°°°°
                            #
                            # More formally, a bubble is an inner bubble iff
                            # after its '(' a ')' follows sooner than another '('.

                            # (analysis) print('rfl', rfl)

                            snipbeg = rfl.find("(");

                            isInnerBubble = False;

                            while not isInnerBubble:

                                if snipbeg < 0:
                                    # no bubble? that's good enough!
                                    isInnerBubble = True
                                else:
                                    snipnextbeg = rfl.find("(", snipbeg+1)
                                    if snipnextbeg < 0:
                                        # no bubble start follows? then this is an inner one!
                                        isInnerBubble = True
                                    else:
                                        snipend = rfl.find(")", snipbeg)
                                        if snipend < snipnextbeg:
                                            # the end is nigh - nigher than the next opening, that is,
                                            # so this is an inner one!
                                            isInnerBubble = True
                                        else:
                                            # another round? then we should update snipbeg
                                            snipbeg = snipnextbeg

                            if snipbeg > -1:

                                snipmidlen = rfl.find("|", snipbeg) - (1 + snipbeg);
                                snipend = rfl.find(")", snipbeg);

                                # we add the virtual read with the first choice and with the
                                # second choice for the first SNIP in it, e.g.
                                # AG(C|T)G(C|T)A -> AGCG(C|T)A, AGTG(C|T)A

                                beforesnip = rfl[:snipbeg]
                                aftersnip = rfl[snipend+1:len(rfl)]

                                snipstart = snipbeg+1;
                                while (snipstart < snipend):
                                    rfsnew.append(beforesnip + rfl[snipstart:snipstart+snipmidlen] + aftersnip)
                                    snipstart += snipmidlen + 1

                            else:

                                # all SNIPs have been replaced by choices from them
                                if not ("," + str(i_absolute) + "," in "," + ret[rfl[:orighorizon]]):
                                    ret[rfl[:orighorizon]] += str(i_absolute) + ","

                                # position [1]:
                                # if a SNIP is in the first position, then add all possible reads
                                # for the following positions as well, all the way through the SNIP
                                if rf[0] == '(':
                                    # we start at 1, as we already added 0:orighorizon+0 two lines above
                                    for lc in range(1, snipmidlens[0]):
                                        # we here check if the location has already been returned for this
                                        # exact virtual read, which seems ridiculous, but actually makes sense,
                                        # considering the following example:
                                        # A(ACCCCCG|GCCCCCA)G
                                        # if we have a virtual read length of 5 (orighorizon == 5),
                                        # then when we get to 'CCCCC' in the second path, it has already
                                        # been added for the first path - and in exactly the same absolute location!
                                        if not ("," + str(i_absolute + lc) + "," in "," + ret[rfl[lc:orighorizon+lc]]):
                                            ret[rfl[lc:orighorizon+lc]] += str(i_absolute + lc) + ","

                        rfs = rfsnew[:]

                else:

                    # this virtual read contains no SNIP, so just use it purely
                    ret[rf[:orighorizon]] += str(i_absolute) + ","

                if rf[0] == '(':
                    sniplen = sniplens.pop(0)
                    snipmidlen = snipmidlens.pop(0)
                    if (sniplen < 0):
                        sniplen = 0
                    horizon -= sniplen

                    i += sniplen + 1
                    i_absolute += snipmidlen

                else:

                    i += 1
                    i_absolute += 1

        else:

            # string reference in STPU

            for i in range(0, len(reference)):
                ret[reference[i:i+horizon]] += str(i) + ","

    fref = open('outref.txt', 'w')

    fref.write(out_reference)

    fref.close()

    return ret

def dicttoadjacency(ourdict):

    ret = []

    for fromnode, tonode in ourdict.items():
        ret.append(fromnode + ' -> ' + tonode[:-1])

    return '\n'.join(sorted(ret))

def getAllCyclicStrings(instr):

    ret = []

    for i in range(0, len(instr)):
        ret.append(instr[i:len(instr)] + instr[0:i])

    return ret

if (useBWT):

    reference, out_reference = loadTextFromFile(referencepath)

    allCyclicStrings = getAllCyclicStrings(reference + '$')

    allCyclicStringsandIndicies = []

    for i in range(0, len(allCyclicStrings)):
        allCyclicStringsandIndicies.append([allCyclicStrings[i], i])

    allCyclicStringsandIndicies.sort()

    # Burrows-Wheeler Transform

    bwt = ''

    for i in range(0, len(allCyclicStringsandIndicies)):
        bwt += allCyclicStringsandIndicies[i][0][len(allCyclicStringsandIndicies[i][0]) - 1]

    fo = open('out.txt', 'w')

    fo.write(bwt)

    fo.close()

    # Suffix Array

    sa = ''

    for i in range(0, len(allCyclicStringsandIndicies)):
        sa += str(allCyclicStringsandIndicies[i][1]) + '\n'

    fo = open('sa.txt', 'w')

    fo.write(sa)

    fo.close()

else:

    res = dicttoadjacency(generate_suffix_array(referencepath, horizon))

    fo = open('out.txt', 'w')

    fo.write(res)

    fo.close()


# Software Business Logic

import os
import qrcode

from time import sleep
from subprocess import Popen
from django.conf import settings

# Constant for filepath and filename
BASE_DIR = settings.BASE_DIR.parent
script_path = BASE_DIR / 'SoftwareController/Scripts/'
qr_path = BASE_DIR / 'SoftwareController/QrCodes/'
qr_name = 'qrcode.png'
scancode_script_name = 'scan_code.sh'

# Constant for background size of qr code
background_width = 2000
background_height = 1500

# Default video source (he-he-he, hi Captain!)
default_video_source = '/dev/video0'

def _save_qr_code(qr_code: str, filepath: str = qr_path, filename: str = qr_name) -> str:
    """Use it for save QrCode from web.whatsapp.com (copied as string)
    to PNG file to your path and your filename.

    :param qr_code: QrCode string from web.whatsapp.com.
    :param filepath: Your path for saving file.
    :param filename: Your name for file.

    :return: Absolute path to saved file.
    """

    path = os.path.join(filepath, filename)
    from PIL import Image
    background = Image.new('RGB', (background_width, background_height), color='white')
    img = qrcode.make(qr_code)

    img_w, img_h = img.size
    bg_w, bg_h = background.size

    offset = ((bg_w - img_w) // 2, (bg_h - img_h) // 2)
    background.paste(img, offset)

    background.save(path)
    return path

def _scan_code() -> bool:
    """Use it for open app (WhatsApp) and scan code

    Plan: start app > more options > WhatsApp Web > scan QR code > waiting > stop app
    Bash-script uses.

    :return: Always True when non-critical error.
    """

    Popen(os.path.join(script_path, scancode_script_name), shell=True)

    return True

def _set_image(path_to_img: str, video_source: str = default_video_source):
    """Use it to loop an image on a video source.

    :param path_to_img: Path to your image to loop.
    :param video_source: A necessary video source for looping an image.

    :return: "subprocess.Popen" object with started ffmpeg stream
    """

    ffmpeg = Popen(
        'sudo ffmpeg -loop 1 -i {} -vf scale=800:600 -f v4l2 -vcodec rawvideo -pix_fmt yuyv422 {} > /dev/null 2>&1 < /dev/null &'.format(
            path_to_img, video_source
        ), shell=True)

    return ffmpeg

def scan_code(qr_code: str) -> bool:
    """Use it for scan QrCode from web.whatsapp.com (copied as string).

    :param qr_code: String of QR code from web.whatsapp.com.
    It is located in "data-ref" attribute at "_3jid7" class.

    :return:
    """

    Popen('killall ffmpeg', shell=True)

    new_qr = _save_qr_code(qr_code)
    _set_image(new_qr)
    _scan_code()

    # TODO: Maybe need to fix it. Cause it could be stopping thread. Idk. (2)
    #       Celery could fix that problem
    sleep(45)

    return True


"""Compile samples that are infeasible or difficult by svg compilation.
"""

import datetime
from pathlib import Path
from fontTools import fontBuilder
from fontTools import ttLib
from fontTools.colorLib import builder as colorBuilder
from fontTools.pens.ttGlyphPen import TTGlyphPen
from fontTools.ttLib.tables._g_l_y_f import Glyph
import sys
from typing import Any, Mapping, NamedTuple, Optional
from fontTools.ttLib.tables import otTables as ot
from nanoemoji.colors import css_colors, Color
from fontTools.misc.transform import Transform

_UPEM = 1000
_ASCENT = 950
_DESCENT = 250
_FAMILY = "More COLR v1 Samples"
_STYLE = "Regular"
_PALETTE = {}  # <3 mutable globals

class SampleGlyph(NamedTuple):
    glyph_name: str
    accessor: str
    advance: int
    glyph: Glyph
    colr: Optional[Mapping[str, Any]] = None

def _cpal(color_str):
    color = Color.fromstring(color_str).to_ufo_color()
    if color not in _PALETTE:
        _PALETTE[color] = len(_PALETTE)
    return _PALETTE[color]

def _sample_sweep():
    glyph_name = "sweep"

    pen = TTGlyphPen(None)
    pen.moveTo((100, 500))
    pen.qCurveTo((500, 1000), (900, 500))
    pen.qCurveTo((500, 0), (100, 500))
    pen.closePath()

    colr = {
        "Format": ot.PaintFormat.PaintGlyph,
        "Glyph": glyph_name,
        "Paint": {
            "Format": ot.PaintFormat.PaintSweepGradient,
            "ColorLine": {
                "ColorStop": [
                    (0.0, _cpal("red")),
                    (0.5, _cpal("yellow")),
                    (1.0, _cpal("red")),
                ]
            },
            "centerX": 500,
            "centerY": 500,
            "startAngle": 0,
            "endAngle": 360,
        },
    }

    return SampleGlyph(
        glyph_name=glyph_name, accessor="c", advance=_UPEM, glyph=pen.glyph(), colr=colr
    )

def _sample_colr_glyph():
    glyph_name = "transformed_sweep"
    # Paint the sweep shifted and rotated
    colr = {
        "Format": ot.PaintFormat.PaintTranslate,
        "dx": 250,
        "dy": 0,
        "Paint": {
            "Format": ot.PaintFormat.PaintRotate,
            "centerX": _UPEM / 2,
            "centerY": _UPEM / 2,
            "angle": 60,
            "Paint": {
                "Format": ot.PaintFormat.PaintColrGlyph,
                "Glyph": "sweep",
            },
        },
    }

    pen = TTGlyphPen(None)
    pen.moveTo((0, 0))
    pen.lineTo((_UPEM, _UPEM))
    pen.endPath()

    return SampleGlyph(
        glyph_name=glyph_name, accessor="t", advance=_UPEM, glyph=pen.glyph(), colr=colr
    )

def _sample_composite_colr_glyph():
    glyph_name = "composite_colr_glyph"
    # Scale down the sweep and use it to cut a hole in the sweep
    # Transforms combine f(g(x)); build up backwards
    t = Transform(dx=-500, dy=-500)  # move to origin
    t = Transform(xx=0.75, yy=0.75).transform(t)
    t = Transform(dx=500, dy=500).transform(t)
    t = tuple(t)

    colr = {
        "Format": ot.PaintFormat.PaintComposite,
        "CompositeMode": "SRC_OUT",
        "SourcePaint": {
            "Format": ot.PaintFormat.PaintColrGlyph,
            "Glyph": "sweep",
        },
        "BackdropPaint": {
            "Format": ot.PaintFormat.PaintTransform,
            "Paint": {
                "Format": ot.PaintFormat.PaintColrGlyph,
                "Glyph": "sweep",
            },
            "Transform": t,
        },
    }

    pen = TTGlyphPen(None)
    pen.moveTo((0, 0))
    pen.lineTo((_UPEM, _UPEM))
    pen.endPath()

    return SampleGlyph(
        glyph_name=glyph_name, accessor="o", advance=_UPEM, glyph=pen.glyph(), colr=colr
    )

def _gradient_stops_repeat(first_stop, second_stop, accessor_char):
    glyph_name = f"linear_repeat_{first_stop}_{second_stop}"

    pen = TTGlyphPen(None)
    pen.moveTo((100, 250))
    pen.lineTo((100, 950))
    pen.lineTo((900, 950))
    pen.lineTo((900, 250))
    pen.closePath()

    colr = {
        "Format": ot.PaintFormat.PaintGlyph,
        "Glyph": glyph_name,
        "Paint": {
            "Format": ot.PaintFormat.PaintLinearGradient,
            "ColorLine": {
                "ColorStop": [
                    (first_stop, _cpal("red")),
                    (second_stop, _cpal("blue")),
                ],
                "Extend": ot.ExtendMode.REPEAT,
            },
            "x0": 100,
            "y0": 250,
            "x1": 900,
            "y1": 250,
            "x2": 100,
            "y2": 300,
        },
    }

    return SampleGlyph(
        glyph_name=glyph_name,
        accessor=accessor_char,
        advance=_UPEM,
        glyph=pen.glyph(),
        colr=colr,
    )

def main():
    assert len(sys.argv) == 2
    build_dir = Path(sys.argv[1])
    build_dir.mkdir(exist_ok=True)

    out_file = (build_dir / _FAMILY.replace(" ", "")).with_suffix(".ttf")

    version = datetime.datetime.now().isoformat()
    names = {
        "familyName": _FAMILY,
        "styleName": _STYLE,
        "uniqueFontIdentifier": " ".join((_FAMILY, version)),
        "fullName": " ".join((_FAMILY, _STYLE)),
        "version": version,
        "psName": "-".join((_FAMILY.replace(" ", ""), _STYLE)),
    }

    glyphs = [
        SampleGlyph(glyph_name=".notdef", accessor="", advance=600, glyph=Glyph()),
        SampleGlyph(glyph_name=".null", accessor="", advance=0, glyph=Glyph()),
        _sample_sweep(),
        _sample_colr_glyph(),
        _sample_composite_colr_glyph(),
        _gradient_stops_repeat(0, 1, "p"),
        _gradient_stops_repeat(0.2, 0.8, "q"),
        _gradient_stops_repeat(0, 1.5, "r"),
        _gradient_stops_repeat(0.5, 1.5, "s"),
    ]

    fb = fontBuilder.FontBuilder(_UPEM)
    fb.setupGlyphOrder([g.glyph_name for g in glyphs])
    fb.setupCharacterMap(
        {ord(g.accessor): g.glyph_name for g in glyphs if len(g.accessor) == 1}
    )
    fb.setupGlyf({g.glyph_name: g.glyph for g in glyphs})
    fb.setupHorizontalMetrics({g.glyph_name: (_UPEM, g.glyph.xMin) for g in glyphs})
    fb.setupHorizontalHeader(ascent=_ASCENT, descent=-_DESCENT)
    fb.setupOS2(sTypoAscender=_ASCENT, usWinAscent=_ASCENT, usWinDescent=_DESCENT)
    fb.setupNameTable(names)
    fb.setupPost()

    fb.font["head"].xMin = 0
    fb.font["head"].yMin = -_DESCENT
    fb.font["head"].xMax = _UPEM
    fb.font["head"].yMax = _ASCENT

    fb.font["OS/2"].fsType = 0
    fb.font["OS/2"].version = 4
    fb.font["OS/2"].fsSelection |= 1 << 7

    fb.font["hhea"].advanceWidthMax = _UPEM

    fb.font["COLR"] = colorBuilder.buildCOLR(
        {g.glyph_name: g.colr for g in glyphs if g.colr}
    )
    fb.font["CPAL"] = colorBuilder.buildCPAL([list(_PALETTE)])

    fb.save(out_file)
    print(f"Wrote {out_file}")

if __name__ == "__main__":
    main()


from .motor import Motor, MotorDirection
import Encoder
from .pins import *
from .sensors import Sensors
from .GPIOhelpers import *
from .PID import *
setGPIO()
import time
import signal, sys

MOTOR_SPEED = 47
TICKS_CELL = 260
TICKS_TURN = 231
WALL_THRESHOLD_DIAG = 85
WALL_DISTANCE_DIAG = 75
WALL_DIST = 80
TIME = 3000
KP3 = 0.5
KP = 0.4
KP2 = .17
KI = 0.01
KD = 0.05
class Motors:
    def __init__(self):
        self.sensors = Sensors([pins.tof_front,pins.tof_rear,pins.tof_fleft,pins.tof_fright,pins.tof_rleft,pins.tof_rright], ["front", "rear","fleft","fright","rleft","rright"], [0x30,0x31,0x32,0x33,0x34,0x35])
        self._frontIR = self.sensors.sensors["front"]
        self._fleftIR = self.sensors.sensors["fleft"]
        self._frightIR = self.sensors.sensors["fright"]
        self._rearIR = self.sensors.sensors["rear"]
        self._rleftIR = self.sensors.sensors["rleft"]
        self._rrightIR = self.sensors.sensors["rright"]

        self.dir = True

        Encoder.init(pins.encoder_pin_l1, pins.encoder_pin_l2, 0)
        Encoder.init(pins.encoder_pin_r1, pins.encoder_pin_r2, 1)

        self.left_motor = Motor("Left", pins.motor_speed_l, pins.motor_direction_l, 0)

        self.right_motor = Motor("Right", pins.motor_speed_r, pins.motor_direction_r, 0)

        self.setpointL = 0
        self.inputL = 0
        self.PIDLeft = PID(self.inputL, self.setpointL, KP3, 0.002, 0.000, DIRECT, Timer)
        self.PIDLeft.set_output_limits(-1 * MOTOR_SPEED*1.5, MOTOR_SPEED*1.5)
        self.PIDLeft.set_mode(AUTOMATIC)

        self.setpointR = 0
        self.inputR = 0
        self.PIDRight = PID(self.inputR, self.setpointR, KP3, 0.002, 0.000, DIRECT, Timer)
        self.PIDRight.set_output_limits(-1 * MOTOR_SPEED*1.5, MOTOR_SPEED*1.5)
        self.PIDRight.set_mode(AUTOMATIC)

        self.setpointfL = 0
        self.inputfL = 0
        self.PIDfLeft = PID(self.inputfL, self.setpointfL, 2.0, 0.002, 0.000, DIRECT, Timer)
        self.PIDfLeft.set_output_limits(-1 * MOTOR_SPEED, MOTOR_SPEED)
        self.PIDfLeft.set_mode(AUTOMATIC)

        self.setpointfR = 0
        self.inputfR = 0
        self.PIDfRight = PID(self.inputfR, self.setpointfR, 2.0, 0.002, 0.000, DIRECT, Timer)
        self.PIDfRight.set_output_limits(-1 * MOTOR_SPEED, MOTOR_SPEED)
        self.PIDfRight.set_mode(AUTOMATIC)

        self.setpointrL = 0
        self.inputrL = 0
        self.PIDrLeft = PID(self.inputrL, self.setpointrL, 2.0, 0.002, 0.000, DIRECT, Timer)
        self.PIDrLeft.set_output_limits(-1 * MOTOR_SPEED, MOTOR_SPEED)
        self.PIDrLeft.set_mode(AUTOMATIC)

        self.setpointrR = 0
        self.inputrR = 0
        self.PIDrRight = PID(self.inputrR, self.setpointrR, 2.0, 0.002, 0.000, DIRECT, Timer)
        self.PIDrRight.set_output_limits(-1 * MOTOR_SPEED, MOTOR_SPEED)
        self.PIDrRight.set_mode(AUTOMATIC)

    def read_encoders(self):
        if self.dir:
            return (-Encoder.read(0), Encoder.read(1))
        else:
            return (Encoder.read(0), -Encoder.read(1))

    def raw_encoders(self):
        return (Encoder.read(0), Encoder.read(1))

    def reverse_direction(self):
        self.dir = not self.dir

    def move_motors(self, left, right):
        if left >= 0:
            self.left_motor.move(MotorDirection.FORWARD, abs(left))
        else:
            self.left_motor.move(MotorDirection.BACKWARD, abs(left))
        if right >= 0:
            self.right_motor.move(MotorDirection.FORWARD, abs(right))
        else:
            self.right_motor.move(MotorDirection.BACKWARD, abs(right))

    def stop(self):
        print("stopped")
        self.right_motor.stop()
        self.left_motor.stop()

    def move_ticks(self, ticks_l, ticks_r):
        Encoder.write(0, 0)
        Encoder.write(0, 1)

        factor = abs(ticks_l)/TICKS_CELL

        self.setpointL = ticks_l
        self.setpointR = ticks_r

        self.inputR = 0
        self.inputL = 0

        start = time.time() * 1000
        while ((abs(self.inputL - self.setpointL) > 5 or abs(self.inputR - self.setpointR) > 5) and (time.time()* 1000 - start < factor *TIME)):
            self.inputL , self.inputR = self.read_encoders()
            #print(self.inputL)
            #print(self.inputR)

            self.PIDRight.compute(self.inputR, self.setpointR)
            self.PIDLeft.compute(self.inputL, self.setpointL)

            l_rem = abs(self.inputL - self.setpointL)
            r_rem = abs(self.inputR - self.setpointR)

            if l_rem > r_rem and (abs(l_rem - r_rem) > 10 or r_rem < 10):
                self.move_motors(self.PIDLeft.output(),0)
            elif r_rem > l_rem and (abs(l_rem - r_rem) > 10 or l_rem < 10):
                self.move_motors(0,self.PIDRight.output())
            else:
                self.move_motors(self.PIDLeft.output(),self.PIDRight.output())

        self.stop()

    def move_cells(self, cells):
        """for _ in range(cells):
            self.advance(TICKS_CELL)
        """
        self.advance(cells*TICKS_CELL)
    def advance(self, ticks):
        Encoder.write(0, 0)
        Encoder.write(0, 1)

        factor = ticks/TICKS_CELL

        distance_l, distance_r = self.read_encoders()
        added = 0
        have_driven = False
        start = time.time()*1000
        while (min(distance_r, distance_l) < ticks and (time.time()*1000 - start < factor * TIME)):
            if have_driven and self.dir and self._frontIR.get_distance() < 40  and self._fleftIR.get_distance() < 65 and  self._frightIR.get_distance() < 65:
                print("break:",self._frontIR.get_distance())
                break
            elif have_driven and not self.dir and self._rearIR.get_distance() < 40 and (self._rleftIR.get_distance() < 65 or  self._rrightIR.get_distance() < 65):
                break

            if abs(distance_l - distance_r) > 140:
                print('added: {}'.format(added))
                added += 4
                ticks += 4
            distance_l, distance_r = self.read_encoders()
            #print(distance_l)
            #print(distance_r)
            dists = {
                'fr': self._frightIR.get_distance(),
                'fl': self._fleftIR.get_distance(),
                'rr': self._rrightIR.get_distance(),
                'rl': self._rleftIR.get_distance()
            }

            front_valid = dists['fr'] < WALL_THRESHOLD_DIAG and dists['fl'] < WALL_THRESHOLD_DIAG and (dists['fr'] < WALL_DIST or dists['fl'] < WALL_DIST)
            rear_valid = dists['rr'] < WALL_THRESHOLD_DIAG and dists['rl'] < WALL_THRESHOLD_DIAG and (dists['rr'] < WALL_DIST or dists['rl'] < WALL_DIST)
            left_valid = dists['fl'] <  WALL_THRESHOLD_DIAG and dists['rr'] <  WALL_THRESHOLD_DIAG and (dists['fl'] <  WALL_DIST or dists['rr'] <  WALL_DIST)
            right_valid = dists['fr'] <  WALL_THRESHOLD_DIAG and dists['rl'] <  WALL_THRESHOLD_DIAG and (dists['fr'] <  WALL_DIST or dists['rl'] <  WALL_DIST)

            if self.dir:
                max2 = min(dists, key = lambda k: dists[k] if (dists[k] < WALL_THRESHOLD_DIAG and k[0] != 'r') else float('inf'))
                single_sensor_functions = {
                        'fr': self.follow_front_right,
                        'fl': self.follow_front_left
                }
            else:
                max2 = min(dists, key = lambda k: dists[k] if (dists[k] < WALL_THRESHOLD_DIAG and k[0] != 'f') else float('inf'))
                single_sensor_functions = {
                        'rr': self.follow_rear_right,
                        'rl': self.follow_rear_left
                }

            if front_valid and self.dir:
                self.follow_front()
            elif rear_valid and not self.dir:
                self.follow_rear()
            elif dists[max2] < WALL_THRESHOLD_DIAG and max2[0] != 'r' and self.dir:
                #print(max2)
                single_sensor_functions[max2]()
            elif dists[max2] < WALL_THRESHOLD_DIAG and max2[0] != 'f' and not self.dir:
                single_sensor_functions[max2]()
            else:
                self.straight()
            have_driven = True

            """
            elif left_valid:
                self.follow_left()
            elif right_valid:
                print("right")
                self.follow_right()

            """
        self.stop()

    def reverse(self, ticks):
        self.reverse_direction()
        self.move_cells(ticks)
        self.reverse_direction()

    def back(self):
        if(self._rearIR.get_distance() > 25 and self._rleftIR.get_distance()> 10 and self._rrightIR.get_distance() > 10):
            print("back")
            self.move_ticks(-TICKS_CELL/4, -TICKS_CELL/4)
        else:
            print("not back")

    def turn_slight_left(self):
        print("turn_slight_left")
        self.PIDLeft.set_tunings(KP3,0.01,0)
        self.PIDRight.set_tunings(KP3,0.01,0)
        self.move_ticks(-1 * TICKS_TURN/6, TICKS_TURN/6)

    def turn_slight_right(self):
        print("turn_slight_right")
        self.PIDLeft.set_tunings(KP3,0.01,0)
        self.PIDRight.set_tunings(KP3,0.01,0)
        self.move_ticks(1 * TICKS_TURN/6, -1*TICKS_TURN/6)

    def attempt_escape(self):
        if(self._frontIR.get_distance() > 40 and self._fleftIR.get_distance()> 60 and self._frightIR.get_distance() > 60):
            print("attempted")
            self.move_cells(1)
            return True
        else:
            print("could not")
            return False

    def escape(self):
        escaped = False
        self.dir = True
        if self._frightIR.get_distance() <= self._fleftIR.get_distance():
            while not escaped:
                print('stuck')
                self.back()
                self.turn_slight_left()
                escaped = self.attempt_escape()
            if(self._frontIR.get_distance() < 40  or self._fleftIR.get_distance() < 10 or self._frightIR.get_distance() < 10):
                print("second escape")
                self.turn_left()
                self.move_cells(2)
        else:
            while not escaped:
                print('stuck')
                self.back()
                self.turn_slight_right()
                escaped = self.attempt_escape()
            if(self._frontIR.get_distance() < 40  or self._fleftIR.get_distance() < 10 or self._frightIR.get_distance() < 10):
                print("second escape")
                self.turn_right()
                self.move_cells(2)

    def turn_around_l(self):
        self.turn_left()
        self.turn_left()

    def turn_around_r(self):
        self.turn_right()
        self.turn_right()

    def turn_left(self):
        self.PIDLeft.set_tunings(KP3,0.01,0)
        self.PIDRight.set_tunings(KP3,0.01,0)
        if self.dir:
            self.move_ticks(-1 * TICKS_TURN, TICKS_TURN)
        else:
            self.move_ticks(TICKS_TURN, -1*TICKS_TURN)
            self.reverse_direction()

    def turn_right(self):
        self.PIDLeft.set_tunings(KP3,0.01,0)
        self.PIDRight.set_tunings(KP3,0.01,0)
        if self.dir:
            self.move_ticks(TICKS_TURN, -1 * TICKS_TURN)
        else:
            self.move_ticks(-1 * TICKS_TURN, TICKS_TURN)
            self.reverse_direction()

    def follow_front(self):
        #print("fFront")
        self.PIDfLeft.set_tunings(KP, KI, KD)
        self.PIDfRight.set_tunings(KP, KI, KD)
        self.setpointfR = WALL_DISTANCE_DIAG
        self.setpointfL = WALL_DISTANCE_DIAG

        self.inputfR = self._frightIR.get_distance()
        self.inputfL = self._fleftIR.get_distance()

        self.PIDfRight.compute(self.inputfR, self.setpointfR)
        self.PIDfLeft.compute(self.inputfL, self.setpointfL)

        self.move_motors((MOTOR_SPEED + self.PIDfLeft.output())/2, (MOTOR_SPEED + self.PIDfRight.output())/2)

    def follow_rear(self):
        #print("fRear")

        self.PIDrLeft.set_tunings(KP, KI, KD)
        self.PIDrRight.set_tunings(KP, KI, KD)
        self.setpointrR = WALL_DISTANCE_DIAG
        self.setpointrL = WALL_DISTANCE_DIAG

        self.inputrR = self._rrightIR.get_distance()
        self.inputrL = self._rleftIR.get_distance()

        #print("R:",self.inputrR)
        #print("L:",self.inputrL)
        self.PIDrRight.compute(self.inputrR, self.setpointrR)
        self.PIDrLeft.compute(self.inputrL, self.setpointrL)

        self.move_motors(-(MOTOR_SPEED + self.PIDrLeft.output())/2, -(MOTOR_SPEED + self.PIDrRight.output())/2)

    def follow_left(self):
        #print("fLeft")

        self.PIDfLeft.set_tunings(KP, KI, KD)
        self.PIDrLeft.set_tunings(KP, KI, KD)
        self.setpointfL = WALL_DISTANCE_DIAG
        self.setpointrR = WALL_DISTANCE_DIAG

        self.inputfL = self._fleftIR.get_distance()
        self.inputrR = self._rrightIR.get_distance()

        self.PIDfLeft.compute(self.inputfL, self.setpointfL)
        self.PIDrRightt.compute(self.inputrR, self.setpointrR)

        if self.dir:
            self.move_motors((MOTOR_SPEED + self.PIDfLeft.output())/2, (MOTOR_SPEED + self.PIDrRight.output())/2)
        else:
            self.move_motors(-(MOTOR_SPEED + self.PIDfLeft.output())/2, -(MOTOR_SPEED + self.PIDrRight.output())/2)

    def follow_right(self):
        #print("fRight")

        self.PIDfRight.set_tunings(KP, KI, KD)
        self.PIDrRight.set_tunings(KP, KI, KD)
        self.setpointfR = WALL_DISTANCE_DIAG
        self.setpointrL = WALL_DISTANCE_DIAG

        self.inputfR = self._frightIR.get_distance()
        self.inputrL = self._rleftIR.get_distance()

        self.PIDfRight.compute(self.inputfR, self.setpointfR)
        self.PIDrLeft.compute(self.inputrL, self.setpointrL)

        if self.dir:
            self.move_motors((MOTOR_SPEED + self.PIDrLeft.output())/2, (MOTOR_SPEED + self.PIDfRight.output())/2)
        else:
            self.move_motors(-(MOTOR_SPEED + self.PIDrLeft.output())/2, -(MOTOR_SPEED + self.PIDfRight.output())/2)

    def follow_front_right(self):
        #print("ffRight")

        self.PIDfRight.set_tunings(KP2, KI, KD)
        self.setpointfR = WALL_DISTANCE_DIAG

        self.inputfR = self._frightIR.get_distance()

        self.PIDfRight.compute(self.inputfR, self.setpointfR)

        if self.dir:
            self.move_motors((MOTOR_SPEED - self.PIDfRight.output())/2, (MOTOR_SPEED + self.PIDfRight.output())/2)
        else:
            self.move_motors(-(MOTOR_SPEED - self.PIDfRight.output())/2, -(MOTOR_SPEED + self.PIDfRight.output())/2)

    def follow_front_left(self):
        #print("ffLeft")

        self.PIDfLeft.set_tunings(KP2, KI, KD)
        self.setpointfL = WALL_DISTANCE_DIAG

        self.inputfL = self._fleftIR.get_distance()

        self.PIDfLeft.compute(self.inputfL, self.setpointfL)

        if self.dir:
            self.move_motors((MOTOR_SPEED + self.PIDfLeft.output())/2, (MOTOR_SPEED - self.PIDfLeft.output())/2)
        else:
            self.move_motors(-(MOTOR_SPEED + self.PIDfLeft.output())/2, -(MOTOR_SPEED - self.PIDfLeft.output())/2)

    def follow_rear_right(self):
        #print("frRight")

        self.PIDrRight.set_tunings(KP2, KI, KD)
        self.setpointrR = WALL_DISTANCE_DIAG

        self.inputrR = self._rrightIR.get_distance()

        self.PIDrRight.compute(self.inputrR, self.setpointrR)

        if self.dir:
            self.move_motors((MOTOR_SPEED - self.PIDrRight.output())/2, (MOTOR_SPEED + self.PIDrRight.output())/2)
        else:
            self.move_motors(-(MOTOR_SPEED - self.PIDrRight.output())/2, -(MOTOR_SPEED + self.PIDrRight.output())/2)

    def follow_rear_left(self):
        #print("frLeft")

        self.PIDrLeft.set_tunings(KP2, KI, KD)
        self.setpointrL = WALL_DISTANCE_DIAG

        self.inputrL = self._rleftIR.get_distance()

        self.PIDrLeft.compute(self.inputrL, self.setpointrL)

        if self.dir:
            self.move_motors((MOTOR_SPEED + self.PIDrLeft.output())/2, (MOTOR_SPEED - self.PIDrLeft.output())/2)
        else:
            self.move_motors(-(MOTOR_SPEED + self.PIDrLeft.output())/2, -(MOTOR_SPEED - self.PIDrLeft.output())/2)

    def straight(self):
        #print("straight")
        if self.dir:
            self.move_motors(MOTOR_SPEED/2, MOTOR_SPEED/2)
        else:
            self.move_motors(-MOTOR_SPEED/2, -MOTOR_SPEED/2)


import socket
import sys
import json
import threading
from threading import Thread, Lock
import time
from block import Transaction, BlockChain, BallotNum

PID = int(sys.argv[1])
print("Process id: ", PID)

IP = "127.0.0.1"
BUFFER_SIZE = 1024
CLIENTS = []
LAMPORT = 0
BALANCE = 10
MAJORITY = 1
SEQ_NUM = 0
BALLOT_NUM = BallotNum()
ACCEPT_NUM = BallotNum()
ACCEPT_VAL = []
ACK_COUNT = 0
ACCEPT_COUNT = 0
MAX_ACK_NUM = BallotNum()
MAX_ACK_VAL = []
isLeader = False
transaction_log = []

PORT = 5000+PID
clientConn = {}
pidConn = {}

def sendMessage(msg, conn):
    time.sleep(5)
    conn.sendall(msg.encode('utf-8'))

def incrementAckCount():
	global ACK_COUNT
	mutex = Lock()
	mutex.acquire()
	ACK_COUNT += 1
	mutex.release()
	print ('ACK_COUNT: ' + str(ACK_COUNT))

def incrementAcceptCount():
	global ACCEPT_COUNT
	mutex = Lock()
	mutex.acquire()
	ACCEPT_COUNT += 1
	mutex.release()
	print ('ACCEPT_COUNT: ' + str(ACCEPT_COUNT))

def sendPrepare():
    BALLOT_NUM.num += 1
    BALLOT_NUM.pid = PID
    SEQ_NUM = chain.getLastSeqNum() + 1
    data = {
        'type': 'prepare',
        'ballot': BALLOT_NUM.toJSON(),
        'seq_num': SEQ_NUM
    }
    message = json.dumps(data)
    for client in CLIENTS:
        threading.Thread(target = sendMessage, args = (message, client,)).start()
    print ('Prepare message sent to clients')

def processMessage(pid, data):
    global BALLOT_NUM
    global ACCEPT_NUM
    global ACCEPT_VAL
    global MAX_ACK_NUM
    global MAX_ACK_VAL
    global ACK_COUNT
    global ACCEPT_COUNT
    print ('Message from client ' + str(pid))
    data = json.loads(data)
    if data['type'] == 'prepare':
        ballotNum = BallotNum.load(data['ballot'])
        if ballotNum.isHigher(BALLOT_NUM):
            BALLOT_NUM = ballotNum
            val = []
            for aval in ACCEPT_VAL:
                val.append(aval.toJSON())
            data = {
                'type': 'ack',
                'ballot': BALLOT_NUM.toJSON(),
                'seq_num': chain.getLastSeqNum(),
                'accept_ballot': ACCEPT_NUM.toJSON(),
                'accept_val': val
            }
            message = json.dumps(data)
            threading.Thread(target = sendMessage, args = (message, pidConn[pid],)).start()
            print ('Ack message sent to client '+str(pid))

    elif data['type'] == 'ack':
        #  check for majority and send accept to followers
        incrementAckCount()
        acceptBallot = BallotNum.load(data['accept_ballot'])
        acceptVal = data['accept_val']
        if len(acceptVal) != 0 and acceptBallot.isHigher(MAX_ACK_NUM):
            MAX_ACK_NUM = acceptBallot
            MAX_ACK_VAL = acceptVal[:]

        time.sleep(5)
        if ACK_COUNT >= MAJORITY:
            log = []
            if len(MAX_ACK_VAL) != 0:
                log = MAX_ACK_VAL[:]
            else:
                for val in transaction_log:
                    log.append(val.toJSON())

            data = {
                'type': 'accept',
                'ballot': BALLOT_NUM.toJSON(),
                'seq_num': SEQ_NUM,
                'value': log
            }
            message = json.dumps(data)
            # for client in CLIENTS:
            threading.Thread(target = sendMessage, args = (message, pidConn[pid],)).start()
            print ('Accept message sent to followers')
            ACK_COUNT = 0

    elif data['type'] == 'accept':
        ballotNum = BallotNum.load(data['ballot'])
        if ballotNum.isHigher(BALLOT_NUM):
            BALLOT_NUM = ballotNum
            ACCEPT_NUM = ballotNum
            val = []
            for aval in transaction_log:
                val.append(aval.toJSON())
            ACCEPT_VAL = [ Transaction.load(val) for val in data['value'] ]
            data = {
                'type': 'accepted',
                'ballot': BALLOT_NUM.toJSON(),
                'seq_num': chain.getLastSeqNum(),
                'value': val
            }
            message = json.dumps(data)
            threading.Thread(target = sendMessage, args = (message, pidConn[pid],)).start()
            print ('Accepted message sent to client '+str(pid))

    elif data['type'] == 'accepted':
        # do stuff and relay message to leader
        incrementAcceptCount()
        for aval in data['value']:
            transaction_log.append(Transaction.load(aval))

        time.sleep(5)
        if ACCEPT_COUNT >= MAJORITY:
            val = []
            for aval in transaction_log:
                val.append(aval.toJSON())
            data = {
                'type': 'commit',
                'ballot': BALLOT_NUM.toJSON(),
                'seq_num': SEQ_NUM,
                'value': val
            }
            message = json.dumps(data)
            # for client in CLIENTS:
            threading.Thread(target = sendMessage, args = (message, pidConn[pid],)).start()
            print ('Decide message sent to followers')
            ACCEPT_COUNT = 0
            chain.printChain()

    elif data['type'] == 'commit':
        print ('Decide message from leader')
        val = []
        for aval in data['value']:
            val.append(Transaction.load(aval))
        chain.append(data['seq_num'], val)
        transaction_log.clear()
        chain.printChain()

def getBalance(pid):
    amount = chain.getBalance(pid)
    for log in transaction_log:
        amount -= log.amount
    return amount

def processInput(data):
    dataList = data.split(',')
    if dataList[0] == 'transfer':
        # Update getBalance to get balance
        receiver = int(dataList[1])
        amount = int(dataList[2])
        amountBefore = getBalance(PID)
        if amountBefore >= amount and PID != receiver:
            transaction_log.append(Transaction(PID, receiver, amount))
            print("SUCCESS")
            print("Balance before: $"+str(amountBefore))
            print("Balance after: $"+str(amountBefore-amount))
        else:
            # Run Paxos
            sendPrepare()

    elif dataList[0] == 'balance':
        if len(dataList) == 1:
            dataList.append(str(PID))
        print("Balance: $"+str(getBalance(int(dataList[1]))))

def listenToClient(pid, conn):
    with conn:
        while True:
            try:
                data = conn.recv(BUFFER_SIZE).decode('utf-8')
                if not data:
                    break
                processMessage(pid, data)
            except socket.error:
                print ("Socket error in receiving message")
                break
        if conn in CLIENTS:
            CLIENTS.remove(conn)

def createServer(pid):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(('', PORT))
        print("socket binded to %s" %(PORT))
        s.listen(1)
        print("socket successfully created")
    except socket.error as err:
        print("socket creation failed with error %s" %(err))

    while True:
        conn, addr = s.accept()
        data = conn.recv(BUFFER_SIZE).decode('utf-8')
        if not data:
            break
        dataList = data.split(',')
        if dataList[0] == 'pid':
            clientConn[conn] = int(dataList[1])
            pidConn[int(dataList[1])] = conn
            print('Accepted connection from client ', dataList[1])
        CLIENTS.append(conn)
        print("#clients connected: ", len(CLIENTS))
        threading.Thread(target = listenToClient,args = (int(dataList[1]),conn,)).start()

def connectToClient(pid, ip, port):
    c_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    c_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    c_socket.connect((ip, port))
    c_socket.sendall(("pid,"+str(PID)).encode('utf-8'))
    CLIENTS.append(c_socket)
    clientConn[c_socket] = pid
    pidConn[pid] = c_socket
    threading.Thread(target = listenToClient,args = (pid,c_socket,)).start()

if __name__ == "__main__":
    # Reading the client configurations
    f = open(sys.argv[2], 'r')
    configList = f.readlines()
    config = configList[PID-1].strip('\n').split(',')
    if len(config) != 3:
        print("Incorrect configuration")
        sys.exit()
    IP = config[0]
    PORT = int(config[1])
    BALANCE = int(config[2])

    # Creating server to listen for connections
    server_thread = threading.Thread(target = createServer,args = (PID,))
    server_thread.start()

    # Connect to existing clients
    for i in range(1, PID):
        clientConfig = configList[i-1].strip('\n').split(',')
        connectToClient(i, clientConfig[0], int(clientConfig[1]))
    print("#clients connected: ", len(CLIENTS))
    print("Balance: $"+str(BALANCE))

    # Listen for client inputs
    chain = BlockChain(BALANCE)

    while True:
        message = input()
        processInput(message)


'''
    Extract spatial and hog feature functions
'''
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import matplotlib.gridspec as gridspec
import glob
import numpy as np
import cv2
from skimage.feature import hog

# Convert RGB to specific color type
def convert_color(img, color_space):
    if color_space == 'HSV':
        feature_image = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
    elif color_space == 'LUV':
        feature_image = cv2.cvtColor(img, cv2.COLOR_RGB2LUV)
    elif color_space == 'HLS':
        feature_image = cv2.cvtColor(img, cv2.COLOR_RGB2HLS)
    elif color_space == 'YUV':
        feature_image = cv2.cvtColor(img, cv2.COLOR_RGB2YUV)
    elif color_space == 'YCrCb':
        feature_image = cv2.cvtColor(img, cv2.COLOR_RGB2YCrCb)
    else:
        feature_image = img
    return feature_image

def convertTo255(img):
    img_cvt = np.array([x*255 for x in img]).astype(np.uint8)
    return img_cvt

def ContrastEnhanceRGB(img):
    # Convert to YUV
    img_yuv = convert_color(img, 'YUV')
    img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])

    # convert  back to RGB format
    img_en = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2RGB)
    img_en = cv2.blur(img_en,(5,5))
    return img_en

# Define a function to return HOG features and visualization
# Note img is 1 channel only: could be a type of RGB, HLS, YCrCb....
def get_hog_features(img, orient, pix_per_cell, cell_per_block, hog_vis=False, feature_vec=True):
    # Call with two outputs if vis==True
    if hog_vis == True:
        features, hog_image = hog(img, orientations=orient,
                                  pixels_per_cell=(pix_per_cell, pix_per_cell),
                                  cells_per_block=(cell_per_block, cell_per_block),
                                  transform_sqrt=True,
                                  visualise=hog_vis, feature_vector=feature_vec)
        return features, hog_image
    # Otherwise call with one output
    else:
        features = hog(img, orientations=orient,
                       pixels_per_cell=(pix_per_cell, pix_per_cell),
                       cells_per_block=(cell_per_block, cell_per_block),
                       transform_sqrt=True,
                       visualise=hog_vis, feature_vector=feature_vec)
        return features

# Define a function to compute binned color features
def bin_spatial(img, size=(32, 32), bin_vis=False):
    # image resize
    img_resize = cv2.resize(img, size)
    # Create the feature vector
    features = img_resize.ravel()
    if bin_vis:
        return features, img_resize
    else:
        # Return the feature vector
        return features

# Define a function to compute color histogram features
def color_hist(img, nbins=32, bins_range=(0, 256)):
    # Compute the histogram of the color channels separately
    channel1_hist = np.histogram(img[:,:,0], bins=nbins, range=bins_range)
    channel2_hist = np.histogram(img[:,:,1], bins=nbins, range=bins_range)
    channel3_hist = np.histogram(img[:,:,2], bins=nbins, range=bins_range)
    # Concatenate the histograms into a single feature vector
    hist_features = np.concatenate((channel1_hist[0], channel2_hist[0], channel3_hist[0]))
    # Return the individual histograms, bin_centers and feature vector
    return hist_features

# Define a function to extract features from a list of images
# Have this function call bin_spatial() and color_hist()
def extract_features(imgs, color_space, spatial_size=(32, 32), hist_bins=32, orient=9,
                     pix_per_cell=8, cell_per_block=2, hog_channel=0, spatial_feat=True,
                     hist_feat=True, hog_feat=True):
    # Create a list to append feature vectors to
    features = []
    # Iterate through the list of images
    for file in imgs:
        file_features = []
        # Read in each one by one
        # Using matplotlib
        #   jpg will be 0-255
        #   png will be 0-1.0
        image = mpimg.imread(file)
        img = np.copy(image)

        # I am using 0-255 scale through out
        # convert png 0-1.0 scale to 0-255
        img = convertTo255(img)

        # enhance contrast
        #img = ContrastEnhanceRGB(img)

        if spatial_feat == True:
            # convert to specific color type for spatial features
            feature_image = convert_color(img, color_space['spatial'])
            spatial_features = bin_spatial(feature_image, size=spatial_size)
            file_features.append(spatial_features)
        if hist_feat == True:
            # convert to specific color type for histogram features
            feature_image = convert_color(img, color_space['hist'])
            hist_features = color_hist(feature_image, nbins=hist_bins)
            file_features.append(hist_features)
        if hog_feat == True:
            # convert to specific color type for hog features
            feature_image = convert_color(img, color_space['hog'])
            # Call get_hog_features() with vis=False, feature_vec=True
            if hog_channel == 'ALL':
                hog_features = []
                for channel in range(feature_image.shape[2]):
                    hog_features.append(get_hog_features(feature_image[:,:,channel],
                                        orient, pix_per_cell, cell_per_block,
                                        hog_vis=False, feature_vec=True))
                hog_features = np.ravel(hog_features)
            else:
                hog_features = get_hog_features(feature_image[:,:,hog_channel], orient,
                            pix_per_cell, cell_per_block, hog_vis=False, feature_vec=True)
            # Append the new feature vector to the features list
            file_features.append(hog_features)

        # combine all feature spaces
        features.append(np.concatenate(file_features))
    # Return list of feature vectors
    return features

def MultiplePlots(grid, images, titles):
    nrow = grid[0]
    ncol = grid[1]
    plt.figure(figsize=(ncol+1, nrow+1))
    gs = gridspec.GridSpec(nrow, ncol,
             wspace=0.2, hspace=0.2,
             top=1.-0.2/(nrow+1), bottom=0.2/(nrow+1),
             left=0.2/(ncol+1), right=1-0.2/(ncol+1))

    for i in range(nrow):
        for j in range(ncol):
            ax = plt.subplot(gs[i,j])
            img = images[i][j]
            title = titles[i][j]
            ax.imshow(img)
            ax.set_title(title)
            xticks = np.arange(0, img.shape[1], 10)
            yticks = np.arange(0, img.shape[0], 10)
            ax.set_xticks(xticks)
            ax.set_yticks(yticks)
            ax.set_xticklabels(xticks)
            ax.set_yticklabels(yticks)
    plt.show()

def test_bin_spatial(img, color_space, spatial_size):
    # convert to specific color type for spatial features
    feature_image = convert_color(img, color_space['spatial'])
    # extract features
    spatial_features_ch0, spatial_image_ch0 = bin_spatial(feature_image[:,:,0], size=spatial_size, bin_vis=True)
    spatial_features_ch1, spatial_image_ch1 = bin_spatial(feature_image[:,:,1], size=spatial_size, bin_vis=True)
    spatial_features_ch2, spatial_image_ch2 = bin_spatial(feature_image[:,:,2], size=spatial_size, bin_vis=True)
    # Grid plot
    grid = [3,2]
    images = [[feature_image[:,:,0],spatial_image_ch0],
              [feature_image[:,:,1],spatial_image_ch1],
              [feature_image[:,:,2],spatial_image_ch2]]
    titles = [[color_space['spatial'] + ' CH-0',color_space['spatial'] + ' CH-0 FEATURE'],
              [color_space['spatial'] + ' CH-1',color_space['spatial'] + ' CH-1 FEATURE'],
              [color_space['spatial'] + ' CH-2',color_space['spatial'] + ' CH-2 FEATURE']]
    MultiplePlots(grid, images, titles)

def test_hog_feature(img, color_space, orient, pix_per_cell, cell_per_block):
    # convert to specific color type for hog features
    feature_image = convert_color(img, color_space['hog'])
    # Call get_hog_features() with vis=False, feature_vec=True
    hog_features_ch0, hog_image_ch0 = get_hog_features(feature_image[:,:,0], orient, pix_per_cell, cell_per_block, hog_vis=True, feature_vec=True)
    hog_features_ch1, hog_image_ch1 = get_hog_features(feature_image[:,:,1], orient, pix_per_cell, cell_per_block, hog_vis=True, feature_vec=True)
    hog_features_ch2, hog_image_ch2 = get_hog_features(feature_image[:,:,2], orient, pix_per_cell, cell_per_block, hog_vis=True, feature_vec=True)

    # Grid Plot
    grid = [3,2]
    images = [[feature_image[:,:,0],hog_image_ch0],
              [feature_image[:,:,1],hog_image_ch1],
              [feature_image[:,:,2],hog_image_ch2]]

    titles = [[color_space['hog'] + ' CH-0',color_space['hog'] + ' CH-0 HOG'],
              [color_space['hog'] + ' CH-1',color_space['hog'] + ' CH-1 HOG'],
              [color_space['hog'] + ' CH-2',color_space['hog'] + ' CH-2 HOG']]

    MultiplePlots(grid, images, titles)

if __name__ == '__main__':
    feature_color = {'hog':'YCrCb','spatial':'HSV','hist':'YCrCb'} #HLS,HSV,LUV,RGB,YCrCb
    orient = 8                  # HOG orientations
    pix_per_cell = 8            # HOG pixels per cell
    cell_per_block = 2          # HOG cells per block
    hog_channel = "ALL"         # HOG channel, can be 0, 1, 2, or "ALL"
    spatial_size = (32, 32)     # Spatial binning dimensions
    hist_bins = 32              # Number of histogram bins
    spatial_feat = True         # Spatial features on or off
    hist_feat = True            # Histogram features on or off
    hog_feat = True             # HOG features on or off

    # read test images
    vehicle = glob.glob('../TrainTestData/Initial_GKU/vehicles/GTI_MiddleClose/image*.png')
    notvehicle = glob.glob('../TrainTestData/Initial_GKU/non_vehicles/Extras/extra*.png')
    # randomly pick one img
    vehicle_indx = 100#np.random.randint(1,len(vehicle))
    notvehicle_indx = 100#np.random.randint(1,len(notvehicle))
    vehicle_img = mpimg.imread(vehicle[vehicle_indx])
    notvehicle_img = mpimg.imread(notvehicle[notvehicle_indx])
    # I am using 255 scale through out the project
    vehicle_img = convertTo255(vehicle_img)
    notvehicle_img = convertTo255(notvehicle_img)
    plt.figure()
    plt.subplot(1,2,1)
    plt.imshow(vehicle_img)
    plt.title('Car')
    plt.subplot(1,2,2)
    plt.imshow(notvehicle_img)
    plt.title('Not car')
    plt.show()

    # show result: car
    test_hog_feature(vehicle_img, feature_color, orient, pix_per_cell, cell_per_block)
    test_bin_spatial(vehicle_img, feature_color, spatial_size)
    # show result: not car
    test_hog_feature(notvehicle_img, feature_color, orient, pix_per_cell, cell_per_block)
    test_bin_spatial(notvehicle_img, feature_color, spatial_size)


from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
import random

data = b'10000000'

key = get_random_bytes(16)

IV = get_random_bytes(16)
# print(key, IV)
cipher = AES.new(key, AES.MODE_OFB, IV)
print(cipher)
ct = cipher.encrypt(pad(data, 16))
# ct = unpad(ct, 16)
print(len(ct))

# print(key, IV)
cipher2 = AES.new(key, AES.MODE_OFB, IV)
pt = unpad(cipher2.decrypt(ct), 16)
print(pt)


# coding: utf-8

from datetime import date
from tqsdk import TqApi, TqReplay, TargetPosTask
# 在创建 api 实例时传入 TqReplay 就会进入复盘模式,设置web_gui=True开启图形化界面
api = TqApi(backtest=TqReplay(date(2018,6,25)),web_gui=True)
# 获得 m1901 5分钟K线的引用
klines = api.get_kline_serial("DCE.m1901", 5 * 60, data_length=15)
# 创建 m1901 的目标持仓 task，该 task 负责调整 m1901 的仓位到指定的目标仓位
target_pos = TargetPosTask(api, "DCE.m1901")
while True:
    api.wait_update()
    if api.is_changing(klines):
        ma = sum(klines.close.iloc[-15:]) / 15
        print("最新价", klines.close.iloc[-1], "MA", ma)
        if klines.close.iloc[-1] > ma:
            print("最新价大于MA: 目标多头5手")
            # 设置目标持仓为多头5手
            target_pos.set_target_volume(5)
        elif klines.close.iloc[-1] < ma:
            print("最新价小于MA: 目标空仓")
            # 设置目标持仓为空仓
            target_pos.set_target_volume(0)


# -*- coding: utf-8 -*-
"""
general functions and fitting.
(a half-decent language would have those functions already).
Python is worth what it costs.
"""

from itertools import product
import sys  # command line argument, print w/o newline, version
import numpy as np

NSmplRst = 2
NGrp = 212
NPad = 45
NADC = 7
NColInBlock = 32
NRowInBlock = NADC  # 7
NCol = NColInBlock * NPad  # 32*45=1440, including RefCol
NRow = NADC * NGrp  # 212*7=1484
NbitPerPix = 15

iGn = 0
iCrs = 1
iFn = 2
NGnCrsFn = 3
iSmpl = 0
#
ERRint16 = -256  # negative value usable to track Gn/Crs/Fn from missing pack
ERRDLSraw = 65535
# forbidden uint16, usable to track "pixel" from missing pack

# percival-specific data reordering functions

# from P2M manual
N_xcolArray = 4
N_ncolArray = 8
N_col_block = N_xcolArray * N_ncolArray
colArray = np.arange(N_col_block).reshape((N_xcolArray,
                                           N_ncolArray)).transpose()
colArray = np.fliplr(colArray)  # in the end it is colArray[ix,in]

# this gives the (iADC,iCol) indices of a pixel in a Rowblk,
# given its sequence in the streamout
ADCcolArray_1DA = []
for i_n, i_adc, i_x in product(range(N_ncolArray),
                               range(NADC)[::-1],
                               range(N_xcolArray)):
    ADCcolArray_1DA.append((i_adc, colArray[i_n, i_x]))

# to use this:  for ipix in range(32*7):
# (ord_ADC,ord_col)=ADCcolArray_1DA[ipix]
ADCcolArray_1DA = np.array(ADCcolArray_1DA)

iG = 0
iH0 = np.arange(21+1, 0+1-1, -1)
iH1 = np.arange(22+21+1, 22+0+1-1, -1)
iP2M_ColGrp = np.append(np.array(iG), iH0)
iP2M_ColGrp = np.append(iP2M_ColGrp, iH1)

def printcol(string, colour):
    ''' write in colour (red/green/orange/blue/purple) '''
    white = '\033[0m'  # white (normal)
    if (colour == 'black'):
        out_color = '\033[30m'  # black
    elif (colour == 'red'):
        out_color = '\033[31m'  # red
    elif (colour == 'green'):
        out_color = '\033[32m'  # green
    elif (colour == 'orange'):
        out_color = '\033[33m'  # orange
    elif (colour == 'blue'):
        out_color = '\033[34m'  # blue
    elif (colour == 'purple'):
        out_color = '\033[35m'  # purple
    else:
        out_color = '\033[30m'
    print(out_color+string+white)
    sys.stdout.flush()

def convert_hex_byteSwap_2nd(data2convert_Ar):
    ''' interpret the ints in an array as 16 bits.
        byte-swap them: (byte0,byte1) => (byte1,byte0)
    '''
    by0 = np.mod(data2convert_Ar, 2**8).astype('uint16')
    by1 = data2convert_Ar//(2**8)
    by1 = by1.astype('uint16')
    data_ByteSwapped_Ar = (by0 * (2**8)) + by1
    data_ByteSwapped_Ar = data_ByteSwapped_Ar.astype('uint16')
    return (data_ByteSwapped_Ar)

def convert_uint_2_bits_Ar(in_intAr, Nbits):
    ''' convert (numpyarray of uint => array of Nbits bits)
        for many bits in parallel
    '''
    inSize_T = in_intAr.shape
    in_intAr_flat = in_intAr.flatten()
    out_NbitAr = np.zeros((len(in_intAr_flat), Nbits), dtype=bool)
    for iBits in range(Nbits):
        out_NbitAr[:, iBits] = (in_intAr_flat >> iBits) & 1
    out_NbitAr = out_NbitAr.reshape(inSize_T+(Nbits,))
    return out_NbitAr

def convert_britishBits_Ar(british_bit_array):
    ''' Conversion of bits defined by RAL to normal bit Conversion:
            0=>1 , 1=>0

         Example:
            >>> convert_britishBis_Ar(1)
                0
    '''
    return 1 - british_bit_array

def convert_bits_2_uint16_Ar(bitarray):
    """ Convert (numpyarray of [... , ... , n_bits] to
        array of [... , ... ](int) """
    shape = bitarray.shape
    n_bits = shape[-1]
    out = np.zeros(shape[:-1], dtype='uint16')
    for ibit in range(n_bits):
        out = (out << 1) | bitarray[..., n_bits-ibit-1]
    return out

def decode_dataset_8bit(arr_in, bit_mask, bit_shift):
    """ Masks out bits and shifts """
    arr_out = np.bitwise_and(arr_in, bit_mask)
    arr_out = np.right_shift(arr_out, bit_shift)
    arr_out = arr_out.astype(np.uint8)
    return arr_out

def aggregate_to_GnCrsFn(raw_dset):
    """Extracts the coarse, fine and gain bits.
    0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15
    -   B0  B1  F0  F1  F2  F3  F4  F5  F6  F7  C0  C1  C2  C3  C4
    """
    coarse_adc = decode_dataset_8bit(arr_in=raw_dset,
                                     bit_mask=0x1F,
                                     bit_shift=0)  # 0x1F -> 0000000000011111
    fine_adc = decode_dataset_8bit(arr_in=raw_dset,
                                   bit_mask=0x1FE0,
                                   bit_shift=5)  # 0x1FE0 -> 0001111111100000
    gain_bits = decode_dataset_8bit(arr_in=raw_dset,
                                    bit_mask=0x6000,
                                    bit_shift=5+8)  # 0x6000->0110000000000000
    return coarse_adc, fine_adc, gain_bits

# P2M specific descrambling
def reorder_pixels_GnCrsFn_par(disord_6DAr, NADC, NColInRowBlk):
    """ P2M pixel reorder for a image.
        (NImg,NSmplrst, NGrp,NDataPads,NADC*NColInRowBlk,3),disordered
          ((NImg,NSmplrst, NGrp,NDataPads,NADC,NColInRowBlk,3),ordered
    """
    (aux_NImg,
     aux_NSmplRst,
     aux_NGrp,
     aux_NPads,
     aux_pixInBlk,
     auxNGnCrsFn) = disord_6DAr.shape

    output_shape = (aux_NImg,
                    aux_NSmplRst,
                    aux_NGrp,
                    aux_NPads,
                    NADC,
                    NColInRowBlk,
                    auxNGnCrsFn)
    ord_7DAr = np.zeros(output_shape, dtype='uint8')
    aux_pixOrd_padDisord_7DAr = np.zeros(output_shape, dtype='uint8')
    # pixel reorder inside each block
    for ipix in range(NADC*NColInRowBlk):
        (ord_ADC, ord_Col) = ADCcolArray_1DA[ipix]
        aux_pixOrd_padDisord_7DAr[...,
                                  ord_ADC, ord_Col, :] = disord_6DAr[..., ipix, :]
    ord_7DAr[...] = aux_pixOrd_padDisord_7DAr[..., iP2M_ColGrp[:], :, :, :]
    return ord_7DAr

def descramble_to_crs_fn_gn(scrmblShot,
                            refColH1_0_Flag,
                            cleanMemFlag,
                            verboseFlag):
    """
    Descramble content of 1 odinDAQ-acquired (raw) shout.
    Return content in Gn/Crs/Fn format.

    Here is how data are scrambled:

    1a) the chips send data out interleaving RowGroups
        (7row x (32 Col x 45 pads) ) from Sample/Reset, as:
        Smpl, Smpl,   Smpl, Rst, Smpl, Rst, ... , Smpl, Rst,   Rst, Rst
    1b) the position of pixels (pix0/1/2 in the next point) is mapped to
        the (7row x 32 Col) block according to the adc_cols lost
    1c) inside a (7row x 32 Col) block, the data are streamed out as:
        bit0-of-pix0, bit0-of-pix1, bit0-of-pix2, ... , bit0-of-pix1, ...
    1d) all the data coming from the sensor are bit-inverted: 0->1; 1->0
    2a) the mezzanine takes the data coming from each (7 x 32) block,
        and add a "0" it in front of every 15 bits:
        xxx xxxx xxxx xxxx  yyy ... => 0xxx xxxx xxxx xxxx 0yyy ...
    2b) the mezzanine takes the data coming from a 44x (7 x 32) blocks
        (this corresponds to a complete RowCrp, ignoring RefCol )
        and interleaves 32 bits at a time:
        32b-from-pad1, 32b-from-pad2, ... , 32b-from-pad44,
        next-32b-from-pad1, next-32b-from-pad2, ...
    2c) the mezzanine packs the bits in Bytes, and the Bytes in UDPackets
        4 UDPackets contain all the bits of a 44x (7 x 32) Rowgrp.
        A complete image (Smpl+Rst) = 1696 UDPackets
        each UDPack has 4928Byte of information, and 112Byte of header.
        each UDPack is univocally identified by the header:
        - which Img (frame) the packet belongs to
        - datatype: whether it is part of a Smpl/Rst (respect. 1 or 0)
        - subframenumber (0 or 1)
        - packetnumber (0:423), which determines the RowGrp the
        packet's data goes into
        there are 1696 packets in an image; a packet is identified by the
        triplet (datatype,subframenumber,packetnumber)
    3a) the packets are sent from 2 mezzanine links (some on one link, some
        on the other), and are saved to 2 h5 files by odinDAQ
    4a) OdinDAQ byte-swaps every 16-bit sequence (A8 B8 becomes B8 A8)
    5a) OdinDAQ rearranges the 4 quarters of each rowblock
    6a) OdinDAQ seems to invert Smpl and Rst

    Args:
        dataSmpl_fl0,dataRst_fl0,dataSmpl_fl1,dataRst_fl1
        swapSmplRstFlag,seqModFlag, refColH1_0_Flag,verboseFlag,cleanMemFlag

    Returns:
        descrambled array (DLSraw format)
    """
    out_dscrmbl = np.copy(scrmblShot)
    scrmblShot = np.asarray(scrmblShot)
    NColInBlk = NColInBlock
    NDataPad = NPad - 1

    # convert to (1-img,row, col) because easier to integrate
    print(scrmblShot.shape)
    (auxNRow, auxNCol) = scrmblShot.shape
    scrmblShot = scrmblShot.reshape((1, auxNRow, auxNCol))
    NImg = 1

    # solving 4a DAQ-scrambling: byte swap in hex (By0,By1) => (By1,By0)
    # N.B.: possible swipe between Smpl and Rst
    if verboseFlag:
        printcol("solving DAQ-scrambling: byte-swapping and Smpl-Rst-swapping",
                 'blue')
    scrmblShot_byteSwap = convert_hex_byteSwap_2nd(scrmblShot)
    if cleanMemFlag:
        del scrmblShot

    # solving DAQ-scrambling: "pixel" reordering
    if verboseFlag:
        printcol("solving DAQ-scrambling: reordering subframes", 'blue')

    def convert_odin_daq_2_mezzanine(shot_in):
        ' descrambles the OdinDAQ-scrambling '
        (aux_n_img, aux_nrow, aux_ncol) = shot_in.shape
        aux_reord = shot_in.reshape((aux_n_img,
                                     NGrp,
                                     NADC,
                                     2,
                                     aux_ncol//2))
        aux_reord = np.transpose(aux_reord, (0, 1, 3, 2, 4))
        aux_reord = aux_reord.reshape((aux_n_img,
                                      NGrp,
                                      2,
                                      2,
                                      NADC*aux_ncol//4))
        aux_reordered = np.ones((aux_n_img,
                                 NGrp,
                                 4,
                                 NADC*aux_ncol//4), dtype='uint16') * ERRDLSraw
        aux_reordered[..., 0, :] = aux_reord[..., 0, 0, :]
        aux_reordered[..., 1, :] = aux_reord[..., 1, 0, :]
        aux_reordered[..., 2, :] = aux_reord[..., 0, 1, :]
        aux_reordered[..., 3, :] = aux_reord[..., 1, 1, :]
        aux_reordered = aux_reordered.reshape((aux_n_img,
                                               NGrp*NADC,
                                               aux_ncol))
        return aux_reordered

    data2srcmbl_noRefCol = np.ones((NImg,
                                    NSmplRst,
                                    NRow,
                                    auxNCol), dtype='uint16') * ERRDLSraw
    data2srcmbl_noRefCol[:, iSmpl, :, :] = convert_odin_daq_2_mezzanine(scrmblShot_byteSwap)
    if cleanMemFlag:
        del scrmblShot_byteSwap

    data2srcmbl_noRefCol = data2srcmbl_noRefCol.reshape((NImg,
                                                         NSmplRst,
                                                         NGrp,
                                                         NADC,
                                                         auxNCol))

    # track missing packets:
    # False==RowGrp OK; True== packet(s) missing makes rowgroup moot
    # (1111 1111 1111 1111 instead of 0xxx xxxx xxxx xxxx)
    missingRowGrp_Tracker = data2srcmbl_noRefCol[..., 0, 0] == ERRDLSraw
    # ---
    # descramble proper
    if verboseFlag:
        printcol("solving mezzanine&chip-scrambling: pixel descrambling",
                 'blue')
    multiImgWithRefCol = np.zeros((NImg,
                                   NSmplRst,
                                   NGrp,
                                   NPad,
                                   NADC*NColInBlk,
                                   NGnCrsFn), dtype='int16')
    #
    # refCol
    multiImgWithRefCol[..., 0, :, :] = ERRint16
    #
    # descrambling
    data2srcmbl_noRefCol = data2srcmbl_noRefCol.reshape((NImg,
                                                         NSmplRst,
                                                         NGrp,
                                                         NADC*auxNCol//(NDataPad*2),
                                                         NDataPad,
                                                         2))
    # 32bit = 2"pix" from 1st pad, 2"pix" from 2nd pad, etc.
    data2srcmbl_noRefCol = np.transpose(data2srcmbl_noRefCol,
                                        (0, 1, 2, 4, 3, 5)).reshape((NImg,
                                                                     NSmplRst,
                                                                     NGrp,
                                                                     NDataPad,
                                                                     NADC*auxNCol//NDataPad))
    # (NSmplRst,NGrp,NDataPad,NADC*aux_NCol//NDataPad)
    theseImg_bitted = convert_uint_2_bits_Ar(data2srcmbl_noRefCol, 16)[..., -2::-1].astype('uint8')
    # n_smplrst,n_grp,n_data_pads,n_adc*aux_ncol//n_data_pads,15bits
    if cleanMemFlag:
        del data2srcmbl_noRefCol
    theseImg_bitted = theseImg_bitted.reshape((NImg,
                                               NSmplRst,
                                               NGrp,
                                               NDataPad,
                                               NbitPerPix,
                                               NADC*NColInBlk))
    theseImg_bitted = np.transpose(theseImg_bitted, (0, 1, 2, 3, 5, 4))
    # (NImg, n_smplrst,n_grp,n_data_pads,NPixsInRowBlk,15)
    theseImg_bitted = convert_britishBits_Ar(theseImg_bitted).reshape((NImg,
                                                                       NSmplRst*NGrp*NDataPad*NADC*NColInBlk,
                                                                       NbitPerPix))

    theseImg_bitted = theseImg_bitted.reshape((NImg*NSmplRst*NGrp*NDataPad*NADC*NColInBlk,
                                               NbitPerPix))
    (aux_coarse, aux_fine, aux_gain) = aggregate_to_GnCrsFn(convert_bits_2_uint16_Ar(theseImg_bitted[:, ::-1]))
    multiImgWithRefCol[..., 1:, :, iGn] = aux_gain.reshape((NImg,
                                                            NSmplRst,
                                                            NGrp,
                                                            NDataPad,
                                                            NADC*NColInBlk))
    multiImgWithRefCol[..., 1:, :, iCrs] = aux_coarse.reshape((NImg,
                                                               NSmplRst,
                                                               NGrp,
                                                               NDataPad,
                                                               NADC*NColInBlk))
    multiImgWithRefCol[..., 1:, :, iFn] = aux_fine.reshape((NImg,
                                                            NSmplRst,
                                                            NGrp,
                                                            NDataPad,
                                                            NADC*NColInBlk))
    if cleanMemFlag:
        del aux_gain
        del aux_coarse
        del aux_fine
        del theseImg_bitted

    # reorder pixels and pads
    if verboseFlag:
        printcol("solving chip-scrambling: pixel reordering", 'blue')
    multiImg_Grp_dscrmbld = reorder_pixels_GnCrsFn_par(multiImgWithRefCol,
                                                       NADC,
                                                       NColInBlk)
    if cleanMemFlag:
        del multiImgWithRefCol

    # add error tracking
    if verboseFlag:
        printcol("lost packet tracking", 'blue')
    multiImg_Grp_dscrmbld = multiImg_Grp_dscrmbld.astype('int16')
    # -256 upto 255
    for iImg in range(NImg):
        for iGrp in range(NGrp):
            for iSmplRst in range(NSmplRst):
                if (missingRowGrp_Tracker[iImg, iSmplRst, iGrp]):
                    multiImg_Grp_dscrmbld[iImg, iSmplRst, iGrp, ...] = ERRint16

    # also err tracking for ref col
    multiImg_Grp_dscrmbld[..., 0, :, :, :] = ERRint16
    if refColH1_0_Flag:
        if verboseFlag:
            printcol("moving RefCol data to G", 'blue')
        multiImg_Grp_dscrmbld[..., 0, :, :, :] = multiImg_Grp_dscrmbld[..., 44, :, :, :]
        multiImg_Grp_dscrmbld[..., 44, :, :, :] = ERRint16
    # ---
    #
    # reshaping as an Img array: (NImg,Smpl/Rst,n_grp,n_adc,n_pad,NColInBlk,Gn/Crs/Fn)
    if verboseFlag:
        printcol("reshaping as an Img array", 'blue')
    dscrmbld_GnCrsFn = np.transpose(multiImg_Grp_dscrmbld,
                                    (0, 1, 2, 4, 3, 5, 6)).astype('int16').reshape((NImg,
                                                                                NSmplRst,
                                                                                NGrp*NADC,
                                                                                NPad*NColInBlk,
                                                                                NGnCrsFn))
    if cleanMemFlag:
        del multiImg_Grp_dscrmbld
    # that's all folks
#    out_dscrmbl = dscrmbld_GnCrsFn[0, 0, :, 32:, iCrs].astype('uint16')
#    return out_dscrmbl

    coarse = dscrmbld_GnCrsFn[0, 0, :, 32:, iCrs].astype('uint16')
    fine = dscrmbld_GnCrsFn[0, 0, :, 32:, iFn].astype('uint16')
    gain = dscrmbld_GnCrsFn[0, 0, :, 32:, iGn].astype('uint16')

    return (coarse, fine, gain)


import matplotlib.pyplot as plt
import os
import pickle
import torch
import json

from collections import defaultdict

def save_best_model(state_dict, model_dir: str, best_epoch: int, keep: int):
    save_to = os.path.join(model_dir, '{}.pkl'.format(best_epoch))
    torch.save(state_dict, save_to)
    model_files = [f for f in os.listdir(model_dir) if os.path.splitext(f)[-1] == '.pkl']
    epochs = [int(os.path.splitext(f)[0]) for f in model_files if str.isdigit(f[0])]
    outdated = sorted(epochs, reverse=True)[keep:]
    for n in outdated:
        os.remove(os.path.join(model_dir, '{}.pkl'.format(n)))

def find_best_model(model_dir: str):
    model_files = [f for f in os.listdir(model_dir) if os.path.splitext(f)[-1] == '.pkl']
    epochs = [int(os.path.splitext(f)[0]) for f in model_files if str.isdigit(f[0])]
    best_epoch = max(epochs)
    return os.path.join(model_dir, '{}.pkl'.format(best_epoch))

def save_and_visual_loss(loss: list, loss_file: str,
                         title: str = None, xlabel: str = None, ylabel: str = None, step: int = 1):
    with open(loss_file, 'wb') as f:
        pickle.dump(loss, f)

    plt.figure()
    plt.plot(range(step, step * len(loss) + 1, step), loss)
    if title:
        plt.title(title)
    if xlabel:
        plt.xlabel(xlabel)
    if ylabel:
        plt.ylabel(ylabel)
    plt.savefig(loss_file[:-3] + 'png')

def save_args(args, save_to: str):
    args_dict = args.__dict__
    with open(save_to, 'w') as f:
        json.dump(args_dict, f, indent=2)

def load_args(args, load_from: str):
    args_dict = args.__dict__
    with open(load_from, 'r') as f:
        tmp_dict = json.load(f)
    for k, v in tmp_dict.items():
        args_dict[k] = v

def drop_feature(x, drop_prob):
    drop_mask = torch.empty(
        (x.shape[1],),
        dtype=torch.float32,
        device=x.device).uniform_(0, 1) < drop_prob
    x = x.clone()
    x[:, drop_mask] = 0
    return x

def read_map(map_file, multi=False):
    if multi:
        d = defaultdict(list)
    else:
        d = {}
    with open(map_file, 'r') as f:
        f.readline()
        if multi:
            for line in f:
                k, v = line.rstrip().split('\t')
                d[k].append(int(v))
        else:
            for line in f:
                k, v = line.rstrip().split('\t')
                d[k] = int(v)
    return d


from sqlalchemy import (
    Column,
    Boolean,
    Integer,
    Text,
    ForeignKey,
)

from sqlalchemy.orm import relationship

from .meta import Base

class Answer(Base):
    __tablename__ = 'answers'
    id = Column(Integer, primary_key=True)
    content = Column(Text)
    is_correct = Column(Boolean(name='correct'))

    question_id = Column(ForeignKey('questions.id'), nullable=False)
    question = relationship('Question', backref='answers')


from __future__ import division
import cv2

while True:
  img = cv2.imread('sampleimage.bmp')
  if img is None:
     continue
  cv2.namedWindow("dst_rt")

    # you can choose different interpolation methods
  frame_display = cv2.resize(img, (320, 240),
                           interpolation=cv2.INTER_CUBIC)
  cv2.imshow("dst_rt", frame_display)
#cv2.imshow('dst_rt', img)
  cv2.waitKey(100)
#  cv2.destroyAllWindows()


import argparse
import os
import glob
import re

from tqdm import tqdm
import pandas as pd
from joblib import Parallel, delayed
from sig2kmer import read_kmer_csv
from sig_utils import SKETCH_INFO_PATTERN
from sourmash.logging import error, notify, set_quiet
import sqlite3

def process_single_kmer_csv(csv):
    try:
        df = read_kmer_csv(csv)
    except (pd.errors.EmptyDataError, pd.errors.ParserError):
        #         print(f"Empty file: {csv}")
        return

    split = csv.split("/")
    test_species = re.findall("((test|train)-\w+)", csv)[0][0]
    species = test_species.split("-")[-1]
    df["species"] = species
    df["cell_id"] = os.path.basename(csv).split(".")[0]
    mol_or_alpha, moltype, ksize, style, value = re.findall(SKETCH_INFO_PATTERN, csv)[0]
    df["sketch_id"] = split[-4]
    df["moltype"] = moltype
    df["ksize"] = ksize
    df[style] = int(value)
    alignment_status = split[-2]
    df["alignment_status"] = alignment_status
    return df

def main():
    p = argparse.ArgumentParser()
    # base directory containing a 2--single-cell-kmers folder which contains sketch id directories with sig2kmer csvs
    p.add_argument("species_base_dir")
    p.add_argument(
        "--n-jobs",
        type=int,
        default=16,
        help="Number of processes to use",
    )
    p.add_argument(
        "--kmer-subdir",
        default="2--single-cell-kmers",
        type=str,
        help="Subdirectory containing csvs within each per-sketch id subdirectory",
    )
    p.add_argument(
        "--no-aligned-unaligned-subdir",
        action="store_true",
        help=(
            "If not set, looks for files in {species_base_dir}/{kmer_subdir}/{sketch_id}/csvs/aligned and "
            "{species_base_dir}/{kmer_subdir}/{sketch_id}/csvs/unaligned. Otherwise, "
            "looks in {species_base_dir}/{kmer_subdir}/{sketch_id}/csvs/"
        ),
    )
#     p.add_argument(
#         "--gene-name-tag",
#         default="GN",
#         help=(
#             "Set the bam file tag to look for gene names in the read information"
#         ),
#     )
    args = p.parse_args()

    kmer_dir = os.path.join(args.species_base_dir, args.kmer_subdir)

    sketch_globber = os.path.join(
        kmer_dir,
        "alphabet-*ksize-*",
    )

    for sketch_dir in glob.glob(sketch_globber):
        notify(f"Reading hash2kmer csvs from {sketch_dir}")
        if args.no_aligned_unaligned_subdir:
            csv_globber = os.path.join(
                sketch_dir,
                "csvs",
                "*.csv",
            )
        else:
            csv_globber = os.path.join(
                sketch_dir,
                "csvs",
                "*",  # "aligned" or "unaligned" directory
                "*.csv",
            )
        total = sum(1 for _ in glob.iglob(csv_globber))

        dfs = Parallel(n_jobs=args.n_jobs)(
            delayed(process_single_kmer_csv)(csv) for csv in glob.iglob(csv_globber)
        )
        try:
            kmers = pd.concat(dfs)
        except ValueError:
            # No objects to contatenate, continue
            notify("No hash2kmer files found, skipping")
            continue
        parquet = os.path.join(sketch_dir, "hash2kmer.parquet")
        notify(f"Writing {parquet}")
        kmers.to_parquet(parquet)

if __name__ == "__main__":
    main()


"""UpdateConfig URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('home', views.home, name='home'),
    path('update', views.update, name='clone'),
    path('add', views.add, name='add'),
    path('upload3ds', views.upload3ds, name='upload3ds'),
    path('uploadprep', views.uploadprep, name='uploadprep'),
    path('delete', views.delete, name='delete'),
    path('deploy', views.deploy, name='deploy'),
    path('setdata', views.setdata, name='setdata')
]