# coding: utf-8

import re
import logging
from collections import OrderedDict
from copy import copy

logger = logging.getLogger(__name__)

try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET

from lxml import etree

def uniq_seq_merge(seq1, seq2):
    new_seq = copy(seq1)
    items_only_in_seq2 = set(seq2) - set(new_seq)
    len2 = len(seq2)
    for item in items_only_in_seq2:
        i2 = seq2.index(item)
        if i2 == len2 - 1:
            new_seq.append(item)
        else:
            for i in range(i2 + 1, len2):
                key = seq2[i]
                if key in new_seq:
                    new_seq.insert(new_seq.index(key), item)
                    break
            else:
                new_seq.append(item)
    return new_seq

def xpath_add_default_ns(xpath, def_ns='__default__'):
    '''
        Add a default ns tag. This is because lxml doesn't support empty namespace
    '''
    def find_brackets(xpath):
        ret = []
        stack = []
        p = re.compile(r'([\[\]])')
        for e in p.finditer(xpath):
            string = e.group()
            index = e.start()
            if string == '[':
                stack.append(index)
            else:
                ret.append((stack[-1], index))
                stack.pop(-1)
        return ret
    def in_brackets(index, brackets):
        if not brackets:
            return False
        for start, end in brackets:
            if start < index < end:
                return True
        return False

    ret = []
    p = re.compile(r'/([^\[\]/\'\"]+)')
    last_end = 0
    brackets = find_brackets(xpath)
    for match in p.finditer(xpath):
        string = match.group()
        start = match.start()
        end = match.end()
        if in_brackets(start, brackets):
            ret.append(xpath[last_end:end])
            last_end = end
        else:
            # is a real node tag
            if ':' in string:
                # has a name space in name
                ret.append(xpath[last_end:end])
                last_end = end
            else:
                ret.append(xpath[last_end:start])
                ret.append('/' + def_ns + ':' + string[1:])
                last_end = end
    if end < len(xpath) - 1:
        ret.append(xpath[last_end:])
    return ''.join(ret)

