# Imports
import pandas
from turtle import Screen
from textwriter import TextWriter
from scoreboard import Scoreboard
from timer import Timer
import time

# Constants
SCREEN_HEIGHT = 491
SCREEN_WIDTH = 725
BG_PATH = "./us-states-game-start/us-states-game-start/blank_states_img.gif"
DATA_PATH = "./us-states-game-start/us-states-game-start/50_states.csv"

# Initialise screen
screen = Screen()
screen.title("U.S. States Game")
screen.setup(width=SCREEN_WIDTH, height=SCREEN_HEIGHT)
screen.bgpic(BG_PATH)

# Initialise text elements
textwriter = TextWriter()
scoreboard = Scoreboard()
timer = Timer()

# Import data
data = pandas.read_csv(DATA_PATH)
data_dict = {}
for state in data.state:
    row = data[data.state == state]
    data_dict[state] = (row.x.to_list()[0], row.y.to_list()[0])

# Variables
states_pool = []
states_guessed = []
game_is_on = True

# Functions
def reset_states():
    states_guessed.clear()
    states_pool.clear()
    for state in data_dict.keys():
        states_pool.append(state)

def get_player_input():
    return screen.textinput(f"{len(states_pool)} states left", "Name a state: ").title()

def check_unguessed_state(toCheck):
    if toCheck in states_pool:
        return True
    return False

def correct_answer_actions(correct_answer):
    states_pool.remove(correct_answer)
    states_guessed.append(correct_answer)
    textwriter.write_text(data_dict[correct_answer][0], data_dict[correct_answer][1], correct_answer)

def display_missed_states():
    textwriter.color("red")
    for state in states_pool:
        textwriter.write_text(data_dict[state][0], data_dict[state][1], state)
    textwriter.color("black")
    time.sleep(5)

def end_game():
    global game_is_on
    display_missed_states()
    timer.reset_timer()
    scoreboard.reset_scoreboard()
    textwriter.reset_screen()
    output_csv()
    reset_states()
    game_is_on = False

def output_csv():
    missed_states = pandas.DataFrame({"States you missed:": states_pool})
    missed_states.to_csv("missed_states.csv")

# Initialise game
timer.start_timer()
reset_states()

# Main loop
while game_is_on:
    scoreboard.update_scoreboard()
    if len(states_guessed) == 50:
        textwriter.write_text(0, 200, "YOU WIN!!!!")
        end_game()
        continue
    timer.calculate_remaining_time()
    timer.display_time()
    if timer.is_timer_expired():
        end_game()
        continue

    guess = get_player_input()
    if guess.lower() == "exit":
        end_game()
    if not check_unguessed_state(guess):
        continue
    else:
        correct_answer_actions(guess)
        scoreboard.increase_score()

screen.exitonclick()

# import csv
# import pandas

# with open("weather_data.csv") as data_file:
#     data = csv.reader(data_file)
#     temperatures = []
#     for row in data:
#         if row[1] != "temp":
#             temperatures.append(int(row[1]))
#
# print(temperatures)

#
# def average(data_in):
#     return sum(data_in) // len(data_in)
#
#
# def c_to_f(temp):
#     return (temp * 1.8) + 32
#
#
# data = pandas.read_csv("weather_data.csv")
# temp_list = data["temp"].to_list()
# print(data["temp"].mean())
# print(f"Average temperature: {average(temp_list)} degrees.")
# print(f"Max temperature this week: {data['temp'].max()} degrees.")
#
# print(data[data.temp == data.temp.max()])
#
# print(data.index)
# print(data.columns)
# print(data[["day", "condition"]])
# s = data.loc[3:5]
# print(s)
# print(s[s.temp == s.temp.min()])
#
# monday = data.loc[0]
# print(f"Monday's temperature was {c_to_f(monday.temp)} degrees F.")
#
# custom_data_dict = {
#     "Artist": ["Phil Collins", "Michael Jackson", "Pink Floyd"],
#     "Title":  ["In The Air Tonight", "Dangerous", "Learning To Fly"]
# }
#
# custom_data = pandas.DataFrame(custom_data_dict, index=["First", "Second", "Third"])
# print(custom_data)
# custom_data.to_csv("charts.csv")

# Squirrel stuff!
#
# squirrel_data = pandas.read_csv("squirrel_data.csv")
#
#
# def get_num_each_colour(colour):
#     return len(squirrel_data[squirrel_data["Primary Fur Color"] == colour])
#
#
# output_dict = {}
# colours = ["Gray", "Cinnamon", "Black"]
# frequencies = []
# for colour in colours:
#     frequencies.append(get_num_each_colour(colour))
#
# output_dict["Fur Colour"] = colours
# output_dict["Count"] = frequencies
#
# output = pandas.DataFrame(output_dict)
# print(output)
# output.to_csv("squirrel_colours.csv")

# sq = squirrel_data.loc[35:40]
# adults = (sq[sq.Age == "Adult"])
# key_info = (adults[["Unique Squirrel ID", "Shift", "Primary Fur Color"]])
# key_info_dict = key_info.to_dict()
# print(key_info_dict)
# for k, v in key_info_dict['Primary Fur Color'].items():
#     key_info_dict["Primary Fur Color"][k] = "Lime Green"
# key_info_updated = pandas.DataFrame(key_info_dict)
# print(key_info_updated)
# key_info_updated.to_csv("lime_green_squirrels.csv")


# coding:utf-8
from __future__ import division, print_function

__author__ = "timmyliang"
__email__ = "820472580@qq.com"
__date__ = "2020-05-06 23:02:37"

"""

"""

import six
import sys
import inspect
import traceback
from collections import OrderedDict
from contextlib import contextmanager
from Qt import QtCore, QtGui
from .eventhook import QEventHook
from .hook import MethodHook

event_hook = QEventHook.instance()

class BindingBase(object):
    pass

class BindingProxy(BindingBase):
    def __init__(self, binder, attr):
        self.binder = binder
        self.attr = attr

    def __rrshift__(self, d):
        self.binder.__setattr__(self.attr, d)
        del self
        return d

    def __iter__(self):
        for attr in dir(self):
            yield attr

class FnBinding(BindingBase):
    def __init__(self, binder=None, func=None):
        from .binder import Binder

        self.cls = None
        self.binder = binder
        self.binded = isinstance(binder, Binder)
        if self.binded:
            self.func = func if six.callable(func) else func.__func__
            self.static = isinstance(self.func, staticmethod)

    def connect_binder(self, name, binder):
        """
        connect_binder automatically run by the BinderBase __setattr__
        """
        self.name = name
        self.binder = binder

    def __call__(self, *args, **kwargs):

        # NOTE if not initialize binded should bind func
        if not self.binded:
            self.binded = True
            func = args[0]
            self.func = func if six.callable(func) else func.__func__
            self.static = isinstance(func, staticmethod)

            stack = inspect.stack()[-2]
            cls_name = stack[3]
            frame = stack[0]
            module = inspect.getmodule(frame)
            dispatcher = self.binder("dispatcher")
            dispatcher._trace_dict_[module][cls_name][self.func.__name__] = self

            return self.func

        arg = self.binder
        if self.cls:
            # TODO not very good solution | may be try __subclasshook__
            # NOTE Try to Get A Default Instance from binder
            for _, member in inspect.getmembers(self.binder, lambda f: not callable(f)):
                if type(member) is self.cls:
                    arg = member
                    return self.func(arg, *args, **kwargs)

        return self.func(*args, **kwargs)

    def __getitem__(self, attr):
        # NOTE special bind
        attr = getattr(self.binder, attr) if type(attr) is str else attr

        @six.wraps(self.func)
        def wrapper(*args, **kw):
            if self.static:
                return self.func(*args, **kw)
            else:
                length = len(inspect.getargspec(self.func).args)
                return self.func(attr, *args[: length - 1], **kw)

        return wrapper

def notify(func):
    def wrapper(self, *args, **kwargs):
        res = func(self, *args, **kwargs)
        if hasattr(self, "STATE"):
            self.STATE.emitDataChanged()
            self.STATE.emit()
        return res

    return wrapper

class NotifyList(list):
    """
    https://stackoverflow.com/questions/13259179/list-callbacks
    """

    __repr__ = list.__repr__

    def __init__(self, val, STATE):
        super(NotifyList, self).__init__(val)
        self.STATE = STATE

    extend = notify(list.extend)
    append = notify(list.append)
    remove = notify(list.remove)
    pop = notify(list.pop)
    __iadd__ = notify(list.__iadd__)
    __imul__ = notify(list.__imul__)

    # Take care to return a new NotifyList if we slice it.
    if sys.version_info[0] < 3:
        __setslice__ = notify(list.__setslice__)
        __delslice__ = notify(list.__delslice__)

    __delitem__ = notify(list.__delitem__)

    def __getitem__(self, item):
        if isinstance(item, slice):
            return list(list.__getitem__(self, item))
        else:
            return list.__getitem__(self, item)

    @notify
    def __setitem__(self, key, value):
        if isinstance(value, dict):
            value = NotifyDict(value, self.STATE)
        elif isinstance(value, list):
            value = NotifyList(value, self.STATE)
        list.__setitem__(self, key, value)

class NotifyDict(OrderedDict):
    """
    https://stackoverflow.com/questions/5186520/python-property-change-listener-pattern
    """

    __repr__ = dict.__repr__

    def __init__(self, val, STATE):
        super(NotifyDict, self).__init__(val)
        self.STATE = STATE

    clear = notify(OrderedDict.clear)
    pop = notify(OrderedDict.pop)
    popitem = notify(OrderedDict.popitem)
    setdefault = notify(OrderedDict.setdefault)
    update = notify(OrderedDict.update)
    __delitem__ = notify(OrderedDict.__delitem__)

    @notify
    def __setitem__(self, key, value):
        if hasattr(self, "STATE"):
            if isinstance(value, dict):
                value = NotifyDict(value, self.STATE)
            elif isinstance(value, list):
                value = NotifyList(value, self.STATE)
        return OrderedDict.__setitem__(self, key, value)

