# The MIT License (MIT)
#
# Copyright (C) 2014-2015 William Whitacre
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

"""
                           _______________________
                         **                       **
                        *||   grex stable v1.0    ||*
                    -=$ ||O         ~~~~~         O|| $=-
                        *|| "What a GReat lEXer!" ||*
                         **_______________________**

                        = submatch register loading =
                     = non-contiguous register contents =
             = deeply explained register manipulation syntax =
              = well documented vm implementation based off
                             of thompson's vm =

Grex is a small lexer for quick and dirty scraping jobs. The implementation
is small, so the module loads fast. I have taken a Thompson style VM approach,
so the regex object is in fact a VM. The instruction set of the VM is well
documented, and it is very possible to construct VMs without using the provided
expression language.

Registers are strings, not indices, and as such one may append many
non-contiguous ranges to each register. In the cases that one may want to prune
out parts of the string like a sieve, this may be extremely useful. The token
output for each token class in a lexer VM may be declared in a manner that
allows swizzling of the registers in to any order desired, as well as automatic
type conversions.

Quick Example

    vmobj = [
        grex_vm("[A-Za-z_][A-Za-z0-9_]*", "IDENT", 0, greedy=True),
        grex_vm("&1[\"']&2(.*)$1", "STRING", 2, greedy=False),
        grex_vm("[0-9]+", "INT", (0, INT), greedy=True),
        grex_vm(",", "COMMA", greedy=False),
        grex_vm("&1[0-9]+:&2[a-z]{3}", "REGISTER",
                (1, INT), 2, greedy=False),
        grex_vm("\\->", "ASSIGN", greedy=False)]),
    ]

    vm = grex_vm_finalize(vmobj)

    with open("duh.txt", "r") as fileobj:
        for token in grex_vm_lex_lines(fileobj):
            print(token)

See the source for a detailed explanation of the VM instruction set and
the syntax used in this flavor.
"""

from sys import stdout, stdin
from functools import partial, reduce
from itertools import chain, count, islice
from collections import deque
import string, io

# set to true to enable building spec
_BUILDSPEC = True

# any character special value
_ANY = (1928,)

# instructions
_SMB, _FRK, _JMP, _YES, _SAV, _LOD = range(6)

__inst_name = {
    _SMB: "sym",  # expect symbol               sym  SYMCLASS
    _FRK: "fork", # fork execution              fork LINENO LINENO
    _JMP: "jmp",  # jump execution              jmp  LINENO
    _YES: "yes",  # accept                      yes  MESSAGE [REGISTERS]
    _SAV: "sav",  # save symbol                 sav  [REGISTERS] SYMCLASS
    _LOD: "load"  # load string                 load REGISTER
}

# register types
STR, INT, FLT, DBL = range(4)

__reg_name = {
    STR: "str",
    INT: "int",
    FLT: "flt",
    DBL: "dbl"
}

__reg_type = {
    STR: str,
    INT: int,
    FLT: float,
    DBL: float
}

__reg_dflt = {
    STR: "",
    INT: 0,
    FLT: 0.0,
    DBL: 0.0
}

__reg_id = { v: k for k, v in __reg_name.items() }

###################
# sym, fork, jump #
###################
#
#  sym
#    if the next symbol is not the given symbol, the thread dies. otherwise,
#    the thread continues. a range of symbols may also be specified.
#  jump
#    continue execution from the line given
#  fork
#    continue execution from the first line given generate a new thread at the
#    second line given
#
#  these are given by the standard regex operators: |?*+ (and the implicit
#  concatination).
#
######################
# saving and loading #
######################
#
#  save works like sym in that if the symbol is not the expected symbol, the
#  execution thread will die. otherwise, it is appended to the given register.
#
#  load will expect the sequence of symbols at the given register. for example:
#
#       sav 1 d
#       sav 1 o
#       sav 1 g
#       load 1
#       yes cat 1
#
#  would say yes to "dogdog" with ("cat", "dog"). the power of this is that if
#  ANY thread writes to a register nondeterministically, that is what will be
#  loaded later, allowing one to transcend the power of pure regex with a kind
#  of ad-hoc "almost" turing machine. this is of course one of the staple
#  concepts of unix, but I attempt here to define a better syntax that is more
#  usable for the usual applications (is this an email address? an ipv6
#  address? a valid url? a telephone number?) A lot of regex languages suffer
#  from syntax bloat.
#
#  these are used in submatching, and an attempt to keep the syntax familiar
#  while cleaning up some of the hideousness Perl has introduced has been made.
#
#  &n(...)
#  &n[...]
#  To specify a save block, one simply writes &n(...) or &n[...] where n may be
#  an integer of any number of digits specifying the register in which to save
#  whatever is matched in the brackets. the parenthesis and square brackets
#  keep their same functions, the former is a concatinating group and the
#  latter is a symbol alternation group. you may only save to register 1 and
#  up. register 0 is reserved as the global register, which holds the
#  characters scanned thus far.
#
#  $n or $(nnn)
#  The familiar $n will load whatever string has been saved to register n and
#  match the entirety of that string exactly. If there is more than one digit,
#  the 'n's must be parenthesized. You may not load the global register inside
#  the expression, because doing so would break determinism in a really awful
#  way, and will guaranteed never be useful for anything.
#
#  $0 match global register (everything read so far)
#
#############
# accepting #
#############
#
#  the yes instruction consists of a message identifying the type of the token,
#  and a space separated sequence of registers. a tuple will be constructed
#  containing the message and contents of the registers. the yes instruction is
#  not part of the syntax of grex. to specify a yes, one must call the library
#  with a yes keyword argument for the given regex to specify the contents of
#  yes in a tuple.
#

# sym
def _sym(cc, inst=(_SMB,)):
    def __incrsym(lc, c, rng):
        if rng[0]:
            rng[0] = False
            a, b = lc[-1], c
            if ord(a) > ord(b): a, b = b, a
            lc.extend(chr(o) for o in range(ord(a),ord(b)+1))
        else:
            lc.append(c)

    if len(cc) == 1:
        return [inst + ({cc},)]

    lc = []
    esc, rng = False, [False]
    for c in cc:
        if esc:
            esc = False
            __incrsym(lc, c, rng)
        elif c == "\\":
            esc = True
        elif c == "-":
            rng[0] = True
        else:
            __incrsym(lc, c, rng)

    sc = set(lc)
    if _ANY in sc:
        return [inst + ({_ANY},)]
    else:
        return [inst + (sc,)]

def _sav(reg, cc):
    return _sym(cc, (_SAV, {int(r) for r in reg}))

def _lod(reg):
    return [(_LOD, int(reg))]

# e1`e2
def _cat(e):
    e[0].extend(e[1])
    return e[0]

# e1|e2
def _alt(e):
    try:
        (sym1,) = e[0]
        (sym2,) = e[1]

        if sym1[0] != sym2[0]:
            raise Exception()

        if sym1[0] == _SMB:
            _inst = (_SMB,)
        elif sym1[0] == _SAV:
            if sym1[1] != sym2[1]:
                raise Exception()
            _inst = (_SAV, sym1[1])
        else:
            raise Exception()

        c1 = sym1[-1]
        c2 = sym2[-1]

        return _sym(c1|c2, inst=_inst)
    except:
        e[0].insert(0, (_FRK, 1, len(e[0])+2))
        e[0].append((_JMP, len(e[1])+1))
        e[0].extend(e[1])

    return e[0]

# e{N}
def _pow(N, e):
    if N < 1:
        raise Exception("Power operator < 1 not allowed.")

    return e[0] * N

# make a fork that puts the favorable branch first.
# this assumes l and r are line numbers, and that
# l < r.
def __mkfork(greedy, l, r):
    return (_FRK, l, r) if greedy else (_FRK, l, r)

# e?[?]
def _may(greedy, e):
    e[0].insert(0, __mkfork(greedy, 1, 2))
    return e[0]

# e*[?]
def _rep(greedy, e):
    e[0].insert(0, __mkfork(greedy, 1, len(e[0])+2))
    e[0].append((_JMP, -len(e[0])))
    return e[0]

# e+[?]
def _pls(greedy, e):
    e[0].append(__mkfork(greedy, -len(e[0]), 1))
    return e[0]

# e1-e2
def _rng(e):
    try:
        (sym1,) = e[0]
        (sym2,) = e[1]
        if sym1[0] != sym2[0]:
            raise Exception("Symbol instruction mismatch: %s %s" % (sym1[0], sym2[0]))

        if sym1[0] == _SMB:
            _inst = (_SMB,)
        elif sym1[0] == _SAV:
            if sym1[1] != sym2[1]:
                raise Exception("Save register mismatch: %s %s" % (sym1[1], sym2[1]))
            _inst = (_SAV, sym1[1])
        else:
            raise Exception("Invalid symbol class: %s" % sym1[0])
        (c1,) = sym1[-1]
        (c2,) = sym2[-1]
    except Exception as err:
        raise Exception("Range operator error: %s" % repr(err))

    return _sym("".join([c1, "-", c2]), inst=_inst)

# eof
def _accept(e, yes, *reg, **kwargs):
    e.append((_YES, kwargs.get("greedy", True), yes) + reg)
    return e

def __cmp_sym(cc, symtab):
    return _sym(symtab[int(cc)])

def __dec_sym(syms):
    return "".join(["sym ", str(syms)])

def __cmp_fork(pl, pr, symtab):
    return (_FRK, int(pl), int(pr))

def __dec_fork(pl, pr):
    return " ".join(["fork", str(pl), str(pr)])

def __cmp_jmp(addr, symtab):
    return (_JMP, int(addr))

def __dec_jmp(addr):
    return "".join(["jmp ", str(addr)])

__yesgreedypredval = {"max": True, "min": False}
def __cmp_yes(*args):
    greedy, yes, *reg = args
    reg = reg[:-1] # knock off symtab

    regt = []
    for R in reg:
        r, t = R.split(":", 1)
        regt.append((int(r), __reg_id[t]))

    return tuple(chain([_YES, __yesgreedypredval[greedy], yes], regt))

__yesgreedypredname = lambda p: "max" if p else "min"
def __dec_yes(*args):
    greedy, yes, *reg = args
    return " ".join(chain(
        ["yes", __yesgreedypredname(greedy), yes],
        [":".join([str(r[0]), __reg_name[r[1]]]) for r in reg]))

def __cmp_sav(reg, cc, symtab):
    return _sav(set(int(r) for r in reg), symtab[int(cc)])

def __dec_sav(reg, syms):
    return " ".join(["sav",
        " ".join([str(r) for r in reg]), str(syms)])

def __cmp_load(reg, symtab):
    return (_LOD, int(reg))

def __dec_load(reg):
    return "".join(["load ", str(reg)])

def __lnk_ctl(ctl, i, symtab):
    return tuple(chain(ctl[:1], (rel + i for rel in ctl[1:])))

def __lnk_iso(iso, i, symtab):
    return iso

# symtab is [dict:tab, int:next_i]
def __lnk_sym(sym, i, symtab):
    syms = frozenset(sym[-1])
    if _ANY in syms:
        syms = frozenset((_ANY,))

    try:
        syms_id = symtab[0][syms]
    except KeyError:
        syms_id, symtab[1] = symtab[1], symtab[1]+1
        symtab[0][syms] = syms_id

    return tuple(chain(sym[:-1], [syms_id]))

def __fin_ctl(ctl, stablen):
    return tuple(chain(ctl[:1], (n + stablen for n in ctl[1:])))

def __fin_iso(iso, stablen):
    return iso

# compiling
__inst_cmp = {
    "sym" : __cmp_sym,
    "fork": __cmp_fork,
    "jmp" : __cmp_jmp,
    "yes" : __cmp_yes,
    "sav" : __cmp_sav,
    "load": __cmp_load
}

# link symtab and line numbers
__inst_lnk1 = {
    _SMB: __lnk_sym,
    _FRK: __lnk_ctl,
    _JMP: __lnk_ctl,
    _YES: __lnk_iso,
    _SAV: __lnk_sym,
    _LOD: __lnk_iso
}