class XmlConfig:
    '''
        using lxml to process xml format file
    '''
    def __init__(self, filename: str='', lines: list=None) -> None:
        if filename:
            et = etree.parse(filename)
        elif not lines:
            et = etree.fromstringlist(lines)
        self.filename = filename
        self.etree = et
        self.root = et.getroot()
        self._nsmap_r = dict([(value, key) for key, value in self.root.nsmap.items()])
        self._children_count = {}
        self._dict = OrderedDict()
        self._node_map = {}
        self._get_node_list()

    def search(self, xpath, name_def_ns='__default__'):
        '''search node which matches xpath'''
        if self._nsmap_r:
            # the file is with namespaces defined
            nsmap = copy(self.root.nsmap)
            if None in nsmap:
                nsmap[name_def_ns] = nsmap[None]
                nsmap.pop(None)
                xpath = xpath_add_default_ns(xpath, name_def_ns)
            return self.etree.xpath(xpath, namespaces=nsmap)
        return self.etree.xpath(xpath)

    def _rm_prefix(self, tag: str):
        # remove the namespace in tag
        if '}' in tag:
            ns, _, name = tag.partition('}')
            ns = ns[1:]
            if self._nsmap_r[ns]:
                return '{}:{}'.format(self._nsmap_r[ns], name)
            else:
                return name
        else:
            return ''

    def _path_split_attr(self, path):
        # split the path to xpath and attrib
        path_attr_pattern = re.compile(r'(.*)\[@([^\]]*)\]$')
        m = path_attr_pattern.match(path)
        if m:
            real_path, attr = m.groups()
        else:
            real_path = path
            attr = None
        return real_path, attr

    def _path_split_seq(self, path):
        # split the path to path and sequence number
        p = re.compile(r'(.*)\[(\d+)\]$')
        m = p.match(path)
        if m:
            # with sequence number
            real_path, seq = m.groups()
            seq = int(seq)
        else:
            real_path = path
            seq = None
        # logger.debug('Sequence number is {}'.format(seq))
        return real_path, seq

    def _get_node_with_ns(self, path):
        # get the node with the namespace in tag
        if not self.root.nsmap:
            return None
        search = ''
        for seg in path.split('/')[1:]:
            if seg[-1] == ']':
                # with a sequence number
                name, _, seq = seg.partition('[')
                search += "/*[name()='{}'][{}".format(name, seq)
            else:
                search += "/*[name()='{}']".format(seg)
        logger.debug('Node search string is: {}'.format(search))
        l = self.etree.xpath(search)
        return l[0] if l else None

    def _get_node_detail(self, node):
        '''extra node tag, text, attribute and count of child'''
        if node is not None:
            tag = self._rm_prefix(node.tag) if self._nsmap_r else node.tag
            text = node.text.strip() if node.text else ''
            attrib = node.attrib
            count_child = len(node)
            return tag, text, attrib, count_child
        return None

    def _walk_node_list(self, node, prefix='', counter=1):
        '''
            This function is the recursive to get node list
            Needed only for xml with namespaces
        '''
        tag, text, attrib, count_child = self._get_node_detail(node)
        if counter == 1:
            new_prefix = prefix + '/' + tag
            sib = node.getnext()
            while sib != None:
                if sib.tag is etree.Comment:
                    sib = sib.getnext()
                    continue
                if self._rm_prefix(sib.tag) == tag:
                    new_prefix = new_prefix + '[1]'
                    break
                sib = sib.getnext()
        else:
            new_prefix = prefix + '/' + tag + '[{}]'.format(str(counter))
        self._dict[new_prefix] = (tag, text, attrib, count_child)
        self._node_map[new_prefix] = node
        counters = {}

        for ch in node.getchildren():
            if ch.tag is etree.Comment:
                continue
            tag = self._rm_prefix(ch.tag)
            counters[tag] = counters.setdefault(tag, 0) + 1
            self._walk_node_list(ch, prefix=new_prefix, counter=counters[tag])

    def _get_parent_name(self, path):
        parent, _, tag = path.rpartition('/')
        if tag.startswith('comment()'):
            return ''
        return parent

    def _get_node_list(self):
        '''
            Generate the _dict
            _dict: OrderedDict
                key: xpath
                value: [tag, text, attrib, child_count]
        '''
        self._dict = OrderedDict()
        self._node_map = {}
        if self.root.nsmap:
            '''
                etree.getpath returns weird string wchich cannot be used for etree.xpath to lookup
                the node.
                So here need to use self._walk_node_list()
            '''
            self._walk_node_list(self.root)
        else:
            for ch in self.root.iter():
                if ch.tag is etree.Comment:
                    continue
                path = self.etree.getpath(ch)
                self._dict[path] = self._get_node_detail(ch)
                self._node_map[path] = ch
        for name in self._dict.keys():
            parent = self._get_parent_name(name)
            if not parent:
                continue
            else:
                self._children_count[parent] = self._children_count.setdefault(parent, 0) + 1

    def _get_node(self, path):
        if self.root.nsmap:
            return self._get_node_with_ns(path)
        else:
            l = self.etree.xpath(path)
            if l:
                return l[0]
            else:
                logger.debug('Not found: {}'.format(path))
                return None
    # alias of get_node
    get_node = _get_node

    def get_path(self, node):
        # Find full path of node
        for path, n in self._node_map.items():
            if n == node:
                return path
        else:
            return ''

    # def _get_siblings(self, path):
    #     real_path, seq = self._path_split_seq(path)
    #     len_rp = len(real_path)
    #     ret = []
    #     if seq:
    #         for k, v in self._dict.items():
    #             if k == path:
    #                 continue
    #             if k.startswith(real_path) and '/' not in k[len_rp:]:
    #                 ret.append(k)
    #     return ret

    def _match_attr(self, attrib1, attrib2, group_id_keys:tuple):
        for key in group_id_keys:
            if key in attrib1 and key in attrib2 and attrib1.get(key) == attrib2.get(key):
                return True
        return False

    def _dict_diff(self, d1, d2, include_ok=True):
        # assume d1 and d2 are dict
        all_keys = uniq_seq_merge(list(d1.keys()), list(d2.keys()))
        diff = []
        for key in all_keys:
            if key in d1 and key not in d2:
                diff.append(('Removed', key, d1.get(key), ''))
            elif key not in d1 and key in d2:
                diff.append(('New', key, '', d2.get(key)))
            else:
                v1 = d1.get(key)
                v2 = d2.get(key)
                if v1 == v2:
                    if include_ok:
                        diff.append(('OK', key, v1, v2))
                else:
                    diff.append(('Change', key, v1, v2))
        return diff

    def __getitem__(self, path):
        return self._dict.get(path, None)

    def _list_children(self, parent_path, tag=''):
        if self[parent_path][-1] == 0:
            return []
        ret = []
        prefix = '/'.join((parent_path, tag))
        l_p = len(prefix)
        for k, v in self._dict.items():
            if k.startswith(prefix) and '/' not in k[l_p:]:
                ret.append(k)
        return ret

    def _get_match_node(self, path, node_match_matrix):
        # to find the correct node to match
        # For example, /groups/group[3] matches the /groups/group[4]
        # Then the children need to compare to each other's children
        # logger.debug('Looking for {} in {}'.format(path, node_match_matrix))
        for p1, p2 in node_match_matrix[::-1]:
            if path == p1:
                return p2
        return None

    def _get_attr(self, path, attr):
        return self._dict[path][2].get(attr, None)

    def _get_children_count(self, path, obj):
        if path in obj._dict:
            return obj._dict[path][-1]
        else:
            return 0

    def _group_node_match(self, parent_path, tag, xc2, node_match_matrix, id_field='id'):
        '''
            _group_node_match: use only when compare two instances
            args:
                parent_path: the group's parent path
                tag: the shared tag of group nodes
                xc2: the instance will be compared
                node_match_matrix: the node match matrix
                id_field: the atrribute to identify the node
        '''
        match = []
        unmatched = []
        id_map = {}
        ppath2 = self._get_match_node(parent_path, node_match_matrix)
        logger.debug('ppath2 is {}'.format(ppath2))
        if ppath2 == None:
            ppath2 = parent_path
        for path in xc2._list_children(ppath2, tag):
            _, seq = xc2._path_split_seq(path)
            node_id = xc2[path][2][id_field]
            id_map[node_id] = seq
        for path in self._list_children(parent_path, tag):
            _, seq = self._path_split_seq(path)
            node_id = self[path][2][id_field]
            if node_id in id_map:
                p2 = '{}/{}[{}]'.format(ppath2, tag, id_map[node_id])
                match.append((path, p2))
                logger.debug('Group {}: {} matched {}'.format(parent_path, path, p2))
                if p2 != path:
                    node_match_matrix.append((path, p2))
                id_map.pop(node_id)
            else:
                logger.debug('Group {}: no match found for {}'.format(parent_path, seq))
                unmatched.append(path)
        unmatched2 = ['{}/{}[{}]'.format(ppath2, tag, seq) for seq in id_map.values()]
        return match, unmatched, unmatched2

    def _mark_children(self, path, status, obj, node_compared):
        # mark all children to one single status
        # this can be used to mark all children of a Removed or New node to the same status
        ret = []
        logger.debug('Marking {}\'s sub nodes to be {}'.format(path, status))
        for sub_path in obj._dict.keys():
            if sub_path.startswith(path):
                _, text, attr, _ = obj[sub_path]
                node_compared.append(sub_path)
                logger.debug('Marking {} to {}'.format(sub_path, status))
                if status == 'New':
                    p1, p2 = '', sub_path
                    t1, t2 = '', text
                else:
                    p1, p2 = sub_path, ''
                    t1, t2 = text, ''
                ret.append((p1, status, t1, t2, '', p2))
                for key, value in attr.items():
                    if status == 'New':
                        p1, p2 = '', sub_path
                        v1, v2 = '', value
                    else:
                        p1, p2 = sub_path, ''
                        v1, v2 = value, ''
                    ret.append((p1, status, key, v1, v2, p2))
        # logger.debug('Diffs before return {}'.format(ret))
        return ret

    def comp(self, filename: str, group_id_field_map=None, include_ok=True):
        '''
            Compare with another xml file
            args:
                filename: file name
                group_id_field_map: a dict contains the id field of each group of sub nodes
                    The format should be this way: {'bean': 'id', 'Field': 'index', 'module': 'name'}
                    The key is the tag name and value should be the attribute to distinguish the node
                include_ok: Whether the return values contains the same content
            return:
                list of changes
        '''
        logger.debug('Compare to {}'.format(filename))
        if group_id_field_map == None:
            group_id_field_map = {}
        xc2 = self.__class__(filename)
        changes = []
        # node_match_matrix
        # This is designed for the nodes have multiple children with same tag but different
        # attributes
        # In some cases the order of childs may vary but actually the node can find equivelent
        # node in the second file. Keeping this matrix to avoid the accuracy problem due to
        # sequence
        # empty = ('', '', {}, 0)
        node_match_matrix = []
        # store the nodes already processed
        node_compared1 = []
        node_compared2 = []

        # check all nodes in self
        for path in self._dict.keys():
            logger.debug('Comparing my path {}'.format(path))
            if path in node_compared1:
                logger.debug('Already compared. Skip {}'.format(path))
                continue
            # logger.debug(node_compared1)
            # logger.debug(node_compared2)
            real_p, seq = self._path_split_seq(path)
            parent = self._get_parent_name(path)
            if not seq:
                # the path is not ending with a sequence number, means not in a group
                logger.debug('Not in a group')
                ppath2 = self._get_match_node(parent, node_match_matrix)
                if ppath2 == None:
                    path2 = path
                else:
                    path2 = path.replace(parent, ppath2)
                    if self._get_children_count(path, self) > 0:
                        node_match_matrix.append((path, path2))
                if path2 in xc2._dict:
                    logger.debug('Compare {} to {}'.format(path, path2))
                    left, right = self[path], xc2[path2]
                    diffs = self._node_comp(left, right, path, path2, include_ok=include_ok)
                    changes.extend(diffs)
                    node_compared1.append(path)
                    node_compared2.append(path2)
                else:
                    # not in xc2, need to mark as 'Removed'
                    diffs = self._mark_children(path, 'Removed', self, node_compared1)
                    changes.append(diffs)
                    node_compared1.append(path)
            else:
                # the path ends with a sequence number, means in a group
                logger.debug('In group: {}'.format(parent))
                _, _, tag = real_p.rpartition('/')
                if tag not in group_id_field_map:
                    raise KeyError('Please indicate id field for tag "{}" to group_id_field_map'.format(tag))
                matched, unmatched1, unmatched2 = self._group_node_match(
                    parent, tag, xc2, node_match_matrix, group_id_field_map[tag]
                )
                # logger.debug('Node match matrix: {}'.format(node_match_matrix))
                for p1, p2 in matched:
                    logger.debug('Comparing {} vs {}'.format(p1, p2))
                    diffs = self._node_comp(self[p1], xc2[p2], p1, p2, include_ok)
                    node_compared1.append(p1)
                    node_compared2.append(p2)
                    # logger.debug('Current diffs: {}'.format(diffs))
                    changes.extend(diffs)
                for p1 in unmatched1:
                    logger.debug('No match found for {} in {}. Mark as Removed'.format(p1, xc2.filename))
                    diffs = self._mark_children(p1, 'Removed', self, node_compared1)
                    # logger.debug('Removed diffs: {}'.format(diffs))
                    node_compared1.append(p1)
                    changes.extend(diffs)
                for p2 in unmatched2:
                    logger.debug('No match found for {} in self, Mark as New'.format(p2))
                    diffs = self._mark_children(p2, 'New', xc2, node_compared2)
                    # logger.debug('New diffs: {}'.format(diffs))
                    node_compared2.append(p2)
                    changes.extend(diffs)
        for path in xc2._dict.keys():
            if path in node_compared2:
                logger.debug('Already compared. Skip {}'.format(path))
                continue
            diffs = self._mark_children(path, 'New', xc2, node_compared2)
            changes.extend(diffs)

        return changes

    def _list_group_node(self, path):
        p = re.compile(r'(.*)\[(\d+)\]$')
        m = p.match(path)
        if m:
            # with sequence number
            real_path, seq = m.groups()
            seq = int(seq)
        return self.etree.xpath(real_path)

    def _node_comp(self, data_node1, data_node2, path1, path2='', include_ok=True):
        '''
            Compare data two nodes
            args:
                data_node1: data of node1 with path1
                data_node2: data of node2 with path2
                path1: the node path of self
                path2: the node path of the file to be compared
                include_ok: whether to inlucde values with no difference
        '''
        _, text1, attr1, _ = data_node1
        _, text2, attr2, _ = data_node2
        changes = []
        if not path2:
            path2 = path1
        if text1 != text2:
            logger.debug('Text difference: {} - {}'.format(text1, text2))
            changes.append((path1, 'Change', '', text1, text2, path2))
        elif text1 != '' and include_ok:
            changes.append((path1, 'OK', '', text1, text1, path2))
        attrib_diff = self._dict_diff(attr1, attr2, include_ok)
        if attrib_diff:
            logger.debug('Attrib diff: {}'.format(attrib_diff))
            for diff in attrib_diff:
                ch, key, v1, v2 = diff
                if ch == 'OK':
                    if include_ok:
                        changes.append((path1, ch, key, v1, v2, path2))
                else:
                    changes.append((path1, ch, key, v1, v2, path2))

        return sorted(changes, key=lambda t:t[0])

    def set(self, path, value):
        real_path, attr = self._path_split_attr(path)
        node = self._get_node(real_path)
        if node is None:
            raise KeyError('Invalid path: {}'.format(path))
        if node is not None:
            if attr:
                # set attrib
                node.set(attr, value)
                self[real_path][2][attr] = value
            else:
                # set text
                if value:
                    node.text = value
                    d = self[real_path]
                    self._dict[real_path] = (d[0], value, d[2], d[3])
        else:
            # cannot find or create the node
            logger.warn('Unable to find or create node')

    def set_attr(self, path, attr, value):
        if attr == '':
            self.set(path, value)
        else:
            new_path = '{}[@{}]'.format(path, attr)
            self.set(new_path, value)

    def get(self, path):
        real_path, attr = self._path_split_attr(path)
        # node = self._get_node(real_path)
        if real_path not in self._dict:
            raise KeyError('No xpath found: {}'.format(path))
        attrib = self[real_path][2]
        if attr:
            if attr not in attrib:
                raise KeyError('No attrib found: {}'.format(path))
            return attrib.get(attr)
        else:
            return self[real_path][1]

    def add_node(self, path:str):
        # if self._get_node(path) is not None:
        #     logger.info('Node exists')
        #     return
        # check if path with sequence number
        real_path, seq = self._path_split_seq(path)
        if seq:
            seq = int(seq)
            parent_path = self._get_parent_name(real_path)
            tag = real_path.rpartition('/')[-1]
            if parent_path not in self._dict:
                raise ValueError('Wrong path: {}'.format(real_path))
            parent_node = self._get_node(parent_path)
            max_child_path = self._list_children(parent_path, tag)[-1]
            max_n = int(self._path_split_seq(max_child_path)[-1])
            element = etree.Element(tag)
            if seq <= max_n:
                parent_node.insert(seq, element)
            else:
                parent_node.append(element)
        else:
            parent_path, _, tag = path.rpartition('/')
            parent_node = self._get_node(parent_path)
            element = etree.Element(tag)
            parent_node.append(element)
        self._get_node_list()
        return element

    def del_node(self, path:str):
        '''delete a node'''
        # delete it's children
        node = self._get_node(path)
        for child in node.getchildren():
            self.del_node(self.get_path(child))
        # delete node from etree
        parent = self._get_parent_name(path)
        parent_node = self.get_node(parent)
        parent_node.remove(node)
        # delete from self._dict and self._node_map
        self._get_node_list()

    def save(self, filename=''):
        # save to disk
        if filename == '':
            filename = self.filename
        logger.debug('Write to {}'.format(filename))
        open(filename, 'w').write(etree.tostring(self.root).decode())

    def walk(self, json=False):
        for k, v in self.get_dict().items():
            print('{}: {}'.format(k, v))

    def get_dict(self, json=False):
        ret = OrderedDict()
        for node_path, vs in self._dict.items():
            if node_path.split('/')[-1].startswith('comment()'):
                continue
            _, text, attrib, _ = vs
            ret[node_path] = text
            for key, value in attrib.iteritems():
                ret['{}[@{}]'.format(node_path, key)] = value
        return ret

    def update_from(self, filename, group_id_field_map=None):
        # Update current file from another file
        for path1, status, key, v1, v2, path2 in self.comp(filename, group_id_field_map, include_ok=False):
            if status == 'Change':
                action = status
            elif status == 'New':
                action = 'Add'
            elif status == 'Remove':
                logger.debug('Remove is not supported yet')
                continue
            logger.debug('{} {}: {} -> {}'.format(status, key, v1, v2))
            self.set(key, v2)

    def _node_validate(node, requirements: list, include_ok=True):
        ret = []
        for req in requirements:
            key = req.get('attrib')
            value = req.get('value')
            current_value = node.attrib.get(key)
            if current_value == None:
                change = 'Missing'
            elif current_value != value:
                change = 'NotComply'
            else:
                if include_ok == False:
                    continue
                change = 'OK'
            ret.append((key, value, current_value, change))
        return ret

    def validate(self, node_path, search_path, requirements: list, include_ok=False):
        '''
            Valid if self values match the requirements
            args:
                node_path: a XPath string can match a node
                search_path: a XPath search string that can to search nodes
                requirements: a list of value requirements
                    Example: [
                        {'attrib': 'key1', 'value': 'value1'},
                        {'attrib': 'key2', 'value': 'value2'},
                        {'attrib': 'key3', 'value': 'value3'},
                    ]
        '''
        ret = []
        if node_path == 'search' or node_path == '':
            logger.debug('Searching {}'.format(search_path))
            xpath = search_path
            nodes = self.search(search_path)
            if len(nodes) == 0:
                logger.debug('No node found for {}'.format(xpath))
                change = 'Missing'
                ret.append((xpath, '', '', '', 'NodeMissing'))
            # elif len(nodes) > 1:
            #     change = 'Deviation'
            #     ret.append((xpath, '', '', '', 'TooManyNode'))
            #     # raise ValueError('XPath matched two or more nodes: {}'.format(search_path))
            # else:
            #     logger.debug('Node found')
            #     node = nodes[0]
        else:
            node = self._get_node(node_path)
            xpath = node_path
            if node is None:
                change = 'Missing'
                ret.append((xpath, '', '', '', 'NodeMissing'))
            else:
                nodes = [node,]
        for node in nodes:
            path = self.get_path(node)
            for req in requirements:
                key = req.get('attrib')
                value = req.get('value')
                current_value = node.attrib.get(key)
                if current_value == None:
                    change = 'Missing'
                elif current_value != value:
                    change = 'NotComply'
                else:
                    if include_ok == False:
                        continue
                    change = 'OK'
                ret.append((path, key, value, current_value, change))
        if not ret:
            logger.debug('No compliance issue found')
        return ret

    def multi_set(self, search_path, attrib, value):
        for node in self.search(search_path):
            path = self.get_path(node)
            if attrib:
                path = '{}[@{}]'.format(path, attrib)
            self.set(path, value)