class Binding(QtGui.QStandardItem, BindingBase):

    __trace = False
    __emit_flag = False
    _trace_dict_ = {}
    _inst_ = []

    __repr__ = lambda self: repr(self.val)
    __str__ = lambda self: str(self.val)

    operator_list = {
        "__add__": lambda self, x: self.val.__add__(x),
        "__sub__": lambda self, x: self.val.__sub__(x),
        "__mul__": lambda self, x: self.val.__mul__(x),
        "__floordiv__": lambda self, x: self.val.__floordiv__(x),
        "__truediv__": lambda self, x: self.val.__truediv__(x),
        "__mod__": lambda self, x: self.val.__mod__(x),
        "__pow__": lambda self, x: self.val.__pow__(x),
        "__lshift__": lambda self, x: self.val.__lshift__(x),
        "__rshift__": lambda self, x: self.val.__rshift__(x),
        "__and__": lambda self, x: self.val.__and__(x),
        "__xor__": lambda self, x: self.val.__xor__(x),
        "__or__": lambda self, x: self.val.__or__(x),
        "__iadd__": lambda self, x: self.val.__iadd__(x),
        "__isub__": lambda self, x: self.val.__isub__(x),
        "__imul__": lambda self, x: self.val.__imul__(x),
        "__idiv__": lambda self, x: self.val.__idiv__(x),
        "__ifloordiv__": lambda self, x: self.val.__ifloordiv__(x),
        "__imod__": lambda self, x: self.val.__imod__(x),
        "__ipow__": lambda self, x: self.val.__ipow__(x),
        "__ilshift__": lambda self, x: self.val.__ilshift__(x),
        "__irshift__": lambda self, x: self.val.__irshift__(x),
        "__iand__": lambda self, x: self.val.__iand__(x),
        "__ixor__": lambda self, x: self.val.__ixor__(x),
        "__ior__": lambda self, x: self.val.__ior__(x),
        "__neg__": lambda self, x: self.val.__neg__(x),
        "__pos__": lambda self, x: self.val.__pos__(x),
        "__abs__": lambda self, x: self.val.__abs__(x),
        "__invert__": lambda self, x: self.val.__invert__(x),
        "__complex__": lambda self, x: self.val.__complex__(x),
        "__int__": lambda self, x: self.val.__int__(x),
        "__long__": lambda self, x: self.val.__long__(x),
        "__float__": lambda self, x: self.val.__float__(x),
        "__oct__": lambda self, x: self.val.__oct__(x),
        "__hex__": lambda self, x: self.val.__hex__(x),
        "__lt__": lambda self, x: self.val.__lt__(x),
        "__le__": lambda self, x: self.val.__le__(x),
        "__eq__": lambda self, x: self.val.__eq__(x),
        "__ne__": lambda self, x: self.val.__ne__(x),
        "__ge__": lambda self, x: self.val.__ge__(x),
        "__gt__": lambda self, x: self.val.__gt__(x),
    }

    def __init__(self, val=None):
        super(Binding, self).__init__()
        self.val = self.retrieve2Notify(val)
        self.overrideOperator(self.val)
        self.event_loop = []
        self.__binder__ = None
        self.__set_flag__ = False

    @classmethod
    @contextmanager
    def set_trace(cls):
        cls._trace_dict_.clear()
        cls.__trace = True
        yield
        cls.__trace = False

    def __get__(self, instance, owner):
        return self.get()

    def __rrshift__(self, d):
        self.set(d)
        return d

    def set(self, value):
        # NOTE set value for the first time but block infinite setter
        if value == self.get() and self.__set_flag__:
            self.__set_flag__ = False
            return
        else:
            self.__set_flag__ = True

        self.val = self.retrieve2Notify(value)
        self.overrideOperator(value)
        self.emitDataChanged()
        self.emit()

    def get(self):
        self.__class__._inst_ = [self]
        hash_code = id(self)
        if self.__trace and not hash_code in self._trace_dict_:
            self._trace_dict_[hash_code] = self
        return self.val

    @classmethod
    def overrideOperator(cls, val):
        for attr, func in cls.operator_list.items():
            if attr in dir(val):
                setattr(cls, attr, func)

    def retrieve2Notify(self, val, initialize=True):
        """ convert to Notify type """
        itr = (
            six.iteritems(val)
            if isinstance(val, dict)
            else enumerate(val)
            if isinstance(val, list)
            else []
        )
        for k, v in itr:
            if isinstance(v, dict):
                self.retrieve2Notify(v, initialize=False)
                val[k] = NotifyDict(v, self)
            elif isinstance(v, list):
                self.retrieve2Notify(v, initialize=False)
                val[k] = NotifyList(v, self)

        if initialize:
            if isinstance(val, dict):
                return NotifyDict(val, self)
            elif isinstance(val, list):
                return NotifyList(val, self)
            else:
                return val

    def data(self, role):
        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            return str(self.val)

    def setData(self, value, role=QtCore.Qt.EditRole):
        if role == QtCore.Qt.EditRole:
            self.set(value)
            return True
        return False

    def connect(self, callback):
        self.event_loop.append(callback)
        return callback

    def disconnect(self, callback):
        self.event_loop.remove(callback)

    def emit(self, *args, **kwargs):
        QtCore.QTimer.singleShot(0, lambda: self.run_event(*args, **kwargs))
        self.__emit_flag = True

    def run_event(self, *args, **kwargs):
        if self.__emit_flag:
            self.__emit_flag = False
            for callback in self.event_loop[:]:
                if six.callable(callback):
                    try:
                        callback(*args, **kwargs)
                    except:
                        # TODO QBinder logger
                        traceback.print_exc()
                        self.event_loop.remove(callback)

class Model(QtGui.QStandardItemModel):
    def __init__(self, source=None):
        super(Model, self).__init__()
        self.setSource(source)

    def dataChangedEmit(self):
        self.dataChanged.emit(QtCore.QModelIndex(), QtCore.QModelIndex())

    @MethodHook
    def setSource(self, source):
        # NOTE update source data remove old callback
        [
            item.disconnect(self.dataChangedEmit)
            for row in self._source
            for item in row
            if isinstance(item, Binding)
        ] if hasattr(self, "_source") else None

        self._source = (
            [
                item
                if isinstance(item, list)
                else [item if isinstance(item, Binding) else item]
                for item in source
            ]
            if source
            else []
        )

        self.setRowCount(len(self._source))
        columns = [len(row) for row in self._source]
        column_count = max(columns) if columns else 0

        self.setColumnCount(column_count)

        # NOTE add data update callback
        for row in self._source:
            for item in row:
                if isinstance(item, Binding):
                    item.connect(self.dataChangedEmit)

        # NOTE fill None to the empty cell
        for row in self._source:
            row_count = len(row)
            if row_count < column_count:
                row.extend([None for i in range(column_count - row_count)])

    # def index(self, row, column, parent=QtCore.QModelIndex()):
    #     return self.createIndex(row, column)

    # def parent(self, index):
    #     return QtCore.QModelIndex()

    # def rowCount(self, parent):
    #     return len(self._source) if parent.row() == -1 else 0

    # def columnCount(self, parent):
    #     return 10
    #     return max([len(row) for row in self._source])

    def item(self, row, column):
        row_list = next(iter(self._source[row:]), None)
        if row_list is None:
            return
        return next(iter(row_list[column:]), None)

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            if index.isValid():
                item = self.item(index.row(), index.column())
                return (
                    item.val
                    if isinstance(item, Binding)
                    else item.text()
                    if isinstance(item, QtGui.QStandardItem)
                    else str(item)
                )

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if role == QtCore.Qt.EditRole:
            if index.isValid():
                row = index.row()
                column = index.column()
                item = self.item(row, column)
                if isinstance(item, Binding):
                    item.set(value)
                elif isinstance(item, QtGui.QStandardItem):
                    item.setText(value)
                else:
                    self._source[row][column] = value
                self.dataChanged.emit(index, index)
                return True
        return False

    def flags(self, index):
        return (
            QtCore.Qt.ItemIsEditable
            | QtCore.Qt.ItemIsEnabled
            | QtCore.Qt.ItemIsSelectable
        )

    def get(self):
        return self._source


import time

from Cobalt.Components.slp import \
    ServiceLocator, PollingServiceLocator, TimingServiceLocator

from test_base import TestComponent

__all__ = [
    "TestServiceLocator",
    "TestPollingServiceLocator", "TestTimingServiceLocator",
]

class TestServiceLocator (TestComponent):

    def setup (self):
        TestComponent.setup(self)
        self.slp = ServiceLocator()

    def test_register (self):
        for each in range(2):
            try:
                self.slp.register("foo_service", "http://localhost:5900")
            except:
                raise
                assert not "Wasn't able to register a service."

    def test_unregister (self):
        try:
            self.slp.unregister("foo_service")
        except:
            assert not "Wasn't able to unregister an unregistered service."
        self.slp.register("foo_service", "http://localhost:5900")
        try:
            self.slp.unregister("foo_service")
        except:
            assert not "Wasn't able to unregister."
        try:
            self.slp.unregister("foo_service")
        except:
            assert not "Wasn't able to unregister multiple times."

    def test_locate (self):
        location = self.slp.locate("foo_service")
        assert location == ""
        self.slp.register("foo_service", "http://localhost:5900")
        location = self.slp.locate("foo_service")
        assert location == "http://localhost:5900"
        self.slp.unregister("foo_service")
        location = self.slp.locate("foo_service")
        assert location == ""

    def test_get_services (self):
        services = self.slp.get_services([{'name':"foo_service"}])
        assert len(services) == 0
        self.slp.register("foo_service", "http://localhost:5900")
        services = self.slp.get_services([{'name':"foo_service"}])
        assert len(services) == 1
        assert services[0].name == "foo_service"
        services = self.slp.get_services([{'name':"*", 'location':"*"}])
        assert len(services) == 1
        assert services[0].name == "foo_service"
        assert services[0].location == "http://localhost:5900"

class TestPollingServiceLocator (TestServiceLocator):

    def setup (self):
        self.slp = PollingServiceLocator()

    def test_check_services (self):
        self.slp.register("foo_service", "http://localhost:5900")
        location = self.slp.locate("foo_service")
        assert location == "http://localhost:5900"
        self.slp.check_services()
        location = self.slp.locate("foo_service")
        assert location == ""

class TestTimingServiceLocator (TestServiceLocator):

    def setup (self):
        self.slp = TimingServiceLocator(expire=2)

    def test_init_expire (self):
        assert self.slp.expire == 2

    def test_expire_services (self):
        self.slp.register("foo_service", "http://localhost:5900")
        start = time.time()
        self.slp.expire_services()
        assert time.time() < start + 2
        location = self.slp.locate("foo_service")
        assert location == "http://localhost:5900"
        time.sleep(3)
        assert (time.time() - start) > 2
        self.slp.expire_services()
        location = self.slp.locate("foo_service")
        assert location == ""