# final line number adjustment pass
__inst_lnk2 = {
    _SMB: __fin_iso,
    _FRK: __fin_ctl,
    _JMP: __fin_ctl,
    _YES: __fin_iso,
    _SAV: __fin_iso,
    _LOD: __fin_iso
}

# decompiling
__inst_dec = {
    _SMB: __dec_sym,
    _FRK: __dec_fork,
    _JMP: __dec_jmp,
    _YES: __dec_yes,
    _SAV: __dec_sav,
    _LOD: __dec_load
}

# enums
_BRKL, _BRKR, _OP, _SYM, _LOAD = range(5)
_STR, _TYP, _FN, _ARITY, _PREC, _SYMINST = range(6)
_MATCHBRK, _IMPLIC = 2, 3
_VM, _SM = 8634, 3720 # some arbitrary unique values

# helper for bracket dict construction
def _mkbrk(k, v):
    if k == v[0]:
        return
    else:
        return

# operator and bracket info
__opgreed = frozenset('?*+')
__opdict = {
    '`' : (_cat, 2, 2, None),
    '|' : (_alt, 2, 1, None),
    '?' : (partial(_may, True ), 1, 3, None),
    '??': (partial(_may, False), 1, 3, None),
    '*' : (partial(_rep, True ), 1, 3, None),
    '*?': (partial(_rep, False), 1, 3, None),
    '+' : (partial(_pls, True ), 1, 3, None),
    '+?': (partial(_pls, False), 1, 3, None),
    '{' : (None, 1, 3, None),
    '}' : (None, 1, 3, None),
    '-' : (_rng, 2, 4, None)
}

__opclasdict = { k: (k, _OP) + v for k, v in __opdict.items() }

def brkitem(d):
    yield d[0], (d[0], _BRKL, d[2], d[1], -1, (_SMB,))
    yield d[2], (d[2], _BRKR, d[0], d[1], -1, (_SMB,))

__brkdef   = { '(`)', '[|]' }
__brkdict  = dict(chain.from_iterable(brkitem(d) for d in __brkdef))
__clasdict = dict(chain(__opclasdict.items(),__brkdict.items()))

# takes definition
def shunt_brkL(cl, stk):
    stk.append(cl)
    return; yield

# takes matching brace to pop to
def shunt_brkR(cl, stk):
    while stk and stk[-1][_STR] != cl[_MATCHBRK]:
        yield stk.pop()
    stk.pop() # throw the other out

# operator shunting
def shunt_op(cl, stk):
    while stk and stk[-1][_PREC] >= cl[_PREC]:
        yield stk.pop()
    stk.append(cl)

# shunt sym or load
def shunt_symorload(cl, stk):
    yield cl

# evaluate shunting
def evalu_op(cl, stk):
    fun, arity = cl[_FN:_ARITY+1]
    stk[-arity:] = [fun(stk[-arity:])]

# evaluate sym
def evalu_sym(cl, stk):
    stk.append(_sym(cl[_STR], inst=cl[_SYMINST]))

# evaluate sym
def evalu_load(cl, stk):
    stk.append(_lod(cl[_STR]))

# call tables
__shuntmethod = {
    _BRKL: shunt_brkL,
    _BRKR: shunt_brkR,
    _OP:   shunt_op,
    _SYM:  shunt_symorload,
    _LOAD: shunt_symorload
}

__evalumethod = {
    _OP:   evalu_op,
    _SYM:  evalu_sym,
    _LOAD: evalu_load
}

# predicate dictating whether or not a pair of
# symbols should have an implicit operator between them.
__implic = {       # l[_ARITY] == 1
    (_BRKR, _BRKL, False),
    (_BRKR, _SYM,  False),
    (_BRKR, _LOAD, False),
    (_SYM,  _BRKL, False),
    (_SYM,  _SYM,  False),
    (_SYM,  _LOAD, False),
    (_LOAD, _BRKL, False),
    (_LOAD, _SYM,  False),
    (_LOAD, _LOAD, False),
    (_OP,   _BRKL, True ),
    (_OP,   _SYM,  True ),
    (_OP,   _LOAD, True )
}

# characters indicating that the pre processor should enter a special scanning
# state.
__preprocscanmode = { '{': 1, '&': 2, '$': 3 }

# retrieve the operator information for a symbol, and generate a plain symbol
# if the symbol is not an operator
def __classify(c):
    return __clasdict.get(c, (c, _SYM, None, None, None, (_SMB,)))

# generate a load instruction
def __loadop(reg):
    return (int(reg), _LOAD, None, None, None, None)

# start scanning state
def _preprocmode0(dat, r, ckgreed=True):
    mode, acc, l = dat
    if l == '\\':
        # last thing was a backslash, escape this character.
        yield __classify('\\'+('\\' if r == '\0' else r))
    elif ckgreed and l in __opgreed:
        if r == '?':
            yield __classify(l+'?')
        else:
            yield __classify(l)
            if r != '\0':
                yield from _preprocmode0(dat, r, False)
    elif r != '\0':
        try:
            # see if the current symbol should trigger a special scanning
            # state. if this table lookup fails, a KeyError will be raised
            # by python.
            dat[0] = __preprocscanmode[r]
        except KeyError:
            # ordinary single char symbols and operators. handle escape
            # sequences and ANY characters here
            if r == '\\':
                # skip backslash, next character will be escaped.
                pass
            if r in __opgreed:
                # greed modifier, need lookahead
                pass
            elif r == '.':
                # any character
                yield __classify(_ANY)
            elif r == '`':
                # if we get a backtick then escape it, because backticks will
                # be inserted in a future pass to explicate concatination.
                yield __classify('\\`')
            else:
                # it's just an ordinary symbol, proceed plainly.
                yield __classify(r)

# finite closure scanner
def _preprocmode1(dat, r):
    if r == '}':
        # we got a close bracket, yield a power operator.  since this is
        # considered a unary operator to keep the trainyard shunting algorithm
        # simple, we must construct a partial function that gives this power
        # operator it's own builtin value so that it can be treated as one.
        tmp = list(__classify('{'))
        tmp[_FN] = partial(_pow, int(dat[1]))
        dat[:2] = [0, ''] # reset state
        yield tuple(tmp)
    elif r.isdigit():
        dat[1] += r # add the current symbol to the accumulator
    else:
        raise Exception("Expected digits in power operator.")

# save register scanner
__saveregchars = frozenset(chain(string.digits, ';'))
def __preprocexcgr(reg):
    if reg == 0:
        raise Exception("Cannot specify global register as save register.")
    return 1

def _preprocmode2(dat, r):
    if r in {'[', '('}:
        # got an open bracket, yield a special open bracket which implies that
        # symbols occuring inside should actually save to the register(s)
        # given.
        tmp = list(__classify(r))
        regs = [ int(reg) for reg in dat[1].split(';') ]
        tmp[_SYMINST] = (_SAV, { reg for reg in regs if __preprocexcgr(reg) })
        dat[:2] = [0, ''] # reset state
        yield tuple(tmp)
    elif r in __saveregchars:
        dat[1] += r # add the current symbol to the accumulator.
    else:
        raise Exception("Expected digits or ';' in save register.")

# load register scanner entry point
def _preprocmode3(dat, r):
    # begin scanning a load instruction. this state looks at the first symbol
    # after the initial dollar sign. load instructions can be of the following
    # forms: '$n' or '$(nnn)'. these will load the register at n. the former
    # will load registers 1-9 identifiable by a single digit number that is not
    # zero, wheras the latter will take one or more digits between parentheses
    # to identify the non-zero local register.
    if r in string.digits:
        # first or fourth form, yield a load instruction
        reg = int(r)
        if reg < 1:
            raise Exception("Local register load must be > 0.")

        yield __loadop(reg)
        dat[0] = 0
    elif r == '(':
        # second form, go to state four
        dat[0] = 4
    else:
        raise Exception("Expected digit, '$', '+', or '('.")

# load register scanner loop
def _preprocmode4(dat, r):
    if r == ')':
        # got the close bracket, yield a load instruction
        reg = int(acc)
        if reg < 1:
            raise Exception("Local register load must be > 0.")

        yield __loadop(reg)
        dat[:2] = [0, ''] # reset state
    elif r.isdigit():
        dat[1] += r # add digit to accumulator
    else:
        raise Exception("Expected digits in parenthesised load register.")

__preprocstatefn = [
    _preprocmode0,
    _preprocmode1,
    _preprocmode2,
    _preprocmode3
]

# compile grex VM
def grex_vm(desc, msg, *reg, **kwargs):
    """
    Generates an unlinked scanner VM program object.

    desc   - the expression to parse
    msg    - the token class name
    reg    - register output descriptor
    kwargs - keyword arguments

    The register output descriptor arguments are positional.
    For example: grex_vm(expr, msg, r1, r2, ...)

    Each a register specification may either be an int specifying the
    register number used, or it may be a tuple of the form (n, kind), where
    n is an integer with the same meaning as the first and 'kind' is one
    of the following:

      STR : convert this register to a string (superfluous and included for
            completeness.
      INT : Convert this register to an integer.
      FLT : Convert this register to a float.
      DBL : Convert this register to a double (meaningless in Python 3,
            but included for completeness as it's part of the spec).

    Currently, the only keyword argument is greedy, which effects greediness
    as per usual for regexes. TODO: make this doc better, too tired right
    now.
    """
    # preprocess to handle escape sequences
    def preproc(desc):
        dat = [0, "", ""]
        for r in chain(desc, '\0'):
            yield from __preprocstatefn[dat[0]](dat, r)
            dat[2] = "" if dat[2] is None else r

    # explicate implicit operators
    def expl(it):
        # make a stack for just brackets so that we know what modifiers
        # the bracket implicates.
        l = __clasdict['(']
        bstk = [l]
        for r in it:
            # see if the bracket is implicating an operator by checking our
            # predicate set.
            l_typ, r_typ = l[_TYP], r[_TYP]
            if (l_typ, r_typ, l[_ARITY] == 1) in __implic:
                # yes it is, yield the operator implied between l and r
                yield __classify(bstk[-1][_IMPLIC])

            if r_typ == _SYM:
                # yield whatever kind of symbol instruction (either _SMB or
                # _SAV, reg) is implied by the top bracket, which might have
                # been a save modifier.
                yield tuple(chain(r[:_SYMINST], [bstk[-1][_SYMINST]]))
            elif r_typ in {_BRKL, _BRKR}:
                # if this is a bracket, run the right shunting function on
                # our stack. since the stack is only brackets, this will
                # yield nothing. yield from is merely used for it's brevity.
                yield from chain(__shuntmethod[r_typ](r, bstk), [r])
            else:
                # nothing special, just pass it out.
                yield r

            # copy r to l and continue.
            l = r

    # shunting yard
    def yard(it):
        ostk = []
        for cl in it:
            yield from __shuntmethod[cl[_TYP]](cl, ostk)

        while ostk:
            yield ostk.pop()

    if desc:
        # evaluation
        nstk = []

        try:
            for cl in yard(expl(preproc(desc))):
                __evalumethod[cl[_TYP]](cl, nstk)
        except Exception as err:
            raise Exception("Grex parser error: %s" % repr(err))

        # give the result or error on bad stack size
        try:
            (cmds,) = nstk
        except:
            raise Exception("Grex unknown syntax error, expected evaluation "
                            "stack size 1, got %i!!! :(" % (len(nstk)))
    else:
        cmds = []

    ereg = tuple((r, STR) if type(r) == int else r for r in reg)
    return _accept(cmds, msg, *ereg, **kwargs)

def grex_vm_union(cmdslist):
    return reduce(lambda e1, e2: _alt([e1, e2]), cmdslist)