from matplotlib import colors
import matplotlib.pyplot as plt

fp = open('out', 'r')
lines = list(map(lambda x: [float(y)
                            for y in x.split(':')[1:]], fp.readlines()))
lines = list(map(lambda x: [x[0], x[1]*100], lines))
for line in lines:
    print(line)

# For found

ns = [lines[x][0] for x in range(0, len(lines), 2)]
times = [lines[x][1] for x in range(0, len(lines), 2)]

ns2 = [2*lines[x][0] for x in range(0, len(lines), 2)]
times2 = [2*lines[x][1] for x in range(0, len(lines), 2)]
print(ns)
print(times)
plt.plot(ns, times)
plt.plot(ns2, times2)
plt.xlabel("number of items")
plt.ylabel("Time*100")
plt.legend(["One", "Two"])

plt.show()

# For not found

ns = [lines[x][0] for x in range(1, len(lines), 2)]
times = [lines[x][1] for x in range(1, len(lines), 2)]

print(ns)
print(times)
plt.plot(ns, times)
plt.xlabel("number of items")
plt.ylabel("Time*100")

plt.show()


import numpy as np
# import networkx as nx
from collections import *
from itertools import *
from functools import *
import math
import re

from common.session import AdventSession

session = AdventSession(day=18, year=2020)
data = session.data.strip()
data = data.split('\n')

p1, p2 = 0, 0

def findmatch(expr, i):
    match = 0
    while i < len(expr):
        if expr[i] == '(':
            match += 1
        elif expr[i] == ')':
            match -= 1
            if match == 0:
                return i
        i += 1

def evaluate(expr):
    i = 0
    while i < len(expr) and len(expr) > 1:
        if i - 1 >= 0 and expr[i - 1].isdigit() and expr[i + 1].isdigit() and \
                not expr[i].isdigit():
            expr[i - 1:i + 2] = [str(eval(''.join(expr[i - 1:i + 2])))]
            i = 0
        elif expr[i] == '(':
            end = findmatch(expr, i)
            expr[i:end + 1] = [evaluate(expr[i + 1:end])]
            i = 0
        i += 1
    return expr[0]

def evaluate2(expr):
    for op in ('+', '*'):
        i = 0
        while i < len(expr) and len(expr) > 1:
            if i - 1 >= 0 and expr[i - 1].isdigit() and expr[i] == op and \
                    expr[i + 1].isdigit():
                expr[i - 1:i + 2] = [str(eval(''.join(expr[i - 1:i + 2])))]
                i = 0
            elif expr[i] == '(':
                end = findmatch(expr, i)
                expr[i:end + 1] = [evaluate2(expr[i + 1:end])]
                i = 0
            i += 1
    return expr[0]

for line in data:
    p1 += int(evaluate([c for c in line if c != ' ']))
    p2 += int(evaluate2([c for c in line if c != ' ']))

print(f'Part 1: {p1}')
print(f'Part 2: {p2}')

# session.submit(p1, part=1)
# session.submit(p2, part=2)

# session.submit(p1, part=2)


# -*- coding: utf-8 -*-
import os
import time

from boto3.dynamodb.conditions import Key

import settings

from db_util import DBUtil
from lambda_base import LambdaBase
from jsonschema import validate
from not_authorized_error import NotAuthorizedError
from user_util import UserUtil

class MeCommentsDelete(LambdaBase):
    def get_schema(self):
        return {
            'type': 'object',
            'properties': {
                'comment_id': settings.parameters['comment']['comment_id']
            },
            'required': ['comment_id']
        }

    def validate_params(self):
        UserUtil.verified_phone_and_email(self.event)
        validate(self.params, self.get_schema())
        comment = DBUtil.get_validated_comment(self.dynamodb, self.params['comment_id'])
        DBUtil.validate_article_existence(self.dynamodb, comment['article_id'], status='public')

    def exec_main_proc(self):
        comment_table = self.dynamodb.Table(os.environ['COMMENT_TABLE_NAME'])
        comment = comment_table.get_item(
            Key={"comment_id": self.params['comment_id']}
        )['Item']

        if not self.__is_accessable_comment(comment):
            raise NotAuthorizedError('Forbidden')

        deleted_comment_table = self.dynamodb.Table(os.environ['DELETED_COMMENT_TABLE_NAME'])
        delete_targets = self.__get_delete_targets(comment)

        with deleted_comment_table.batch_writer() as batch:
            for item in delete_targets:
                item.update({'deleted_at': int(time.time())})
                batch.put_item(Item=item)

        with comment_table.batch_writer() as batch:
            for item in delete_targets:
                batch.delete_item(Key={'comment_id': item['comment_id']})

        return {'statusCode': 200}

    def __is_accessable_comment(self, comment):
        user_id = self.event['requestContext']['authorizer']['claims']['cognito:username']

        article_info_table_name = self.dynamodb.Table(os.environ['ARTICLE_INFO_TABLE_NAME'])
        article_info = article_info_table_name.get_item(Key={"article_id": comment['article_id']})['Item']

        if article_info['user_id'] == user_id or comment['user_id'] == user_id:
            return True

        return False

    def __get_delete_targets(self, comment):
        comment_table = self.dynamodb.Table(os.environ['COMMENT_TABLE_NAME'])

        targets = [comment]

        query_params = {
            'IndexName': 'parent_id-sort_key-index',
            'KeyConditionExpression': Key('parent_id').eq(comment['comment_id'])
        }

        thread_comments = comment_table.query(**query_params)['Items']

        targets.extend(thread_comments)

        return targets


from flask import Flask,request
from flask_restful import Resource, Api
from tensorflow import keras
import numpy as np
from flask_cors import CORS

COLUMNS = ['temp', 'wind', 'rain', 'FFMC', 'DMC', 'DC', 'ISI', 'RH', 'BUI', 'FWI']

app = Flask(__name__)
#
CORS(app)
# creating an API object
api = Api(app)

# Load model
model = keras.models.load_model('model.h5', compile=False)

#prediction api call
class predict(Resource):
    def get(self):
        # Get data
        data = np.array([[float(request.args.get(field)) for field in COLUMNS]])

        # Predict
        prediction = model.predict(data)
        prediction = float(prediction[0])

        return prediction

#
api.add_resource(predict, '/predict/')

if __name__ == '__main__':
    app.run()


import setuptools                               # Must be before Cython import

import Emma

with open("README.md", "r") as fp:
    long_description = fp.read()

try:
    from Cython.Compiler import Options
    from Cython.Build import cythonize
    Options.docstrings = True
    Options.fast_fail = True

    extensions = cythonize(
        [
            setuptools.Extension("Emma.emma_libs.memoryMap", sources=["Emma/emma_libs/memoryMap.py"]),
            setuptools.Extension("Emma.emma_libs.memoryEntry", sources=["Emma/emma_libs/memoryEntry.py"])
        ]
    )
except ImportError:
    extensions = None

setuptools.setup(
    name="pypiemma",
    version=Emma.EMMA_VERSION,
    license="GPLv3+",
    description="Emma Memory and Mapfile Analyser (Emma) | Conduct static (i.e. worst case) memory consumption \
    analyses based on arbitrary linker map files. It produces extensive .csv files which are easy to filter and \
    post-process. Optionally .html and markdown reports as well as neat figures help you visualising your results.",
    long_description=long_description,
    long_description_content_type="text/markdown",
    maintainer="The Emma Authors",
    maintainer_email="emma-dev@googlegroups.com",
    url="https://github.com/bmwcarit/Emma",
    zip_safe=False,                                             # Needed for Cython
    packages=setuptools.find_namespace_packages(),              # Recursively find package files (i.e. sub-folders, ...)
    python_requires=Emma.PYTHON_REQ_VERSION,
    install_requires=["Pygments",
                      "Markdown",
                      "matplotlib",
                      "pandas",
                      "pypiscout>=2.0",
                      "graphviz",
                      "svgwrite"
                      ],
    extras_require={"dev":                                      # Install dev version via `pip3 install pypiemma[dev]`
                        ["gprof2dot",
                         "pylint",
                         "mkdocs>=1.1.2",                       # There was a break in the config files: https://squidfunk.github.io/mkdocs-material/releases/5/
                         "mkdocs-material>=5.2.1"               # There was a break in the config files: https://squidfunk.github.io/mkdocs-material/releases/5/
                         ],
                    },
    entry_points={                                              # Make Emma available as independent scripts
        "console_scripts": [
            "emma=Emma.emma:runEmma",
            "emma_vis=Emma.emma_vis:runEmmaVis",
            "emma_deltas=Emma.emma_vis:runEmmaDeltas"
        ],
    },
    ext_modules=extensions,                                     # Needed for Cython
    keywords=[
        "memory-analysis",
        "mapfile",
        "memory-analyzer",
        "embedded",
        "ghs",
        "gcc",
        "mcu",
        "linker",
        "visualization",
        "reports",
        "csv",
        "python",
        "categorisation",
        "memory-consumption",
        "mapfile-analyser"
        ],
    classifiers=[
        "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
        "Programming Language :: Python :: 3",
        "Operating System :: OS Independent",
        "Development Status :: 5 - Production/Stable",
        "Environment :: Console",
        "Topic :: Scientific/Engineering :: Visualization",
        "Topic :: Software Development",
        "Topic :: Software Development :: Embedded Systems",
        "Topic :: Software Development :: Quality Assurance",
    ],
)


import os
from django.core.files.storage import FileSystemStorage

try:
    FileNotFoundError
except:
    FileNotFoundError = IOError