# Find a Highest-Scoring Alignment of Two Strings
import sys

from textbook_track.resources.utils import read_scoring_matrix

def collect_global_alignment(backtrack, string1, string2):
    ix = len(string1)
    jy = len(string2)
    aligned = []
    while ix > 0 or jy > 0:
        if ix == 0:
            aligned.append(('-', string2[jy-1]))
            jy -= 1
        elif jy == 0:
            aligned.append((string1[ix-1], '-'))
            ix -= 1
        elif backtrack[ix-1][jy-1] == 0:
            aligned.append((string1[ix-1], string2[jy-1]))
            ix -= 1
            jy -= 1
        elif backtrack[ix-1][jy-1] == -1:
            aligned.append((string1[ix-1], '-'))
            ix -= 1
        else:
            aligned.append(('-', string2[jy-1]))
            jy -= 1

    return map(''.join, zip(*aligned[::-1]))

def calc_global_alignment(string1, string2, scoring_matrix, sigma):
    n = len(string1)
    m = len(string2)
    longest_path = [[0] * (m+1) for _ in range(n+1)]
    backtrack = [[0] * m for _ in range(n)]
    for ix in range(1, n+1):
        longest_path[ix][0] = -ix * sigma
    for jy in range(1, m+1):
        longest_path[0][jy] = -jy * sigma

    for ix, c1 in enumerate(string1):
        for jy, c2 in enumerate(string2):
            deletion = longest_path[ix][jy+1] - sigma
            insertion = longest_path[ix+1][jy] - sigma
            match = longest_path[ix][jy] + scoring_matrix[(c1, c2)]
            longest_path[ix+1][jy+1] = max(insertion, deletion, match)

            if longest_path[ix+1][jy+1] == deletion:
                backtrack[ix][jy] = -1
            elif longest_path[ix+1][jy+1] == insertion:
                backtrack[ix][jy] = 1

    aligned_string1, aligned_string2 = collect_global_alignment(backtrack, string1, string2)
    return longest_path[n][m], aligned_string1, aligned_string2

def main():
    data = sys.stdin.read().splitlines()
    string1 = data[0]
    string2 = data[1]
    blosum62 = read_scoring_matrix('BLOSUM62')
    sigma = 5
    score, aligned_string1, aligned_string2 = calc_global_alignment(string1, string2, blosum62, sigma)
    print(score)
    print(aligned_string1)
    print(aligned_string2)

if __name__ == '__main__':
    main()


from .blocks import ParameterBlock, CompartmentBlock, ObservableBlock
from .blocks import SpeciesBlock, MoleculeTypeBlock
from .blocks import FunctionBlock, RuleBlock
from .blocks import EnergyPatternBlock, PopulationMapBlock

from .pattern import Pattern, Molecule, Component

from .rulemod import RuleMod

###### Base object  ######
class XMLObj:
    """
    Base object that contains XMLs that is the parent of
    all XML object that will be used for BNGL blocks as
    we read from BNGXML. This sets up the python internals
    such as __repr__ and __str__ for the rest of the XML
    classes.

    This base class assumes at least two methods will be
    defined by each class that inherits this base object
    which are defined in the methods below.

    Attributes
    ----------
    xml : list/OrderedDict
        XML loaded via xmltodict to be parsed. Either a
        list of items or an OrderedDict.
    parsed_obj : obj
        appropriate parsed object, one of the Block objects

    Methods
    -------
    resolve_xml(xml)
        the method that parses the XML given and is written
        separately for each subclass of this one
    gen_string()
        the method to generate the string from the parsed
        object
    """

    def __init__(self, xml):
        self.xml = xml
        self.parsed_obj = self.parse_xml(self.xml)

    def __repr__(self):
        return self.gen_string()

    def __str__(self):
        return self.gen_string()

    def gen_string(self):
        return str(self.parsed_obj)

    def parse_xml(self, xml):
        """ """
        raise NotImplementedError

###### Fundamental parsing objects ######
# This is for handling bond XMLs
class BondsXML:
    """
    Bonds XML parser, derived from XMLObj.
    """

    def __init__(self, bonds_xml=None):
        self.bonds_dict = {}
        if bonds_xml is not None:
            self.resolve_xml(bonds_xml)

    def set_xml(self, bonds_xml):
        self.resolve_xml(bonds_xml)

    def get_bond_id(self, comp):
        # Get the ID of the bond from an XML id something
        # belongs to, e.g. O1_P1_M1_C2
        num_bonds = comp["@numberOfBonds"]
        comp_id = comp["@id"]
        try:
            num_bonds = int(num_bonds)
        except:
            # This means we have something like +/?
            return num_bonds
        # use the comp_id to find the bond index from
        # self.bonds_dict
        comp_key = self.get_tpl_from_id(comp_id)
        bond_id = self.bonds_dict[comp_key]
        return bond_id

    def get_tpl_from_id(self, id_str):
        # ID str is looking like O1_P1_M2_C3
        # we are going to assume a 4-tuple per key
        id_list = id_str.split("_")
        id_tpl = tuple(id_list)
        return id_tpl

    def tpls_from_bond(self, bond):
        s1 = bond["@site1"]
        s2 = bond["@site2"]
        id_list_1 = s1.split("_")
        s1_tpl = tuple(id_list_1)
        id_list_2 = s2.split("_")
        s2_tpl = tuple(id_list_2)
        return (s1_tpl, s2_tpl)

    def resolve_xml(self, bonds_xml):
        # self.bonds_dict is a dictionary you can key
        # with the tuple taken from the ID and then
        # get a bond ID cleanly
        if isinstance(bonds_xml, list):
            for ibond, bond in enumerate(bonds_xml):
                bond_partner_1, bond_partner_2 = self.tpls_from_bond(bond)
                if bond_partner_1 not in self.bonds_dict:
                    self.bonds_dict[bond_partner_1] = [ibond + 1]
                else:
                    self.bonds_dict[bond_partner_1].append([ibond + 1])
                if bond_partner_2 not in self.bonds_dict:
                    self.bonds_dict[bond_partner_2] = [ibond + 1]
                else:
                    self.bonds_dict[bond_partner_2].append(ibond + 1)
        else:
            bond_partner_1, bond_partner_2 = self.tpls_from_bond(bonds_xml)
            self.bonds_dict[bond_partner_1] = [1]
            self.bonds_dict[bond_partner_2] = [1]

# The full pattern parser
class PatternXML(XMLObj):
    """
    Pattern XML parser, derived from XMLObj.

    Methods
    -------
    _process_mol(xml)
        processes a molecule XML dictionary and returns
        a Molecule object
    _process_comp(self, xml)
        processes a component XML dictionary and returns
        a list of Compartment objects
    """

    def __init__(self, xml) -> None:
        super().__init__(xml)

    def parse_xml(self, xml) -> Pattern:
        # initialize
        pattern = Pattern()
        if "ListOfBonds" in xml:
            # TODO: FIX THIS
            bonds = BondsXML(xml["ListOfBonds"]["Bond"])
            pattern._bonds = bonds
            self._bonds = bonds
        else:
            bonds = BondsXML()
            pattern._bonds = bonds
            self._bonds = bonds
        # check for compartment and add if exists
        if "@compartment" in xml:
            pattern.compartment = xml["@compartment"]
        # check for label and add if exists
        if "@label" in xml:
            pattern.label = xml["@label"]
        # check to see if pattern is fixed
        if "@Fixed" in xml:
            if xml["@Fixed"] == "1":
                pattern.fixed = True
        # check to see if pattern is only matched once
        if "@matchOnce" in xml:
            if xml["@matchOnce"] == "1":
                pattern.MatchOnce = True
        # check for relation & quantity, add if exist
        if ("@relation" in xml) and ("@quantity" in xml):
            relation = xml["@relation"]
            quantity = xml["@quantity"]
            pattern.relation = relation
            try:
                n = int(quantity)
                f = float(quantity)
                if n == f:
                    pattern.quantity = quantity
            except ValueError as e:
                print("Quantity needs to be an integer")
        # check for either list of molecules or single molecule, add if exist
        mols = xml["ListOfMolecules"]["Molecule"]
        molecules = []
        if isinstance(mols, list):
            # list of molecules
            for imol, mol in enumerate(mols):
                mol_obj = self._process_mol(mol)
                molecules.append(mol_obj)
        else:
            # a single molecule
            mol_obj = self._process_mol(mols)
            molecules.append(mol_obj)
        pattern.molecules = molecules
        # return a complete pattern object
        return pattern

    def _process_mol(self, xml) -> Molecule:
        """ """
        # initialize
        molecule = Molecule()
        #
        if "@name" in xml:
            molecule.name = xml["@name"]
        #
        if "@label" in xml:
            molecule.label = xml["@label"]
        #
        if "@compartment" in xml:
            molecule.compartment = xml["@compartment"]
        #
        if "ListOfComponents" in xml:
            # Single molecule can't have bonds
            molecule.components = self._process_comp(
                xml["ListOfComponents"]["Component"]
            )
        #
        return molecule

    def _process_comp(self, xml) -> list:
        # bonds = compartment id, bond id
        # comp xml can be a list or a dict
        comp_list = []
        if isinstance(xml, list):
            # we have multiple and this is a list
            for icomp, comp in enumerate(xml):
                component = Component()
                component.name = comp["@name"]
                if "@label" in comp:
                    component.label = comp["@label"]
                if "@state" in comp:
                    component.state = comp["@state"]
                if comp["@numberOfBonds"] != "0":
                    # DEBUG
                    bond_id = self._bonds.get_bond_id(comp)
                    for bi in bond_id:
                        component.bonds.append(bi)
                comp_list.append(component)
        else:
            # single comp, this is a dict
            component = Component()
            component.name = xml["@name"]
            if "@label" in xml:
                component.label = xml["@label"]
            if "@state" in xml:
                component.state = xml["@state"]
            if xml["@numberOfBonds"] != "0":
                bond_id = self._bonds.get_bond_id(xml)
                for bi in bond_id:
                    component.bonds.append(bi)
            comp_list.append(component)
        return comp_list