def grex_vm_finalize(cmdslist, leading = ".*"):
    """Link grex VM objects into a grex executable VM.

 e.g.

 tokentype1 = grim_vm(expr1, msg1, *registers1, greed1=True)
 tokentype2 = grim_vm(expr2, msg2, *registers2, greed2=True)
 tokentype3 = grim_vm(expr3, msg3, *registers3, greed3=True)
 finalvm = grim_vm_finalize([tokentype1, tokentype2, tokentype3])

consists of _VM identifier, a symbol table, and the VM bytecode tuples
if one wishes to do anchored matching as opposed to unanchored matching,
one should set leading to None. The default leading string will produce
a simple unanchored match that will accept any characters.
"""

    cmds = grex_vm_union(cmdslist)

    # linking stage:
    # 1. make the line references in forks and jumps absolute
    # 2. make sure there are no duplicate symbol sets by making a global symbol
    #    table.
    try:
        symtab = [dict(), 0]
        linked1 = [ __inst_lnk1[cmd[0]](cmd, i, symtab) for cmd, i in zip(
            cmds, count()) ]

        linked2 = [ __inst_lnk2[cmd[0]](cmd, 0) for cmd in linked1 ]
        return (_VM, { v: k for k, v in symtab[0].items() }, linked2)
    except KeyError as err:
        raise Exception("Linking failed because of instruction key "
                        "error: %s" % repr(err))

# yield grim vm lines
def grex_vm_lines(vm, lineno=False):
    """generator which produces the textual form for the VM line by line."""
    try:
        _id, symtab, cmds = vm
        if _id != _VM: raise Exception()
    except:
        raise Exception("Expected finalized VM.")

    for cmd, i in zip(chain(((-1, k, v) for k, v in symtab.items()), cmds), count()):
        icmd, *args = cmd
        if lineno:
            if icmd < 0:
                syms = "" if _ANY in args[1] else "".join(sorted(list(args[1])))
                yield " ".join(["%4i stab %i" % (i, args[0]), syms])
            else:
                yield " ".join(["%4i" % i, __inst_dec[icmd](*args)])
        else:
            if icmd < 0:
                syms = "" if _ANY in args[1] else "".join(sorted(list(args[1])))
                yield " ".join(["stab %i" % args[0], syms])
            else:
                yield __inst_dec[icmd](*args)

# save a vm
def grex_vm_print(vm, outfile=stdout, lineno=False):
    """Print out the VM, effectively saving it.
    vm      The vm to print
    outfile The file to save to (defaults to stdout)
    lineno  Toggle line number display. Defaults to False.
    """
    for line in grex_vm_lines(vm, lineno):
        print(line, file=outfile)

# load a vm
def grex_vm_load(infile=stdin):
    """Load a VM from text, compatible with grex_vm_print with the
line numbers off."""
    cmds, symtab = [], dict()
    for line in infile:
        scmd, args = line.split(None, 1)

        if scmd == "stab":
            i = 0
            if not args[0].isdigit():
                raise Exception("must have a table index for stab entry.")
            try:
                while args[i].isdigit(): i += 1

                if args[i] not in string.whitespace:
                    raise Exception("Must be a single space between stab index and symbol string.")

                idx = int(args[:i])
                syms = args[i+1:]
            except IndexError:
                syms = (_ANY,)
            finally:
                symtab[idx] = frozenset(syms)
        else:
            cmds.append(__inst_cmp[scmd](*chain(args.split(), [symtab])))

    return (_VM, symtab, cmds)

# scan a string with a vm
def grex_vm_scan(vm, text):
    """Scan a string with a grex VM. Returns a match."""
    try:
        _id, symtab, cmds = vm
        if _id != _VM: raise Exception()
    except:
        raise Exception("Expected finalized VM.")

    def makereturn(lastyes):
        if lastyes is None:
            return None

        return tuple(chain(
            lastyes[:1], (__reg_type[typ](lex) for lex, typ in lastyes[1:])))

    reg0, lastlen, lastyes = "", 0, None
    clist, nlist = [(0, dict(), cmds[0])], []

    for c in text:
        while clist:
            ilist, clist = clist, []
            for th in ilist:
                line, reg, (cmd, *args), *dat = th
                if cmd == _SMB:
                    if c in symtab[args[0]] or _ANY in symtab[args[0]]:
                        nline = line + 1
                        try:
                            nlist.append((nline, reg, cmds[nline]))
                        except IndexError:
                            pass
                elif cmd == _YES:
                    greedy, yes, *R = args

                    lastlen = len(reg0)
                    lastyes = list(chain([yes], ((reg0, r[1]) if r[0] == 0 else (reg.get(r[0], None), r[1]) for r in R)))

                    if not greedy:
                        return lastlen, makereturn(lastyes)
                elif cmd == _JMP:
                    (nline,) = args
                    try:
                        clist.append((nline, reg, cmds[nline]))
                    except IndexError:
                        pass
                elif cmd == _FRK:
                    ln, rn = args

                    try:
                        clist.append((ln, reg, cmds[ln]))
                    except IndexError:
                        pass

                    try:
                        clist.append((rn, reg.copy(), cmds[rn]))
                    except IndexError:
                        pass
                elif cmd == _SAV:
                    if c in symtab[args[1]] or _ANY in symtab[args[1]]:
                        nline = line + 1
                        try:
                            nlist.append((nline, reg, cmds[nline]))
                        except IndexError:
                            pass
                        for r in args[0]:
                            try:
                                reg[r] += c
                            except KeyError:
                                reg[r] = c
                elif cmd == _LOD:
                    if len(dat) == 1:
                        (dat,) = dat
                    else:
                        dat = deque(reg.get(args[0], [None]))

                    if c == dat.popleft():
                        if len(dat):
                            nlist.append((line, reg, cmds[line], dat))
                        else:
                            nline = line+1
                            try:
                                nlist.append((nline, reg, cmds[nline]))
                            except IndexError:
                                pass

        clist, nlist = nlist, []
        reg0 += c

    return lastlen, makereturn(lastyes)

# use the vm to lex a line iterator
# note that greedy matching will not work across lines. if you need this,
# load the file or input in to core first.
def grex_vm_lex_lines(vm, it):
    """Lex the contents of a line iterator with a grex VM. Useful for file
objects. For example:

    with open("somefile.txt", "r") as fileobj:
        for token in grex_vm_lex_lines(vm, fileobj):
            print(token)
    """
    acc = ""
    for chunk in it:
        text, acc = "".join([acc, chunk]), ""
        textlen = len(text)
        i = 0
        while i < textlen:
            length, match = grex_vm_scan(vm, islice(text, i, None))
            if match:
                i += max(length, 1)
                yield tuple(chain([match], [acc]))
                acc = ""
            else:
                acc += text[i]
                i += 1

    yield (acc,)

# use the vm to tokenize a string
def grex_vm_lex(vm, text):
    """Lex the contents of a string with a grex VM. For example:

    str = "hello world 42"
    for token in grex_vm_lex(vm, str):
        print(token)
    """
    yield from grex_vm_lex_lines(vm, [text])

# compile a vm to an sm
def grex_sm_compile(vm, minimized=False):
    pass # TBI

# minimize an sm
def grex_sm_minimize(sm):
    pass # TBI

# generate a grex expression from an sm
def grex_sm_expr(sm):
    pass # TBI

# scan a string with an sm
def grex_sm_scan(sm, text, greedy=True):
    pass # TBI

# use the sm to lex a line iterator
# note that greedy matching will not work across lines. if you need this,
# load the file or input in to core first.
def grex_sm_lex_lines(sm):
    pass # TBI

# use the sm to lex a string
def grex_sm_lex(sm):
    pass # TBI

#__specvm = None
#def grex_vm_from_spec(infile=stdin):
#    global __specvm
#    if not __specvm:
#        if _BUILDSPEC:
#            __specvm = grex_vm_finalize([
#                grex_vm("[A-Za-z_][A-Za-z0-9_]*", "IDENT", 0, greedy=True),
#                grex_vm("&1[\"']&2(.*)$1", "STRING", 2, greedy=False),
#                grex_vm("[0-9]+", "INT", (0, INT), greedy=True),
#                grex_vm(",", "COMMA", greedy=False),
#                grex_vm("&1[0-9]+:&2[a-z]{3}", "REGISTER",
#                        (1, INT), 2, greedy=False),
#                grex_vm("\\->", "ASSIGN", greedy=False)])
#            grex_vm_print(__specvm)
#
#    specvm = __specvm
#    #grex_vm_print(specvm, lineno=True)
#    ts = clock()
#    toks = list(grex_vm_lex_lines(specvm, iter(infile.readline, '')))
#    te = clock()
#    print('Lexed from file stream in {:e} second(s).\n\n'.format(te-ts), "TOKENS::\n", toks)
#
#if __name__ == '__main__':
#    from sys import argv
#    from time import clock
#    from os import path
#
#    scinum = lambda n: '{:e}'.format(float(n))
#
#    with open(argv[1]) as ff:
#        vm = grex_vm_from_spec(ff)
#
#'''        specvm = __specvm
#        grex_vm_print(specvm, lineno=True)
#        ts = clock()
#        toks = list(grex_vm_lex_lines(specvm, infile))
#        te = clock()
#        print('{:e}'.format(te-ts), toks)'''
#


def countBattleships(board):
    def is_valid(row, col):
        if row < 0 or col < 0 or row >= len(board) or col >= len(board[0]):
            return False
        else:
            return True

    def dfs(row, col):
        if not is_valid(row, col):
            return
        if board[row][col] == ".":
            return

        board[row][col] = "."
        dfs(row + 1, col)   # below
        dfs(row - 1, col)   # above
        dfs(row, col + 1)   # right
        dfs(row, col - 1)   # left

    if not board:
        return

    count = 0
    for row in range(len(board)):
        for col in range(len(board[0])):
            if board[row][col] == 'X':
                count += 1
                dfs(row, col)

    return count

print(countBattleships([["X",".",".","X"],
                        [".",".",".","X"],
                        [".",".",".","X"]]))


"""
    Module name: reddit_comment_collector
    Description: Module for collecting reddit comments related to bitcoin
    and cryptocurrency for performing sentiment analysis.
"""

from datetime import datetime, timedelta
import time
import json

import requests
import pandas as pd

DAYINSECS = 86400
START_LABEL = 'START_UTC'
END_LABEL = 'END_UTC'
JSON_FILE = 'output.json'

class RedditDataCollector(object):

    """
        The object for retrieving daily bitcoin related comments
        from Reddit.The comments are retrieved accross all subreddits.
            :member attributes: logger: logger instance

            :member functions:  fetch_reddit_comments

    """

    def __init__(self, config):
        self.api_uri = config['Reddit']['api-uri']
        self.output_path = config['Reddit']['data_path']

    def fetch_reddit_comments(self):
        """
            Method to fetch the bitcoin related comments from reddit.
            The max limit for the number of comments is 10000
            the CoinDesk index.
            : param self
            : return reddit_comments(DataFrame)
                     error_val(int)
        """
        error_val = -1
        try:
            day_count = 1
            today = datetime.now().replace(hour=0, minute=0,
                                           second=0, microsecond=0)
            for single_date in (today - timedelta(n)
                                for n in range(day_count)):
                # self.logger.error('Fetching Reddit comments for:'
                #                   , single_date)
                single_date_utc = single_date.timetuple()
                single_date_utc = time.mktime(single_date_utc)
                url = self.api_uri
                url = url.replace(START_LABEL,
                                  str(int(single_date_utc - DAYINSECS)))
                url = url.replace(END_LABEL, str(int(single_date_utc)))
                res = requests.get(url)
                data = res.json()
                data = data['hits']['hits']
                comments = []
                for meta_data in data:
                    comment = meta_data['_source']
                    comments.append({
                                    'text': comment['body'],
                                    'Date': comment['created_utc']
                                    })
                with open(self.output_path + JSON_FILE,
                          'w+', encoding='utf-8') as f:
                    json.dump(comments, f)
            reddit_comments = pd.read_json(self.output_path + JSON_FILE,
                                           orient='records')
            reddit_comments['Date'] = (today - timedelta(1)).date()
            return reddit_comments
        except Exception as e:
            print(e)
            return error_val