class BaseStorage(FileSystemStorage):
    def _open(self, name, mode='rb'):
        try:
            return super(BaseStorage, self)._open(name, mode)
        except FileNotFoundError:
            if 'w' in mode: # if writing, make sure the parent structure exists
                self._ensure_directory(name)

            try:
                try:
                    f = self._get(name)
                except IOError:
                    # if the underlying file doesn't exist, no matter.
                    pass
                else:
                    # if it does, write the contents locally
                    self._write(f, name)

            except Exception:
                pass
        return super(BaseStorage, self)._open(name, mode)

    def _exists_locally(self, name):
        return super(BaseStorage, self).exists(name)

    def exists(self, name):
        if self._exists_locally(name):
            return True
        return self._exists_upstream(name)

    def _ensure_directory(self, name):
        dirname = os.path.dirname(self.path(name))
        if not os.path.exists(dirname):
            os.makedirs(dirname)

    def _write(self, filelike, name):
        self._ensure_directory(name)
        f = open(self.path(name), mode='wb')
        f.write(filelike.read())

    def _fetch_local(self, name, force=False):
        if self._exists_locally(name) and not force:
            return

        return self._write(self._get(name), name)


# pylint: disable=unused-variable
# pylint: disable=unused-argument
# pylint: disable=redefined-outer-name

import json
from copy import deepcopy

import httpx
import pytest
import respx
from fastapi import FastAPI
from respx import MockRouter
from simcore_service_api_server._meta import API_VTAG
from simcore_service_api_server.core.settings import ApplicationSettings
from simcore_service_api_server.models.schemas.profiles import Profile
from starlette import status

@pytest.fixture
def mocked_webserver_service_api(app: FastAPI):
    """Mocks some responses of web-server service"""

    settings: ApplicationSettings = app.state.settings
    assert settings.API_SERVER_WEBSERVER

    # pylint: disable=not-context-manager
    with respx.mock(
        base_url=settings.API_SERVER_WEBSERVER.api_base_url,
        assert_all_called=False,
        assert_all_mocked=True,
    ) as respx_mock:
        # NOTE: webserver-api uses the same schema as api-server!
        # in-memory fake data
        me = deepcopy(Profile.Config.schema_extra["example"])

        def _get_me(request):
            return httpx.Response(status.HTTP_200_OK, json={"data": me})

        def _update_me(request: httpx.Request):
            changes = json.loads(request.content.decode(request.headers.encoding))
            me.update(changes)
            return httpx.Response(status.HTTP_200_OK, json={"data": me})

        respx_mock.get("/me", name="get_me").mock(side_effect=_get_me)
        respx_mock.put("/me", name="update_me").mock(side_effect=_update_me)

        yield respx_mock

        del me

async def test_get_profile(
    client: httpx.AsyncClient,
    auth: httpx.BasicAuth,
    mocked_webserver_service_api: MockRouter,
):
    # needs no auth
    resp = await client.get(f"/{API_VTAG}/meta")
    assert resp.status_code == status.HTTP_200_OK

    # needs auth
    resp = await client.get(f"/{API_VTAG}/me")
    assert resp.status_code == status.HTTP_401_UNAUTHORIZED
    assert not mocked_webserver_service_api["get_me"].called

    resp = await client.get(f"/{API_VTAG}/me", auth=auth)
    assert resp.status_code == status.HTTP_200_OK
    assert mocked_webserver_service_api["get_me"].called

    profile = Profile(**resp.json())
    assert profile.first_name == "James"
    assert profile.last_name == "Maxwell"

async def test_update_profile(
    client: httpx.AsyncClient,
    auth: httpx.BasicAuth,
    mocked_webserver_service_api: MockRouter,
):
    # needs auth
    resp = await client.put(
        f"/{API_VTAG}/me",
        json={"first_name": "Oliver", "last_name": "Heaviside"},
        auth=auth,
    )
    assert resp.status_code == status.HTTP_200_OK, resp.text

    profile = Profile.parse_obj(resp.json())
    assert profile.first_name == "Oliver"
    assert profile.last_name == "Heaviside"


""" Outlnies the methods to be used for the signUp app. """
from django.shortcuts import render, redirect
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from django.contrib.sites.shortcuts import get_current_site
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
from django.contrib.auth.models import Group
from accounts.models import CustomUser
from signUp import forms
from signUp.tokens import account_activation_token

def activate(request, uidb64, token):
    """ Activates a new user account with their id being their primary key.

    Args:
        request: The HTTP request submitted by the user.
        uidb64: A unique ID for the user's email.
        token: A object to help identify the user.

    Returns:
        redirect: 'login': Redirects the user to the login page once their,
            account has been validated.
    """
    # User = CustomUser.objects.get

    try:
        user = CustomUser.objects.get(pk=id)
        user.is_user = True
        user.save()

    except:
        user = None

    # If the user exists and has a valid token, save the account
    if user is not None and account_activation_token.check_token(user, token):
        user.is_user = True
        user.save()

    return redirect('login')

def activate_email(request, user, to_email) -> None:
    """ Formulates the message that gets sent in the activation email and
    sends the email to the user.

    Args:
        request: The HTTP request submitted by the user.

        user: user: The user object representing the user who is having their
            email validated.

        to_email: (str): The user's email, given as a string for ease of
            processing.
    """
    mail_subject = "Activate your user account"

    # Converts the message to be sent to the user into a string
    message = render_to_string(
        "signUp/template_activate_user.html",
        {"user": user.username,
         "domain": get_current_site(request).domain,
         "uid": urlsafe_base64_encode(force_bytes(user.pk)),
         "token": account_activation_token.make_token(user),
         "protocol": 'https' if request.is_secure() else "http"
         }
    )
    email = EmailMessage(mail_subject, message, to=[to_email])
    email.send()

def signup(request):
    """ Displays the sign up page (GET request) and takes the data from the
    sign up form, validates it and creates a new user, displaying any error
    messages if necessary.

    Args:
        request: The HTTP request submitted by the user.

    Returns:
        render: Signup page is shown to the user if they enter the wrong
            details.

        redirect: (leaderboard): The user is redirected to the leaderboard
            page if they have submitted a valid form.
    """
    if request.method == "POST":

        form = forms.SignUpForm(request.POST)

        # If the data entered into the form is valid save the details and
        # create a new user, otherwise throw the relevant error message
        if form.is_valid():
            user = form.save(commit=False)
            user.is_user = False
            user.save()
            user_group = Group.objects.get(name='user')
            user_group.user_set.add(user)
            activate_email(request, user, form.cleaned_data.get('email'))
            return redirect('leaderboard')

    else:
        # GET request case
        form = forms.SignUpForm()

    return render(request, 'registration/signup.html', {'form': form})


import io
from PIL import Image
import pytesseract
from wand.image import Image as wi
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

pdf = wi(filename = "AvradeepGupta.pdf", resolution = 300)   # To read the pdf file and create a pdf object
pdfImage = pdf.convert('jpeg')                               # To convert the pdf to a pdf of images of jpeg format

imageBlobs = []                                              # Empty List to store each page

for img in pdfImage.sequence:
    imgPage = wi(image= img)                                 # To retrieve the actual image and not the object definition
    imageBlobs.append(imgPage.make_blob('jpeg'))             # Append to the ImageBlobs and to make the binary string of the image

recognized_text = []                                         # List of recognized text for each page

for imgBlob in imageBlobs:                                   # Iterate for all the Images
    im = Image.open(io.BytesIO(imgBlob))                     # Using PIL library and using io to open the image
    text = pytesseract.image_to_string(im, lang='eng')       # Convert the image to string
    recognized_text.append(text)                             # Appending the text content for each image

print(recognized_text)                                       # Printing the entire list

#Image_To_Text
#im = Image.open("acknowledgement.png")
#text = pytesseract.image_to_string(im, lang='eng')

#print(text)


# -*- coding: utf-8 -*-
# ---
# @Software: PyCharm
# @Site:
# @File: num_clustering.py
# @Author: Alan D.Chen
# @E-mail: chense_mail@126.com
# @Time: 2020,八月 07
# ---
import pandas as pd
from sklearn.cluster import KMeans, MeanShift, AgglomerativeClustering, DBSCAN, spectral_clustering
from sklearn import metrics
from sklearn.metrics import calinski_harabasz_score
import matplotlib.pyplot as plt
from xml_extract2 import xml_extract
from DBSCAN2x import dbscanx
import numpy as np
from mean_shiftx import mean_shift
from k_meansx import mainx
from prettytable import PrettyTable
import math

path = '/home/alanc/Documents/faster-rcnn.pytorch-pytorch-1.0/data/VOCdevkit2007/VOC2007/Annotations'
m = num_items_selected = 500
Zdata = xml_extract(path, m)

## just for AgglomerativeClustering
linkages = ['ward', 'average', 'complete']
## just for spectral_clustering
##变换成矩阵，输入必须是对称矩阵
metrics_metrix = (-1 * metrics.pairwise.pairwise_distances(Zdata)).astype(np.int32)
metrics_metrix += -1 * metrics_metrix.min()

## SSE sum of the squared errors
sse_list = []
sse_list2 = []
sse_list3 = []
K = range(1, 15)
for k in range(1,15):
    kmeans=KMeans(n_clusters=k)
    kmeans.fit(Zdata)
    sse_list.append([k, kmeans.inertia_, 0])   #model.inertia_返回模型的误差平方和，保存进入列表

# Calculate the slope difference between the two sides of a point #
for i in range(1,13):
    sse_list[i][2] = (sse_list[i][1]-sse_list[i-1][1])/(sse_list[i][0]-sse_list[i-1][0]) - (sse_list[i+1][1]-sse_list[i][1])/(sse_list[i+1][0]-sse_list[i][0])

for i in range(len(sse_list)-1):
    # 获得第一个元素,将其与剩余的元素进行比较,如果大于即交换位置
    for j in range(i+1,len(sse_list)):
        if sse_list[i][2]>sse_list[j][2]:
            temp=sse_list[j]
            sse_list[j]=sse_list[i]
            sse_list[i]=temp
#print("The best number for K-means clustering by SSE(sum of the squared errors) is ", sse_list[0][0])

## 轮廓系数
## silhouette_score & Calinski-Harabaz Index
clusters = range(2,15)

sc_scores = []
sc_scores2 = []

ac_scores = []
ac_scores2 = []

pc_scores = []
pc_scores2 = []
for k in clusters:
    kmeans_model = KMeans(n_clusters=k).fit(Zdata)
    ac_model = AgglomerativeClustering(linkage=linkages[2], n_clusters=k).fit(Zdata)
    pc_model = spectral_clustering(metrics_metrix, n_clusters=k)

    sc_score = metrics.silhouette_score(Zdata, kmeans_model.labels_,sample_size=10000, metric='euclidean')
    sc_scores.append([k, sc_score])
    sc_score2 = metrics.calinski_harabasz_score(Zdata, kmeans_model.labels_)
    sc_scores2.append([k, sc_score2])
    ## Agglomerative
    ac_score = metrics.silhouette_score(Zdata, ac_model.labels_, sample_size=10000, metric='euclidean')
    ac_scores.append([k, ac_score])
    ac_score2 = metrics.calinski_harabasz_score(Zdata, ac_model.labels_)
    ac_scores2.append([k, ac_score2])
    ## spectral_clustering
    pc_score = metrics.silhouette_score(Zdata, pc_model, sample_size=10000, metric='euclidean')
    pc_scores.append([k, pc_score])
    pc_score2 = metrics.calinski_harabasz_score(Zdata, pc_model)
    pc_scores2.append([k, pc_score2])