# Helper parser for pattern list (for observables)
class PatternListXML:
    """
    Pattern list XML parser. Takes a list of patterns
    and parses them using PatternXML and generates a
    list of patterns.

    Attributes
    ----------
    patterns : list[Pattern]
        list of patterns parsed from the XML dict list
    """

    def __init__(self, xml) -> None:
        self.patterns = self.parse_xml(xml)

    def parse_xml(self, xml) -> list:
        pats = xml["Pattern"]
        patterns = []
        if isinstance(pats, list):
            # we have multiple patterns so this is a list
            for ipattern, pattern in enumerate(pats):
                patterns.append(PatternXML(pattern).parsed_obj)
        else:
            patterns.append(PatternXML(pats).parsed_obj)
        return patterns

###### Parsers ######
class ParameterBlockXML(XMLObj):
    """
    PatternBlock XML parser, derived from XMLObj. Creates
    a ParameterBlock that contains the parameters parsed.
    """

    def __init__(self, xml) -> None:
        super().__init__(xml)

    def parse_xml(self, xml) -> ParameterBlock:
        # make block
        block = ParameterBlock()
        # parse parameters
        if isinstance(xml, list):
            for b in xml:
                # add content to line
                name = b["@id"]
                value = b["@value"]
                expression = None
                if "@expr" in b:
                    expression = b["@expr"]
                block.add_parameter(name, value, expr=expression)
        else:
            # add content to line
            name = xml["@id"]
            value = xml["@value"]
            expression = None
            if "@expr" in xml:
                expression = xml["@expr"]
            # add to list of lines
            block.add_parameter(name, value, expr=expression)
        block.reset_compilation_tags()
        return block

#
class CompartmentBlockXML(XMLObj):
    """
    CompartmentBlock XML parser, derived from XMLObj. Creates
    a CompartmentBlock that contains the compartments parsed.
    """

    def __init__(self, xml) -> None:
        super().__init__(xml)

    def parse_xml(self, xml):
        block = CompartmentBlock()

        if isinstance(xml, list):
            for comp in xml:
                cname = comp["@id"]
                dim = comp["@spatialDimensions"]
                size = comp["@size"]
                outside = None
                if "@outside" in comp:
                    outside = comp["@outside"]
                block.add_compartment(cname, dim, size, outside=outside)
        else:
            cname = xml["@id"]
            dim = xml["@spatialDimensions"]
            size = xml["@size"]
            outside = None
            if "@outside" in xml:
                outside = xml["@outside"]
            block.add_compartment(cname, dim, size, outside=outside)

        block.reset_compilation_tags()
        return block

#
class ObservableBlockXML(XMLObj):
    """
    ObservableBlock XML parser, derived from XMLObj. Creates
    an ObservableBlock that contains the observables parsed.
    """

    def __init__(self, xml) -> None:
        super().__init__(xml)

    def parse_xml(self, xml) -> ObservableBlock:
        #
        block = ObservableBlock()
        #
        if isinstance(xml, list):
            for b in xml:
                name = b["@name"]
                otype = b["@type"]
                patterns = PatternListXML(b["ListOfPatterns"]).patterns
                block.add_observable(name, otype, patterns)
        else:
            name = xml["@name"]
            otype = xml["@type"]
            patterns = PatternListXML(xml["ListOfPatterns"]).patterns
            block.add_observable(name, otype, patterns)
        #
        return block

#
class SpeciesBlockXML(XMLObj):
    """
    SpeciesBlock XML parser, derived from XMLObj. Creates
    a SpeciesBlock that contains the species parsed.
    """

    def __init__(self, xml):
        super().__init__(xml)

    def parse_xml(self, xml):
        block = SpeciesBlock()

        if isinstance(xml, list):
            # we have multiple patterns so this is a list
            for ispec, spec in enumerate(xml):
                pattern = PatternXML(spec)
                count = spec["@concentration"]
                block.add_species(pattern, count)
        else:
            pattern = PatternXML(xml)
            count = xml["@concentration"]
            block.add_species(pattern, count)

        return block

#
class MoleculeTypeBlockXML(XMLObj):
    """
    MoleculeTypeBlock XML parser, derived from XMLObj. Creates
    a MoleculeTypeBlock that contains the molecule types parsed.

    Methods
    -------
    add_molecule_type_to_block(block,xml)
        parses the XML to create a MoleculeType object and
        adds it to a given MoleculeTypeBlock object
    """

    def __init__(self, xml):
        super().__init__(xml)

    def parse_xml(self, xml):
        block = MoleculeTypeBlock()
        #
        if isinstance(xml, list):
            for md in xml:
                self.add_molecule_type_to_block(block, md)
        else:
            self.add_molecule_type_to_block(block, xml)
        #
        return block

    def add_molecule_type_to_block(self, block, xml):
        name = xml["@id"]
        components = []
        if "ListOfComponentTypes" in xml:
            comp_obj = Component()
            comp_dict = xml["ListOfComponentTypes"]["ComponentType"]
            if "@id" in comp_dict:
                comp_obj.name = comp_dict["@id"]
                if "ListOfAllowedStates" in comp_dict:
                    # we have states
                    al_states = comp_dict["ListOfAllowedStates"]["AllowedState"]
                    if isinstance(al_states, list):
                        for istate, state in enumerate(al_states):
                            comp_obj.states.append(state["@id"])
                    else:
                        comp_obj.states.append(al_states["@id"])
                components.append(comp_obj)
            else:
                # multiple components
                for icomp, comp in enumerate(comp_dict):
                    comp_obj = Component()
                    comp_obj.name = comp["@id"]
                    if "ListOfAllowedStates" in comp:
                        # we have states
                        al_states = comp["ListOfAllowedStates"]["AllowedState"]
                        if isinstance(al_states, list):
                            for istate, state in enumerate(al_states):
                                comp_obj.states.append(state["@id"])
                        else:
                            comp_obj.states.append(al_states["@id"])
                    components.append(comp_obj)
        block.add_molecule_type(name, components)

class FunctionBlockXML(XMLObj):
    # TODO for some reason the resolve_xml doesn't set the full
    # function string and it's also not used downstream.

    """
    FunctionBlock XML parser, derived from XMLObj. Creates
    a FunctionBlock that contains the functions parsed.

    Methods
    -------
    get_arguments(xml)
        parses the argument list XML and returns a list of
        argument names
    """

    def __init__(self, xml):
        super().__init__(xml)

    def parse_xml(self, xml):
        block = FunctionBlock()
        #
        if isinstance(xml, list):
            for f in xml:
                # add content to line
                fname = f["@id"]
                expr = f["Expression"]
                args = []
                if "ListOfArguments" in f:
                    args = self.get_arguments(f["ListOfArguments"]["Argument"])
                #
                block.add_function(fname, expr, args=args)
        else:
            fname = xml["@id"]
            expr = xml["Expression"]
            args = []
            if "ListOfArguments" in xml:
                args = self.get_arguments(xml["ListOfArguments"]["Argument"])
            #
            block.add_function(fname, expr, args=args)

        return block

    def get_arguments(self, xml) -> list:
        args = []
        if isinstance(xml, list):
            for arg in xml:
                args.append(arg["@id"])
            return args
        else:
            return [xml["@id"]]