import json
import requests
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv

from datetime import timedelta
from datetime import datetime

from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
from homeassistant.components.sensor import PLATFORM_SCHEMA

MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=5)

CONF_NAME = "name"
CONF_API_KEY = "api_key"
CONF_SN = "sn"

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
    {
        vol.Required(CONF_NAME): cv.string,
        vol.Required(CONF_API_KEY): cv.string,
        vol.Required(CONF_SN): cv.string
    }
)

def setup_platform(hass, config, add_entities, discovery_info=None):
    solax_cloud = SolaxCloud(
        hass, config[CONF_NAME], config[CONF_API_KEY], config[CONF_SN])
    add_entities([InverterTotalYieldSensor(hass, solax_cloud),
                  InverterDailyYieldSensor(hass, solax_cloud),
                  InverterACPowerSensor(hass, solax_cloud)
                  ], True)

class SolaxCloud:
    def __init__(self, hass, name, api_key, sn):
        self.hass = hass
        self.logger = logging.getLogger(__name__)
        self.api_key = api_key
        self.sn = sn
        self.inverter_name = name
        self.data = {}
        # maybe the user has to change .eu
        self.uri = f'https://www.eu.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId={api_key}&sn={sn}'
        self.last_data_time = None

    def get_data(self):
        if not self.data or datetime.now() - self.last_data_time > MIN_TIME_BETWEEN_UPDATES:
            try:
                data = requests.get(self.uri).json()
                if data['success'] == True:
                    self.data = data['result']
                    self.last_data_time = datetime.now()
                    self.logger.info(
                        f'Retrieved new data from solax cloud {self.inverter_name}')
                else:
                    self.data = {}
                    self.logger.error(data['exception'])
            except requests.exceptions.ConnectionError as e:
                self.logger.error(str(e))
                self.data = {}

class InverterTotalYieldSensor(Entity):
    def __init__(self, hass, solax_cloud):
        self._name = solax_cloud.inverter_name + ' Total yield'
        self.hass = hass
        self.solax_cloud = solax_cloud

    @property
    def name(self):
        return self._name

    @property
    def state(self):
        data = self.solax_cloud.data.get('yieldtotal')
        return float('nan') if data is None else data

    @property
    def unit_of_measurement(self):
        return 'kWh'

    @property
    def icon(self):
        return 'mdi:solar-power'

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    def update(self):
        self.solax_cloud.get_data()

class InverterDailyYieldSensor(Entity):
    def __init__(self, hass, solax_cloud):
        self._name = solax_cloud.inverter_name + ' Daily yield'
        self.hass = hass
        self.solax_cloud = solax_cloud

    @property
    def name(self):
        return self._name

    @property
    def state(self):
        data = self.solax_cloud.data.get('yieldtoday')
        return float('nan') if data is None else data

    @property
    def unit_of_measurement(self):
        return 'kWh'

    @property
    def icon(self):
        return 'mdi:solar-power'

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    def update(self):
        self.solax_cloud.get_data()

class InverterACPowerSensor(Entity):
    def __init__(self, hass, solax_cloud):
        self._name = solax_cloud.inverter_name + ' AC Power'
        self.hass = hass
        self.solax_cloud = solax_cloud

    @property
    def name(self):
        return self._name

    @property
    def state(self):
        data = self.solax_cloud.data.get('acpower')
        return float('nan') if data is None else data

    @property
    def unit_of_measurement(self):
        return 'W'

    @property
    def icon(self):
        return 'mdi:solar-power'

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    def update(self):
        self.solax_cloud.get_data()


from __future__ import print_function
import tensorflow as tf
import numpy as np
import math
import sklearn