for i in range(len(sc_scores)-1):
    # 获得第一个元素,将其与剩余的元素进行比较,如果小于即交换位置
    for j in range(i+1,len(sc_scores)):
        if sc_scores[i][1]<sc_scores[j][1]:
            temp=sc_scores[j]
            sc_scores[j]=sc_scores[i]
            sc_scores[i]=temp
        if sc_scores2[i][1] < sc_scores2[j][1]:
            temp = sc_scores2[j]
            sc_scores2[j] = sc_scores2[i]
            sc_scores2[i] = temp

        if ac_scores[i][1]<ac_scores[j][1]:
            temp=ac_scores[j]
            ac_scores[j]=ac_scores[i]
            ac_scores[i]=temp
        if ac_scores2[i][1] < ac_scores2[j][1]:
            temp = ac_scores2[j]
            ac_scores2[j] = ac_scores2[i]
            ac_scores2[i] = temp

        if pc_scores[i][1]<pc_scores[j][1]:
            temp=pc_scores[j]
            pc_scores[j]=pc_scores[i]
            pc_scores[i]=temp
        if pc_scores2[i][1] < pc_scores2[j][1]:
            temp = pc_scores2[j]
            pc_scores2[j] = pc_scores2[i]
            pc_scores2[i] = temp
        # if sc_scores3[i][1] < sc_scores3[j][1]:
        #     temp = sc_scores3[j]
        #     sc_scores3[j] = sc_scores3[i]
        #     sc_scores3[i] = temp
num_cluster, cluster_ids = mean_shift(Zdata, 70.0)
num_cluster_dbscanx = dbscanx(path, m)
# #print(sc_scores)
# print("The best number for K-means clustering by Silhouette Coefficient is ", sc_scores[0][0])
# #print(sc_scores2)
# print("The best number for K-means clustering by Calinski-Harabaz Index is ", sc_scores2[0][0])
#
# #print(ac_scores)
# print("The best number for Agglomerative clustering by Silhouette Coefficient is ", ac_scores[0][0])
# #print(ac_scores2)
# print("The best number for Agglomerative clustering by Calinski-Harabaz Index is ", ac_scores2[0][0])
#
# #print(pc_scores)
# print("The best number for Spectral clustering by Silhouette Coefficient is ", pc_scores[0][0])
# #print(pc_scores2)
# print("The best number for Spectral clustering by Calinski-Harabaz Index is ", pc_scores2[0][0])
#
# print("The best number for DBSCAN clustering is ", num_cluster_dbscanx)

num_clusterx = (sse_list[0][0] + sc_scores[0][0] + sc_scores2[0][0] + ac_scores[0][0] + ac_scores2[0][0]
                + pc_scores[0][0] + pc_scores2[0][0] + num_cluster_dbscanx)/8
num_clusterx = int(math.ceil(num_clusterx))
#################################
x = PrettyTable(["Method for clustering", "Automatic presentation", "SSE(sum of the squared errors)", "Silhouette Coefficient", "Calinski-Harabaz Index"])
x.align["Method for clustering"] = "l" # Left align city names
x.padding_width = 1 # One space between column edges and contents (default)
x.add_row(["K-means/PAM",0,sse_list[0][0],sc_scores[0][0],sc_scores2[0][0]])
x.add_row(["Hierarchical",0, 0,ac_scores[0][0],ac_scores2[0][0]])
x.add_row(["Spectral",0,0,pc_scores[0][0],pc_scores2[0][0]])
x.add_row(["DBSCANx",num_cluster_dbscanx,0,0,0])
x.add_row(["Mean-shift", num_cluster, 0, 0,0])
print(x)
print("Based on the above information, the following suggestions by the clustering system are : \n ")
nx, centerx = mainx(num_clusterx)
print("Plan 1:\n", "Number of clusters(K-means/PAM):",nx,"\n Cluster center:")
for l in range(len(centerx)):
    print(centerx[l])
print("Plan 2:\n", "Number of clusters(mean shift):",num_cluster,"\n Cluster center:")
for l in range(len(cluster_ids)):
    print(cluster_ids[l])


"""
This module takes care of starting the API Server, Loading the DB and Adding the endpoints
"""
from flask import Flask, request, jsonify, url_for, Blueprint
from api.models import db, User, Family
from api.utils import generate_sitemap, APIException

api = Blueprint('api', __name__)

@api.route('/Family', methods=['GET'])
def get_members():
    Members = Family.query.all()
    result = [element.serialize() for element in Members]
    response_body = {
        "message": "lista familiar"
    }

    return jsonify(result), 200

@api.route('/Family/<int:family_id>', methods=['GET'])
def get_members_id(family_id):
    GetMember = Family.query.get(family_id)
    result = GetMember.serialize()
    response_body = {"msg": "un familiar"}
    return jsonify(result), 200

@api.route('/Family', methods=['POST'])
def create_members():
    data = request.data
    data = json.loads(data)

    Member = Family(
        name= data["name"],
        lastname = data ["lastname"],
        years = data["years"])
    db.session.add(Member)
    db.session.commit()

    response_body = {
        "message": "Creado!"
    }
    return jsonify(Member.serialize())

@api.route('/Family', methods=['DELETE'])
def delete_members():
    data = request.data
    data = json.loads(data)

    memberDel = Family(
    name= data["name"],
    lastname = data ["lastname"],
    years = data["years"])

    db.session.delete(memberDel)
    db.session.commit()

    response_body = {
        "message": "borrado!"
    }

    return jsonify(memberDel), 200


import torch
import copy
from torch.quantization.quantize import add_observer_

_RELU_BRANCH = {'son':None,'can_be_fused':True}
_BN_BRANCH = {'son': {torch.nn.ReLU:_RELU_BRANCH},'can_be_fused':True}
_NN_BRANCH = {'son': {torch.nn.ReLU:_RELU_BRANCH},'can_be_fused':False}
_CONV_BRANCH = {'son': {torch.nn.BatchNorm2d:_BN_BRANCH,torch.nn.ReLU:_RELU_BRANCH},'can_be_fused':False}
_FUSETREE = {'son':{torch.nn.Conv2d:_CONV_BRANCH,torch.nn.Linear:_NN_BRANCH},'can_be_fused':False}
# FuseTree = {torch.nn.Conv2d:{torch.nn.ReLU:None,torch.nn.BatchNorm2d:{torch.nn.ReLU:None}},torch.nn.Linear:{torch.nn.ReLU:None}}

def fuse_module(module, inplace = False):
    if not inplace:
        module = copy.deepcopy(module)
    _fuse_module_helper(module)
    return module

def _fuse_module_helper(module):
    names = []
    tmpTree = _FUSETREE
    for name,child in module.named_children():
        if type(child) in tmpTree['son']:
            tmpTree = tmpTree['son'][type(child)]
            names.append(name)
        else:
            _fuse_module_helper(child)
            if tmpTree['can_be_fused']:
                torch.quantization.fuse_modules(module,names,inplace=True)
                names = []
                tmpTree = _FUSETREE
    if tmpTree['can_be_fused']:
        torch.quantization.fuse_modules(module,names,inplace=True)

# QCONFIGS = {} #use class method
# def propagate_qconfig(module,qconfig=None,inplace=False):
#     if not inplace:
#         module = copy.deepcopy(module)
#     module.qconfig = QCONFIGS[getattr(module,'qconfig',qconfig)]
#     if module.config is None:
#         raise Exception('not qconfig passed in or set in module')
#     for name, child in module.named_children():
#         propagate_qconfig(child,qconfig)
#
# def prepare(model,inplace=False):
#     assert hasattr(model,'qconfig')
#     propagate_qconfig(model,qconfig=model.qconfig,inplace=inplace)
#     add_observer_(model)
#     return model


from mesa import Agent
import random