class RuleBlockXML(XMLObj):
    """
    RuleBlock XML parser, derived from XMLObj. Creates
    a RuleBlock that contains the rules parsed.

    Methods
    -------
    resolve_ratelaw(xml)
        parses a rate law XML and returns the rate constant
    resolve_rxn_side(xml)
        parses either reactants or products XML and returns
        a list of Pattern objects
    get_operations(xml)
        creates and populates a list of operations and their arguments
    get_rule_mod(xml)
        stores rule modifier used by a given rule as a string
    """

    def __init__(self, xml):
        self.bidirectional = False
        super().__init__(xml)

    def parse_xml(self, xml):
        block = RuleBlock()

        # check for multiple rules and parse each one
        if isinstance(xml, list):
            for irule, rule in enumerate(xml):
                name = rule["@name"]
                reactants = self.resolve_rxn_side(rule["ListOfReactantPatterns"])
                products = self.resolve_rxn_side(rule["ListOfProductPatterns"])
                if "RateLaw" not in rule:
                    print(
                        "Rule seems to be missing a rate law, please make sure that XML exporter of BNGL supports whatever you are doing!"
                    )
                rate_constants = [self.resolve_ratelaw(rule["RateLaw"])]
                rule_modifier = self.get_rule_mod(rule)
                if rule["ListOfOperations"] is not None:
                    if len(rule["ListOfOperations"]) > 0:
                        operations = self.get_operations(rule["ListOfOperations"])

                block.add_rule(
                    name,
                    reactants=reactants,
                    products=products,
                    rate_constants=rate_constants,
                    rule_mod=rule_modifier,
                    operations=operations,
                )
        else:
            name = xml["@name"]
            reactants = self.resolve_rxn_side(xml["ListOfReactantPatterns"])
            products = self.resolve_rxn_side(xml["ListOfProductPatterns"])
            if "RateLaw" not in xml:
                print(
                    "Rule seems to be missing a rate law, please make sure that XML exporter of BNGL supports whatever you are doing!"
                )
            rate_constants = [self.resolve_ratelaw(xml["RateLaw"])]
            rule_modifier = self.get_rule_mod(xml)
            operations = self.get_operations(xml["ListOfOperations"])

            block.add_rule(
                name,
                reactants=reactants,
                products=products,
                rate_constants=rate_constants,
                rule_mod=rule_modifier,
                operations=operations,
            )
        block.consolidate_rules()
        return block

    def resolve_ratelaw(self, xml):
        rate_type = xml["@type"]
        if rate_type == "Ele":
            rate_cts_xml = xml["ListOfRateConstants"]
            rate_cts = rate_cts_xml["RateConstant"]["@value"]
        elif rate_type == "Function":
            rate_cts = xml["@name"]
        elif (
            rate_type == "MM"
            or rate_type == "Sat"
            or rate_type == "Hill"
            or rate_type == "Arrhenius"
        ):
            # A function type
            rate_cts = rate_type + "("
            args = xml["ListOfRateConstants"]["RateConstant"]
            if isinstance(args, list):
                for iarg, arg in enumerate(args):
                    if iarg > 0:
                        rate_cts += ","
                    rate_cts += arg["@value"]
            else:
                rate_cts += args["@value"]
            rate_cts += ")"
        else:
            print("don't recognize rate law type")
        return rate_cts

    def resolve_rxn_side(self, xml):
        # this is either reactant or product
        if xml is None:
            return [Molecule()]
        elif "ReactantPattern" in xml:
            # this is a lhs/reactant side
            sl = []
            side = xml["ReactantPattern"]
            if "@compartment" in side:
                self.react_comp = side["@compartment"]
            else:
                self.react_comp = None
            if isinstance(side, list):
                # this is a list of reactant patterns
                for ireact, react in enumerate(side):
                    sl.append(PatternXML(react).parsed_obj)
            else:
                sl.append(PatternXML(side).parsed_obj)
            return sl
        elif "ProductPattern" in xml:
            # rhs/product side
            side = xml["ProductPattern"]
            sl = []
            if "@compartment" in side:
                self.prod_comp = side["@compartment"]
            else:
                self.prod_comp = None
            if isinstance(side, list):
                # this is a list of product patterns
                for iprod, prod in enumerate(side):
                    sl.append(PatternXML(prod).parsed_obj)
            else:
                sl.append(PatternXML(side).parsed_obj)
            return sl
        else:
            print("Can't parse rule XML {}".format(xml))

    def get_operations(self, xml):
        # TODO: create working operations class
        ops = []
        # List all possible operations & arguments
        ops_types = [
            "AddBond",
            "DeleteBond",
            "ChangeCompartment",
            "StateChange",
            "Add",
            "Delete",
        ]
        op_args = [
            "@site1",
            "@site2",
            "@id",
            "@source",
            "@destination",
            "@flipOrientation",
            "@moveConnected",
            "@site",
            "@finalState",
            "@DeleteMolecules",
        ]
        # Loop through valid arguments and record
        for op_type in ops_types:
            if op_type in xml:
                for op_arg in op_args:
                    if op_arg in xml:
                        n_op = xml[op_arg]
                        ops.append(n_op)
        return ops

    def get_rule_mod(self, xml):
        # TODO: create working rule mods class
        rule_mod = RuleMod()
        list_ops = xml["ListOfOperations"]
        if list_ops is None:
            return None
        # determine which rule mod is being used, if any
        if "Delete" in list_ops:
            del_op = list_ops["Delete"]
            # check if modifier was called or automatic
            if not isinstance(del_op, list):
                mod_call = del_op["@DeleteMolecules"]
                if mod_call == "1":
                    # get mod information & add to string
                    rule_mod.type = "DeleteMolecules"
                    rule_mod.id = del_op["@id"]
        elif "ChangeCompartment" in list_ops:
            move_op = list_ops["ChangeCompartment"]
            if not isinstance(move_op, list):
                # get mod information & add to string
                mod_call = move_op["@moveConnected"]
                # check if modifier was called or automatic
                if mod_call == "1":
                    rule_mod.type = "MoveConnected"
                    rule_mod.id = move_op["@id"]
                    rule_mod.source = move_op["@source"]
                    rule_mod.destination = move_op["@destination"]
                    rule_mod.flip = move_op["@flipOrientation"]
                    rule_mod.call = mod_call
            else:
                rule_mod.id = []
                rule_mod.source = []
                rule_mod.destination = []
                rule_mod.flip = []
                rule_mod.call = []
                for mo in move_op:
                    if mo["@moveConnected"] == "1":
                        rule_mod.type = "MoveConnected"
                        rule_mod.id.append(move_op["@id"])
                        rule_mod.source.append(move_op["@source"])
                        rule_mod.destination.append(move_op["@destination"])
                        rule_mod.flip.append(move_op["@flipOrientation"])
                        rule_mod.call.append(mo["@moveConnected"])
        elif "RateLaw" in xml:
            # check if modifier is called
            ratelaw = xml["RateLaw"]
            rate_type = ratelaw["@type"]
            if rate_type == "Function" and ratelaw["@totalrate"] == 1:
                rule_mod.type = "TotalRate"
                rule_mod.id = ratelaw["@id"]
                rule_mod.rate_type = ratelaw["@type"]
                rule_mod.name = ratelaw["@name"]
                rule_mod.call = ratelaw["@totalrate"]

        # TODO: add support for include/exclude reactants/products
        if (
            "ListOfIncludeReactants" in xml
            or "ListOfIncludeProducts" in xml
            or "ListOfExcludeReactants" in xml
            or "ListOfExcludeProducts" in xml
        ):
            print(
                "WARNING: Include/Exclude Reactants/Products not currently supported as rule modifiers"
            )
        return rule_mod

class EnergyPatternBlockXML(XMLObj):
    """
    EnergyPatternBlock XML parser, derived from XMLObj. Creates
    an EnergyPatternBlock that contains the energy patterns parsed.
    """

    def __init__(self, xml):
        super().__init__(xml)

    def parse_xml(self, xml):
        block = EnergyPatternBlock()

        if isinstance(xml, list):
            for b in xml:
                # get id & expression
                epid = b["@id"]
                expr = b["@expression"]
                # get pattern
                pattern_node = b["Pattern"]
                pattern = PatternXML(pattern_node).parsed_obj
                block.add_energy_pattern(epid, pattern, expr)
        else:
            # get id & expression
            epid = xml["@id"]
            expr = xml["@expression"]
            # get pattern
            pattern_node = xml["Pattern"]
            pattern = PatternXML(pattern_node).parsed_obj
            block.add_energy_pattern(epid, pattern, expr)

        return block

class PopulationMapBlockXML(XMLObj):
    """
    PopulationMapBlock XML parser, derived from XMLObj. Creates
    a PopulationMapBlock that contains the population maps parsed.

    Methods
    -------
    resolve_ratelaw(xml)
        parses a rate law XML and returns the rate constant
    """

    def __init__(self, xml):
        super().__init__(xml)

    def parse_xml(self, xml):
        block = PopulationMapBlock()

        if isinstance(xml, list):
            for b in xml:
                # get id
                pmid = b["@id"]
                # get structured species
                struct_spec_node = b["StructuredSpecies"]
                spec_node = struct_spec_node["Species"]
                struct_spec = PatternXML(spec_node).parsed_obj
                # get population species
                pop_spec_node = b["PopulationSpecies"]
                pop_node = pop_spec_node["Species"]
                pop_spec = PatternXML(pop_node).parsed_obj
                # get rate law
                rate_constant = self.resolve_ratelaw(b["RateLaw"])
                block.add_population_map(pmid, struct_spec, pop_spec, rate_constant)
        else:
            # get id
            pmid = xml["@id"]
            # get structured species
            struct_spec_node = xml["StructuredSpecies"]
            spec_node = struct_spec_node["Species"]
            struct_spec = PatternXML(spec_node).parsed_obj
            # get population species
            pop_spec_node = xml["PopulationSpecies"]
            pop_node = pop_spec_node["Species"]
            pop_spec = PatternXML(pop_node).parsed_obj
            # get rate law
            rate_constant = self.resolve_ratelaw(xml["RateLaw"])
            block.add_population_map(pmid, struct_spec, pop_spec, rate_constant)

        return block

    def resolve_ratelaw(self, xml):
        rate_type = xml["@type"]
        if rate_type == "Ele":
            rate_cts_xml = xml["ListOfRateConstants"]
            rate_cts = rate_cts_xml["RateConstant"]["@value"]
        elif rate_type == "Function":
            rate_cts = xml["@name"]
        elif (
            rate_type == "MM"
            or rate_type == "Sat"
            or rate_type == "Hill"
            or rate_type == "Arrhenius"
        ):
            # A function type
            rate_cts = rate_type + "("
            args = xml["ListOfRateConstants"]["RateConstant"]
            if isinstance(args, list):
                for iarg, arg in enumerate(args):
                    if iarg > 0:
                        rate_cts += ","
                    rate_cts += arg["@value"]
            else:
                rate_cts += args["@value"]
            rate_cts += ")"
        else:
            print("don't recognize rate law type")
        return rate_cts

# TODO: Store operations!
class Operation:
    """
    To be used for parsing & storing ListOfOperations information.
    """

    # valid operation types
    valid_ops = [
        "AddBond",
        "DeleteBond",
        "ChangeCompartment",
        "StateChange",
        "Add",
        "Delete",
    ]


import cv2
import numpy as np
import stack

cap = cv2.VideoCapture('drone.mp4')
frame_width = 640
frame_height = 480

# minimum
min_width_rect = 80
min_height_rect = 80

# Count line position
count_line_position = 300

# INITIALIZE Substracts
algo = cv2.createBackgroundSubtractorMOG2()

# saving video
result = cv2.VideoWriter('filename.avi',
                         cv2.VideoWriter_fourcc(*'MJPG'),
                         30, (640, 480))

def center_handle(x, y, w, h):
    x1 = int(w / 2)
    y1 = int(h / 2)
    cx = x + x1
    cy = y + y1
    return cx, cy

detect = []
offset = 6
counter = 0

while True:
    sucess, img = cap.read()
    img = cv2.resize(img, (frame_width, frame_height))
    imgContour = img.copy()
    imgContour = imgContour[60:480, :]
    imgGray = cv2.cvtColor(img[60:480, :], cv2.COLOR_BGR2GRAY)
    imgBlur = cv2.GaussianBlur(imgGray, (3, 3), 5)
    imgEdge = cv2.Canny(imgGray, 100, 100)
    contours, hierarchy = cv2.findContours(imgEdge, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # # applying on each frame
    # imgSub = algo.apply(imgBlur)
    #
    # imgDilate = cv2.dilate(imgSub, np.ones((5, 5)))
    # kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    # dilate = cv2.morphologyEx(imgDilate, cv2.MORPH_CLOSE, kernel)
    # dilate = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel)
    # imgContour, h = cv2.findContours(dilate, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    #
    # line
    cv2.line(img, (25, count_line_position), (600, count_line_position), (255, 255, 0), 1)

    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area > 490:
            # cv2.drawContours(imgContour, cnt, -1, (255, 0, 255), 2)  # 7width of boundary
            # to get corner points of our shape object
            para = cv2.arcLength(cnt, True)  # true for closed contours
            # to approximate the points to get what shape is this
            approx = cv2.approxPolyDP(cnt, 0.02 * para, True)  # 0.02*para = resolution
            print(len(approx))  # here we get ex:4 it indicates it is square or rectangle
            objCor = len(approx)
            x, y, w, h = cv2.boundingRect(approx)
            cv2.rectangle(img[60:480, :], (x, y), (x + w, y + h), (0, 90, 255), 1)
            center = center_handle(x, y, w, h)
            detect.append(center)
            cv2.circle(img[60:480, :], center, 4, (0, 0, 255), -1)

            for (x, y) in detect:
                if y<(count_line_position + offset) and y>(count_line_position - offset):
                    counter += 1
                cv2.line(imgContour, (25, count_line_position), (600, count_line_position), (0, 255, 255), 2)
                detect.remove((x, y))
                print("Vechile Count: ", str(counter))
                cv2.putText(img, str(counter), (x-30, y + 30), cv2.FONT_HERSHEY_PLAIN, 1, (204, 153, 255), 2)

    cv2.putText(img,  str(counter), (550, 50), cv2.FONT_HERSHEY_DUPLEX, 1, (0, 100, 255), 2)
    cv2.putText(img,  'Gowtham R', (280, 40), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 100, 255), 2)

    result.write(img)
    # cv2.imshow("Image", imgContour)
    cv2.imshow("CarCounter", img)
    # imgStack = stack.stackImages(([img], [imgContour]), 0.3)

    if cv2.waitKey(30) and 0xFF == ord('q'):
            break