class Conv1DClassifier:
    def __init__(self, seq_len, vocab_size, n_out, sess=tf.Session(),
                 n_filters=250, embedding_dims=50, padding='valid', top_k=5):
        """
        Parameters:
        -----------
        seq_len: int
            Sequence length
        vocab_size: int
            Vocabulary size
        embedding_dims: int
            Word embedding dimensions
        n_filters: int
            Number output of filters in the convolution
        kernel_size: int
            Size of the 1D convolution window
        hidden_dims: int
            Ouput dimensions of the fully-connected layer
        n_out: int
            Output dimensions
        sess: object
            tf.Session() object
        """
        self.seq_len = seq_len
        self.vocab_size = vocab_size
        self.n_filters = n_filters
        self.embedding_dims = embedding_dims
        self.padding = padding
        self.n_out = n_out
        self.top_k = top_k
        self.sess = sess
        self._pointer = None
        self.build_graph()
    # end constructor

    def build_graph(self):
        self.add_input_layer()
        self.add_word_embedding()

        self.kernels = [3, 4, 5]
        parallels = []
        for k in self.kernels:
            p = self.add_conv1d(self.n_filters//len(self.kernels), kernel_size=k)
            p = self.add_kmax_pooling(p)
            parallels.append(p)
        self.merge_layers(parallels)

        self.add_fully_connected_layer()
        self.add_output_layer()
        self.add_backward_path()
    # end method build_graph

    def add_input_layer(self):
        self.X = tf.placeholder(tf.int32, [None, self.seq_len])
        self.Y = tf.placeholder(tf.int64, [None])
        self.keep_prob = tf.placeholder(tf.float32)
        self.lr = tf.placeholder(tf.float32)
        self._pointer = self.X
        self._batch_size = tf.shape(self.X)[0]
    # end method add_input_layer

    def add_word_embedding(self):
        embedding = tf.get_variable('encoder', [self.vocab_size,self.embedding_dims], tf.float32)
        embedded = tf.nn.embedding_lookup(embedding, self._pointer)
        self._pointer = tf.nn.dropout(embedded, self.keep_prob)
    # end method add_word_embedding_layer

    def add_conv1d(self, n_filters, kernel_size, strides=1):
        Y = tf.layers.conv1d(inputs = self._pointer,
                             filters = n_filters,
                             kernel_size  = kernel_size,
                             strides = strides,
                             padding = self.padding,
                             use_bias = True,
                             activation = tf.nn.relu)
        return Y
    # end method add_conv1d_layer

    def add_kmax_pooling(self, x):
        Y = tf.transpose(x, [0, 2, 1])
        Y = tf.nn.top_k(Y, self.top_k, sorted=False).values
        Y = tf.transpose(Y, [0, 2, 1])
        Y = tf.reshape(Y, [self._batch_size, self.top_k, self.n_filters//len(self.kernels)])
        return Y
    # end method add_kmax_pooling

    def merge_layers(self, layers):
        self._pointer = tf.concat(layers, axis=-1)
    # end method merge_layers

    def add_fully_connected_layer(self):
        self._pointer = tf.reshape(self._pointer,
            [self._batch_size, self.top_k * (len(self.kernels)*(self.n_filters//len(self.kernels)))])
        self._pointer = tf.layers.dense(self._pointer, self.n_filters, tf.nn.relu)
        self._pointer = tf.nn.dropout(self._pointer, self.keep_prob)
    # end method add_flatten_layer

    def add_output_layer(self):
        self.logits = tf.layers.dense(self._pointer, self.n_out)
    # end method add_output_layer

    def add_backward_path(self):
        self.loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.logits, labels=self.Y))
        self.train_op = tf.train.AdamOptimizer(self.lr).minimize(self.loss)
        self.acc = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(self.logits, 1), self.Y), tf.float32))
    # end method add_backward_path

    def fit(self, X, Y, val_data=None, n_epoch=10, batch_size=128, keep_prob=0.8, en_exp_decay=True,
            en_shuffle=True):
        if val_data is None:
            print("Train %d samples" % len(X))
        else:
            print("Train %d samples | Test %d samples" % (len(X), len(val_data[0])))
        log = {'loss':[], 'acc':[], 'val_loss':[], 'val_acc':[]}
        global_step = 0

        self.sess.run(tf.global_variables_initializer()) # initialize all variables
        for epoch in range(n_epoch):
            if en_shuffle:
                X, Y = sklearn.utils.shuffle(X, Y)
            local_step = 1

            for X_batch, Y_batch in zip(self.gen_batch(X, batch_size),
                                        self.gen_batch(Y, batch_size)): # batch training
                lr = self.decrease_lr(en_exp_decay, global_step, n_epoch, len(X), batch_size)
                _, loss, acc = self.sess.run([self.train_op, self.loss, self.acc],
                                             {self.X:X_batch, self.Y:Y_batch,
                                              self.lr:lr, self.keep_prob:keep_prob})
                local_step += 1
                global_step += 1
                if local_step % 50 == 0:
                    print ("Epoch %d/%d | Step %d/%d | train_loss: %.4f | train_acc: %.4f | lr: %.4f"
                        %(epoch+1, n_epoch, local_step, int(len(X)/batch_size), loss, acc, lr))

            if val_data is not None: # go through test dara, compute averaged validation loss and acc
                val_loss_list, val_acc_list = [], []
                for X_test_batch, Y_test_batch in zip(self.gen_batch(val_data[0], batch_size),
                                                      self.gen_batch(val_data[1], batch_size)):
                    v_loss, v_acc = self.sess.run([self.loss, self.acc],
                                                  {self.X:X_test_batch, self.Y:Y_test_batch,
                                                   self.keep_prob:1.0})
                    val_loss_list.append(v_loss)
                    val_acc_list.append(v_acc)
                val_loss, val_acc = self.list_avg(val_loss_list), self.list_avg(val_acc_list)

            # append to log
            log['loss'].append(loss)
            log['acc'].append(acc)
            if val_data is not None:
                log['val_loss'].append(val_loss)
                log['val_acc'].append(val_acc)
            # verbose
            if val_data is None:
                print ("Epoch %d/%d | train_loss: %.4f | train_acc: %.4f |" % (epoch+1, n_epoch, loss, acc),
                    "lr: %.4f" % (lr) )
            else:
                print ("Epoch %d/%d | train_loss: %.4f | train_acc: %.4f |" % (epoch+1, n_epoch, loss, acc),
                    "test_loss: %.4f | test_acc: %.4f |" % (val_loss, val_acc),
                    "lr: %.4f" % (lr) )
        # end "for epoch in range(n_epoch):"

        return log
    # end method fit

    def predict(self, X_test, batch_size=128):
        batch_pred_list = []
        for X_test_batch in self.gen_batch(X_test, batch_size):
            batch_pred = self.sess.run(self.logits, {self.X:X_test_batch, self.keep_prob:1.0})
            batch_pred_list.append(batch_pred)
        return np.argmax(np.vstack(batch_pred_list), 1)
    # end method predict

    def gen_batch(self, arr, batch_size):
        for i in range(0, len(arr), batch_size):
            yield arr[i : i+batch_size]
    # end method gen_batch

    def decrease_lr(self, en_exp_decay, global_step, n_epoch, len_X, batch_size):
        if en_exp_decay:
            max_lr = 0.005
            min_lr = 0.001
            decay_rate = math.log(min_lr/max_lr) / (-n_epoch*len_X/batch_size)
            lr = max_lr*math.exp(-decay_rate*global_step)
        else:
            lr = 0.005
        return lr
    # end method adjust_lr

    def list_avg(self, l):
        return sum(l) / len(l)
    # end method list_avg
# end class


# -*- coding:UTF-8 -*-
import collections

class Solution(object):
    def orangesRotting(self, grid):
        R, C = len(grid), len(grid[0])

        # queue - all starting cells with rotting oranges
        queue = collections.deque()
        for r, row in enumerate(grid):
            for c, val in enumerate(row):
                if val == 2:
                    queue.append((r, c, 0))

        def neighbors(r, c):
            for nr, nc in ((r - 1, c), (r, c - 1), (r + 1, c), (r, c + 1)):
                if 0 <= nr < R and 0 <= nc < C:
                    yield nr, nc

        d = 0
        while queue:
            r, c, d = queue.popleft()
            for nr, nc in neighbors(r, c):
                if grid[nr][nc] == 1:
                    grid[nr][nc] = 2
                    queue.append((nr, nc, d + 1))

        if any(1 in row for row in grid):
            return -1
        return d

if __name__ == "__main__":
    grid = [[2, 1, 1], [1, 1, 0], [0, 1, 1]]
    grid = [[2, 1, 1], [0, 1, 1], [1, 0, 1]]
    print(Solution().orangesRotting(grid))

#
# import sys
#
#
# class Solution:
#     def orangesRotting(self, grid):
#         res = 0
#         rows = grid
#         for i in range(len(rows)):
#             for j in range(len(rows[0])):
#                 if rows[i][j] == 1:
#                     if not is_path(rows, i, j):
#                         res = -1
#                         break
#                         break
#                     else:
#                         step = min_dfs(rows, i, j)
#                         print(i, j, step)
#                         res = max(res, step)
#         print(res)
#
#
# def is_path(rows, i, j):
#     res = False
#     width = len(rows[0])
#     height = len(rows)
#     if i - 1 >= 0 and rows[i - 1][j] > 0:
#         return True
#     if i + 1 < height and rows[i + 1][j] > 0:
#         return True
#     if j - 1 >= 0 and rows[i][j - 1] > 0:
#         return True
#     if j + 1 < width and rows[i][j + 1] > 0:
#         return True
#     return res
#
#
# def min_dfs(rows, i, j):
#     step = 0
#     width = len(rows[0])
#     height = len(rows)
#     _queue = [[i, j, step]]
#     while _queue:
#         i, j, step = _queue.pop(0)
#         if i - 1 >= 0 and rows[i - 1][j] > 0:
#             if rows[i - 1][j] == 2:
#                 step += 1
#                 return step
#             elif rows[i - 1][j] == 1:
#                 step += 1
#                 _queue.append([i - 1, j, step])
#         if i + 1 < height and rows[i + 1][j] > 0:
#             if rows[i + 1][j] == 2:
#                 step += 1
#                 return step
#             elif rows[i + 1][j] == 1:
#                 step += 1
#                 _queue.append([i + 1, j, step])
#         if j - 1 >= 0 and rows[i][j - 1] > 0:
#             if rows[i][j - 1] == 2:
#                 step += 1
#                 return step
#             elif rows[i][j - 1] == 1:
#                 step += 1
#                 _queue.append([i, j - 1, step])
#         if j + 1 < width and rows[i][j + 1] > 0:
#             if rows[i][j + 1] == 2:
#                 step += 1
#                 return step
#             elif rows[i][j + 1] == 1:
#                 step += 1
#                 _queue.append([i, j + 1, step])
#     return step
#
#


import tensorflow as tf
from sklearn import datasets, svm, metrics
from sklearn.linear_model import LogisticRegression, LinearRegression
from sklearn import datasets, linear_model
import numpy as np
from struct import unpack
import seaborn as sns
import matplotlib.pyplot as plt
import time

start_time = time.time()
tf.logging.set_verbosity(tf.logging.DEBUG)
sess = tf.Session()

# Import Sports data
#from tensorflow.examples.tutorials.mnist import input_data
from readMnist import read_data_sets
mnist = read_data_sets("sports_data/", one_hot=True)

# **** cmd command for tensorboard **** tensorboard --logdir=train
# restore the saved model
new_saver = tf.train.import_meta_graph('data/mnist_model/00000001/export.meta')
new_saver.restore(sess, 'data/mnist_model/00000001/export')

# print to see the restored variables
for v in tf.get_collection('variables'):
    print(v.name)
print(sess.run(tf.global_variables()))

# get saved weights
W = tf.get_collection('variables')[0]
b = tf.get_collection('variables')[1]

# placeholders for test images and labels
x = tf.placeholder(tf.float32, [None, 784],name='x')
y_ = tf.placeholder(tf.float32, [None, 10],name='y_')

# predict equation
y = tf.nn.softmax(tf.matmul(x, W) + b,name='y')

# compare predicted label and actual label
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

# accuracy op
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

accu=sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
print("\nSoftmax regression accuracy: " + str(accu))
print("Softmax execution time = "+str(time.time() - start_time)+ " seconds")

# ------------------------------ for logistic regression of mnist data ---------------
# code from https://gist.github.com/mGalarnyk/aa79813d7ecb0049c7b926d53f588ae1

def loadmnist(imagefile, labelfile):

    # Open the images with gzip in read binary mode
    images = open(imagefile, 'rb')
    labels = open(labelfile, 'rb')

    # Get metadata for images
    images.read(4)  # skip the magic_number
    number_of_images = images.read(4)
    number_of_images = unpack('>I', number_of_images)[0]
    rows = images.read(4)
    rows = unpack('>I', rows)[0]
    cols = images.read(4)
    cols = unpack('>I', cols)[0]

    # Get metadata for labels
    labels.read(4)
    N = labels.read(4)
    N = unpack('>I', N)[0]

    # Get data
    x = np.zeros((N, rows*cols), dtype=np.uint8)  # Initialize numpy array
    y = np.zeros(N, dtype=np.uint8)  # Initialize numpy array
    for i in range(N):
        for j in range(rows*cols):
            tmp_pixel = images.read(1)  # Just a single byte
            tmp_pixel = unpack('>B', tmp_pixel)[0]
            x[i][j] = tmp_pixel
        tmp_label = labels.read(1)
        y[i] = unpack('>B', tmp_label)[0]

    images.close()
    labels.close()
    return (x, y)

# load training images and labels, load test images and labels
train_img, train_lbl = loadmnist('sports-data-unzip/train-images-idx3-ubyte'
                                 , 'sports-data-unzip/train-labels-idx1-ubyte')
test_img, test_lbl = loadmnist('sports-data-unzip/test-images-idx3-ubyte'
                               , 'sports-data-unzip/test-labels-idx1-ubyte')

print("\nTraining Image shape: "+str(train_img.shape))
print("Training label shape: "+str(train_lbl.shape))
print("Test label shape: "+str(test_img.shape))
print("Test label shape: "+str(test_lbl.shape))

# start execution time after loading the data
start_time1 = time.time()

#init logistic regression model
logReg = LogisticRegression(solver='lbfgs')
linReg = linear_model.LinearRegression()
linReg.fit(train_img,train_lbl)
logReg.fit(train_img, train_lbl)
logReg.predict(test_img)
linReg.predict(test_img)

acc1 = linReg.score(test_img,test_lbl)

print("\nlinear regression accuracy: "+str(acc1))

# get logistic regression acurracy, correct predictions / total number of data points
acc = logReg.score(test_img,test_lbl)
print("\nlogistic regression accuracy: "+str(acc))
print("Logistic execution time = "+str(time.time() - start_time1)+ " seconds")

# make confusion matrix with seaborn and display it
predictions = logReg.predict(test_img)
cm = metrics.confusion_matrix(test_lbl, predictions)
cm_normalized = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
plt.figure(figsize=(5,5))
sns.heatmap(cm_normalized, annot=True, fmt=".3f", linewidths=.5, square = True, cmap = 'Blues_r');
plt.ylabel('Actual label');
plt.xlabel('Predicted label');
all_sample_title = 'Accuracy Score: {:.3f}'.format(acc)
plt.title(all_sample_title, size = 15);

plt.show()

# Plot outputs
# plt.scatter(test_img, test_lbl,  color='black')
# plt.plot(test_img, test_lbl, color='blue', linewidth=3)


import os
import random
import sys
sys.path.append('.')

import torch
import torch.autograd as autograd
from torch.autograd import Variable
import torch.nn.functional as F
from torch.utils.data import DataLoader
import torchaudio
from tqdm import tqdm
import yaml

from speech_generation import config
from speech_generation.utils import text_utils, audio_utils
from speech_generation.speech_model.model import EncoderRNN, AttnDecoderRNN
from speech_generation.speech_model.loader import LibriSpeech

torch.backends.cudnn.benchmark = True

DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
FACTOR = 32768
SOS_token = config.N_LETTERS - 1

def main(cfg_path):
    cfg_file = open(os.path.abspath(cfg_path))
    cfg = yaml.load(cfg_file.read())
    data_dir = cfg.get('data')
    test_data_dir = cfg.get('test-data')

    try:
        assert data_dir
    except AssertionError:
        raise 'No "dataset_dir" found in config'

    hidden_size = cfg.get('hidden_size', 128)
    batch_size = cfg.get('batch_size', 10)
    max_length = cfg.get('max_length', 400)
    max_time = cfg.get('max_time', 5)
    num_classes = cfg.get('num_classes')

    if not num_classes:
        raise AssertionError('Number of classes not provided')

    learning_rate = cfg.get('learning_rate', 1e-3)

    dataset = LibriSpeech(data_dir, DEVICE, scale_factor=FACTOR, max_time=max_time, max_length=max_length)
    dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True, num_workers=4)

    test_dataset = LibriSpeech(test_data_dir, DEVICE, scale_factor=FACTOR, max_time=max_time, max_length=max_length)

    encoder = EncoderRNN(config.N_LETTERS, hidden_size, DEVICE).to(DEVICE)
    decoder = AttnDecoderRNN(hidden_size, config.N_LETTERS, dropout_p=0.1).to(DEVICE)

    optimizer_g = torch.optim.Adam(encoder.parameters() + decoder.parameters(), lr=2e-4)

    criterion = torch.nn.NLLLoss()

    for epoch in range(100):
        for sample_idx, (audio, speaker, text) in enumerate(dataloader):
            audio, speaker, text = audio.to(DEVICE), speaker.to(DEVICE), text.to(DEVICE)
            encoder.zero_grad()
            decoder.zero_grad()
            optimizer_g.zero_grad()

            batch_size = audio.size(0)

            encoder_hidden = encoder.initHidden()
            encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=DEVICE)

            for ei in range(max_length):
                encoder_output, encoder_hidden = encoder(
                    text[:, ei], encoder_hidden
                )
                encoder_outputs[ei] = encoder_output[0, 0]

            decoder_input = torch.tensor([[SOS_token]], device=device)
            decoder_hidden = encoder_hidden

            use_teacher_forcing = True if random.random() < teacher_forcing_ratio else False
            loss = 0
            if use_teacher_forcing:
                # Teacher forcing: Feed the target as the next input
                for di in range(target_length):
                    decoder_output, decoder_hidden, decoder_attention = decoder(
                        decoder_input, decoder_hidden, encoder_outputs)
                    loss += criterion(decoder_output, text[di])
                    decoder_input = target_tensor[di]  # Teacher forcing

            else:
                # Without teacher forcing: use its own predictions as the next input
                for di in range(target_length):
                    decoder_output, decoder_hidden, decoder_attention = decoder(
                        decoder_input, decoder_hidden, encoder_outputs)
                    topv, topi = decoder_output.topk(1)
                    decoder_input = topi.squeeze().detach()  # detach from history as input

                    loss += criterion(decoder_output, target_tensor[di])

            loss.backward()
            optimizer_g.step()
            if sample_idx % cfg.get('sample_iter', 100) == 0:
                print(f"Epoch {epoch}, sample {sample_idx} -- errG: {err_g.item()}, errD: {0}")
                _, speaker, text = random.choice(test_dataset)
                text = text.to(DEVICE)
                speaker = speaker.to(DEVICE)
                sample(text, speaker, encoder, encoder_downsample, leaky_relu, batch_norm, decoder, 'generated', epoch, sample_idx, 16000, max_length, batch_size, hidden_size)

            if sample_idx % cfg.get('save_iter', 1000) == 0:
                with open('encoder.pt', 'wb') as enc_file:
                    torch.save(encoder.state_dict(), enc_file)

                with open('audio_decoder.pt', 'wb') as dec_file:
                    torch.save(decoder.state_dict(), dec_file)