class GameAgent(Agent):
    """ An agent that is more likely to choose the mean option. """

    def __init__(self, unique_id, model, home_cell=None):
        super().__init__(unique_id, model)
        self.score = 1
        self.home_cell = home_cell
        self.spouse = None
        self.partner = None
        self.choice = None
        self.age = 0
        self.children = []
        self.dead_spouse = False
        self.health = 10

    def __str__(self):
        return f"Agent {self.unique_id}, with score {self.score}. \n Home cell: {str(self.home_cell)}, Spouse: {self.spouse.unique_id if self.spouse else None}. \n Age: {self.age}, Children: {str([[child.age, child.home_cell == self.home_cell] for child in self.children])}. \n Had spouse: {str(self.dead_spouse)}"

    def step(self):
        if self.health < 1 or self.age > 85:
            adult_at_home = [child for child in self.children if
                             ((child.age >= 18) and (child.home_cell == self.home_cell))]
            children_at_home = [child for child in self.children if child.age < 18]
            parents_at_home = [parent for parent in self.parents if parent.home_cell == self.home_cell]
            for child in self.children:
                child.parents.remove(self)
            for parent in self.parents:
                parent.children.remove(self)
            if self.spouse:
                self.spouse.dead_spouse = True
                self.spouse.spouse = None
            else:
                if len(adult_at_home) == 0:

                    if len(children_at_home) > 0:
                        for child in children_at_home:
                            self.model.schedule.remove(child)
                            self.model.grid.remove_agent(child)
                        self.children = []
                    if len(parents_at_home) == 0:
                        if self.home_cell not in self.model.unoccupied_houses:
                            self.model.unoccupied_houses.append(self.home_cell)
                        if self.home_cell in self.model.occupied_houses:
                            self.model.occupied_houses.remove(self.home_cell)
                else:
                    for child in children_at_home:
                        new_parent = random.choice(adult_at_home)
                        new_parent.children.append(child)
                        child.parents.append(new_parent)

            self.model.schedule.remove(self)
            self.model.grid.remove_agent(self)

        else:
            if self.age < 18:
                if self.model.time != "night":
                    pass
                else:
                    self.age += 1
            elif self.spouse is None and len([child for child in self.children if child.spouse is None]) == 0:
                if self.model.time == "morning":
                    self.move(mingle=True)
                elif self.model.time == "midday":
                    if self.partner:
                        self.move_in()
                elif self.model.time == "afternoon":
                    self.move(destination=self.home_cell)
                elif self.model.time == "evening":
                    if self.spouse:
                        self.reproduce()
                else:
                    self.sleep()
            else:
                if self.model.time == "morning":
                    self.move()
                elif self.model.time == "midday":
                    if self.partner:
                        self.choose_action()
                elif self.model.time == "afternoon":
                    self.move(destination=self.home_cell)
                elif self.model.time == "evening":
                    if self.spouse:
                        self.reproduce()
                else:
                    self.sleep()

    def move(self, destination=None, mingle=False):
        if destination is None:
            # Find other player to play with and move to their cell
            # If no other player, move randomly
            if mingle:
                other_players = self.model.out_minglers
            else:
                other_players = self.model.out_agents
            if len(other_players) > 0:
                other_player = random.choice(other_players)
                self.partner = other_player
                other_player.partner = self
                self.move(other_player.pos)
                other_players.remove(other_player)
            else:
                # Move to random cell
                random_cell = (
                    random.randint(1, self.model.grid.width - 2), random.randint(1, self.model.grid.height - 2))
                while not self.model.grid.is_cell_empty(random_cell):
                    random_cell = (
                        random.randint(1, self.model.grid.width - 2), random.randint(1, self.model.grid.height - 2))
                self.move(destination=random_cell)
                other_players.append(self)
        else:
            # Move to destination cell
            self.model.grid.move_agent(self, destination)
            self.pos = destination

    def reproduce(self):
        type_dict = {"mean": MeanAgent, "altruistic": AltruisticAgent, "greenbeard": GreanBeardAltruistic,
                     "imposter": ImposterGreenBeards, "spiteful_family": SpitefulFamily, "spiteful": Spiteful, "tft": TitForTat,
                     "tft_family": TitForTatFamily}
        # print("Trying for babys")
        if self.score > 10 and self.spouse.score > 10:
            # Create new agent
            if 18 < self.age < 55 and 18 < self.spouse.age < 55:
                # print("BABY!")
                num_children = random.randint(1, 2)
                for i in range(num_children):
                    child_type = random.choice([self.type, self.spouse.type])
                    self.model.num_agents += 1
                    child = type_dict[child_type](self.model.num_agents, self.model)
                    child.home_cell = self.home_cell
                    self.model.schedule.add(child)
                    self.model.grid.place_agent(child, child.home_cell)
                    self.children.append(child)
                    self.spouse.children.append(child)
                    child.parents = [self, self.spouse]
                self.score -= 10
                self.spouse.score -= 10

    def sleep(self):
        food_to_eat = self.model.harshness * (1 + sum(
            0.5 for child in self.children if child.home_cell == self.home_cell and child.age >= 18) + sum(
            0.3 for child in self.children if child.home_cell == self.home_cell and child.age < 18))
        if self.score < food_to_eat:
            self.health -= 20
            for child in self.children:
                if child.home_cell == self.home_cell:
                    child.health -= 20
        else:
            self.score -= food_to_eat
            self.health += 10
            for child in self.children:
                if child.home_cell == self.home_cell:
                    child.health += 10
        self.age += 1

    def move_in(self):
        if self.age - 5 <= self.partner.age <= self.age + 5:
            if len(self.model.unoccupied_houses) > 0:
                # Move to random unoccupied house
                self.home_cell = random.choice(self.model.unoccupied_houses)
                self.partner.home_cell = self.home_cell
                self.spouse = self.partner
                self.partner.spouse = self
                self.model.unoccupied_houses.remove(self.home_cell)
                self.model.occupied_houses.append(self.home_cell)

    def fight(self):
        # Prisoner's dilemma
        if self.choice == "cooperate":
            if self.partner.choice == "cooperate":
                self.score += 3
                self.partner.score += 3
            else:
                self.score += 0
                self.partner.score += 5
        else:
            if self.partner.choice == "cooperate":
                self.score += 5
                self.partner.score += 0
            else:
                self.score += 1
                self.partner.score += 1
        self.choice = None
        self.partner.choice = None

class MeanAgent(GameAgent):
    """ An agent that is more likely to choose the mean option. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "mean"

    def choose_action(self):
        # Choose action
        self.choice == "defect"
        if self.partner.choice:
            self.fight()

class AltruisticAgent(GameAgent):
    """ An agent that is more likely to be altruistic. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "altruistic"

    def choose_action(self):
        # Choose action
        self.choice = "cooperate"
        if self.partner.choice:
            self.fight()

class GreanBeardAltruistic(GameAgent):
    """ An agent that is more likely to be altruistic to other greenbeards."""

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "greenbeard"

    def choose_action(self):
        # Choose action

        if self.partner.type == "greenbeard" or self.partner.type == "imposter":
            self.choice = "cooperate"
        else:
            self.choice = "defect"

        if self.partner.choice:
            self.fight()

class ImposterGreenBeards(GameAgent):
    """ An agent who pretends to be a green beard to take advantage of the other greenbeard's altruism."""

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "imposter"

    def choose_action(self):
        # Choose action
        if self.partner.type == "greenbeard" or self.partner.type == "imposter":
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

class SpitefulFamily(GameAgent):
    """ An agent who pretends is altruistic, unless they have been betrayed before. At which point they (and their
    family) will defect. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "spiteful_family"
        self.wronged_list = []

    def choose_action(self):
        # Choose action
        if self.partner in self.wronged_list:
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

    def tell_related(self, agent):
        # Tells the other agent that they have been wronged
        list_of_family = self.children + [self.partner] + self.parents + [[i for i in child.children] for child in
                                                                          self.children]
        for member in list_of_family:
            if member.type == "spiteful_family":
                member.wronged_list.append(agent)

    def fight(self):
        super().fight()
        if self.partner.choice == "defect":
            if self.partner not in self.wronged_list:
                self.wronged_list.append(self.partner)
                self.tell_related(self.partner)

class Spiteful(GameAgent):
    """ An agent who pretends is altruistic, unless they have been betrayed before. At which point they will defect. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "spiteful"
        self.wronged_list = []

    def choose_action(self):
        # Choose action
        if self.partner in self.wronged_list:
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

    def fight(self):
        super().fight()
        if self.partner.choice == "defect":
            if self.partner not in self.wronged_list:
                self.wronged_list.append(self.partner)