cap.release()
result.release()
cv2.destroyAllWindows()


mod = 998244353
memo_max = 3 * 10 ** 5
fact = [1] * memo_max
inv = [1] * memo_max
f_inv = [1] * memo_max
for i in range(2, memo_max):
    fact[i] = fact[i - 1] * i % mod
    inv[i] = mod - inv[mod % i] * (mod // i) % mod
    f_inv[i] = f_inv[i - 1] * inv[i] % mod

def P(n, r):
    if n < r:
        return 0
    else:
        return fact[n] * f_inv[n-r] % mod

def C(n, r):
    if n < r:
        return 0
    else:
        return (fact[n] * f_inv[r] % mod) * f_inv[n-r] % mod

def main():

    n, m, k = map(int, input().split())
    gl = [[] for _ in range(n)]
    for _ in range(m):
        u, v = map(int, input().split())
        gl[u-1].append(v-1)
        gl[v-1].append(u-1)
    oddlen = len([1 for ll in gl if len(ll) % 2 == 1])
    evenlen = n - oddlen
    ct = 0
    i = 0
    while i * 2 <= k:
        k_even = k - i * 2
        k_odd = i * 2
        ct += C(evenlen, k_even) * C(oddlen, k_odd)
        ct %= mod
        i += 1
    print(ct)

if __name__ == '__main__':
    main()


from news.models import *

# пишем статьи
NEWS1_HEADER ='Дефицит бюджета'
NEWS1_TEXT = 'Дефицит бюджета РФ достиг максимальных показателей: он уже больше,' \
             ' чем дефицит за весь прошлый год'

NEWS2_HEADER = 'Долги россиян'
NEWS2_TEXT = 'Россияне задолжали по кредитам 2 трлн рублей. «Проблема не то что' \
             ' актуальна, она суперкрайне актуальна», — заявил директор' \
             ' Федеральной службы судебных приставов. Сейчас у ведомства' \
             ' в работе 12 млн документов с просрочками по оплате.'

ARTICLE1_HEADER = 'Информационная служба Хабра посетила первый день ' \
                  'конференция «Тема Еды»'
ARTICLE1_TEXT = 'На конференции выступал руководитель аналитики «Яндекс Еды» ' \
                'и Delivery Club Роман Халкечев. В своём докладе он рассказал,' \
                ' как локдаун ускорил развитие доставки готовой еды и продуктов,' \
                ' что снятия ограничений не уменьшило популярность доставки. ' \
                'По словам Халчкевича, количество заказов из ресторанов в ' \
                '«Яндекс Еде» среди пользователей из Москвы с 2019 выросло в ' \
                '2,5, Санкт‑Петербурга — в 5,5 раз. Остальные регионы по ' \
                'доставке из ресторанов растут с того же периода значительно ' \
                'больше — в 16 раз. Больше половины заказов готовой еды в ' \
                '«Яндекс Еде» приходятся на регионы, в 2019 году этот показатель' \
                ' составлял 20%. По данным компании, треть жителей Москвы, ' \
                'Санкт‑Петербурга и Казани хотя бы раз заказывал еду из ' \
                'ресторанов с доставкой в прошлом году. Сейчас в сервисах ' \
                '«Яндекс Еда» и Delivery Clu используются технологии машинного ' \
                'обучения. С их помощью популярные сочетания позиций и на ' \
                'стадии оформления заказа предлагают пользователю дополнить' \
                ' заказ. В некоторых регионах идёт тест улучшения изображений' \
                ' блюд с помощью генеративных нейросетей. Кроме того, компания' \
                ' представила топ-3 фактора, влияющих на выбор ресторана среди' \
                ' пользователей — это скорость доставки в 66%, стоимость' \
                ' доставки в 65% и рейтинг заведения в 57%.'

ARTICLE2_HEADER = 'Memo (FMX)'
ARTICLE2_TEXT = 'Модифицировал штатный Memo (FMX) для добавления возможности' \
                ' форматирования текста. А также, ускорил его работу в разных' \
                ' аспектах (прокрутка, выделение, вставка строк и т.д.)' \
                ' Актуально для Delphi 11.3 (на более ранних, скорее всего,' \
                ' работать не будет, т.к. внесены изменения в штатный модуль' \
                ' FMX.Memo.Style.pas, который может быть несовместим между' \
                ' версиями. Модуль находится рядом с проектом).'

# вводим данные
User.objects.create_user('Bасильев Василий')
User.objects.create_user('Иванов Иван')
User.objects.create_user('Петров Петр')
User.objects.create_user('Просто Федя')
User.objects.create_user('Пушкин')

Author.objects.create(user=User.objects.get(pk=1), nick_name='Черный плащ')
Author.objects.create(user=User.objects.get(pk=2), nick_name='Чип не Дейл')
Author.objects.create(user=User.objects.get(username='Пушкин'), nick_name='Много пишу')
Author.objects.create(user=User.objects.get(username='Просто Федя'))

Category.objects.create(category='Политика')
Category.objects.create(category='Философия')
Category.objects.create(category='Экономика')
Category.objects.create(category='Как я провел лето')

Post.objects.create(author=Author.objects.get(nick_name='Черный плащ'),
                    post_type=Post.NEWS,
                    header=NEWS1_HEADER, text=NEWS1_TEXT)
Post.objects.create(author=Author.objects.get(nick_name='Чип не Дейл'),
                     post_type=Post.NEWS,
                     header=NEWS2_HEADER, text=NEWS2_TEXT)
Post.objects.create(author=Author.objects.get(nick_name='Много пишу'),
                     post_type=Post.NEWS,
                     header=ARTICLE1_HEADER, text=ARTICLE1_TEXT)
Post.objects.create(author=Author.objects.get(nick_name='Много пишу'),
                     post_type=Post.NEWS,
                     header=ARTICLE2_HEADER, text=ARTICLE2_TEXT)

Post.objects.get(pk=1).category.add(Category.objects.get(pk=2))
Post.objects.get(pk=1).category.add(Category.objects.get(pk=3))
Post.objects.get(pk=1).category.add(Category.objects.get(pk=1))
Post.objects.get(pk=2).category.add(Category.objects.get(pk=2))
Post.objects.get(pk=2).category.add(Category.objects.get(pk=3))
Post.objects.get(pk=3).category.add(Category.objects.get(pk=4))
Post.objects.get(pk=4).category.add(Category.objects.get(pk=4))

Comment.objects.create(post=Post.objects.get(pk=1),
                       user=User.objects.get(username='Просто Федя'),
                       comment_text='Первый')
Comment.objects.create(post=Post.objects.get(pk=2),
                       user=User.objects.get(username='Просто Федя'),
                       comment_text='Первый')
Comment.objects.create(post=Post.objects.get(pk=3),
                       user=User.objects.get(username='Просто Федя'),
                       comment_text='Первый')
Comment.objects.create(post=Post.objects.get(pk=4),
                       user=User.objects.get(username='Просто Федя'),
                       comment_text='Первый')
Comment.objects.create(post=Post.objects.get(pk=3),
                       user=User.objects.get(username='Пушкин'),
                       comment_text='Мало русского языка')
Comment.objects.create(post=Post.objects.get(pk=4),
                       user=User.objects.get(username='Пушкин'),
                       comment_text='Мало русского языка')
Comment.objects.create(post=Post.objects.get(pk=1),
                       user=User.objects.get(username='Иванов Иван'),
                       comment_text='Фу...не интересно')
Comment.objects.create(post=Post.objects.get(pk=2),
                       user=User.objects.get(username='Васильев Василий'),
                       comment_text='Актуальненько')
Comment.objects.create(post=Post.objects.get(pk=3),
                       user=User.objects.get(username='Васильев Василий'),
                       comment_text='Скучно')
Comment.objects.create(post=Post.objects.get(pk=4),
                       user=User.objects.get(username='Bасильев Василий'),
                       comment_text='Еще скучнее')
Comment.objects.create(post=Post.objects.get(pk=1),
                       user=User.objects.get(username='Иванов Иван'),
                       comment_text='Еще раз фуу')
Comment.objects.create(post=Post.objects.get(pk=2),
                       user=User.objects.get(username='Иванов Иван'),
                       comment_text='Ну не очень')

Comment.objects.get(pk=1).like()
for i in range(100):
    Comment.objects.get(pk=2).like()
Comment.objects.get(pk=1).like()
for i in Comment.objects.filter(user=User.objects.get(username='Пушкин')):
    for j in range(1356):
        i.like()
for i in range(21):
    Comment.objects.get(pk=3).like()
for i in range(9):
    Comment.objects.get(pk=11).like()
for i in range(12):
    Comment.objects.get(pk=12).dislike()
for i in Comment.objects.filter(user=User.objects.get(username='Иванов Иван')):
    for j in range(17):
        i.dislike()

for i in range(1000):
     Post.objects.get(pk=1).like()
for i in range(1340):
     Post.objects.get(pk=2).dislike()
for i in range(643):
     Post.objects.get(pk=3).like()
for i in range(643):
     Post.objects.get(pk=4).like()

# обновляем рейтинг всех авторов
for auth in  Author.objects.all():
    auth.update_rating()

# Вывести username и рейтинг лучшего пользователя
# (применяя сортировку и возвращая поля первого объекта).
Author.objects.order_by('-rating').values_list('user__username', 'rating')\
    .first()

# Вывести дату добавления, username автора, рейтинг, заголовок и превью лучшей
# статьи, основываясь на лайках/дислайках к этой статье.
Post.objects.order_by('-rating').values('creation_time__date',
                                        'author__user__username', 'rating',
                                        'header').first()

# Вывести все комментарии (дата, пользователь, рейтинг, текст) к этой статье.
Comment.objects.filter(post=Post.objects.order_by('-rating')
                       .first()).values_list('creation_time__date',
                                             'user__username', 'rating',
                                             'comment_text')


from PyQt4 import QtCore, QtGui
from gui.theme import CurrentTheme
from gui.common_widgets import QToolWindowInterface
from gui.bookmark_alias import QAliasTable, QAliasTableWidgetItem

################################################################################

class QRangeString(QtGui.QFrame):

    def __init__(self, row, parent=None):
        QtGui.QFrame.__init__(self, parent)
        self.setObjectName('RangeString')
        layout = QtGui.QVBoxLayout()
        self.groupBox = parent
        self.setLayout(layout)
        self.frame = self # hack to make qvaluelineedit happy
        self.strings = []
        self.row = row
        self.setLineEdits()

    def setLineEdits(self):
        self.setUpdatesEnabled(False)
        hl = QtGui.QHBoxLayout()

        self.lineEdit = MultiLineWidget('','String', self, multiLines=True)
        hl.addWidget(self.lineEdit)
        self.addBtn = QtGui.QToolButton()
        self.addBtn.setToolTip(self.tr("Add string"))
        self.addBtn.setIcon(CurrentTheme.ADD_STRING_ICON)
        self.addBtn.setIconSize(QtCore.QSize(16,16))
        self.connect(self.addBtn, QtCore.SIGNAL("clicked()"), self.addString)
        hl.addWidget(self.addBtn)
        hl.setSpacing(0)
        hl.setMargin(0)
        self.layout().addLayout(hl)
        self.layout().setSpacing(0)
        self.layout().setMargin(0)

        self.listWidget = QStringListWidget(self.groupBox)
        vl = QtGui.QVBoxLayout()
        vl.setSpacing(0)
        vl.setMargin(0)

        self.upBtn = QtGui.QToolButton()
        self.upBtn.setToolTip(self.tr("Move up"))
        self.upBtn.setIcon(CurrentTheme.UP_STRING_ICON)
        self.upBtn.setIconSize(QtCore.QSize(16,16))
        self.connect(self.upBtn, QtCore.SIGNAL("clicked()"), self.moveUp)
        vl.addWidget(self.upBtn)

        self.downBtn = QtGui.QToolButton()
        self.downBtn.setToolTip(self.tr("Move down"))
        self.downBtn.setIcon(CurrentTheme.DOWN_STRING_ICON)
        self.downBtn.setIconSize(QtCore.QSize(16,16))
        self.connect(self.downBtn, QtCore.SIGNAL("clicked()"), self.moveDown)
        vl.addWidget(self.downBtn)

        hl2 = QtGui.QHBoxLayout()
        hl2.setSpacing(0)
        hl2.setMargin(0)
        hl2.addWidget(self.listWidget)
        hl2.addLayout(vl)
        self.parent().layout().addLayout(hl2,self.row + 1, 1, 1, 2)

        self.setUpdatesEnabled(True)
        self.parent().adjustSize()
        if self.parent().parent().layout():
            self.parent().parent().layout().invalidate()

    def addString(self):
        if not self.lineEdit.text().isEmpty():
            slist = self.lineEdit.text().split(",",QtCore.QString.SkipEmptyParts)
            self.listWidget.addText(slist)

    def moveUp(self):
        row = self.listWidget.currentRow()
        if row > 0:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row-1,item)
            self.listWidget.setCurrentRow(row-1)

    def moveDown(self):
        row = self.listWidget.currentRow()
        if row < self.listWidget.count()-1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row+1,item)
            self.listWidget.setCurrentRow(row+1)

    def updateMethod(self):
        pass