def sample(text, speaker, encoder, encoder_downsample, leaky_relu, batch_norm, decoder, outfolder, epoch, sample_idx, sample_rate, max_length, batch_size, hidden_size):
    with torch.no_grad():
        """
        text = text_utils.get_input_vectors(
            text_utils.unicode_to_ascii("I'M SORRY DAVE I'M AFRAID I CAN'T DO THAT")
        ).to(DEVICE)
        """
        text = text.unsqueeze(0)
        speaker = speaker.unsqueeze(0)
        encoder_hidden = encoder.initHidden()

        encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=DEVICE)

        for ei in range(max_length):
            encoder_output, encoder_hidden = encoder(
                text[:, ei], encoder_hidden
            )
            encoder_outputs[ei] = encoder_output[0, 0]

        encoder_outputs = encoder_outputs.view(batch_size, max_length * hidden_size)
        downsampled = encoder_downsample(encoder_outputs)
        downsampled = downsampled.unsqueeze(1)
        downsampled = batch_norm(downsampled)
        downsampled = leaky_relu(downsampled)
        downsampled = downsampled.view(batch_size, 4, 2352)

        audio_output = decoder(downsampled)

    torchaudio.save("{}/{:06d}-{:06d}.wav".format(outfolder, epoch, sample_idx),
                    audio_output.view(-1).cpu(), sample_rate)

if __name__ == '__main__':
    main(sys.argv[1])


__author__ = 'GitHub:Air-Zhuang'

from flask import render_template,jsonify,request
from flask_login import login_required,current_user

from app.view_models.goods_view_model import GoodsCollection
from app.view_models.user_view_model import UserViewModel
from . import web
from app.models.goods import Goods

from flask import current_app

@web.route('/')
def index():
    resp_data = {'code': 200, 'msg': '操作成功~~', 'page':{'from':1,'pagelist':[1],'cate':'index'}, 'data': {}}
    addNav(resp_data)
    addBanner(resp_data)
    goods = Goods()
    goodsList = goods.getAllGoodsLimitPerPage()

    canPage(resp_data,goods.getAllGoods,current_app.config['PER_PAGE'],index)               #能分多少页
    if len(request.args)>0:                                                 #处理分页
        goodsList=paging(resp_data, goods.getAllGoodsPaging,index)

    if goodsList==[]:
        resp_data['code'] = -1
        resp_data['msg']='取不到数据库的信息~'
    goodscollection=GoodsCollection(goodsList)
    resp_data['data']=goodscollection.data
    return render_template('index.html',data=resp_data)

@web.route('/goods/<outlook>')
def outlook(outlook):
    resp_data = {'code': 200, 'msg': '操作成功~~', 'page':{'from':1,'pagelist':[1],'cate':'outlook','cate_para':outlook}, 'data': {}}
    addNav(resp_data)
    addBanner(resp_data)
    goods = Goods()
    goodsList = goods.getGoodListByOutlookLimitPerPage(outlook)

    canPage(resp_data, goods.getGoodListByOutlook, current_app.config['PER_PAGE'], outlook)
    if len(request.args) > 0:
        goodsList = paging(resp_data, goods.getGoodListByOutlookPaging, outlook)

    if goodsList==[]:
        resp_data['code'] = -1
        resp_data['msg']='取不到数据库的信息~'
    goodscollection = GoodsCollection(goodsList)
    resp_data['data'] = goodscollection.data
    return render_template('index.html', data=resp_data)

@web.route('/company/<company>')
def company(company):
    resp_data = {'code': 200, 'msg': '操作成功~~','page':{'from':1,'pagelist':[1],'cate':'company','cate_para':company}, 'data': {}}
    addNav(resp_data)
    addBanner(resp_data)
    goods = Goods()
    goodsList = goods.getGoodListByCompanyLimitPerPage(company)

    canPage(resp_data, goods.getGoodListByCompany, current_app.config['PER_PAGE'], company)
    if len(request.args) > 0:
        goodsList = paging(resp_data, goods.getGoodListByCompanyPaging, company)

    if goodsList==[]:
        resp_data['code'] = -1
        resp_data['msg']='取不到数据库的信息~'
    goodscollection = GoodsCollection(goodsList)
    resp_data['data'] = goodscollection.data
    return render_template('index.html', data=resp_data)

@web.route('/goods/search')
def search():
    search_name=request.args['q']
    resp_data = {'code': 200, 'msg': '操作成功~~','page':{'from':1,'pagelist':[1],'cate':'search'}, 'data': {}}
    addNav(resp_data)
    addBanner(resp_data)
    goods = Goods()
    goodsList = goods.getGoodListByNameLimitPerPage(search_name)
    if goodsList == []:
        resp_data['code'] = -1
        resp_data['msg'] = '取不到数据库的信息~'
    goodscollection = GoodsCollection(goodsList)
    resp_data['data'] = goodscollection.data
    return render_template('index.html', data=resp_data)

def addNav(resp_data):
    if current_user.is_active:              #addUserInfo
        userviewmodel=UserViewModel(current_user)
        resp_data['user']=userviewmodel.data
    companys = Goods.getDistinctCompany()   #addCompanyList
    resp_data['companys'] = companys

def addBanner(resp_data):
    bannerList = Goods().getAllGoodsLimit3()
    if bannerList == []:
        return None
    bannerCollection = GoodsCollection(bannerList)
    resp_data['banner'] = bannerCollection.data

def canPage(resp_data,func_all,per_page,url):   #能分多少页
    pagenum = len(func_all(url)) // per_page
    pagelist = [i for i in range(1, pagenum + 2)]
    resp_data['page']['pagelist'] = pagelist

def paging(resp_data,func_paging,url):      #处理分页
    if request.args['paging'] == 'next_page':
        goodsList = func_paging(url,int(request.args['from']) + 1)
        resp_data['page']['from'] = int(request.args['from']) + 1
    elif request.args['paging'] == 'last_page':
        goodsList = func_paging(url,int(request.args['from']) - 1)
        resp_data['page']['from'] = int(request.args['from']) - 1
    else:
        goodsList = func_paging(url,int(request.args['paging']))
        resp_data['page']['from'] = int(request.args['paging'])
    return goodsList


#!/usr/bin/env python3

##################################################
# based on https://www.thepythoncode.com/article/get-hardware-system-information-python
##################################################

import psutil
import GPUtil
import platform
import time

def get_size(bytes, suffix="B"):
    """
    Scale bytes to its proper format
    e.g:
        1253656 => '1.20MB'
        1253656678 => '1.17GB'
    """
    factor = 1024
    for unit in ["", "K", "M", "G", "T", "P"]:
        if bytes < factor:
            return f"{bytes:.2f}{unit}{suffix}"
        bytes /= factor

class HardwareMonitor():
    def __init__(self):
        pass

    def get_platform_info(self):
        """Returns basic plattform information"""

        uname = platform.uname()
        platform_info = {
            'System': uname.system,
            'PC-Name': uname.node,
            'Release': uname.release,
            'Version': uname.version,
            'Machine': uname.machine,
            'Processor': uname.processor
        }

        return platform_info

    def get_cpu_info(self):
        """Returns amount of CPU cores and actual detailed CPU load"""

        cpufreq = psutil.cpu_freq()
        cpu_info = {
            'Phys. cores': psutil.cpu_count(logical=False),
            'Total cores': psutil.cpu_count(logical=True),
            'Max Frequency': f'{cpufreq.max:.2f}Mhz',
            'Min Frequency': f'{cpufreq.min:.2f}Mhz',
            'Current Frequency': f'{cpufreq.current:.2f}Mhz'
        }

        for i, percentage in enumerate(psutil.cpu_percent(percpu=True, interval=1)):
            cpu_info.update({f'Core {i}': f'{percentage}%'})

        cpu_info.update({'Total CPU Usage': f'{psutil.cpu_percent()}%'})

        return cpu_info

    def get_fast_cpu_info(self):
        cpufreq = psutil.cpu_freq()
        cpu_info = {
            'Phys. cores': psutil.cpu_count(logical=False),
            'Total cores': psutil.cpu_count(logical=True),
            'Max Frequency': f'{cpufreq.max:.2f}Mhz',
            'Min Frequency': f'{cpufreq.min:.2f}Mhz',
            'Current Frequency': f'{cpufreq.current:.2f}Mhz'
        }

        cpu_info.update({'Total CPU Usage': f'{psutil.cpu_percent()}%'})

        return cpu_info

    def get_memory_info(self):
        svmem = psutil.virtual_memory()
        swap = psutil.swap_memory()
        memory_info = {
            'Total memory': get_size(svmem.total),
            'Available memory': get_size(svmem.available),
            'Used memory': get_size(svmem.used),
            'Percentage memory in use': f'{svmem.percent}%',
            'Total swap': get_size(swap.total),
            'Free swap': get_size(swap.free),
            'Used swap': get_size(swap.used),
            'Percentage swap in use': f'{swap.percent}%'
        }

        return memory_info

    def get_gpu_info(self):
        gpus = GPUtil.getGPUs()
        gpu_info = {}

        for i in range(len(gpus)):
            gpu_dict = {
                f'GPU{i+1}': {
                    'ID': gpus[i].id,
                    'Name': gpus[i].name,
                    'Load': f"{gpus[i].load*100}%",
                    'Free memory': f"{gpus[i].memoryFree}MB",
                    'Used memory': f"{gpus[i].memoryUsed}MB",
                    'Total memory': f"{gpus[i].memoryTotal}MB",
                    'Temperature': f"{gpus[i].temperature} °C",
                    'UUID': gpus[i].uuid
                }}

            gpu_info.update(gpu_dict)

        return gpu_info

    def get_base_info(self):
        base_info = {
            'System': self.get_platform_info(),
            'CPU': self.get_fast_cpu_info(),
            'Memory': self.get_memory_info(),
            'GPUs': self.get_gpu_info()
        }

        return base_info

    def get_performance_info(self):
        cpufreq = psutil.cpu_freq()
        svmem = psutil.virtual_memory()
        swap = psutil.swap_memory()
        gpus = GPUtil.getGPUs()

        gpu_info = {}
        for i in range(len(gpus)):
            gpu_dict = {
                f'GPU{i+1}': {
                    'ID': gpus[i].id,
                    'Load': f"{gpus[i].load*100}%",
                    'Used memory': f"{gpus[i].memoryUsed}MB",
                    # 'Temperature': f"{gpus[i].temperature} °C",
                }}

            gpu_info.update(gpu_dict)

        perf_info = {
            'CPU': {
                'Total CPU usage': f'{psutil.cpu_percent()}%',
                'Current Frequency': f'{cpufreq.current:.2f}Mhz'
            },
            'Memory': {
                'Used memory': get_size(svmem.used),
                '% memory in use': f'{svmem.percent}%',
                'Used swap': get_size(swap.used),
                r'% swap in use': f'{swap.percent}%'
            },
            'GPU': gpu_info
        }

        return perf_info

def test():
    HM = HardwareMonitor()

    print(HM.get_platform_info())
    print(HM.get_cpu_info())
    print(HM.get_memory_info())
    print(HM.get_gpu_info())

def speed_test():
    HM = HardwareMonitor()

    start = time.perf_counter()
    print(HM.get_platform_info())
    print(
        f'Calculation time for system info: {round(time.perf_counter() - start, 6)}s\n\n')

    start = time.perf_counter()
    print(HM.get_cpu_info())
    print(
        f'Calculation time for CPU info: {round(time.perf_counter() - start, 6)}s\n\n')

    start = time.perf_counter()
    print(HM.get_fast_cpu_info())
    print(
        f'Calculation time for CPU info without core loads: {round(time.perf_counter() - start, 6)}s\n\n')

    start = time.perf_counter()
    print(HM.get_memory_info())
    print(
        f'Calculation time for memory info: {round(time.perf_counter() - start, 6)}s\n\n')

    start = time.perf_counter()
    print(HM.get_gpu_info())
    print(
        f'Calculation time for gpu info: {round(time.perf_counter() - start, 6)}s\n\n')