class TitForTat(GameAgent):
    """ Classical Tit for Tat strategy. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "tft"
        self.wronged_list = []

    def choose_action(self):
        # Choose action
        if self.partner in self.wronged_list:
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

    def fight(self):
        super().fight()
        if self.partner.choice == "defect":
            if self.partner not in self.wronged_list:
                self.wronged_list.append(self.partner)
        else:
            if self.partner in self.wronged_list:
                self.wronged_list.remove(self.partner)

class TitForTatFamily(GameAgent):
    """ Classical Tit for Tat strategy. """

    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)
        self.type = "tft_family"
        self.wronged_list = []

    def choose_action(self):
        # Choose action
        if self.partner in self.wronged_list:
            self.choice = "defect"
        else:
            self.choice = "cooperate"

        if self.partner.choice:
            self.fight()

    def fight(self):
        super().fight()
        if self.partner.choice == "defect":
            if self.partner not in self.wronged_list:
                self.wronged_list.append(self.partner)
                self.tell_related(self.partner)
        else:
            if self.partner in self.wronged_list:
                self.wronged_list.remove(self.partner, remove=True)

    def tell_related(self, agent, remove=False):
        # Tells the other agent that they have been wronged
        list_of_family = self.children + [self.partner] + self.parents + [[i for i in child.children] for child in
                                                                          self.children]
        for member in list_of_family:
            if member.type == "tft_family":
                if remove:
                    member.wronged_list.remove(agent)
                else:
                    member.wronged_list.append(agent)


'''
Created on May 12, 2015

@author: wohlhart
'''
from tnetcore.layers.base import LayerParams, Layer
from tnetcore.util import readCfgIntNoneListParam, readCfgIntParam  # @UnresolvedImport
import theano.tensor as T
import numpy

class CatLayerParams(LayerParams):
    '''
    Concatenation Layer Parameters
    '''
    yaml_tag = u'!CatLayerParams'

    def __init__(self, inputDim=None,axis=1):
        '''
        '''
        super(CatLayerParams,self).__init__(inputDim=inputDim,outputDim=None)

        self.LayerClass = CatLayer

        self._inputDim = inputDim
        self._axis = axis
        self.update()

    def initFromConfig(self,cfg,sectionKey):
        super(CatLayerParams,self).initFromConfig(cfg,sectionKey)
        self._inputDim = readCfgIntNoneListParam(cfg,sectionKey,'inputDim',self._inputDim)
        self._axis = readCfgIntParam(cfg,sectionKey,'axis',self._axis)
        self.update()

    @property
    def axis(self):
        return self._axis

    @axis.setter
    def axis(self,value):
        self._axis = value
        self.update()

    def update(self):
        '''
        calc outputDim
        '''
        if (self._axis is None) or (self._inputDim is None):
            return

        #assert len(self._inputDim) > 1 and len(self._inputDim[0]) > 1, "CatLayer needs more than one input"
        self.checkInputDim(expectMultipleInputs=True)

        # inputDim is a list of inputDims. check if they agree along the non-cat-axes
        inDim = numpy.array(self._inputDim)
        #print("self._inputDim {}".format(self._inputDim))
        #print("inDim {}".format(inDim))
        assert inDim.shape[1] == 4, "Wrong inputDim shape {}; each row must have 4 entries (bs,nchan,h,w)".format(inDim.shape)
        numInputs = inDim.shape[0]
        nonCatAxes = numpy.setdiff1d(numpy.arange(inDim.shape[1]),[self._axis])
        numEqual = numpy.sum(inDim == inDim[0],axis=0)
        assert all(numEqual[nonCatAxes] == numInputs), "the axes along which not to concatenate must be equal, but are (axis={})\n{}".format(self._axis,inDim)

        # outDim is inDim for all non-cat-axes and sum over inDims for the cat axis
        outDim = inDim[0]
        outDim[self._axis] = sum(inDim[:,self._axis])
        self._outputDim = list(outDim)

        self.checkOutputDim()

    def debugPrint(self,indent=0):

        iStr = " "*indent
        print("CatLayer:")

        print(iStr + "inputs =          {}".format(self._inputs))
        print(iStr + "inputDim =        {}".format(self._inputDim))
        print(iStr + "axis =        {}".format(self._axis))
        print(iStr + "outputDim =       {}".format(self._outputDim))

    def __getstate__(self):
        state = super(CatLayerParams,self).__getstate__()
        state['axis'] = self._axis
        return state

    def __setstate__(self,state):
        super(CatLayerParams,self).__setstate__(state)
        self._axis = state['axis']
        self.update()

class CatLayer(Layer):
    """
    Concatenation Layer
    """

    def __init__(self, rng, inputVar, cfgParams, copyLayer=None, layerNum=None):
        """
        :type rng: numpy.random.RandomState
        :param rng: a random number generator used to initialize weights

        :type inputVar: theano.tensor.dtensor4
        :param inputVar: symbolic image tensor, of shape image_shape

        :type cfgParams: ConvLayerParams
        """
        self.cfgParams = cfgParams

        axis  = cfgParams.axis

        self.inputVar = inputVar

        self.output = T.concatenate(inputVar, axis)

        # store parameters of this layer; has none
        self.params = []
        self.weights = []


from django.conf.urls import include, url
from rest_framework import routers

from App.views import UserViewSet, GroupViewSet, BookViewSet

router = routers.DefaultRouter()
router.register('user',UserViewSet)
router.register('group',GroupViewSet)
router.register('book',BookViewSet)

urlpatterns = [
    url('^drf/',include(router.urls))
]


#! usr/bin/env python
# -*- coding : utf-8 -*-

import codecs
from sklearn import datasets, linear_model
from sklearn.metrics import mean_squared_error, make_scorer
import time
import numpy as np
np.random.seed(123)
from skopt import gp_minimize
import matplotlib.pyplot as plt
from random import uniform
from skopt.acquisition import gaussian_ei

def main():
    # import some data to play with
    X = []
    y = []
    with codecs.open("../data/machine.data", 'r', 'utf-8') as infile:
        for line in infile:
            tokens = line.split(',')
            X.append([float(x) for x in tokens[:5]])
            y.append(float(tokens[6]))
    slice = int(round(len(X)*0.8))
    X_train = X[:slice]
    X_test = X[slice:]
    y_train = y[:slice]
    y_test = y[slice:]
    regr = linear_model.Lasso()
    regr.fit(X_train, y_train)
    y_predict = [i for i in regr.predict(X_test)]
    print("loss of the model:{}".format(mean_squared_error(y_test, y_predict)))

    #  apply gridsearch
    worst_case = float("inf")
    mse_gs_scores = []
    t0 = time.time()
    for g in [(i+1)*0.001 for i in range(8000)]:
        regr = linear_model.Lasso(alpha=g)
        regr.fit(X_train, y_train)
        y_pred = [i for i in regr.predict(X_test)]
        mse = mean_squared_error(y_test, y_pred)
        mse_gs_scores.append([g,mse])
        # save if best
        if mse < worst_case:
            worst_case = mse
            best_grid = g
    t1 = time.time()
    print("time taken by gridserach: {}".format(t1 - t0))
    print((worst_case,best_grid))

    # applying random search
    worst_case = float("inf")
    mse_rs_scores = []
    t0 = time.time()
    for _ in range(1000):
        g = uniform(0, 8)
        regr = linear_model.Lasso(alpha=g)
        regr.fit(X_train, y_train)
        y_pred = [i for i in regr.predict(X_test)]
        mse = mean_squared_error(y_test, y_pred)
        mse_rs_scores.append([g, mse])
        # save if best
        if mse < worst_case:
            worst_case = mse
            best_random = g
    t1 = time.time()
    print("time taken by randomserach: {}".format(t1 - t0))
    print((worst_case,best_random))

    # apply bayesian optimization
    noise_level = 0.1
    def f(alphavalue):
        regr = linear_model.Lasso(alpha=alphavalue)
        regr.fit(X_train, y_train)
        y_pred = [i for i in regr.predict(X_test)]
        return mean_squared_error(y_test, y_pred)
    x = np.array([(i+1)*0.001 for i in range(8000)])
    fx = [f(x_i) for x_i in x]
    plt.plot(x, fx, "r--", label="True (unknown)")
    plt.fill(np.concatenate([x, x[::-1]]),
             np.concatenate(([fx_i - 1.9600 * noise_level for fx_i in fx],
                             [fx_i + 1.9600 * noise_level for fx_i in fx[::-1]])),
             alpha=.2, fc="r", ec="None")
    t4 = time.time()
    res = gp_minimize(f,  # the function to minimize
                      [(0.001, 8.0)],  # the bounds on each dimension of x
                      acq_func="EI",  # the acquisition function
                      n_calls=15,  # the number of evaluations of f
                      n_random_starts=5,  # the number of random initialization points
                      random_state=123)
    t5 = time.time()
    print("time taken by BO_search: {}".format(t5 - t4))
    print(res['fun'])
    print(res['x'])

    plt.plot(res.x_iters, res.func_vals, "b--", label="BO")
    plt.plot([i[0] for i in mse_rs_scores][:10], [i[1] for i in mse_rs_scores][:10], "g--", label="Random Search")
    plt.legend()
    plt.grid()
    plt.show()

    plt.rcParams["figure.figsize"] = (8, 14)

    x = np.linspace(0.001, 8.0, 8000).reshape(-1, 1)
    x_gp = res.space.transform(x.tolist())
    fx = np.array([f(x_i) for x_i in x])

    # Plot the 5 iterations following the 5 random points
    for n_iter in range(5):
        gp = res.models[n_iter]
        curr_x_iters = res.x_iters[:5 + n_iter]
        curr_func_vals = res.func_vals[:5 + n_iter]

        # Plot true function.
        plt.subplot(5, 2, 2 * n_iter + 1)
        plt.plot(x, fx, "r--", label="True (unknown)")
        plt.fill(np.concatenate([x, x[::-1]]),
                 np.concatenate([fx - 1.9600 * noise_level,
                                 fx[::-1] + 1.9600 * noise_level]),
                 alpha=.2, fc="r", ec="None")

        # Plot GP(x) + contours
        y_pred, sigma = gp.predict(x_gp, return_std=True)
        plt.plot(x, y_pred, "g--", label=r"$\mu_{GP}(x)$")
        plt.fill(np.concatenate([x, x[::-1]]),
                 np.concatenate([y_pred - 1.9600 * sigma,
                                 (y_pred + 1.9600 * sigma)[::-1]]),
                 alpha=.2, fc="g", ec="None")

        # Plot sampled points
        plt.plot(curr_x_iters, curr_func_vals,
                 "r.", markersize=8, label="Observations")

        # Adjust plot layout
        plt.grid()

        if n_iter == 0:
            plt.legend(loc="best", prop={'size': 6}, numpoints=1)

        if n_iter != 4:
            plt.tick_params(axis='x', which='both', bottom='off',
                            top='off', labelbottom='off')

            # Plot EI(x)
        plt.subplot(5, 2, 2 * n_iter + 2)
        acq = gaussian_ei(x_gp, gp, y_opt=np.min(curr_func_vals))
        plt.plot(x, acq, "b", label="EI(x)")
        plt.fill_between(x.ravel(), -2.0, acq.ravel(), alpha=0.3, color='blue')

        next_x = res.x_iters[5 + n_iter]
        next_acq = gaussian_ei(res.space.transform([next_x]), gp, y_opt=np.min(curr_func_vals))
        plt.plot(next_x, next_acq, "bo", markersize=6, label="Next query point")

        # Adjust plot layout
        plt.ylim(0, 0.1)
        plt.grid()

        if n_iter == 0:
            plt.legend(loc="best", prop={'size': 6}, numpoints=1)

        if n_iter != 4:
            plt.tick_params(axis='x', which='both', bottom='off',
                            top='off', labelbottom='off')

    plt.show()

if __name__ == '__main__':
    main()


#python
import os
import socket
import time
import csv
from pathlib import Path

#django modules
from django.shortcuts import render, redirect
from django.views.generic.edit import CreateView
from django.views.generic import DetailView, FormView, ListView

#models
from apps.start_block.models import Session
from apps.admin2.models import Athletes, Coach

#local functions
from .math_functions import graph_data, save_csv_data

class DetailSessionView(DetailView):
    template_name = 'start_point/results.html'
    model = Session
    pk_url_kwarg = 'session_id'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        session_id = context['object'].id
        session_data = Session.objects.get(pk = session_id)
        file_name = session_data.data
        context["graph_gauche"] = F"data/{file_name}_left.png"
        context["graph_droit"] = F"data/{file_name}_right.png"
        context["max_force_gauche"] = session_data.max_force_left
        context['max_force_droit'] = session_data.max_force_right
        return context

def delete(request, session_id):
    data = Session.objects.filter(id = session_id)
    data.update(
            enabled = False,
            )
    return redirect("start_block:SessionList")

class CreateSessionView(CreateView):
    model = Session
    fields = [
            'athlete',
            'coach',
            ]
    template_name = "start_point_home.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['file_name'] = generate_file_name()
        return context

def generate_file_name():
    year = time.localtime()[0]
    month =  time.localtime()[1]
    day =  time.localtime()[2]
    hour =  time.localtime()[3]
    mins =  time.localtime()[4]
    sec =  time.localtime()[5]
    name = F"{year}_{month}_{day}_{hour}_{mins}_{sec}"
    return name

def results(request):
    BASE_DIR = Path(__file__).resolve().parent.parent.parent
    template_name = 'start_point/results.html'

    #get info from web page
    coach_id = request.POST["coach"]
    coach_name = Coach.objects.get(
            id = coach_id
            ).nom
    athlete_id = request.POST["athlete"]
    athlete_name = Athletes.objects.get(
            id = athlete_id
            ).nom
    file_name = request.POST["data"]
    file_name = F"{coach_name}__{athlete_name}_{file_name}"
    save_csv_data(file_name)

    print("graficando")
    max_force_gauche, max_force_droit = graph_data(file_name)

    #context data
    data = {
            "graph_gauche": F"data/{file_name}_left.png",
            "max_force_gauche": max_force_gauche,
            'max_force_droit': max_force_droit,
            }

    #saving model
    new_data = Session(
            data = file_name,
            athlete = Athletes.objects.get(id=request.POST['athlete']),
            coach = Coach.objects.get(id=request.POST['coach']),
            max_force_left = max_force_gauche,
            max_force_right = max_force_droit,
            )
    new_data.save()

    return render(
            request,
            template_name,
            context = data
            )

def get_data(request):
    name = request.POST["data"]
    file = open(name, "a")

    #if(request.method == "GET"):
    #    return redirect("start_block:home")

    s_point = socket.socket()
    port = 50
    host = "10.20.1.56"
    print(F"Connecting to {host} in port {port}")
    s_point.connect((host, port))
    try:
        message = b"1"
        s_point.send(message)

        data = b""
        number = 0
        llega = b""
        print(F'Receiving data in {name}')
        while (not data == b"!"):
            data = s_point.recv(1)
            #print(data)
            llega += data
            if (data == b"\n"):
                number += 1
                #print(F"{number} = {str(llega)}")
                file.write(F"{llega.decode('ascii')}")
                llega = b""

    except Exception as E:
        print("Error: ")
        print(E)

    file.close()
    s_point.close()
    new_data = Session()
    new_data.athlete = Athletes.objects.get(id=request.POST['athlete'])
    new_data.data = request.POST['data']
    new_data.save()

    return redirect("start_block:home")

class ListSessionView(ListView):
    model = Session
    template_name = 'start_point/list_sessions.html'

    def get_queryset(self):
        return Session.objects.filter(
                athlete__enabled = True,
                ).exclude(
                enabled = False,
                )

    def get_ordering(self):
        ordering = self.request.GET.get('ordering', 'created')
        # validate ordering here
        return ordering


import json
import os
import settings

from jsonschema import validate
from decimal_encoder import DecimalEncoder
from lambda_base import LambdaBase

class ArticlesEyecatch(LambdaBase):
    def get_schema(self):
        return {
            'type': 'object',
            'properties': {
                'topic': settings.parameters['topic']
            },
            'required': ['topic']
        }

    def validate_params(self):
        validate(self.params, self.get_schema())

    def exec_main_proc(self):
        screened_article_table = self.dynamodb.Table(os.environ['SCREENED_ARTICLE_TABLE_NAME'])
        eyecatch_articles = screened_article_table.get_item(Key={'article_type': 'eyecatch'}).get('Item')

        if not eyecatch_articles \
                or not eyecatch_articles.get('articles') \
                or not eyecatch_articles.get('articles').get(self.params['topic']):
            items = []
            return {
                'statusCode': 200,
                'body': json.dumps({'Items': items})
            }

        items = [self.__get_public_article(article_id) for article_id in
                 eyecatch_articles.get('articles').get(self.params['topic'])]
        items = [item for item in items if item is not None]

        return {
            'statusCode': 200,
            'body': json.dumps({'Items': items}, cls=DecimalEncoder)
        }

    def __get_public_article(self, article_id):
        article_info_table = self.dynamodb.Table(os.environ['ARTICLE_INFO_TABLE_NAME'])
        article_info = article_info_table.get_item(Key={'article_id': article_id}).get('Item')

        if not article_info or not article_info['status'] == 'public':
            return None

        return article_info


"""
  This module contains a basic orchestrator for the execution of sequential data transformation stages.