################################################################################

class QAliasExplorationPanel(QtGui.QFrame, QToolWindowInterface):
    """
    QAliasExplorationPanel shows aliases to be explored.

    """
    def __init__(self, parent=None, manager=None):
        """ QAliasExplorationPanel(parent: QWidget, manaager: BookmarksManager)
                                                 -> QAliasExplorationPanel
        Initializes the panel and sets bookmark manager

        """
        QtGui.QFrame.__init__(self, parent)
        self.bookmarkPanel = None
        self.setFrameStyle(QtGui.QFrame.Panel|QtGui.QFrame.Sunken)
        self.manager = manager
        self.dimLabels = ['Dim %d' % (i+1) for i in xrange(4)]
        vLayout = QtGui.QVBoxLayout()
        vLayout.setSpacing(0)
        vLayout.setMargin(0)
        self.setLayout(vLayout)
        self.dimTab = QtGui.QTabWidget()
        for t in xrange(4):
            tab = QAliasDimensionWidget(manager=self.manager)
            tab.paramEx = self
            self.dimTab.addTab(tab, self.dimLabels[t]+' (1)')
            self.connect(tab.dropbox.parameters,
                         QtCore.SIGNAL("tableChanged"),
                         self.updateButton)
        vLayout.addWidget(self.dimTab)
        self.peButton = QtGui.QPushButton("Perform Exploration")
        self.peButton.setEnabled(False)
        vLayout.addWidget(self.peButton)
        if parent:
            self.bookmarkPanel = parent.bookmarkPanel
        self.connect(self.peButton, QtCore.SIGNAL('clicked()'),
                     self.startParameterExploration)
        self.setWindowTitle('Parameter Exploration')

    def updateButton(self):
        """updateButton() -> None
        enable/disable peButton according to data to be explored

        """
        enable = False
        for dim in xrange(self.dimTab.count()):
            tab = self.dimTab.widget(dim)
            if tab.dropbox.parameters.rowCount() > 0:
                enable = True
        self.peButton.setEnabled(enable)

    def startParameterExploration(self):
        """ startParameterExploration() -> None
        Collects inputs from widgets and the builders to setup and
        start a parameter exploration

        """
        specs = []
        dimCount = 0
        for dim in xrange(self.dimTab.count()):
            tab = self.dimTab.widget(dim)
            stepCount = tab.sizeEdit.value()
            specsPerDim = []
            for row in xrange(tab.dropbox.parameters.rowCount()):
                type = tab.dropbox.parameters.verticalHeaderItem(row).type
                alias = tab.dropbox.parameters.verticalHeaderItem(row).alias
                ranges = []
                if type == 'String':
                    wgt = tab.dropbox.parameters.cellWidget(row,0)
                    strCount = wgt.listWidget.count()
                    strings = [str( wgt.listWidget.item(i%strCount).text())
                               for i in xrange(stepCount)]
                    ranges.append(strings)
                else:
                    convert = {'Integer': int,
                               'Float': float}
                    cv = convert[type]
                    sItem = tab.dropbox.parameters.item(row,0)
                    eItem = tab.dropbox.parameters.item(row,1)
                    ranges.append((cv(sItem.text()),cv(eItem.text())))
                interpolator = (alias, type, ranges, stepCount)
                specsPerDim.append(interpolator)
            specs.append(specsPerDim)
        ids = self.bookmarkPanel.bookmarkPalette.checkedList
        self.manager.parameterExploration(ids, specs)

    def clear(self):
        """ clear() -> None
        Clear all settings and leave the GUI empty

        """
        for dim in xrange(self.dimTab.count()):
            tab = self.dimTab.widget(dim)
            tab.dropbox.clear()

    def removeAlias(self,alias):
        """removeAlias(alias:str) -> None
        Propagates event down to each tab. """
        for dim in xrange(self.dimTab.count()):
            tab = self.dimTab.widget(dim)
            tab.dropbox.parameters.removeAlias(alias)

class QAliasDimensionWidget(QtGui.QWidget):
    """
    QALiasDimensionWidget is the tab widget holding parameter info for a
    single dimension

    """
    def __init__(self, parent=None, manager=None):
        """ QAliasDimensionWidget(parant: QWidget) -> QALiasDimensionWidget
        Initialize the tab with appropriate labels and connect all
        signals and slots

        """
        QtGui.QWidget.__init__(self, parent)
        self.manager = manager
        self.sizeLabel = QtGui.QLabel('&Step Count')
        self.sizeEdit = QtGui.QSpinBox()
        self.sizeEdit.setMinimum(1)
        self.connect(self.sizeEdit,QtCore.SIGNAL("valueChanged(int)"),
                     self.stepCountChanged)
        self.sizeLabel.setBuddy(self.sizeEdit)

        sizeLayout = QtGui.QHBoxLayout()
        sizeLayout.addWidget(self.sizeLabel)
        sizeLayout.addWidget(self.sizeEdit)
        sizeLayout.addStretch(0)

        topLayout = QtGui.QVBoxLayout()
        topLayout.addLayout(sizeLayout)
        self.dropbox = QAliasDropBox(None, self.manager)
        topLayout.addWidget(self.dropbox)
        self.setLayout(topLayout)
        self.paramEx = None

    def stepCountChanged(self, count):
        """ stepCountChanged(count: int)
        When the number step in this dimension is changed, notify and
        invalidate all of its children

        """
        idx = self.paramEx.dimTab.indexOf(self)
        self.paramEx.dimTab.setTabText(idx,
                                       self.paramEx.dimLabels[idx] +
                                       ' (' + str(count) + ')')
        for i in xrange(self.dropbox.parameters.rowCount()):
            item = self.dropbox.parameters.verticalHeaderItem(i)
            if item.type =='String':
                child = self.dropbox.parameters.cellWidget(i,0)
                child.updateStepCount(child.listWidget.count())