if __name__ == '__main__':
    HM = HardwareMonitor()
    print(HM.get_base_info())


from variables import *
from cardDetection import *
from advancedFunctionality import *
import pyautogui as pa

def countCardsBool(pos):
    """
    Checks if there is a Card at the given x Position
    (int x) -> bool
    """

    pa.moveTo(pos,940,0.05)
    if pa.pixel(pos-20,940)[0]+pa.pixel(pos-20,940)[1]+pa.pixel(pos-20,940)[2]<120 and pa.pixel(pos,920)[0]+pa.pixel(pos,920)[1]+pa.pixel(pos,920)[2]>450:
        return True
    else:
        return False

def countCards():
    """
    Counts the cards held in hand
    () -> int
    """

    handCardOuterBoundries=[1355,1300,1230,1150,1090,1015,944,870]

    for i in range(8):

        if countCardsBool(handCardOuterBoundries[i]):
            print("THERE ARE ",8-i," CARDS IN HAND")
            return 8-i

    return 0

def getHand(landPlayedInThisGetHand,turn):
    """
    Get the names of all Cards held in hand and returns a List of Tuples with the name of the Card at the first and the position of the card at the second position
    (bool landPlayedInThisGetHand,int turn) -> list

    Variables
    bool landPlayedInThisGetHand #Is False when called from mainloop. Recursivly plays a land as soon as the cursor hovers over a Land. Then calls it self again to return the Hand to the mainloop

    """

    global landplay
    hands={}
    hand=[]
    cardCount=countCards()

    for i in range(cardCount):
        for card in cards:
            lookup=lookUp(goto(i,cardCount),card)
            if lookup == 2 and landPlayedInThisGetHand==False and landplay==False:
                landUp()
                return getHand(True,0)

            if lookup:
                hands[i]=card
                break

    for i in range(cardCount):
        if i in hands:
            hand.append(hands[i])

        else:
            hand.append("NONE")

    handWithPosTemp=[]
    if cardCount>0:
        for (x, y) in zip(hand, eval(f"Positions{cardCount}")):
            handWithPosTemp.append((x,y))

    return handWithPosTemp


import lxml.etree
from ..utils import make_NS
from ...core.utils import try_or_log
from ...core.counters import Counters

from lxml.etree import QName
from collections import namedtuple, defaultdict

NS = make_NS('loc', {'loc': 'http://www.loc.gov/MARC21/slim'})

class MarcError(Exception):
    """error interpreting a MARC record"""
    pass

_Datafield = namedtuple('_Datafield', ['tag', 'ind1', 'ind2', 'subfields',
                                       'extra', 'flavor'])

def normalize(*datafields):
    """returns unified dict of {name: [value, value...]} from all datafields"""
    fields = defaultdict(set)
    for df in datafields:
        f = df.normalized()
        if f is not None:
            for k, v in f.items():
                    fields[k].add(v)

    # make values lists
    return {k: sorted(v) for k, v in fields.items()}

class Datafield(_Datafield):
    """A MARC datafield

    :cvar str FLAVOR: constant defining the flavor of MARC in use
    """

    # use new instead of init b/c we are a namedtuple subclass
    def __new__(cls, *args, **kwargs):
        if 'flavor' not in kwargs and len(args) < len(cls._fields):
            kwargs.update(flavor=cls.FLAVOR)
        ret = super().__new__(cls, *args, **kwargs)
        if ret.flavor != cls.FLAVOR:
            raise ValueError('Conflicting flavors: %r, %r' %
                             (ret.flavor, cls.FLAVOR))
        return ret

    @classmethod
    def rebuild(cls, *args, **kwargs):
        """rebuild a specific Datafield subclass after loading from parquet"""

        flavor = kwargs.get('flavor')
        if flavor is None and len(args) == len(cls._fields):
            flavor = args[-1]
        else:
            raise ValueError("Couldn't find a flavor")

        try:
            f = {s.FLAVOR: s for s in cls.__subclasses__()}[flavor]
        except KeyError:
            raise ValueError("Unknown flavor %r" % flavor)
        else:
            return f(*args, **kwargs)

    @classmethod
    def from_xml(cls, node, extra=None):
        # tags can appear more than once
        subfields = defaultdict(list)
        for s in node:
            if QName(s.tag).localname == 'subfield':
                subfields[s.attrib['code']].append(s.text)

        return cls(tag=node.attrib['tag'],
                   ind1=node.get('ind1', ''),
                   ind2=node.get('ind2', ''),
                   subfields=dict(subfields),
                   extra=extra if extra is not None else {})

    def normalized(self):
        """return a dict of normalized data.

        Returns None for unknown tags
        """
        d = self.extra.copy()
        try:
            f = getattr(self, 'tag_%s' % self.tag)
        except AttributeError as e:
            return None
        else:
            d.update(f())
            return d

    def _subfield(self, k1, k2, d, strip=False):
        """copy subfield with key `k1` from to `k2` in dict `d`.

        `d` will not be modified if `k1` not in subfields.
        if `k2` is already in `d`, join to existing value with a space

        if `strip` is True

        For internal use.
        """
        v = self.subfields.get(k1, ())
        if strip:
            v = (s.strip() for s in v if s is not None)
        v = list(filter(None, v))
        if v:
            v = " ".join(v)

            if k2 in d:
                d[k2] = " ".join((d[k2], v))
            else:
                d[k2] = v

class Marc21Datafield(Datafield):

    FLAVOR = 'marc21'

    def tag_010(self):
        # LOC Control Number
        d = {}
        self._subfield('a', 'loc_control_number', d, strip=True)
        return d

    def tag_020(self):
        # isbn
        d = {}
        self._subfield('a', 'isbn', d, strip=True)
        return d

    def tag_022(self):
        # issn
        d = {}
        self._subfield('a', 'issn', d, strip=True)
        return d

    def tag_100(self):
        # person author
        d = {}
        self._subfield('t', 'title', d)
        self._subfield('f', 'publication_date', d)
        self._subfield('a', 'person_name', d)
        if self.ind1 == '0':
            self._subfield('b', 'person_name', d)
        return d

    def tag_110(self):
        # corporate author
        d = {}
        self._subfield('t', 'title', d)
        self._subfield('f', 'publication_date', d)
        self._subfield('a', 'organization_name', d)
        self._subfield('b', 'organization_name', d)
        return d

    def tag_130(self):
        # uniform title
        d = {}
        self._subfield('a', 'title', d)
        self._subfield('p', 'subtitle', d)
        self._subfield('n', 'subtitle', d)
        return d

    def tag_245(self):
        # title & medium
        d = {}
        self._subfield('a', 'title', d)
        self._subfield('b', 'subtitle', d)
        self._subfield('h', 'medium', d)
        return d

    def tag_260(self):
        # publisher & medium
        d = {}
        self._subfield('b', 'publisher', d)
        self._subfield('c', 'publication_date', d)
        self._subfield('h', 'medium', d)
        return d

    # 400 & 410 are obsolete. used extensively in VIAF for translated titles
    def tag_400(self):
        d = {}
        self._subfield('a', 'person_name', d)
        self._subfield('b', 'person_name', d)
        self._subfield('t', 'title', d)
        self._subfield('f', 'publication_date', d)
        return d

    def tag_410(self):
        d = {}
        self._subfield('a', 'organization_name', d)
        self._subfield('b', 'organization_name', d)
        self._subfield('t', 'title', d)
        self._subfield('f', 'publication_date', d)
        return d

    def tag_490(self):
        # series name & volume. related to the 8xx tags?
        d = {}
        self._subfield('a', 'series', d)
        self._subfield('v', 'series', d)
        self._subfield('x', 'issn', d)
        return d

    tag_440 = tag_490

    def tag_6XX(self):
        # basic subject tag; some 6XX variants use multiple fields
        d = {}
        self._subfield('a', 'subject', d)
        self._subfield('x', 'subject', d)
        self._subfield('v', 'subject', d)
        return d

    tag_600 = tag_6XX
    tag_650 = tag_6XX
    tag_651 = tag_6XX

    def tag_700(self):
        # person author
        d = {}
        self._subfield('a', 'person_name', d)
        self._subfield('b', 'person_name', d)
        return d

    def tag_710(self):
        # corporate author
        d = {}
        self._subfield('a', 'organization_name', d)
        if self.ind1 == '1':
            self._subfield('b', 'organization_name', d)
        return d

class UnimarcDatafield(Datafield):
    # we don't extract any fields from UNIMARC
    FLAVOR = 'unimarc'

class SourceMARCRecord:

    @classmethod
    def iterfile(cls, fh):
        """yield instances of `cls` from a file handle"""
        it = (cls(x[1]) for x in
              lxml.etree.iterparse(
                  fh,
                  tag=NS('{loc}record'),
                  events=('end',)))
        yield from filter(None, it)

    @try_or_log
    def __init__(self, node):
        Counters.inc('SourceMARCRecord.node_count')
        self.root = node
        self.datafields = [Marc21Datafield.from_xml(node)
                           for node in self.root.iter(NS('datafield'))]

    @property
    def marc_id(self):
        return self.root.findtext(NS("controlfield[@tag='001']")).strip()

    @property
    def marc_source(self):
        s = self.root.findtext(NS("controlfield[@tag='003']"))
        return s.strip() if s else ''

    @property
    def timestamp(self):
        return self.root.findtext(NS("controlfield[@tag='005']")).strip()


"""Point class and associated routines.
"""

import re
import xml.dom.minidom as minidom
import xml.etree.ElementTree as etree
from datetime import datetime, timedelta

import pytz

from utils import meters_per_user_unit, user_units_per_meter