"""
from __future__ import annotations
import typing as t
import types
from fontai.config.pipeline import Config as PipelineConfig, ConfigHandler as PipelineConfigHandler
from fontai.runners.base import ConfigurableTransform, FittableTransform
from fontai.config.core import BasePipelineTransformConfig

class ManyToManyTransform(object):

  """Helper class to execute one-to-many many-to-many transformations in the pipeline

  Attributes:
      core_transform (ConfigurableTransform): Core transformer class
  """

  def __init__(self, core_transform):
    self.core_transform = core_transform

  def transform(self, data: t.Any):
    """Outputs a generator of transformed elements

    Args:
        data (t.Any): Input data

    Yields:
        t.Any: individual outputs
    """
    for elem in self.to_generator(data):
      for out in self.to_generator(self.core_transform.transform(elem)):
        yield out

  def to_generator(self, data):
    if not isinstance(data, types.GeneratorType):
      return iter((data,))
    else:
      return data

class Pipeline(ConfigurableTransform):

  """Pipeline class to execute a sequence of ConfigurableTransforms; this allows to perform the whole set of transformations from raw data to (possible multiple) trained models

  Attributes:
      streaming_pipeline (t.List[ConfigurableTransform]): List of instantiated transforms
      transforms (type): classes of pipeline stages inheriting from ConfigurableTransform. Possible choices are defined in the fontai.runners.stages module
      configs (t.List[BasePipelineTransformConfig]): Sequence of configuration files to instantiate and execute each stage
      fit_stage (t.List[bool]): If True, fit the corresponding pipeline stage instead of using it for scoring. It is ignored if the stage is not fittable.
  """

  def __init__(self, transforms: t.List[type], configs: t.List[BasePipelineTransformConfig], fit_stage: t.List[bool]):
    """Summary

    Args:
        transforms (t.List[type]): List of transformations in the pipeline
        configs (t.List[BasePipelineTransformConfig]): List of parsed configurations, one per stage in the pipeline
        fit_stage (t.List[bool]): If True, fit the corresponding pipeline stage instead of using it for scoring. It is ignored if the stage is not fittable.
    """
    self.transforms = transforms
    self.configs = configs
    self.fit_stage = fit_stage

    self.streaming_pipeline = [
      ManyToManyTransform(core_transform = transform.from_config_object(config)) for transform, config in zip(self.transforms, self.configs)]

  def transform(self, data: t.Any) -> t.Any:

    out = data
    for streaming_transform in self.streaming_pipeline:
      out = streaming_transform.transform(out)

    return out

  @classmethod
  def from_config_object(cls, config: PipelineConfig) -> Pipeline:
    return cls(config.stages, config.configs, config.fit_stage)

  @classmethod
  def run_from_config_object(cls, config: PipelineConfig) -> None:
    pipeline = cls.from_config_object(config)
    for transform, config, fit in zip(pipeline.transforms, pipeline.configs, pipeline.fit_stage):
      if fit and issubclass(transform, FittableTransform):
        transform.fit_from_config_object(config)
      else:
        transform.run_from_config_object(config)

  @classmethod
  def get_config_parser(cls) -> PipelineConfigHandler:
    return PipelineConfigHandler()


from Models import pi_net, weights_init_1st
import multiprocessing
import torch.optim as optim
import torch
from torch.distributions import Categorical
import torch.nn.functional as F
from torch import tanh
import numpy as np
from utils import get_state_repr_from_int, get_state_from_int, get_state_as_int, get_state_repr, get_state_as_pair

FloatTensor =  torch.FloatTensor
LongTensor = torch.LongTensor
ByteTensor = torch.ByteTensor

def __repr__(self):
    return '<%s.%s object at %s>' % (
        self.__class__.__module__,
        self.__class__.__name__,
        hex(id(self))
    )

class Agent():

    def __init__(self, agent_id, sending_queue, response_queue, episodes, exp_conf, results):
        self.agent_id = agent_id
        self.action_queue = sending_queue
        self.continue_queue = response_queue

        self.net = pi_net()
        self.net.apply(weights_init_1st)
        self.lr = exp_conf['lr']
        self.optimizer = optim.RMSprop(self.net.parameters(), lr=self.lr)

        self.episodes = episodes
        self.results = results
        self.net_class = exp_conf['net']
        self.DEBUG = exp_conf["DEBUG"]
        self.GAMMA = exp_conf['gamma']

    def reset(self):
        print("reset")

    def start(self):
        #print(multiprocessing.current_process(), __repr__(self.net), __repr__(self))
        reward_per_day = []
        score = []
        times_trained = 0
        times_reach_goal = 0
        for k in range(self.episodes):
            observation = np.zeros((6,6))
            observation[0,0] = 6

            episode_series = []
            reward_acum = []

            time_of_day = 0
            done = False
            while not done:
                np_observation = get_state_repr(observation)
                # np_observation = np.expand_dims(np_observation, axis=0)
                np_observation = np.expand_dims(np_observation, axis=0)
                observation_tensor = torch.FloatTensor(np_observation)

                action_probs = self.net(observation_tensor)
                action_probs_orig = action_probs

                # FOR EXPLORATION:
                action_probs = F.dropout(action_probs, p=0.3, training=True)

                action_probs = F.softmax(action_probs, dim=1)

                m = Categorical(action_probs)
                action = m.sample()

                log_prob = m.log_prob(action)

                # break
                # Execute action in environment.

                if k % 1000 == 0 and self.DEBUG:
                    # print("action_probs_orig ")
                    # print(action_probs_orig)
                    print("Time of day=" + str(time_of_day) + ", on state=" + str(get_state_as_pair(observation)) +
                          ", selected action=" + str(get_state_as_pair(get_state_from_int(action.item()))) + " ,")

                time_of_day += 1

                # sending to env:
                self.action_queue.put((self.agent_id, action.item()))

                # waiting for result:
                observation, reward, done, info = self.continue_queue.get()

                if k % 1000 == 0 and self.DEBUG:
                    print(
                    "new state=" + str(get_state_as_pair(observation)) + ", rewards=" + str(reward) + ", done=" + str(
                        done))

                # if done and reward != 1.0:
                # 	if observation == 5 or observation == 7 or observation == 11 or observation == 12:
                # 		reward = -1.0

                step_data = [get_state_repr(observation), action, log_prob, reward, done, info]
                episode_series.append(step_data)
                last_reward = reward
                reward_acum.append(reward)

            # FINISH EPISODE

            reward_per_day.append(np.sum(reward_acum))

            if len(score) < 100 :
                score.append(np.sum(reward_acum))
            else:
                score[k % 100] = np.sum(reward_acum)

            if k % 1000 == 0 and self.DEBUG:
                print(
                    "Episode {} finished after {} timesteps with r={}. Running score: {}. Times trained: {}. Times reached goal: {}.".format(
                        k, len(episode_series), np.sum(reward_acum), np.mean(score), times_trained, times_reach_goal))
                times_trained = 0
                times_reach_goal = 0

            policy_loss = []
            rewards_list = []
            for i in range(len(episode_series)):
                j = i
                G = 0
                # alpha = 1 / len(episode_series)

                # get the log_prob of the last state:
                gamma_cum = 1

                while j < len(episode_series):
                    [observation, action, log_prob, reward, done, info] = episode_series[j]
                    G = G + reward * gamma_cum

                    gamma_cum = gamma_cum * self.GAMMA
                    j = j + 1

                [observation, action, log_prob, reward, done, info] = episode_series[i]

                policy_loss.append(G * -log_prob)

                rewards_list.append(G)

            policy_loss = torch.cat(policy_loss).sum()
            policy_loss.backward()
            self.optimizer.step()
            policy_loss = []

            times_trained = times_trained + 1

            if reward > 0.0:
                times_reach_goal = times_reach_goal + 1

        self.results.put(reward_per_day) # MP.Queue()

        #print("reward_per_day")
        #print(reward_per_day)


from django.shortcuts import render
from fristapp.models import People, Aritcle
from django.http import HttpResponse
from django.template import Context, Template
# Create your views here.

def first_try(request):
    person = People(name='Spork', job="officer")
    html_string = '''

    <title>firstApp</title>
    <meta charset="UTF-8">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.4/semantic.css" rel="stylesheet">

         Hello,{{person.name}}

    '''
    t = Template(html_string)
    c = Context({'person': person})
    web_page = t.render(c)

    return HttpResponse(web_page)

def index(request):
    queruset = request.GET.get('tag')
    if queruset:
        article_list = Aritcle.objects.filter(tag=queruset)
    else:
        article_list = Aritcle.objects.all()

    print(queruset)
    Context = {}

    Context['article_list'] = article_list
    index_page = render(request, 'firstweb.html', Context)
    return index_page


from cloud.filestore.tests.python.lib.common import get_nfs_mount_path
import os
import pytest
import shutil
import tempfile

def pytest_addoption(parser):
    parser.addoption(
        "--target-dir",
        action="store",
        default="Path to target directory to run tests on",
    )

@pytest.fixture
def target_dir_path(pytestconfig):
    try:
        tmp_dir = tempfile.mkdtemp(dir=get_nfs_mount_path())
        yield tmp_dir
    finally:
        if tmp_dir is not None:
            shutil.rmtree(tmp_dir, ignore_errors=True)

def lock_file_descriptor(target_dir_path: str, flags: int):
    flags |= os.O_CREAT
    suffix = 'read' if flags & os.O_RDONLY else 'write'
    lock_file_path = os.path.join(target_dir_path, f'test_lockfile_{suffix}')
    if not os.path.exists(lock_file_path):
        os.mknod(lock_file_path)
    fd = os.open(lock_file_path, flags)
    assert fd > 0
    try:
        yield fd
    finally:
        os.close(fd)

@pytest.fixture()
def read_lock_file_descriptor(target_dir_path):
    yield from lock_file_descriptor(target_dir_path, os.O_RDONLY)

@pytest.fixture()
def read_lock_file_descriptor_second(target_dir_path):
    yield from lock_file_descriptor(target_dir_path, os.O_RDONLY)

@pytest.fixture()
def write_lock_file_descriptor(target_dir_path):
    yield from lock_file_descriptor(target_dir_path, os.O_WRONLY)