class QAliasDropBox(QtGui.QScrollArea):
    """
    QAliasDropBox is just a widget such that alias items from
    QBookmarkAliasPanel can be dropped into its client rect. It then
    construct an input form based on the type of handling widget

    """
    def __init__(self, parent=None, manager=None):
        """ QAliasDropBox(parent: QWidget) -> QAliasDropBox
        Initialize widget constraints

        """
        QtGui.QScrollArea.__init__(self, parent)
        self.setAcceptDrops(True)
        self.panel = self.createPanel()
        self.panel.setVisible(False)
        self.setWidgetResizable(True)
        self.setWidget(self.panel)
        self.updateLocked = False
        self.manager = manager

    def createPanel(self):
        """createPanel() -> QWidget
        Creates a widget with a layout to hold a QAliasExplorationTable

        """
        widget = QtGui.QWidget(self)
        layout = QtGui.QVBoxLayout()
        widget.setLayout(layout)
        widget.layout().setMargin(0)
        widget.layout().setSpacing(0)

        self.parameters = QAliasExplorationTable()

        layout.addWidget(self.parameters, 1)

        return widget

    def dragEnterEvent(self, event):
        """ dragEnterEvent(event: QDragEnterEvent) -> None
        Set to accept drops from alias table

        """
        if type(event.source())==QAliasTable:
            data = event.mimeData()
            if hasattr(data, 'aliases'):
                event.accept()
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        """ dragMoveEvent(event: QDragMoveEvent) -> None
        Set to accept drag move event from alias table

        """
        if type(event.source())==QAliasTable:
            data = event.mimeData()
            if hasattr(data, 'aliases'):
                event.accept()

    def dropEvent(self, event):
        """ dropEvent(event: QDragMoveEvent) -> None
        Accept drop event to add a new alias

        """
        if type(event.source())==QAliasTable:
            data = event.mimeData()
            if hasattr(data, 'aliases'):
                event.setDropAction(QtCore.Qt.CopyAction)
                event.accept()
                for item in data.aliases:
                    if self.parameters.rowCount() == 0:
                        self.parameters.horizontalHeader().show()

                    self.parameters.createAliasRow(item.alias, item.type)
                    self.scrollContentsBy(0, self.viewport().height())

class QAliasExplorationTable(QtGui.QTableWidget):
    """
    QAliasExplorationTable just inherits from QTableWidget to have a customized
    table and items

    """
    def __init__(self, parent=None, manager=None):
        """ QAliasExplorationTable(parent: QWidget, manager:BookmarkManager ) ->
        QAliasExplorationTable
        Set bookmark manager
        """
        QtGui.QTableWidget.__init__(self, parent)
        self.manager = manager
        self.aliases = {}
        self.setColumnCount(2)
        self.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems)
        self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
        self.horizontalHeader().setStretchLastSection(True)
        labels = QtCore.QStringList()
        labels << "Start" << "End"
        self.setHorizontalHeaderLabels(labels)
        self.horizontalHeader().hide()
        self.connect(self.verticalHeader(),
                     QtCore.SIGNAL("sectionClicked(int)"),
                     self.updateFocus)
        self.verticalHeader().setResizeMode(QtGui.QHeaderView.Interactive)

    def createAliasRow(self, alias, type):
        """ createAliasRow( alias: str, type: str) -> None
        Creates a row in the table

        """
        row = self.rowCount()
        self.insertRow(row)

        item = QAliasTableWidgetItem(alias, type, alias)
        item.setFlags(QtCore.Qt.ItemIsEnabled)
        self.setVerticalHeaderItem(row,item)

        if type != 'String':
            sItem = QAliasTableWidgetItem(alias, type, "")
            sItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable \
                           | QtCore.Qt.ItemIsSelectable)
            eItem = QAliasTableWidgetItem(alias, type, "")

            self.setItem(row, 0, sItem)
            self.setSpan(row,0,1,1)
            self.setItem(row, 1, eItem)
        else:
            #join the two columns in one
            self.setSpan(row,0,1,2)
            widget = QRangeStringContainer(self)
            layout = QtGui.QGridLayout()
            widget.setLayout(layout)
            lineEdit = QRangeString(0, widget)
            widget.listWidget = lineEdit.listWidget
            layout.addWidget(lineEdit,0,1,1,2)
            self.connect(widget.listWidget,
                         QtCore.SIGNAL("changed(int)"),
                         widget.updateStepCount)
            h = widget.sizeHint().height()
            w = widget.sizeHint().width()
            self.setRowHeight(row,h)
            self.setCellWidget(row,0,widget)
            widget.updateStepCount(widget.listWidget.count())
        self.emit(QtCore.SIGNAL("tableChanged"))

    def updateFocus(self, row):
        """ updateFocus(row: int) -> None
        Set focus to the alias cell when clicking on the header cell

        """
        self.setCurrentCell(row,0)

    def getItemRow(self, alias):
        """getItemRow(alias:str) -> int
        Searches for the row that contains the alias name

        """
        for i in xrange(self.rowCount()):
            item = self.verticalHeaderItem(i)
            if item:
                if item.alias == alias:
                    return i
        return -1

    def removeAlias(self, alias):
        """removeAlias(alias:str) -> None Removes the row containing alias """
        row = self.getItemRow(alias)
        self.deleteRow(row)

    def keyPressEvent(self, event):
        """keyPressEvent(event: QKeyEvent) -> None
        Event handler for key press events.
         - Ctrl(Command) + Backspace or Ctrl(command) + Del
                     removes the current row
        """
        if (event.key() == QtCore.Qt.Key_Delete or
            event.key() == QtCore.Qt.Key_Backspace):
            if event.modifiers() & QtCore.Qt.ControlModifier:
                event.accept()
                row = self.currentRow()
                self.deleteRow(row)
            else:
                event.ignore()
        else:
            event.ignore()

    def deleteRow(self, row):
        """deleteRow(row: int) -> None
        Removes a row and updates the table.

        """
        if row > -1:
            #looking at the next item and set colspan before removing
            # the row. Otherwise the layout is not updated
            item = self.verticalHeaderItem(row+1)
            if item and item.type != 'String':
                self.setSpan(row,0,1,1)
            else:
                self.setSpan(row,0,1,2)
            self.removeRow(row)
            if self.rowCount() == 0:
                self.horizontalHeader().hide()
            self.emit(QtCore.SIGNAL("tableChanged"))

class QRangeStringContainer(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

    def stepCount(self):
        dropbox = self.parent().parent().parent().parent().parent()
        return dropbox.parent().sizeEdit.value()

    def updateStepCount(self, count):
        display = 'Count: '+ str(count)
        stepCount = self.stepCount()
        if count>stepCount:
            display = display + ' (Too many values)'
        if count<stepCount:
            display = display + ' (Need more values)'
        self.setToolTip(display)


import wave
import os
import time

def encode_lsb_1_bit(wavfile, textfile, save_path, file_name):
    start = time.time()
    # read wave audio file
    song = wave.open(wavfile, mode='rb')
    # Convert to byte array
    frame_bytes = bytearray(list(song.readframes(song.getnframes())))

    # Text message
    f = open(textfile, "r")
    string = f.read()
    f.close()

    # Padding preprocess
    string = string + int((len(frame_bytes) - (len(string) * 8 * 8)) / 8) * "#"

    # Convert text to bit array
    bits = list(map(int, ''.join([bin(ord(i)).lstrip('0b').rjust(8, '0') for i in string])))

    # Replace LSB of each byte of the audio data by one bit from the text bit array
    for i, bit in enumerate(bits):
        frame_bytes[i] = (frame_bytes[i] & 254) | bit
    frame_modified = bytes(frame_bytes)

    complete_name = os.path.join(save_path, file_name)
    print(complete_name)
    # Write bytes to a new wave audio file
    with wave.open(complete_name + ".wav", 'wb') as fd:
        fd.setparams(song.getparams())
        fd.writeframes(frame_modified)
    song.close()

    decodeTime = "Decode time: " + str(round(time.time() - start, 2)) + "seconds"
    print(decodeTime)

    return decodeTime


## advent of code 2020
## https://adventofcode.com/2020
## day 16

from aocpuzzle import *
from parsehelp import *

class TicketField:
    def __init__(self, line):
        self.name, ranges = line.split(': ')
        self.ranges = []
        for r in ranges.split(' or '):
            min, max = r.split('-')
            self.ranges.append((int(min), int(max)))
        self.index = -1

    def is_valid(self, value):
        for r in self.ranges:
            if value >= r[0] and value <= r[1]:
                return True
        return False

    def set_candidate_columns(self, n):
        self.candidates = set(range(n))

    def remove_candidate(self, n):
        if n in self.candidates:
            self.candidates.remove(n)

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name

class Puzzle(AoCPuzzle):
    def __init__(self, lines, is_test=False):
        AoCPuzzle.__init__(self, lines, is_test)
        self.always_run_part_1 = True
        self.fields = []
        stage = "fields"
        self.tickets = []
        for line in lines:
            if stage == "fields":
                if line == '':
                    stage = "my ticket"
                    continue

                self.fields.append(TicketField(line))
            elif stage == "my ticket":
                if line == '':
                    stage = "nearby tickets"
                    continue

                if line.startswith('your ticket:'):
                    continue
                self.my_ticket = get_all_ints(line)
            elif stage == "nearby tickets":
                if line.startswith('nearby tickets:'):
                    continue

                self.tickets.append(get_all_ints(line))

    def resolve_fields(self):

        for f in self.fields:
            f.set_candidate_columns(len(self.my_ticket))
            for i in range(len(self.tickets[0])):
                for t in self.tickets:
                    if not f.is_valid(t[i]):
                        f.remove_candidate(i)
                        break
        resolved_columns = set()
        unresolved_fields = list(self.fields)

        while len(unresolved_fields) > 0:
            unresolved_fields.sort(key=lambda f: len(f.candidates))
            f = unresolved_fields[0]
            assert(len(f.candidates) == 1)

            index = f.candidates.pop()
            f.index = index
            resolved_columns.add(f.index)
            unresolved_fields.remove(f)

            for f in unresolved_fields:
                if index in f.candidates:
                    f.candidates.remove(index)

    def part1(self):
        bad_values = []
        bad_tickets = []
        for t in self.tickets:
            for v in t:
                valid = False
                for f in self.fields:
                    if f.is_valid(v):
                        valid = True
                        break
                if not valid:
                    bad_values.append(v)
                    if t not in bad_tickets:
                        bad_tickets.append(t)
        print(bad_values)
        for t in bad_tickets:
            self.tickets.remove(t)
        return sum(bad_values)

    def part2(self):
        self.resolve_fields()
        result = 1
        count = 0
        for f in self.fields:
            if f.name.startswith('departure'):
                result *= self.my_ticket[f.index]
                count += 1
        assert(count == 6)
        return result


from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated

from .models import Address
from .serializers import AddressSerializer
from common.permissions import IsOwnUserOrAdmin

class AddressViewSet(viewsets.ModelViewSet):
    permission_classes = (IsAuthenticated, IsOwnUserOrAdmin)
    serializer_class = AddressSerializer

    def get_queryset(self):
        if self.request.user.is_staff:
            return Address.objects.all()
        else:
            return Address.objects.filter(user=self.request.user)

    def perform_create(self, serializer):
        curr_user = self.request.user
        prev_address = Address.objects.filter(user_id=curr_user.id)
        if prev_address:
            prev_address[0].delete()
        serializer.save(user=self.request.user)