class Point:
    """Cartesian coordinates of a geographic location."""

    def __init__(self, x, y, z, type, units):

        # Internally coordinate/elevation values are in meters.
        # Keep the original user units type for use in IO operations.
        self.user_units = units

        # Convert x/y/z to meters as necessary.
        ufactor = meters_per_user_unit(self.user_units)
        self.x = x * ufactor
        self.y = y * ufactor
        self.z = z * ufactor

        self.type = type
        self.name = None
        self.desc = None

    def __str__(self):
        name = self.name if self.name != '' else 'Empty'
        desc = self.desc if self.desc != '' else 'Empty'
        ufactor = user_units_per_meter(self.user_units)
        n, e, z = [d * ufactor for d in (self.y, self.x, self.z)]
        s = "{0},{1:.4f},{2:.4f},{3:.4f},{4}".format(name, n, e, z, desc)
        return s

    def __repr__(self):
        return Point.__str__(self)

    @staticmethod
    def read_local_points(filename, units):
        """ Read points from a PNEZD comma delimited text file.
        """

        pts = []
        with open(filename, 'r') as f:
            for line in f:
                line = line.strip()
                if len(line) == 0 or line[0] == '#':
                    continue
                values = re.split(',', line, 4)
                if len(values) != 5:
                    print("PNEZD format error: \"{0}\"".format(line))
                    continue
                (p, n, e, z, d) = values
                pt = Point(float(e), float(n), float(z), 'LOCAL', units)
                pt.name = p
                pt.desc = d
                pts.append(pt)

        return pts

    @staticmethod
    def read_gpx_waypoints(filename, units, projection):
        """ Parse wpt elements from a GPX file and transform coordinates to grid.
        """

        ns = {
            'gpx': 'http://www.topografix.com/GPX/1/1',
            'gpxx': 'http://www.garmin.com/xmlschemas/GpxExtensions/v3',
            'wpt1': 'http://www.garmin.com/xmlschemas/WaypointExtension/v1',
            'ctx': 'http://www.garmin.com/xmlschemas/CreationTimeExtension/v1'
        }

        etree.register_namespace('', 'http://www.topografix.com/GPX/1/1')
        etree.register_namespace('gpxx', 'http://www.garmin.com/xmlschemas/GpxExtensions/v3')
        etree.register_namespace('wpt1', 'http://www.garmin.com/xmlschemas/WaypointExtension/v1')
        etree.register_namespace('ctx', 'http://www.garmin.com/xmlschemas/CreationTimeExtension/v1')

        def parse_value(e, tag, default):
            t = e.find(tag, ns)
            if t is None: return default
            if type(default) is int: return int(t.text)
            if type(default) is float: return float(t.text)
            return t.text

        pts = []
        gpx = etree.parse(filename).getroot()
        for e in gpx.findall('gpx:wpt', ns):

            x, y = projection.to_grid(float(e.get('lat')), float(e.get('lon')))
            z = parse_value(e, 'gpx:ele', 0.0)
            pt = Point(x, y, z, type='GRID', units='meters')

            pt.user_units = units
            pt.name = parse_value(e, 'gpx:name', None)
            pt.cmt = parse_value(e, 'gpx:cmt', None)
            pt.desc = parse_value(e, 'gpx:desc', pt.cmt)
            pt.time = parse_value(e, 'gpx:time', None)
            pt.sym = parse_value(e, 'gpx:sym', 'Waypoint')
            pt.samples = parse_value(e, './/wpt1:Samples', 0)
            pts.append(pt)

        return pts

    @staticmethod
    def write_gpx_waypoints(pts, filename, projection, transform=None):
        """ Convert local/grid points into geographic coordinates and write to a GPX file.

        :param pts: list of local points
        :param filename: filename for gpx data file
        :param projection: grid to geographic projection
        :param transform: local to grid transform for local points

        GPX format for a waypoint -

        <?xml version="1.0" encoding="utf-8" standalone="no"?>
        <gpx creator="Python pyloc" version="1.1"
            xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd
            xmlns="http://www.topografix.com/GPX/1/1"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
            <metadata>
                <link href="http://www.asis.com/users/chas.mack">
                    <text>Charles Mack</text>
                </link>
                <time>2015-04-27T23:09:11Z</time>
            </metadata>
            <wpt lat="41.097316" lon="-123.696170">
                <ele>107.753052</ele>
                <time>2015-04-27T23:33:44Z</time>
                <name>4501</name>
                <cmt>SW212</cmt>
                <desc>SW212</desc>
                <sym>Waypoint</sym>
            </wpt>
        </gpx>

        """
        ns = {
            'gpx': 'http://www.topografix.com/GPX/1/1'
        }
        etree.register_namespace('', 'http://www.topografix.com/GPX/1/1')

        gpx_attrib = {
            'creator': 'Python pyloc', 'version': '1.1',
            'xsi:schemaLocation': 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd',
            'xmlns': 'http://www.topografix.com/GPX/1/1',
            'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance'
        }

        # Get the ISO 8601 date-time string.
        time = datetime.now(pytz.utc)
        time -= timedelta(microseconds=time.microsecond)    # get rid of the microseconds
        time = time.isoformat()

        gpx = etree.Element('gpx', attrib=gpx_attrib)
        meta = etree.SubElement(gpx, 'metadata')
        link = etree.SubElement(meta, 'link', attrib={'href': 'http://www.asis.com/users/chas.mack'})
        etree.SubElement(link, 'text').text = 'Charles Mack'
        etree.SubElement(meta, 'time').text = time

        for pt in pts:
            if transform != None:
                grid_x, grid_y = transform.to_grid(pt.x, pt.y)
            else:
                grid_x, grid_y = (pt.x, pt.y)
            lat, lon = ['{0:.8f}'.format(x) for x in projection.to_geographic(grid_x, grid_y)]
            ele = '{0:.4f}'.format(pt.z)
            coords = {'lat': lat, 'lon': lon}
            wpt = etree.SubElement(gpx, 'wpt', attrib=coords)
            etree.SubElement(wpt, 'ele').text = ele
            etree.SubElement(wpt, 'time').text = time
            etree.SubElement(wpt, 'name').text = pt.name
            etree.SubElement(wpt, 'cmt').text = pt.desc
            etree.SubElement(wpt, 'desc').text = pt.desc
            etree.SubElement(wpt, 'sym').text = 'Waypoint'

        # Reparse the etree gpx with minidom and write pretty xml.
        dom = minidom.parseString(etree.tostring(gpx, encoding='utf-8'))
        with open(filename, 'w') as o:
            dom.writexml(o, addindent='  ', newl='\n', encoding='utf-8')

if __name__ == "__main__":

    from projection_lc import ProjectionLC

    p = Point(32808.3333, 16404.1667, 328.0833, 'LOCAL', units='sft')
    print(p)
    p.name = ''
    print(p)
    p.name = '1001'
    print(p)
    p.desc = ''
    print(p)
    p.desc = 'BASE'
    print(p)
    p.user_units = 'meters'
    print(p)

    print('\n********************')

    filename = 'data/150331_Stapp_PTS.txt'
    units = 'sft'

    pts = Point.read_local_points(filename, units)
    if not pts:
        print("No points. Nothing to do.")
        exit(1)

    print('\nLocal points ({0}):'.format(units))
    for p in pts:
        print(p)

    filename = 'data/Waypoints.gpx'
    projection = ProjectionLC('SPCS', '0401')
    units = 'meters'

    pts = Point.read_gpx_waypoints(filename, units, projection)
    if not pts:
        print("No waypoints. Nothing to do.")
        exit(1)

    print('\nGeographic points ({0}):'.format(units))
    for p in pts:
        print(p, end='')
        if p.samples > 0:
            print(' (samples={0})'.format(p.samples))
        else:
            print()

    units = 'sft'

    pts = Point.read_gpx_waypoints(filename, units, projection)
    if not pts:
        print("No waypoints. Nothing to do.")
        exit(1)

    print('\nGeographic points ({0}):'.format(units))
    for p in pts:
        print(p, end='')
        if p.samples > 0:
            print(' (samples={0})'.format(p.samples))
        else:
            print()

    exit(0)


import tensorflow as tf

class Model:

    def __init__(self, size):
        self.x = tf.placeholder(tf.float32, [None, 300])
        y = encode(self.x)
        self.y = y
        self.z = decode(y)
        self.loss = tf.losses.mean_squared_error(self.x, self.z)
        #optimizer = tf.train.AdamOptimizer(learning_rate=0.0001)
        optimizer = tf.train.RMSPropOptimizer(learning_rate=0.00001)
        self.train_op = optimizer.minimize(self.loss)

    def train(self, sess, x):
        return sess.run([self.loss, self.train_op], {
            self.x: x
        })[0]

    def infer(self, sess, x):
        return sess.run(self.z, {
            self.x: x
        })

    def test(self, sess, x):
        return sess.run(self.y, {
            self.x: x
        })

def encode(x):
    y = tf.reshape(x, (-1, 300, 1))
    y = conv('conv1', 5, 8, y)
    y = tf.nn.pool(y, (5,), 'MAX', 'VALID', strides=(5,))
    y = conv('conv2', 5, 32, y)
    y = tf.nn.pool(y, (5,), 'MAX', 'VALID', strides=(5,))
    y = conv('conv3', 3, 64, y)
    y = tf.nn.pool(y, (3,), 'MAX', 'VALID', strides=(3,))
    y = tf.reshape(y, (-1, 4 * 64))
    y = tf.layers.dense(y, 4 * 64, activation=tf.nn.relu)
    return y

def decode(x):
    y = tf.layers.dense(x, 4 * 64, activation=tf.nn.relu)
    y = tf.reshape(y, (-1, 4, 64))
    y = upsampling(y, 3)
    y = conv('conv4', 3, 32, y)
    y = upsampling(y, 5)
    y = conv('conv5', 5, 8, y)
    y = upsampling(y, 5)
    y = conv('conv6', 5, 1, y)
    y = tf.reshape(y, (-1, 300))
    y = tf.layers.dense(y, 300)
    return y

def conv(name, window_size, channel, x):
    with tf.variable_scope(name) as scope:
        return tf.layers.conv1d(
            inputs=x,
            filters=channel,
            kernel_size=window_size,
            strides=1,
            padding='same',
            dilation_rate=2,
            activation=tf.nn.relu)

'''
def conv(name, window_size, channel1, channel2, x):
    with tf.variable_scope(name) as scope:
        initializer = tf.random_uniform_initializer(-0.1, 0.1)
        weight = tf.get_variable(
            'weight', (window_size, channel1, channel2),
            initializer=initializer)
        bias = tf.get_variable(
            'bias', (channel2,),
            initializer=initializer)
        return tf.nn.relu(tf.nn.conv1d(x, weight, 1, 'SAME') + bias)
'''

def upsampling(x, size):
    s1 = x.shape[1].value
    s2 = x.shape[2].value
    return tf.reshape(tf.concat([x] * size, 2), (-1, s1 * size, s2))


# Mailroom_pt3.py Exercise by tfbanks

# !/usr/bin/env python3

# Donor Database containing names and donations
donor_names = {
    'Tim Cooker': [1500.50, 25050.50, 15680.75],
    'Elon Musket': [5250.25, 26500],
    'Frank Petersmankempt': [550.60],
    'Megan Morgan': [650.40, 1600, 20625.40],
    'Marlene Wheeler': [820, 1222.80]}

def thank_you():  # Code for selecting Donor and writing a Thank You Note
    ty_donor = input('Enter the Full Name of a donor (for list of previous donors type list): ').title()
    letter = ('''\n\nDear {},\n
Thank you for your generous donation of ${:,.2f}, your generosity is greatly appreciated.
These funds will help continue our efforts to teach Python to the next generation.\n
Sincerely,\n\n
Joesef Edword Bringingham\n\n''')
    if ty_donor == 'List':  # If List, Prints Donor List and restarts the function
        for donor in donor_names.keys():
            print(donor)
        print('\n')
        ty_donor = input('Enter the Full Name of a donor (for list of previous donors type list): ').title()

    while True:
        try:
            amount = float(input('Please enter the donation amount: '))
        except ValueError:
            print('Please enter a valid donation amount')
            continue
        break

    if ty_donor in donor_names:  # Actions if donor is already in donor_names
        donor_names[ty_donor].append(amount)  # Appends donation amount to donators donation values
    else:
        donor_names[ty_donor] = [amount]

    print(letter.format(ty_donor, amount))

def report():  # Defines parameters of the report of donors, creates a new list of summarized details per donor, sorts, and prints it.
    print('\nDonor Name            |  Total Given | Num Gifts |  Average Gift')
    print('------------------------------------------------------------------')
    donor_rpt = [[donor, sum(donations), len(donations), sum(donations)/len(donations)] for donor, donations in donor_names.items()]
    sorted_rpt = sorted(donor_rpt, key=lambda x: x[1], reverse=True)
    for donor_rpt in sorted_rpt:
        print('{:24s} ${:11,.2f} {:^12} ${:12,.2f}'.format(donor_rpt[0], donor_rpt[1], donor_rpt[2], donor_rpt[3]))
    print('\n')

def mass_mail():
    mm_letter = ('''\n\nDear {},\n
Thank you for your generous donations totaling ${:,.2f}, your generosity is greatly appreciated.
These funds will help continue our efforts to teach Python to the next generation.\n
Sincerely,\n\n
Joesef Edword Bringingham\n\n''')
    for donor, donations in donor_names.items():
        letter = mm_letter.format(donor, sum(donations))
        letter_output = donor + '.txt'
        with open(letter_output, 'w') as op:
            for line in letter:
                op.write(line)
    print('\nLetters are located in your working directory folder\n\n')

if __name__ == '__main__':
    while True:
        answer = input('''Please choose an action from the following options:
 1 - Send a Thank You
 2 - Create a Report
 3 - Send letters to everyone
 4 - Quit\n''')

        try:
            answer = int(answer)
        except ValueError:
            print('''Enter the actions's associated number''')
        if answer == 1:
            thank_you()
        elif answer == 2:
            report()
        elif answer == 3:
            mass_mail()
        elif answer == 4:
            print('Have a nice day')
            break