import logging
log = logging.getLogger(__name__)

import re
import requests

from bs4 import BeautifulSoup
try:
    # Python 2 has a standard urlparse library
    from urlparse import urlparse, ParseResult
except:
    # Python 3 has the same library hidden in urllib.parse
    from urllib.parse import urlparse, ParseResult

MAX_FILEIZE =  2**19  # bytes; this is .5MB
MAX_CONNECTIONTIME = 20  # in seconds

RE_bad_title = re.compile(
    """(?:<title>|<title>)(.*)(?:<?/title>|(?:<)?/title>)""", re.I)

REGEX_doctype = re.compile("^\s*<!DOCTYPE[^>]*>", re.IGNORECASE)

RE_whitespace = re.compile("\s+")

PARSE_SAFE_FILES = ('html', 'txt', 'json', 'htm', 'xml',
                    'php', 'asp', 'aspx', 'ece', 'xhtml', 'cfm', 'cgi')

# based on DJANGO
# https://github.com/django/django/blob/master/django/core/validators.py
# not testing ipv6 right now, because rules are needed for ensuring they are correct
RE_VALID_HOSTNAME = re.compile(
    r'(?:'
        r'(?P<ipv4>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ipv4
        r'|'
        #  r'(?P<ipv6>\[?[A-F0-9]*:[A-F0-9:]+\]?)'  # ...or ipv6
        #  r'|'
        r'(?P<localhost>localhost)'  # localhost...
        r'|'
        r'(?P<domain>([A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}(?<!-)\.?))'  # domain...
        r'(?P<port>:\d+)?'  # optional port
    r')', re.IGNORECASE)

RE_PORT = re.compile(
    r'^'
    r'(?P<main>.+)'
    r':'
    r'(?P<port>\d+)'
    r'$', re.IGNORECASE
)

RE_DOMAIN_NAME = re.compile(
    r"""(^
            (?:
                [A-Z0-9]
                (?:
                    [A-Z0-9-]{0,61}
                    [A-Z0-9]
                )?
                \.
            )+
            (?:
                [A-Z]{2,6}\.?
                |
                [A-Z0-9-]{2,}
            (?<!-)\.?)
        $)""",
    re.VERBOSE | re.IGNORECASE)

RE_IPV4_ADDRESS = re.compile(
    r'^(\d{1,3})\.(\d{1,3}).(\d{1,3}).(\d{1,3})$'  # grab 4 octets
)

RE_ALL_NUMERIC = re.compile("^[\d\.]+$")

def is_parsed_valid_url(parsed, require_public_netloc=True, http_only=True):
    """returns bool
        `http_only`
            defaults True
            requires http or https for the scheme
    """
    assert isinstance(parsed, ParseResult)
    log.debug("is_parsed_valid_url = %s", parsed)
    if not all((parsed.scheme, parsed.netloc)):
        log.debug(" FALSE - missing `scheme` or `netloc`")
        return False
    if http_only:
        if parsed.scheme not in ('http', 'https'):
            log.debug(" FALSE - invalid `scheme`")
            return False
    if require_public_netloc:
        log.debug(" validating netloc")
        _netloc_match = RE_VALID_HOSTNAME.match(parsed.netloc)
        if not _netloc_match:
            log.debug(" did not match regex")
            return False

        # we may assign these
        _netloc_clean = parsed.netloc
        _port = None

        _netloc_ported = RE_PORT.match(parsed.netloc)
        if _netloc_ported:
            _netloc_ported_groudict = _netloc_ported.groupdict()
            _netloc_clean = _netloc_ported_groudict['main']
            _port = _netloc_ported_groudict['port']

        _netloc_groudict = _netloc_match.groupdict()
        if _netloc_groudict['ipv4'] is not None:
            octets = RE_IPV4_ADDRESS.match(_netloc_clean)
            if octets:
                log.debug(" validating against ipv4")
                for g in octets.groups():
                    g = int(g)
                    if int(g) > 255:
                        log.debug(" invalid ipv4; encountered an octect > 255")
                        return False
                log.debug(" valid ipv4")
                return True
            log.debug(" invalid ipv4")
            return False
        else:
            if _netloc_clean == 'localhost':
                log.debug(" localhost!")
                return True

            if RE_ALL_NUMERIC.match(_netloc_clean):
                log.debug(" This only has numeric characters. "
                          "this is probably a fake or typo ip address.")
                return False
            if _port:
                try:
                    _port = int(_port)
                    if parsed.port != _port:
                        log.debug(" netloc.port does not match our regex _port")
                        return False
                except:
                    raise
                    log.debug(" _port is not an int")
                    return False
            if RE_DOMAIN_NAME.match(_netloc_clean):
                log.debug(" valid public domain name format")
                return True
        log.debug(" this appears to be invalid")
        return False
    return True

def is_parsed_valid_relative(parsed):
    """returns bool"""
    assert isinstance(parsed, ParseResult)
    if parsed.path and not any((parsed.scheme, parsed.hostname)):
        return True
    return False

def parsed_to_relative(parsed):
    """turns a parsed url into a full relative url"""
    assert isinstance(parsed, ParseResult)
    _path = parsed.path
    # cleanup, might be unnecessary now
    if _path and _path[0] != "/":
        # prepend a slash
        _path = "/%s" % _path
    if parsed.query:
        _path += "?" + parsed.query
    if parsed.fragment:
        _path += "#" + parsed.fragment
    return _path

def is_url_valid(url, require_public_netloc=None):
    """
    tries to parse a url. if valid returns `ParseResult`
    (boolean eval is True); if invalid returns `False`
    """
    if url is None:
        return False
    parsed = urlparse(url)
    if is_parsed_valid_url(parsed, require_public_netloc=require_public_netloc):
        return parsed
    return False

def url_to_absolute_url(url_test, url_fallback=None, require_public_netloc=None):
    """
        returns an "absolute url" if we have one.
        if we don't, it tries to fix the current url based on the fallback

        this shouldn't be needed, but it is.

        called by:

            MetadataParser.absolute_url()
            MetadataParser.get_discrete_url()

        args:
            `url_test` - the url to return/fix
            `url_fallback` - a fallback url.  this is returned in VERY bad
                errors. in "not so bad" errors, this is parsed and used as the
                base to construct a new url.
            `require_public_netloc` - requires the hostname/netloc to be a
                valid IPV4 or public dns domain name
    """
    if url_test is None and url_fallback is not None:
        return url_fallback

    parsed = urlparse(url_test)

    _path = parsed.path
    if _path:
        # sanity check
        # some stock plugins create invalid urls/files like '/...' in meta-data
        if _path[0] != "/":
            # prepend a slash
            _path = "/%s" % _path
        known_invalid_plugins = ['/...', ]
        if _path in known_invalid_plugins:
            return url_fallback

    # finally, fix the path
    # this isn't nested, because we could have kwargs
    _path = parsed_to_relative(parsed)

    if not _path:
        # so if our _path is BLANK, fuck it.
        # this can happen if someone puts in "" for the canonical
        return url_fallback

    rval = None

    # we'll use a placeholder for a source 'parsed' object that has a domain...
    parsed_domain_source = None

    # if we have a valid URL (OMFG, PLEASE)...
    if is_parsed_valid_url(parsed, require_public_netloc=require_public_netloc):
        parsed_domain_source = parsed
    else:
        # ok, the URL isn't valid
        # can we re-assemble it
        if url_fallback:
            parsed_fallback = urlparse(url_fallback)
            if is_parsed_valid_url(
                parsed_fallback,
                require_public_netloc=require_public_netloc
            ):
                parsed_domain_source = parsed_fallback
    if parsed_domain_source:
        rval = "%s://%s%s" % (
            parsed_domain_source.scheme,
            parsed_domain_source.netloc, _path)
    return rval

class NotParsable(Exception):

    def __init__(self, message='', raised=None, code=None):
        self.message = message
        self.raised = raised
        self.code = code

    def __str__(self):
        return "ApiError: %s | %s | %s" % (self.message, self.code, self.raised)

class NotParsableFetchError(NotParsable):
    pass

class MetadataParser(object):
    """
    turns text or a URL into a dict of dicts, extracting as much relevant
    metadata as possible.

    the 'keys' will be either the 'name' or 'property' attribute of the node.

    we EXPECT/REQUIRE a `head` in the document.

    the attribute's prefix are removed when storing into it's bucket
    eg:
        og:title -> 'og':{'title':''}

    metadata is stored into subgroups:

    page
        extracted from page elements
        saved into MetadataParser.metadata['page']
        example:
            <head><title>Awesome</title></head>
            MetadataParser.metadata = {'page': {'title':'Awesome'}}

    opengraph
        has 'og:' prefix
        saved into MetadataParser.metadata['og']
        example:
            <meta property="og:title" content="Awesome"/>
            MetadataParser.metadata = {'og': {'og:title':'Awesome'}}

    dublin core
        has 'dc:' prefix
        saved into MetadataParser.metadata['dc']
        example:
            <meta property="dc:title" content="Awesome"/>
            MetadataParser.metadata = {'dc': {'dc:title':'Awesome'}}

    meta
        has no prefix
        saved into MetadataParser.metadata['meta']
        example:
            <meta property="title" content="Awesome"/>
            MetadataParser.metadata = {'meta': {'dc:title':'Awesome'}}

    NOTE:
        passing in ssl_verify=False will turn off ssl verification checking
        in the requests library.
        this can be necessary on development machines
    """
    url = None
    url_actual = None
    strategy = None
    metadata = None
    LEN_MAX_TITLE = 255
    only_parse_file_extensions = None
    require_public_netloc = None
    force_doctype = None
    requests_timeout = None

    # allow for the beautiful_soup to be saved
    soup = None

    og_minimum_requirements = ['title', 'type', 'image', 'url']
    twitter_sections = ['card', 'title', 'site', 'description']
    strategy = ['og', 'dc', 'meta', 'page']

    def __init__(
        self,
        url=None, html=None, strategy=None, url_data=None, url_headers=None,
        force_parse=False, ssl_verify=True, only_parse_file_extensions=None,
        force_parse_invalid_content_type=False, require_public_netloc=True,
        force_doctype=False, requests_timeout=None,
    ):
        """
        creates a new `MetadataParser` instance.

        kwargs:
            `url`
                url to parse
            `html`
                instead of a url, parse raw html
            `strategy`
                default: None
                sets default metadata strategy (['og', 'dc', 'meta', 'page'])
                see also `MetadataParser.get_metadata()`
            `url_data`
                data passed to `requests` library as `params`
            `url_headers`
                data passed to `requests` library as `headers`
            `force_parse`
                default: False
                force parsing invalid content
            `ssl_verify`
                default: True
                disable ssl verification, sometimes needed in development
            `only_parse_file_extensions`
                default: None
                set a list of valid file extensions.
                see `metadata_parser.PARSE_SAFE_FILES` for an example list
            `force_parse_invalid_content_type`
                default: False
                force parsing invalid content types
                by default this will only parse text/html content
            `require_public_netloc`
                default: True
                require a valid `netloc` for the host.  if `True`, valid hosts
                must be a properly formatted public domain name, IPV4 address
                or "localhost"
            `force_doctype`
                default: False
                if set to true, will replace a doctype with 'html'
                why? some cms give a bad doctype (like nasa.gov)
                which can break lxml/bsd
            `requests_timeout`
                default: None
                if set, proxies the value into `requests.get` as `timeout`

        """
        self.metadata = {
            'og': {},
            'meta': {},
            'dc': {},
            'page': {},
            'twitter': {}
        }
        if strategy:
            self.strategy = strategy
        if url is not None:
            url = url.strip()
        self.url = url
        self.url_actual = url
        self.ssl_verify = ssl_verify
        self.soup = None
        self.force_doctype = force_doctype
        self.response = None
        self.response_headers = {}
        self.require_public_netloc = require_public_netloc
        self.requests_timeout = requests_timeout
        if only_parse_file_extensions is not None:
            self.only_parse_file_extensions = only_parse_file_extensions
        if html is None:
            html = self.fetch_url(
                url_data=url_data, url_headers=url_headers,
                force_parse=force_parse,
                force_parse_invalid_content_type=force_parse_invalid_content_type
            )
        self.parser(html, force_parse=force_parse)

    def is_opengraph_minimum(self):
        """
        returns true/false if the page has the minimum amount of opengraph tags
        """
        return all([hasattr(self, attr)
                   for attr in self.og_minimum_requirements])

    def fetch_url(
        self,
        url_data=None, url_headers=None, force_parse=False,
        force_parse_invalid_content_type=False
    ):
        """
        fetches the url and returns it.
        this was busted out so you could subclass.
        """
        # should we even download/parse this?
        if not force_parse and self.only_parse_file_extensions is not None:
            parsed = urlparse(self.url)
            path = parsed.path
            if path:
                url_fpath = path.split('.')
                if len(url_fpath) == 0:
                    # i have no idea what this file is, it's likely using a
                    # directory index
                    pass
                elif len(url_fpath) > 1:
                    url_fext = url_fpath[-1]
                    if url_fext in self.only_parse_file_extensions:
                        pass
                    else:
                        raise NotParsable("I don't know what this file is")

        # borrowing some ideas from
        # http://code.google.com/p/feedparser/source/browse/trunk/feedparser/feedparser.py#3701
        if not url_headers:
            url_headers = {}

        # if someone does usertracking with sharethis.com, they get a hashbang
        # like this: http://example.com/page#.UHeGb2nuVo8
        # that fucks things up.
        url = self.url.split('#')[0]

        r = None
        try:
            # requests gives us unicode and the correct encoding, yay
            r = requests.get(
                url, params=url_data, headers=url_headers,
                allow_redirects=True, verify=self.ssl_verify,
                timeout=self.requests_timeout, stream=True,
            )
            content_type = None
            if 'content-type' in r.headers:
                content_type = r.headers['content-type']
                # content type can have a character encoding in it...
                content_type = [i.strip() for i in content_type.split(';')]
                content_type = content_type[0].lower()

            if (
                (
                    (content_type is None)
                    or
                    (content_type != 'text/html')
                )
                and
                (not force_parse_invalid_content_type)
            ):
                raise NotParsable("I don't know what type of file this is! "
                                  "content-type:'[%s]" % content_type)

            # okay, now we need to read
            ## TODO
            ## TODO
            ## TODO
            ## TODO

            html = r.text
            self.response = r

            # lowercase all of the HTTP headers for comparisons per RFC 2616
            self.response_headers = dict((k.lower(), v)
                                         for k, v in r.headers.items())
            self.url_actual = r.url

            if r.status_code != 200:
                raise NotParsableFetchError(
                    message="Status Code is not 200",
                    code=r.status_code
                )

        except requests.exceptions.RequestException as error:
            raise NotParsableFetchError(
                message="Error with `requests` library.  Inspect the `raised`"
                        " attribute of this error.",
                raised=error
            )

        return html

    def absolute_url(self, link=None):
        """
        makes the url absolute, as sometimes people use a relative url. sigh.
        """
        url_fallback = self.url_actual or self.url or None
        return url_to_absolute_url(
            link,
            url_fallback=url_fallback,
            require_public_netloc=self.require_public_netloc
        )

    def parser(self, html, force_parse=False):
        """parses the html
        """
        if not isinstance(html, BeautifulSoup):
            # clean the html?
            if self.force_doctype:
                html = REGEX_doctype.sub("<!DOCTYPE html>", html)
            try:
                doc = BeautifulSoup(html, "lxml")
            except:
                doc = BeautifulSoup(html, "html.parser")
        else:
            doc = html

        # let's ensure that we have a real document...
        if not doc or not doc.html or not doc.html.head:
            return

        # stash the bs4 doc for further operations
        self.soup = doc

        ogs = doc.html.head.findAll(
            'meta',
            attrs={'property': re.compile(r'^og')}
        )
        for og in ogs:
            try:
                self.metadata['og'][og['property'][3:]] = og['content'].strip()
            except (AttributeError, KeyError):
                pass
            except:
                log.debug("Ran into a serious error parsing `og`")
                pass

        twitters = doc.html.head.findAll(
            'meta',
            attrs={'name': re.compile(r'^twitter')}
        )
        for twitter in twitters:
            try:
                self.metadata['twitter'][
                    twitter['name'][8:]] = twitter['value'].strip()
            except (AttributeError, KeyError):
                pass

        # pull the text off the title
        try:
            _title_text = doc.html.head.title.text
            if len(_title_text) > self.LEN_MAX_TITLE:
                _title_text = _title_text[:self.LEN_MAX_TITLE]
            self.metadata['page']['title'] = _title_text

        except AttributeError:
            pass

        # is there an image_src?
        images = doc.findAll(
            'link',
            attrs={'rel': re.compile("^image_src$", re.I)}
        )
        if images:
            image = images[0]
            if image.has_attr("href"):
                img_url = image['href'].strip()
                self.metadata['page']['image'] = img_url
            elif image.has_attr("content"):
                img_url = image['content'].strip()
                self.metadata['page']['image'] = img_url
            else:
                pass

        # figure out the canonical url
        canonicals = doc.findAll(
            'link',
            attrs={'rel': re.compile("^canonical$", re.I)}
        )
        if canonicals:
            canonical = canonicals[0]
            if canonical.has_attr("href"):
                link = canonical['href'].strip()
                self.metadata['page']['canonical'] = link
            elif canonical.has_attr("content"):
                link = canonical['content'].strip()
                self.metadata['page']['canonical'] = link
            else:
                pass

        # pull out all the metadata
        meta = doc.html.head.findAll(name='meta')
        for m in meta:
            try:
                k = None
                v = None
                attrs = m.attrs
                k = None
                if 'name' in attrs:
                    k = 'name'
                elif 'property' in attrs:
                    k = 'property'
                elif 'http-equiv' in attrs:
                    k = 'http-equiv'
                if k:
                    k = attrs[k].strip()
                    if 'content' in attrs:
                        v = attrs['content'].strip()
                    if (len(k) > 3) and (k[:3] == 'dc:'):
                        self.metadata['dc'][k[3:]] = v
                    else:
                        self.metadata['meta'][k] = v
            except AttributeError:
                pass

    def get_metadata(self, field, strategy=None):
        """
            looks for the field in various stores.  defaults to the core
            strategy, though you may specify a certain item.  if you search for
            'all' it will return a dict of all values.
        """
        if strategy:
            _strategy = strategy
        else:
            _strategy = self.strategy
        if _strategy == 'all':
            rval = {}
            for store in self.metadata:
                if field in self.metadata[store]:
                    rval[store] = self.metadata[store][field]
            return rval
        for store in _strategy:
            if store in self.metadata:
                if field in self.metadata[store]:
                    return self.metadata[store][field]
        return None

    def get_discrete_url(
        self,
        og_first=True, canonical_first=False, allow_invalid=False
    ):
        """convenience method.
            if `allow_invalid` is True, it will return the raw data.
            if `allow_invalid` is False (default), it will try to correct
                the data (relative to absolute) or reset to None.
        """
        og = self.get_metadata('url', strategy=['og'])
        canonical = self.get_metadata('canonical', strategy=['page'])

        if not allow_invalid:

            # fallback url is used to drop a domain
            url_fallback = self.url_actual or self.url or None

            if og and not is_url_valid(
                og,
                require_public_netloc=self.require_public_netloc
            ):
                # try making it absolute
                og = url_to_absolute_url(
                    og,
                    url_fallback=url_fallback,
                    require_public_netloc=self.require_public_netloc
                )
                if not is_url_valid(
                    og,
                    require_public_netloc=self.require_public_netloc
                ):
                    # set to NONE if invalid
                    og = None

            if canonical and not is_url_valid(
                canonical,
                require_public_netloc=self.require_public_netloc
            ):
                # try making it absolute
                canonical = url_to_absolute_url(
                    canonical,
                    url_fallback=url_fallback,
                    require_public_netloc=self.require_public_netloc
                )
                if not is_url_valid(
                    canonical,
                    require_public_netloc=self.require_public_netloc
                ):
                    # set to NONE if invalid
                    canonical = None

        rval = []
        if og_first:
            rval = (og, canonical)
        elif canonical_first:
            rval = (canonical, og)

        for i in rval:
            if i:
                return i

        return self.absolute_url()

    def get_metadata_link(self, field, strategy=None):
        """sometimes links are bad; this tries to fix them.  most useful for meta images"""
        # `_value` will be our raw value
        _value = self.get_metadata(field, strategy=strategy)
        if not _value:
            return None
        # `value` will be our clean value
        # remove whitespace, because some bad blogging platforms add in whitespace by printing elements on multiple lines. d'oh!
        value = RE_whitespace.sub('', _value)

        # if the url is valid, RETURN IT
        if is_url_valid(value, require_public_netloc=self.require_public_netloc):
            return value

        # fallback url is used to drop a domain
        url_fallback = self.url_actual or self.url or None

        # try making it absolute
        value_fixed = url_to_absolute_url(
            value,
            url_fallback = url_fallback,
            require_public_netloc = self.require_public_netloc
        )
        if is_url_valid(value_fixed, require_public_netloc=self.require_public_netloc):
            return value_fixed

        return None


from sklearn import datasets
import pandas as pd

iris = datasets.load_iris()
iris_df = pd.DataFrame(iris.data)
iris_df.columns = iris.feature_names
iris_df['target'] = iris.target

# original target = 0,1,2 int32
print(iris_df.target)

# changing them by using DF.astype(type)
print(iris_df.target.astype(float))


import sys, math
from math import pi as pi
import numpy as np
import cv2
from PyQt5.QtCore import QPoint, QRect, QSize, Qt, QPointF, QRectF, pyqtSignal, QTimer
from PyQt5.QtGui import (QBrush, QConicalGradient, QLinearGradient, QPainter, QPainterPath, QPalette, QPen, QPixmap, QPolygon, QRadialGradient, QColor, QTransform, QPolygonF, QKeySequence, QIcon)
from PyQt5.QtWidgets import (QApplication, QProgressBar, QCheckBox, QComboBox, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, QSpinBox, QWidget, QPushButton, QSpacerItem, QSizePolicy, QLCDNumber )
from PyQt5 import QtGui, QtCore
from parallelIce.pose3dClient import Pose3DClient
from parallelIce.laserClient import LaserClient
import easyiceconfig as EasyIce
from gui.threadGUI import ThreadGUI

class MainWindow(QWidget):

    updGUI=pyqtSignal()
    def __init__(self, pose3d, laser1, laser2, laser3, parent=None):
        super(MainWindow, self).__init__(parent)

        layout = QGridLayout()
        self.quesito = quesoWidget(self, pose3d)
        self.tiempo = tiempoWidget(self)
        self.calidad = calidadWidget(self, laser1, laser2, laser3)
        self.distancia = distanciaWidget(self, pose3d)
        self.nota = notaWidget(self,pose3d, self.tiempo, self.calidad, self.distancia)
        self.logo = logoWidget(self)
        layout.addWidget(self.quesito,1,0)
        layout.addWidget(self.tiempo,0,0)
        layout.addWidget(self.distancia,0,2)
        layout.addWidget(self.calidad,1,2)
        layout.addWidget(self.nota,0,1)
        layout.addWidget(self.logo,2,2)

        vSpacer = QSpacerItem(30, 50, QSizePolicy.Ignored, QSizePolicy.Ignored)
        layout.addItem(vSpacer,1,0)

        self.setFixedSize(940,640);

        self.setLayout(layout)
        self.updGUI.connect(self.update)

    def update(self):
        self.quesito.updateG()
        self.distancia.updateG()
        self.calidad.updateG()
        self.nota.updateG()

class logoWidget(QWidget):
    def __init__(self, winParent):
        super(logoWidget, self).__init__()
        self.winParent=winParent
        self.logo = cv2.imread("resources/logo_jderobot1.png",cv2.IMREAD_UNCHANGED)
        self.logo = cv2.resize(self.logo, (100, 100))
        image = QtGui.QImage(self.logo.data, self.logo.shape[1], self.logo.shape[0],  QtGui.QImage.Format_ARGB32);
        self.pixmap = QtGui.QPixmap.fromImage(image)
        self.height = self.pixmap.height()
        self.width = self.pixmap.width()
        self.mapWidget = QLabel(self)
        self.mapWidget.setPixmap(self.pixmap)
        self.mapWidget.resize(self.width, self.height)
        self.setMinimumSize(100,100)

class calidadWidget(QWidget):
    def __init__(self,winParent, laser1, laser2, laser3):
        super(calidadWidget, self).__init__()
        self.winParent=winParent
        self.laser1 = laser1
        self.laser2 = laser2
        self.laser3 = laser3
        self.numCrash = 0
        self.MAX_CRASH = 1000

        vLayout = QVBoxLayout()
        choquesLabel = QLabel("Choques:")
        self.bar = QProgressBar()
        self.bar.setValue(self.numCrash)
        st = "QProgressBar::chunk {background-color: #ff0000;}\n QProgressBar {border: 1px solid grey;border-radius: 2px;text-align: center;background: #eeeeee;}"
        self.bar.setStyleSheet(st)
        self.bar.setTextVisible(False)
        vLayout.addWidget(choquesLabel, 0)
        vLayout.addWidget(self.bar, 0)

        vSpacer = QSpacerItem(30, 80, QSizePolicy.Ignored, QSizePolicy.Ignored)
        vLayout.addItem(vSpacer)

        self.setLayout(vLayout)

    def get_laser_distance(self, laser):
        DIST = 15
        maxAngle = 180
        crash = False
        for i in range(0, maxAngle+1):
            # Distance in millimeters, we change to cm
            laserI = float(laser.distanceData[i])/float(10)
            if i != 0 and i != 180:
                if laserI <= DIST:
                    crash = True
        return crash

    def updateG(self):
        laser_data_Front = self.laser1.getLaserData()
        laser_data_Rear = self.laser2.getLaserData()
        laser_data_Right = self.laser3.getLaserData()
        crashFront = self.get_laser_distance(laser_data_Front)
        crashRear = self.get_laser_distance(laser_data_Rear)
        crashRight = self.get_laser_distance(laser_data_Right)
        if crashFront or crashRear or crashRight:
            self.numCrash = self.numCrash + 1
        percentajeCrash = self.numCrash * 100/self.MAX_CRASH
        self.bar.setValue(self.numCrash)
        self.update()

class distanciaWidget(QWidget):
    def __init__(self,winParent, pose3d):
        super(distanciaWidget, self).__init__()
        self.winParent=winParent
        self.pose3d = pose3d
        self.distFrontFinal = 0
        self.distRearFinal = 0
        self.distanceSidewalk = 0

        vLayout = QVBoxLayout()

        self.distances()

        distancesLabel = QLabel("Distancias:")
        self.distanceFrontalLabel = QLabel("Distancia frontal: " + str(round(self.distFrontFinal, 3)) + ' m')
        self.distanceRearLabel = QLabel("Distancia trasera: " + str(round(self.distRearFinal, 3)) + ' m')
        self.distanceSidewalkLabel = QLabel("Distancia a la acera: " + str(round(self.distanceSidewalk, 3)) + ' m')
        vLayout.addWidget(distancesLabel, 0)
        vLayout.addWidget(self.distanceFrontalLabel, 0)
        vLayout.addWidget(self.distanceRearLabel, 0)
        vLayout.addWidget(self.distanceSidewalkLabel, 0)

        self.setLayout(vLayout)

    def RTx(self, angle, tx, ty, tz):
        RT = np.matrix([[1, 0, 0, tx], [0, math.cos(angle), -math.sin(angle), ty], [0, math.sin(angle), math.cos(angle), tz], [0,0,0,1]])
        return RT

    def RTy(self, angle, tx, ty, tz):
        RT = np.matrix([[math.cos(angle), 0, math.sin(angle), tx], [0, 1, 0, ty], [-math.sin(angle), 0, math.cos(angle), tz], [0,0,0,1]])
        return RT

    def RTz(self, angle, tx, ty, tz):
        RT = np.matrix([[math.cos(angle), -math.sin(angle), 0, tx], [math.sin(angle), math.cos(angle),0, ty], [0, 0, 1, tz], [0,0,0,1]])
        return RT

    def RTCar(self):
        yaw = self.pose3d.getYaw()
        RTz = self.RTz(yaw, 0, 0, 0)
        return RTz

    def distancePoint2Segment(self, A, B, C):
        # Segment: A[ax,ay] ; B[bx,by]
        # Point: C[cx, cy]
        # Calculate U parameter
        u = self.parameterU(A, B, C)
        if u < 0:
            distance = self.distancePoint2Point(A, C)
        elif u > 1:
            distance = self.distancePoint2Point(B, C)
        else:
            distance = self.distancePoint2Rect(A, B, C)
        return distance

    def parameterU(self, A, B, C):
        # Point A: [ax, ay]
        # Point B: [bx, by]
        # Point C: [cx, cy]
        # Parameter U of equations: Px = ax + u*(bx-ax); and Py = ay + u*(by-ay)
        u = ((C[0] - A[0])*(B[0] - A[0]) + (C[1] - A[1])*(B[1] - A[1])) / (pow((B[0] - A[0]),2) + pow((B[1] - A[1]),2))
        return u

    def distancePoint2Point(self, Point1, Point2):
        # Point: 1[x1,y1]
        # Point: 2[x2,y2]
        return math.sqrt(pow((Point2[0]-Point1[0]),2) + pow((Point2[1]-Point1[1]),2))

    def distancePoint2Rect(self, A, B, C):
        # Rect: A[ax,ay] ; B[bx,by]
        # Point: C[cx,cy]
        distance = abs((B[0] - A[0])*(C[1] - A[1]) - (B[1] - A[1])*(C[0] - A[0])) / (math.sqrt(pow((B[0]-A[0]),2) + pow((B[1]-A[1]),2)))
        return distance

    def distanceCar2Car(self, pointCarLeft, pointCarRight, pointFrontLeft, pointFrontRight, pointRearLeft, pointRearRight):
        # Mide la minima distancia desde los 4 vertices de un coche a la parte delantera o trasera de otro coche (segmento)
        # Segment: pointCarLeft[x,y] ; pointCarRight[x,y]
        # Point 1: pointFrontLeft[x,y]
        # Point 2: pointFrontRight[x,y]
        # Poitn 3: pointRearLeft[x,y]
        # Point 4: pointRearRight[x,y]

        distance = self.distancePoint2Segment(pointCarLeft, pointCarRight, pointFrontLeft)

        if (self.distancePoint2Segment(pointCarLeft, pointCarRight, pointFrontRight) < distance):
            distance = self.distancePoint2Segment(pointCarLeft, pointCarRight, pointFrontRight)
        if (self.distancePoint2Segment(pointCarLeft, pointCarRight, pointRearLeft) < distance):
            distance = self.distancePoint2Segment(pointCarLeft, pointCarRight, pointRearLeft)
        if (self.distancePoint2Segment(pointCarLeft, pointCarRight, pointRearRight) < distance):
            distance = self.distancePoint2Segment(pointCarLeft, pointCarRight, pointRearRight)

        return distance

    def distances(self):
        carSize = [5.75, 2.5]
        carSizeTaxi = [4, 2]

        #Poses sidewalk
        positionSideWalk_start = [-25, -4.25]
        positionSideWalk_final = [35, -4.25]

        # Poses parked cars (origin poses)
        # Frontal car
        pointCarFrontal_RearLeft = [14 - carSize[0]/2, -3+carSize[1]/2]
        pointCarFrontal_RearRight = [14 - carSize[0]/2, -3-carSize[1]/2]
        pointCarFrontal_FrontLeft = [14 + carSize[0]/2, -3+carSize[1]/2]
        pointCarFrontal_FrontRight = [14 + carSize[0]/2, -3-carSize[1]/2]
        # Rear Car
        pointCarRear_FrontLeft = [0.5 + carSize[0]/2, -3+carSize[1]/2]
        pointCarRear_FrontRight = [0.5 + carSize[0]/2, -3-carSize[1]/2]
        pointCarRear_RearLeft = [0.5 - carSize[0]/2, -3+carSize[1]/2]
        pointCarRear_RearRight = [0.5 - carSize[0]/2, -3-carSize[1]/2]

        # Pose 3D (origin poses)
        xFront = self.pose3d.getX() + carSizeTaxi[0]/2
        xRear = self.pose3d.getX() - carSizeTaxi[0]/2
        yLeft = self.pose3d.getY() + carSizeTaxi[1]/2
        yRight = self.pose3d.getY() - carSizeTaxi[1]/2

        # Final poses (Car's rotation)
        pointFrontLeft = self.RTCar() * np.matrix([[xFront], [yLeft], [1], [1]])
        pointFrontLeft = [pointFrontLeft.flat[0],pointFrontLeft.flat[1]]
        pointFrontRight = self.RTCar() * np.matrix([[xFront], [yRight], [1], [1]])
        pointFrontRight = [pointFrontRight.flat[0], pointFrontRight.flat[1]]
        pointRearLeft = self.RTCar() * np.matrix([[xRear], [yLeft], [1], [1]])
        pointRearLeft = [pointRearLeft.flat[0],pointRearLeft.flat[1]]
        pointRearRight = self.RTCar() * np.matrix([[xRear], [yRight], [1], [1]])
        pointRearRight = [pointRearRight.flat[0],pointRearRight.flat[1]]

        # Distance car -> parked front car
        distFrontFinal_1 = self.distanceCar2Car(pointCarFrontal_RearLeft, pointCarFrontal_RearRight, pointFrontLeft, pointFrontRight, pointRearLeft, pointRearRight)

        # Distance parked front car -> car
        distFrontFinal_2 = self.distanceCar2Car(pointFrontLeft, pointFrontRight, pointCarFrontal_RearLeft, pointCarFrontal_RearRight, pointCarFrontal_FrontLeft , pointCarFrontal_FrontRight)

        # Distance car -> parked rear car
        distRearFinal_1 = self.distanceCar2Car(pointCarRear_FrontLeft, pointCarRear_FrontRight, pointFrontLeft, pointFrontRight, pointRearLeft, pointRearRight)

        # Distance parked rear car -> car
        distRearFinal_2 = self.distanceCar2Car(pointRearLeft, pointRearRight, pointCarRear_FrontLeft , pointCarRear_FrontRight, pointCarRear_RearLeft , pointCarRear_RearRight)

        # Minimal distance
        if distFrontFinal_1 > distFrontFinal_2:
            self.distFrontFinal = distFrontFinal_1
        else:
            self.distFrontFinal = distFrontFinal_2

        if distRearFinal_1 > distRearFinal_2:
            self.distRearFinal = distRearFinal_1
        else:
            self.distRearFinal = distRearFinal_2

        # Distance car -> sidewalk
        self.distanceSidewalk = self.distanceCar2Car(positionSideWalk_start, positionSideWalk_final, pointFrontLeft, pointFrontRight, pointRearLeft, pointRearRight)

    def updateG(self):
        self.distances()
        self.distanceFrontalLabel.setText("Distancia frontal: " + str(round(self.distFrontFinal, 3)) + ' m')
        self.distanceRearLabel.setText("Distancia trasera: " + str(round(self.distRearFinal, 3)) + ' m')
        self.distanceSidewalkLabel.setText("Distancia a la acera: " + str(round(self.distanceSidewalk, 3)) + ' m')
        self.update()

class notaWidget(QWidget):
    def __init__(self,winParent,pose3d, tiempo, calidad, distancia):
        super(notaWidget, self).__init__()
        self.winParent=winParent
        self.pose3d = pose3d
        self.time = tiempo
        self.calidad = calidad
        self.distancia = distancia

        self.hLayout = QHBoxLayout()

        self.button = QPushButton('Show me my mark')
        self.button.clicked.connect(self.notaFinal)
        self.hLayout.addWidget(self.button, 0)

        self.setLayout(self.hLayout)

    def notaFinal(self):
        notaAngle = self.testAngle() * 0.025
        notaTime = self.testTime() * 0.025
        notaDist = self.testDistance() * 0.025
        notaCol = self.testCollision() * 0.025
        nota = notaAngle + notaTime + notaDist + notaCol
        notaLabel = QLabel('Nota final: ' + str(nota))
        self.hLayout.addWidget(notaLabel, 0)

    def testAngle(self):
        yawRad = self.pose3d.getYaw()
        angle = math.degrees(yawRad) + 90
        if (angle >= 85 and angle <= 105):
            notaAngle = 100
        elif (angle < 85 and angle >= 70 or angle > 105 and angle <= 120):
            notaAngle = 80
        elif (angle < 70 and angle >= 60 or angle > 120 and angle <= 130):
            notaAngle = 50
        else:
            notaAngle = 0
        return notaAngle

    def testTime(self):
        minTime = 170
        myTime = self.time.seconds
        notaTime = float(minTime*100)/float(myTime)
        if myTime < 170:
            notaTime = 100
        return notaTime

    def testDistance(self):
        MyDistFront = self.distancia.distFrontFinal
        MyDistRear = self.distancia.distRearFinal
        MyDistSidewalk = self.distancia.distanceSidewalk

        if MyDistFront >= 1.5 and MyDistFront < 3.5:
            notaDistFront = 100
        elif MyDistFront < 1.5 and MyDistFront >= 1:
            notaDistFront = 50
        else:
            notaDistFront = 0

        if MyDistRear >= 1.5 and MyDistRear < 3.5:
            notaDistRear = 100
        elif MyDistRear < 1.5 and MyDistRear >= 1:
            notaDistRear = 50
        else:
            notaDistRear = 0

        if MyDistSidewalk > 0 and MyDistSidewalk <= 0.75:
            notaDistSidewalk = 100
        elif MyDistSidewalk > 0.75 and MyDistSidewalk < 1.5:
            notaDistSidewalk = 50
        else:
            notaDistSidewalk = 0

        notaDist = float(notaDistFront+notaDistRear+notaDistSidewalk)/float(3)
        return notaDist

    def testCollision(self):
        minCrash = 0
        if self.calidad.numCrash == 0:
            notaCol = 100
        else:
            notaCol = float(minCrash*100)/float(self.calidad.numCrash)
        return notaCol

    def updateG(self):
        self.update()

class tiempoWidget(QWidget):

    time = pyqtSignal()
    def __init__(self,winParent):
        super(tiempoWidget, self).__init__()
        self.winParent=winParent
        self.seconds = 0

        hLayout = QHBoxLayout()

        tiempoLabel = QLabel("Tiempo")
        self.lcd = QLCDNumber(self)
        self.lcd.setMaximumSize(100,50)
        hLayout.addWidget(tiempoLabel,0)
        hLayout.addWidget(self.lcd, 1)

        hSpacer = QSpacerItem(300, 30, QSizePolicy.Ignored, QSizePolicy.Ignored)
        hLayout.addItem(hSpacer)

        self.setLayout(hLayout)

        timer = QTimer(self)
        timer.start(1000)
        timer.timeout.connect(self.printTime)

        # get the palette
        palette = self.lcd.palette()

        # foreground color
        palette.setColor(palette.WindowText, QColor(85, 85, 255))
        # background color
        palette.setColor(palette.Background, QColor(0, 170, 255))
        # "light" border
        palette.setColor(palette.Light, QColor(255, 0, 0))
        # "dark" border
        palette.setColor(palette.Dark, QColor(0, 255, 0))

        # set the palette
        self.lcd.setPalette(palette)

    def printTime(self):
        self.seconds += 1
        self.lcd.display(self.seconds)

class quesoWidget(QWidget):

    def __init__(self,winParent, pose3d):
        super(quesoWidget, self).__init__()
        self.winParent=winParent
        self.rectangle = QRectF(0.0, 0.0, 300.0, 300.0)
        self.pose3d = pose3d

    def drawRedZones(self, painter):
        self.setStyle(painter, QColor(255,70,70),QColor(255,70,70),1)
        startAngle = 0 * 16
        spanAngle = 45 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 135 * 16
        spanAngle = 45 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 180 * 16
        spanAngle = 180 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawOrangeZones(self, painter):
        self.setStyle(painter, QColor(255,220,23),QColor(255,220,23),1)
        startAngle = 45 * 16
        spanAngle = 30 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 105 * 16
        spanAngle = 30 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawGreenZones(self, painter):
        self.setStyle(painter, QColor(117,240,154),QColor(117,240,154),1)
        startAngle = 75 * 16
        spanAngle = 15 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)
        startAngle = 90 * 16
        spanAngle = 15 * 16
        painter.drawPie(self.rectangle, startAngle, spanAngle)

    def drawArrow(self, painter, angle=90):
        radius = 130
        yawRad = self.pose3d.getYaw()
        angle = -(yawRad + pi/2) # PI/2 para centrar la aguja
        origx = self.rectangle.width() / 2
        origy = self.rectangle.height() / 2
        finx = radius * math.cos(angle) + origx
        finy = radius * math.sin(angle) + origy
        self.setStyle(painter, Qt.black,Qt.black,3)
        painter.drawLine(QPoint(origx,origy), QPoint(finx,finy))
        painter.drawEllipse(145,145, 10, 10)

    def resetPen(self, painter):
        pen = QPen(Qt.black, 1)
        brush = QBrush()
        painter.setPen(pen)
        painter.setBrush(brush)

    def setStyle(self, painter, fillColor, penColor, stroke):
        brush = QBrush()
        pen = QPen(penColor, stroke)
        brush.setColor(fillColor)
        brush.setStyle(Qt.SolidPattern)
        painter.setBrush(brush)
        painter.setPen(pen)
        painter.setRenderHint(QPainter.Antialiasing)

    def paintEvent(self, event):
        painter = QPainter(self)
        self.drawRedZones(painter)
        self.drawOrangeZones(painter)
        self.drawGreenZones(painter)
        self.drawArrow(painter,120)

    def updateG(self):
        self.update()

if __name__ == "__main__":

    app = QApplication(sys.argv)
    ic = EasyIce.initialize(sys.argv)
    pose3d = Pose3DClient(ic, "Autopark.Pose3D", True)
    laser1 = LaserClient(ic, "Autopark.Laser1", True)
    laser2 = LaserClient(ic, "Autopark.Laser2", True)
    laser3 = LaserClient(ic, "Autopark.Laser3", True)

    myGUI = MainWindow(pose3d, laser1, laser2, laser3)
    myGUI.show()
    t2 = ThreadGUI(myGUI)
    t2.daemon=True
    t2.start()
    sys.exit(app.exec_())


""" Module containing routines to setup the training of policies.
"""
import argparse
from typing import Optional, Sequence

from aizynthfinder.training.utils import Config
from aizynthfinder.training.keras_models import (
    train_expansion_keras_model,
    train_filter_keras_model,
    train_recommender_keras_model,
)

def main(optional_args: Optional[Sequence[str]] = None) -> None:
    """Entry-point for the aizynth_training tool"""
    parser = argparse.ArgumentParser("Tool to train a network policy")
    parser.add_argument("config", help="the filename to a configuration file")
    parser.add_argument(
        "model",
        choices=["expansion", "filter", "recommender"],
        help="the model to train",
    )
    args = parser.parse_args(optional_args)

    config = Config(args.config)
    if args.model == "expansion":
        train_expansion_keras_model(config)
    elif args.model == "filter":
        train_filter_keras_model(config)
    elif args.model == "recommender":
        train_recommender_keras_model(config)

if __name__ == "__main__":
    main()


import torch
import torch.nn as nn
from torch.optim import Adam
import torch.nn.functional as F
from random import randint
import numpy as np
# import subprocess
# import multiprocessing
# import concurrent.futures
from time import time
from math import sqrt

CHANNEL = 256
BLOCKNUM = 40
BOARDSIZE = 8
BATCH = 50
EPOCHS = 20
DATASIZE = 7200
DATAUSE = 2000
ROUNDLIMIT = 500
PROCESS = 3
OUTPUT_INFO = 1

class resBlock(nn.Module):
    def __init__(self, x):
        super(resBlock, self).__init__()
        self.resBlock = nn.Sequential(
            nn.Conv2d(x, x, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(x),
            nn.ReLU(inplace=True),
            nn.Conv2d(x, x, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(x)
        )
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        shortCut = x
        out = self.resBlock(x)
        out += shortCut
        out = self.relu(out)
        return out

class resCNN(nn.Module):
    def __init__(self):
        super(resCNN, self).__init__()
        self.input = nn.Sequential(
            nn.Conv2d(3, CHANNEL, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(CHANNEL),
            nn.ReLU(inplace=True)
        )
        self.resnet = nn.Sequential()
        for i in range(BLOCKNUM):
            self.resnet.add_module(str(i),resBlock(CHANNEL))

        self.ph = nn.Sequential(
            nn.Conv2d(CHANNEL, 2, kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(2),
            nn.ReLU(inplace=True),
            nn.Flatten(),
            nn.Linear(BOARDSIZE*BOARDSIZE*2, BOARDSIZE*BOARDSIZE),
            # nn.Softmax(dim=1)
        )
        self.vh = nn.Sequential(
            nn.Conv2d(CHANNEL, 1, kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(1),
            nn.ReLU(inplace=True),
            nn.Flatten(),
            nn.Linear(BOARDSIZE*BOARDSIZE, CHANNEL),
            nn.ReLU(inplace=True),
            nn.Linear(CHANNEL, 1),
            nn.Tanh()
        )

    def forward(self, x):
        model = self.input(x)
        model = self.resnet(model)
        p = self.ph(model)
        v = self.vh(model)
        return p, v

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

cnn = resCNN()
cnn.load_state_dict(torch.load(r'./rescnn.pth'))
cnn.to(device)
optimizer = Adam(cnn.parameters(), weight_decay=1e-4)

stateData = torch.zeros(DATASIZE, 3, 8, 8, dtype=float)
policyData = torch.zeros(DATASIZE, 64, dtype=float)
valueData = torch.zeros(DATASIZE, 1, dtype=float)
policyLossFunc = nn.CrossEntropyLoss()
valueLossFunc = nn.MSELoss()

def calc(cood):
    return cood[0] * BOARDSIZE + cood[1]

def lossFunction(policyOutput, valueOutput, policyTarget, valueTarget):
    policyLoss = policyLossFunc(policyOutput, policyTarget)
    valueLoss = valueLossFunc(valueOutput, valueTarget)
    return policyLoss + valueLoss

def train():
    cnn.train()
    use = torch.zeros(DATASIZE)
    inputData = torch.zeros(DATAUSE,3,8,8)
    policyTargetData = torch.zeros(DATAUSE,64)
    valueTargetData = torch.zeros(DATAUSE,1)

    i = 0
    while i < DATAUSE:
        x = randint(0, DATASIZE - 1)
        if use[x] == 1:
            continue
        inputData[i] = stateData[x]
        policyTargetData[i] = policyData[x]
        valueTargetData[i] = valueData[x]
        use[x] = 1
        i += 1

    optimizer.zero_grad()
    for i in range(EPOCHS):
        policyLossAvg = 0.0
        valueLossAvg = 0.0

        if OUTPUT_INFO:
            print(f'epoch {i+1}:')

        for j in range(0, DATAUSE, BATCH):

            input = inputData[j:j+BATCH]
            policyTarget = policyTargetData[j:j+BATCH]
            valueTarget = valueTargetData[j:j+BATCH]

            policyOutput, valueOutput = cnn(input.to(device))

            policyLoss = policyLossFunc(policyOutput, policyTarget.to(device))
            valueLoss = valueLossFunc(valueOutput, valueTarget.to(device))
            loss = policyLoss + valueLoss
            policyLossAvg += float(policyLoss)
            valueLossAvg += float(valueLoss)

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

        if OUTPUT_INFO:
            print(f'    policy loss: {policyLossAvg / (DATAUSE / BATCH)}')
            print(f'    value loss: {valueLossAvg / (DATAUSE / BATCH)}')
            print(f'    total loss: {(policyLossAvg + valueLossAvg) / (DATAUSE / BATCH)}')

    torch.save(cnn.state_dict(), r'./rescnn.pth')

class GameState:
    def __init__(self):
        self.board = np.zeros((8, 8), dtype=np.int8) # 0 ~ 7
        self.board[3, 3] = self.board[4, 4] = -1
        self.board[3, 4] = self.board[4, 3] = 1 #Black 1 White -1
        self.history = []

    def copy(self):
        state = GameState()
        state.board = np.copy(self.board)
        state.history = self.history[:]
        return state

    def makeMove(self, move, player):
        self.history.append(move)
        self.board[move] = player
        for d in (-1, 0, 1):
            for e in (-1, 0, 1):
                if d == 0 and e == 0:
                    continue
                x, y = move
                x += d
                y += e
                to_flip = []
                while x >= 0 and y >= 0 and x < 8 and y < 8 and self.board[x, y] == -player:
                    to_flip.append((x, y))
                    x += d
                    y += e
                if x >= 0 and y >= 0 and x < 8 and y < 8 and self.board[x, y] == player:
                    for f in to_flip:
                        self.board[f] = player

    def isValid(self, move, player):
        if self.board[move] != 0:
            return False
        for d in (-1, 0, 1):
            for e in (-1, 0, 1):
                if d == 0 and e == 0:
                    continue
                x, y = move
                x += d
                y += e
                num = 0
                while x >= 0 and y >= 0 and x < 8 and y < 8 and self.board[x, y] == -player:
                    x += d
                    y += e
                    num += 1
                if num > 0 and x >= 0 and y >= 0 and x < 8 and y < 8 and self.board[x, y] == player:
                    return True
        return False

    def getValidMoves(self, player):
        moves = []
        for i in range(8):
            for j in range(8):
                if self.isValid((i, j), player):
                    moves.append((i, j))
        return moves

    def isTerminal(self):
        if len(self.getValidMoves(1)) > 0:
            return False
        if len(self.getValidMoves(-1)) > 0:
            return False
        return True

    def getWinner(self):
        count = np.sum(self.board)
        if count > 0:
            return 1
        elif count < 0:
            return -1
        else:
            return 0

    def getScore(self, player):
        cnt = 0
        for i in range(8):
            for j in range(8):
                if self.board[i,j] == player:
                    cnt += 1
        return cnt

    def print(self):
        print('  ',end='')
        for i in range(8):
            print(i,end=' ')
        print('')
        for i in range(8):
            print(i,end=' ')
            for j in range(8):
                if self.board[i,j] == 1:
                    print('#',end=' ')
                elif self.board[i,j] == -1:
                    print('O',end=' ')
                else:
                    print('.',end=' ')
            print('')

PUCT_CONSTANT = 1
class MCTSNode:
    def __init__(self, state:GameState, player):
        self.state:GameState = state.copy()
        self.parent:MCTSNode = None
        self.children = []
        self.unexploredMoves = state.getValidMoves(player)
        self.player = player
        self.n = 0
        self.v = 0.0
        self.p = 0.0
        self.policyPredict = torch.zeros(64)
        self.valuePredict = 0.0
        if type == 2:
            input = torch.zeros(3,8,8)
            for i in range(8):
                for j in range(8):
                    if state.board[i,j] == 1:
                        input[0,i,j] = 1
            for i in range(8):
                for j in range(8):
                    if state.board[i,j] == -1:
                        input[1,i,j] = 1
            for i in range(8):
                for j in range(8):
                    input[2,i,j] = player
            input.unsqueeze_(0)
            output = cnn(input.to(device))
            self.policyPredict = F.softmax(output[0][0], dim=-1)
            self.valuePredict = float(output[1][0])

    def expand(self):
        if len(self.unexploredMoves) <= 0:
            return None

        move = self.unexploredMoves.pop()
        newState = self.state.copy()
        newState.makeMove(move, self.player)

        child = None
        if len(newState.getValidMoves(-self.player)) > 0:
            child = MCTSNode(newState, -self.player)
        else:
            child = MCTSNode(newState, self.player)
        child.parent = self
        child.p = float(self.policyPredict[calc(move)])
        self.children.append(child)
        return child

    def puct(self, player):
        Q = self.v / self.n
        U = PUCT_CONSTANT * self.p * sqrt(self.parent.n + 1) / (self.n + 1)
        if player == -1:
            Q = -Q
        return Q + U

    def select(self, player):
        return max(self.children, key=lambda c: c.puct(player))

    def backpropagate(self, v):
        self.n += 1
        self.v += v
        if self.parent:
            self.parent.backpropagate(v)

class CNNMCTS:
    def __init__(self):
        return

    def CNNMCTSBestMove(self, state, player, timeIterations):
        rootNode = MCTSNode(state, player)

        for i in range(timeIterations):
            node = rootNode

            while len(node.unexploredMoves) == 0 and node.state.isTerminal() == False:
                if len(node.children) > 0:
                    node = node.select(player)
                else:
                    break

            if len(node.unexploredMoves) > 0 and node.state.isTerminal() == False:
                node = node.expand()

            if node.state.isTerminal() == False:
                node.backpropagate(node.valuePredict)
            else:
                node.backpropagate(node.state.getWinner())

        bestChild = rootNode.children[0]
        for child in rootNode.children:
            if child.n > bestChild.n:
                bestChild = child
        return bestChild.state.history[-1]

def gen_py():
    MCTS = CNNMCTS()
    cnt = 0
    cnn.eval()
    while cnt < DATASIZE:
        c_state = GameState()
        currentPlayer = 1
        cur = 0
        lst = cnt

        while c_state.isTerminal() == 0:
            if len(c_state.getValidMoves(currentPlayer)) <= 0:
                currentPlayer = -currentPlayer
                continue
            bestMove = MCTS.CNNMCTSBestMove(c_state, currentPlayer, ROUNDLIMIT)
            cur += 1
            if 5 <= cur and cur <= 54 and cnt < DATASIZE:
                for i in range(8):
                    for j in range(8):
                        if c_state.board[i,j] == 1:
                            stateData[cnt,0,i,j] = 1
                for i in range(8):
                    for j in range(8):
                        if c_state.board[i,j] == -1:
                            stateData[cnt,1,i,j] = 1
                for i in range(8):
                    for j in range(8):
                        stateData[cnt,2,i,j] = currentPlayer
                policyData[cnt] = calc(bestMove)
                cnt += 1

            c_state.makeMove(bestMove, currentPlayer)
            currentPlayer = -currentPlayer

        valueData[lst:cnt] = c_state.getWinner()
        if OUTPUT_INFO:
            print(f'{cnt} / {DATASIZE}\r', end='')

    if OUTPUT_INFO:
        print('')

if __name__ == '__main__':
    np.set_printoptions(suppress=True, precision=7)
    # multiprocessing.freeze_support()
    times = 0
    while 1 :
        if OUTPUT_INFO:
            print(f'iteration {times}:')
            print('self-matching:')

        gen_py()
        # gen_cpp()
        # gen_mainProcess() # in train.py

        if OUTPUT_INFO:
            print('train start:')

        train()
        # archivePath = 'D:/Desktop/yanxue/rescnn_archive/rescnn-iteration' + str(times) +'.pth'
        # torch.save(cnn.state_dict(), archivePath)


from yaml_parser import parse_yaml
from voluptuous import Schema,Object, Range, Coerce, All, Any, Optional, Lower, Invalid

import re
import sys
import argparse

"""
Python YAML validator
"""
list_of_ints = All([Coerce(int)], msg='invalid list of ints')

from datetime import datetime
def check_date(datestring):
    try:
       fmt='%Y-%m-%d'
       date_to_test = datetime.strptime(datestring, fmt)
       Coerce(datetime)
    except:
       raise Invalid('expected in Y-m-d')

simulation_schema=Schema({
    'quantiles': [All(Coerce(int), Range(1, 100), msg='not a valid quantile')],
    'prediction': {
            'model': str,
            'window': int
     },
    'startdate': check_date,
    'enddate': check_date,
    'replenishment': {
             'model': str
    },
    'input_file' : str
})

replenishment_schema=Schema({
    'quantiles': [All(Coerce(int), Range(1, 100), msg='not a valid quantile')],
    'prediction': {
            'model': str,
            'window': int
     },
    'replenishment': {
            'model': str
    },
    'input_file' : str
})

def test_file(yamlconfig, types):
    if types=='simulation':
        simulation_schema(yamlconfig['simulation'])
    if types=='replenishemnt':
        replenishment_schema(yamlconfig['replenishment'])

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-y","--yaml", help="yaml inputfile to test", type=str)
    parser.add_argument("-t","--types", help="type of yaml", type=str)

    args = parser.parse_args()

    ### Parse YAML to test

    to_test = parse_yaml(args.yaml)

    test_file(to_test,args.types)


import keras
from keras import backend as K
from keras.callbacks import Callback

import numpy as np

class BitsLogger(Callback):

  def __init__(self, nConvs=9, **kwargs):
    self.norm = 1./np.log(float(nConvs))
    self.bits_history=[]
    self.filterLayers=[]
    super(BitsLogger, self).__init__(**kwargs)

  def on_train_begin(self, logs):
    layers = self.model.layers
    for l in layers:
      if l.name == 'model_1':
          layers=l.layers

    for l in layers:
      if "filter_mask" in l.name:
        self.filterLayers.append(l)

  def on_epoch_end(self, epoch, logs={}):

    bitsum=0.
    for l in self.filterLayers:
      weights=K.flatten(l.filterProbs)
      b=-self.norm*K.sum(weights*K.log(weights))
      bitsum += b

    print(' Activation bits: ' + str(K.eval(bitsum)))
    logs['activation_bits'] = K.eval(bitsum)
    self.bits_history.append(K.eval(bitsum))

class EntropyLogger(Callback):

  def __init__(self, **kwargs):

    self.entropy_history=[]
    self.filterLayers=[]
    self.constant = 0.5*np.log(2*np.pi) + 0.5
    self.hmin=0.
    self.hmax=0.
    self.norm=1.
    super(EntropyLogger, self).__init__(**kwargs)

  def on_train_begin(self, logs):
    layers = self.model.layers
    for l in layers:
      if l.name == 'model_1':
        layers=l.layers

    for l in layers:
      if "filter_mask" in l.name:
        self.filterLayers.append(l)

    nFilters = K.eval(K.shape(self.filterLayers[-1].filterProbs)[-1])

    r=np.random.uniform(size=(1000000, nFilters))
    sigma = np.std(r, axis=1)
    self.hmin = 1.05 * np.log(np.amin(sigma, axis=0))
    self.hmax = 0.95 * np.log(np.amax(sigma, axis=0))
    self.norm = 1. / (self.hmax - self.hmin)

  def on_epoch_end(self, epoch, logs={}):

    s=0.
    for l in self.filterLayers:
      weights = K.flatten(l.filterProbs)
      s += self.norm*(K.log(K.std(weights)) - self.hmin)

    print(' entropy: ' + str(K.eval(s)) )
    logs['entropy'] = K.eval(s)
    self.entropy_history.append(K.eval(s))


import glob
import platform
import setuptools
import Cython.Build

# By compiling this separately as a C library, we avoid problems
# with passing C++-specific flags when building the extension
lrslib = ('lrslib', {'sources': glob.glob("solvers/lrs/*.c")})

cppgambit = setuptools.Extension(
    "pygambit.lib.libgambit",
    sources=(
        ["pygambit/lib/libgambit.pyx"] +
        glob.glob("core/*.cc") +
        glob.glob("games/*.cc") +
        glob.glob("games/agg/*.cc") +
        glob.glob("solvers/*/*.cc") +
        ["tools/lp/nfglp.cc",
         "tools/lp/efglp.cc",
         "tools/logit/path.cc",
         "tools/logit/nfglogit.cc",
         "tools/logit/efglogit.cc"]
    ),
    language="c++",
    include_dirs=["."],
    extra_compile_args=(
        ["-std=c++11"] if platform.system() == "Darwin" else []
    )
)

def readme():
    with open("README.rst") as f:
        return f.read()

setuptools.setup(
    name="pygambit",
    version="16.0.2",
    description="Software tools for game theory",
    long_description=readme(),
    classifiers=[
        "Development Status :: 4 - Beta",
        "Intended Audience :: Science/Research",
        "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: Implementation :: CPython",
        "Topic :: Scientific/Engineering :: Mathematics"
    ],
    keywords="game theory Nash equilibrium",
    license="GPL2+",
    author="Theodore Turocy",
    author_email="ted.turocy@gmail.com",
    url="http://www.gambit-project.org",
    project_urls={
        'Documentation': 'https://gambitproject.readthedocs.io/',
        'Source': 'https://github.com/gambitproject/gambit',
        'Tracker': 'https://github.com/gambitproject/gambit/issues',
    },
    python_requires=">=3.7",
    install_requires=[
        'lxml',  # used for reading/writing GTE files
        'numpy',
        'scipy',
    ],
    libraries=[lrslib],
    packages=['pygambit', 'pygambit.games', 'pygambit.lib'],
    ext_modules=Cython.Build.cythonize(cppgambit)
)


"""Some useful functions to deal with GitHub."""
import datetime

from github import Github
from github import UnknownObjectException

import click

class GitHubMux:
    """Class that let's you operate in multiple repos of the same org at the same time."""

    def __init__(self, organization, token, exclude):
        """
        Instantiate class.

        Args:
            organization(string): Organization name.
            token(string): Token to interact with GitHub API.
            exclude(tuple): Tuple with all the repo names that have to excluded from processing.
        """
        self.token = token
        self.gh = Github(self.token)
        self.exclude = exclude
        try:
            self.org = self.gh.get_organization(organization)
        except UnknownObjectException:
            raise Exception("Looks like organization `{}` doesn't exist.".format(organization))

    def exclude_repo(self, repo):
        """
        Exclude a repo.

        Args:
            repo(string): Repo of the name to exclude
        """
        self.exclude = self.exclude + (repo, )

    def repos(self):
        """Return repos to process."""
        for repo in self.org.get_repos():
            if repo.name in self.exclude:
                self.exclude_repo
                click.secho("Skipping repo `{}`.".format(repo.name), fg="blue")
            else:
                yield repo

    def _set_label_repo(self, repo, name, color):
        """
        Create a label if it doesn't exist already.

        Args:
            repo(Repository): Repo where you want to create the label
            name(string): Name of the label
            color(string): Color of the label

        Return:
            (Label) Either the label that was created of the existing one.
        """
        try:
            label = repo.get_label(name)

            if label.color == color:
                click.secho("Label `{}` already exists in repo `{}`. ".format(name,
                                                                              repo.name),
                            fg='green')
            else:
                click.secho("Label `{}` already exists in repo `{}` "
                            "but has a different color. Fixing.".format(name,
                                                                        repo.name),
                            fg='yellow')
                label.edit(name, color)

        except UnknownObjectException:
            click.secho("Label `{}` doesn't exist in repo `{}`. Creating.".format(name,
                                                                                repo.name),
                        fg='yellow')
            label = repo.create_label(name, color)
        return label

    def set_label(self, name, color):
        """
        Create a label in all repos if it doesn't exist.

        Args:
            name(string): Name of the label
            color(string): Color of the label
        """
        for repo in self.repos():
            self._set_label_repo(repo, name, color)

    def _unset_label_repo(self, repo, name):
        """
        Delete a label if it exists.

        Args:
            repo(Repository): Repo where you want to create the label
            name(string): Name of the label
        """
        try:
            label = repo.get_label(name)
            click.secho("Label `{}` exists in repo `{}`. Deleting.".format(name,
                                                                           repo.name),
                        fg='yellow')
            label.delete()
        except UnknownObjectException:
            click.secho("Label `{}` is already missing in repo `{}`.".format(name,
                                                                             repo.name),
                        fg='green')

    def unset_label(self, name):
        """
        Delete a label in all the repos that it exists.

        Args:
            name(string): Name of the label
        """
        for repo in self.repos():
            self._unset_label_repo(repo, name)

    def rename_label(self, name, new_name):
        """
        Rename an existing label in all the repos that it exists.

        Args:
            name(str): Current name of the label
            new_name(str): New name for the label
        """
        for repo in self.repos():
            try:
                label = repo.get_label(name)
                click.secho("Label `{}` exists in repo `{}`. Renaming.".format(name,
                                                                               repo.name),
                            fg='yellow')
                label.edit(new_name, label.color)
            except UnknownObjectException:
                click.secho("Couldn't find label `{}` in repo `{}`.".format(name,
                                                                            repo.name),
                            fg='green')

    def _get_labels_from_repo(self, repo):
        """
        Get labels from a repo.

        Args:
            repo(Repository): Repository to process.

        Return:
            list(Label): List of Labels of repo.
        """
        labels = set()
        for label in repo.get_labels():
            labels.add((label.name, label.color))
        return labels

    def synch_from_repo(self, repo):
        """
        Synch labels across repos.

        Ensure that all repos have exactly the same labels as another repo that holds
        the source of truth. If labels exists same color is enforced, if labels don't exist they
        are created and if there are more labels than necessary they are deleted.

        Args:
            repo(str): Name of the repo that holds the truth.
        """
        repo = self.org.get_repo(repo)

        orig_labels = self._get_labels_from_repo(repo)

        for r in self.repos():
            if r.name == repo.name:
                continue
            click.secho("Processing {}".format(r.name), fg="cyan")
            r_labels = self._get_labels_from_repo(r)
            to_update = orig_labels - r_labels

            for l_tuple in to_update:
                self._set_label_repo(r, l_tuple[0], l_tuple[1])

            # We refresh labels as some might have changed color in the previous step
            r_labels = self._get_labels_from_repo(r)
            to_delete = r_labels - orig_labels

            for l_tuple in to_delete:
                self._unset_label_repo(r, l_tuple[0])

    def search_issue_by_title(self, title, org, repo):
        """
        Search for an issue with `title` in org/repo.

        Args:
            title(string): Title of the issue
            org(string): Organization name the issue has to belong to
            repo(string): Repository name the issue has to belong to

        Return:
            (Issue): that matches the criteria or None.

        Raise:
            (Exception): If there is more than one match.
        """
        query = "{} in:Title repo:{}/{}".format(title, org, repo)
        issues = self.gh.search_issues(query)

        for i in issues:
            if i.title == title:
                return i
        return None

    def move_issue(self, issue_id, src_repo, dst_repo):
        """
        Move an issue between different repos.

        Original issue is going to be closed while the new one will reference to the original issue
        and mention the original reporter.

        Args:
            issue_id(int): Issue number
            src_repo(string): Name of the source repo where the issue lives
            dst_repo(string): Name of the repo where you want to move the issue to
        """
        src_repo = self.org.get_repo(src_repo)
        dst_repo = self.org.get_repo(dst_repo)

        issue = src_repo.get_issue(issue_id)

        new_body = "Original issue {}/{}#{} created by @{}\n\n{}".format(
                                                            src_repo.organization.name,
                                                            src_repo.name,
                                                            issue.number,
                                                            issue.user.login,
                                                            issue.body)

        issue.edit(state="closed")
        new_issue = dst_repo.create_issue(title=issue.title, body=new_body, labels=issue.labels)
        click.secho("Issue moved, new ID is #{} - {}".format(new_issue.id, new_issue.url),
                    fg="yellow")
        issue.create_comment("This issue has been 'moved' to {}/{}#{}".format(
                                                                         dst_repo.organization.name,
                                                                         dst_repo.name,
                                                                         new_issue.number))

    def spread_issue(self, issue_id, src_repo):
        """
        Spread an issue to multiple repos.

        Given a issue_id from a source repo it will create issues in the rest of the repos
        linking back to the original one.

        Args:
            issue_id(int): Issue number of the issue you want to spread.
            src_repo(string): Repository name where the issue lives.
        """
        issue = self.org.get_repo(src_repo).get_issue(issue_id)
        self.exclude_repo(issue.repository.name)
        body = "See details in the parent issue {}/{}#{}\n\n".format(
                                                            issue.repository.organization.name,
                                                            issue.repository.name,
                                                            issue.number)
        for repo in self.repos():
            new_issue = self.search_issue_by_title(issue.title, repo.organization.name, repo.name)
            if new_issue:
                click.secho("Issue already exists, ID is {}/{}#{} - {}".format(
                                                             new_issue.repository.organization.name,
                                                             new_issue.repository.name,
                                                             new_issue.number,
                                                             new_issue.url),
                            fg="green")
            else:
                new_issue = repo.create_issue(title=issue.title, body=body, labels=issue.labels)
                click.secho("Issue created, ID is {}/{}#{} - {}".format(
                                                             new_issue.repository.organization.name,
                                                             new_issue.repository.name,
                                                             new_issue.number,
                                                             new_issue.url),
                            fg="yellow")

    def pr_stats(self, days):
        """Gather stats for the past few days."""
        stats = {}
        summary_user = {}
        summary_repo = {}

        for repo in self.repos():
            stats[repo.name] = {}
            summary_repo[repo.name] = {
                 "count": 0,
                 "commits": 0,
                 "additions": 0,
                 "deletions": 0,
            }
            for pr in repo.get_pulls(state="all", sort="created", direction="desc"):
                if pr.created_at < (datetime.datetime.now() - datetime.timedelta(days=days)):
                    break

                summary_repo[repo.name]["count"] += 1
                summary_repo[repo.name]["commits"] += pr.commits
                summary_repo[repo.name]["additions"] += pr.additions
                summary_repo[repo.name]["deletions"] += pr.deletions

                if pr.user.login not in stats[repo.name]:
                    stats[repo.name][pr.user.login] = {
                        "count": 1,
                        "commits": pr.commits,
                        "additions": pr.additions,
                        "deletions": pr.deletions,
                    }
                else:
                    stats[repo.name][pr.user.login]["count"] += 1
                    stats[repo.name][pr.user.login]["commits"] += pr.commits
                    stats[repo.name][pr.user.login]["additions"] += pr.additions
                    stats[repo.name][pr.user.login]["deletions"] += pr.deletions

                if pr.user.login not in summary_user:
                    summary_user[pr.user.login] = {
                        "count": 1,
                        "commits": pr.commits,
                        "additions": pr.additions,
                        "deletions": pr.deletions,
                    }
                else:
                    summary_user[pr.user.login]["count"] += 1
                    summary_user[pr.user.login]["commits"] += pr.commits
                    summary_user[pr.user.login]["additions"] += pr.additions
                    summary_user[pr.user.login]["deletions"] += pr.deletions

        return {
            "stats": stats,
            "summary_user": summary_user,
            "summary_repo": summary_repo
        }

    def issue_stats(self, days):
        """Gather stats for the past few days."""
        stats = {}

        for repo in self.repos():
            stats[repo.name] = {"count": 0}
            for issue in repo.get_issues(state="closed", sort="updated", direction="desc"):
                if issue.updated_at < (datetime.datetime.now() - datetime.timedelta(days=days)):
                    break

                stats[repo.name]["count"] += 1

        return {
            "stats": stats,
        }


import os
import xlsxwriter

# Change basepath if applicable
basepath = "C:\\Users\\AYuen\\Environmental Protection Agency (EPA)\\ECMS - Documents\\newfiles\\"

workbook = xlsxwriter.Workbook(basepath+'fileandid.xlsx')
worksheet = workbook.add_worksheet("Sheet 1")

# Start from the first cell.
# Rows and columns are zero indexed.
row = 0
col = 0

# Get all files in the directory
qq = []

for (root, dirs, files) in os.walk(basepath, topdown=False):
    if len(files) > 0:
        for file in files:
            qq.append(os.path.join(root,file))

print(qq[1])

for item in qq:
    rid = item.split('\\')[6]
    fname = item.split('\\')[7]
    print(f'record id is {rid}')
    print(f'file name is {fname}')
    worksheet.write(row, col, rid)
    worksheet.write(row, col + 1, fname)
    row += 1

workbook.close()


import requests
from data_access.openWeatherMap.client import OpenWeatherMap
from business_logic.services import GetWeatherService
from config import OWM_API_KEY, OWM_BASE_URL
from .server import Request, Response

def get_weather_controller(request: Request) -> Response:
    cities = request.params.get('query')[0]
    with requests.Session() as session:
        weather_api = OpenWeatherMap(session=session, api_key=OWM_API_KEY, base_url=OWM_BASE_URL)
        weather_service = GetWeatherService(weather_api_adapter=weather_api)
        weather_data_in_cities = weather_service.get_weather_in_cities(cities=cities)

        headers = {"Content-Type": "text/html"}
        mes = "
Weather Data Table

"
        mes += "
city	temp	description	humidity
"
        for weather_data in weather_data_in_cities:
            mes += (f"
{weather_data.name}	{weather_data.main.temp}	"
                    f"{weather_data.weather[0].description}	{weather_data.main.humidity}
")
        mes += "
"
        return Response(
            status="200 OK",
            headers=headers,
            body=mes
        )

def hello_world_controller(request: Request) -> Response:
    mes = "
Hello World!
"
    headers = {"Content-Type": "text/html"}
    return Response(
        status="200 OK",
        headers=headers,
        body=mes
    )

urlpatterns = [
    ('/', get_weather_controller),
    ('/hello', hello_world_controller)
]

class WebApplication:  # Web-Frameworks: Django, Flask, FastAPI
    def _get_404_error(self, request: Request) -> Response:
        mes = f"
404 ERROR, URL {request.path} NOT FOUND"
        headers = {"Content-Type": "text/html"}
        return Response(
            status="404 NOT FOUND",
            headers=headers,
            body=mes
        )

    def __call__(self, request: Request) -> Response:
        for url_path, controller in urlpatterns:
            if url_path == request.path:
                resp = controller(request)
                return resp

        return self._get_404_error(request=request)


import torch
import torchaudio
import numpy as np
import opensmile

from collections import namedtuple
from .scan_data import scan_rootdir, CHANNELS
from .load_data import load_anno_tensor, load_vad_df
from .segment_data import SegmentEgs

class ChunkOpenSmileDataSet:
    def __init__(self, rootdir,
                 channels=CHANNELS,
                 #transform=torchaudio.transforms.MFCC(n_mfcc=40), # n_mfcc=80, melkwargs={'n_fft': 1280}
                feats2anno_rate=1,
                chunk_size_s=2,
                chunk_hop_s=1, use_vad=True):
        """ feats2anno_rate = feats_sr / anno_sr """
        self.rootdir = rootdir
        self.channels = channels
        self.transform = opensmile.Smile(
                feature_set=opensmile.FeatureSet.ComParE_2016,
                feature_level=opensmile.FeatureLevel.Functionals)

        #self.transform = transform
        self.feats2anno_rate = feats2anno_rate
        self.finfos = scan_rootdir(rootdir, channels)
        preloaded_annos = [load_anno_tensor(f.anno[0]) for f in self.finfos]
        self.segments = []
        Chunk = namedtuple('Chunk', ['start_sec', 'end_sec'])
        for f, p_a in zip(self.finfos, preloaded_annos):
            if use_vad and f.vad:
                for _, row in load_vad_df(f.vad).iterrows():
                    start = row.start_sec
                    #row.end_sec
                    keep_doing=True
                    while keep_doing:
                        end = start + chunk_size_s
                        if end > row.end_sec:
                            end = row.end_sec
                            start = max(0, end-chunk_size_s)
                            keep_doing=False
                        chunk = Chunk(start, end)
                        start += chunk_hop_s
                        self.segments.append(SegmentEgs(f, chunk, p_a))
            else:
                total = torchaudio.info(f.wav[0]).num_frames//f.wav[1]
                for start in range(0, total - chunk_size_s, chunk_hop_s):
                    chunk = Chunk(start, start + chunk_size_s)
                    self.segments.append(SegmentEgs(f, chunk, p_a))
        print(f"{len(self.segments)} chunks")

    def __len__(self):
        return len(self.segments)

    def total_sec(self):
        return sum(s.duration for s in self.segments)

    def size(self, index):
        return self.segments[index].duration

    def __getitem__(self, index):
        seq = self.segments[index]
        wav_keeper = seq.wav_keeper
        feats = self.transform.process_file(wav_keeper.wav_fname,
                                           start=wav_keeper.start_sec,
                                           end = wav_keeper.end_sec).values# 1 X feats
        feats = torch.from_numpy(feats).T # feats X 1
        anno = seq.anno.mean(dim=-2)
        #corr_anno_len = round(feats.shape[-1] / self.feats2anno_rate)
#         if abs(anno.shape[0] - corr_anno_len) > 2:
#             print(f"WARNING: element {index}, {anno.shape[0]=} ({corr_anno_len=}), {feats.shape[-1]=}, {self.feats2anno_rate=}")
#         anno = anno[:corr_anno_len]
#         corr_feats_len = round(anno.shape[0] * self.feats2anno_rate)
#         feats = feats[:, :corr_feats_len]
        return {'feats': feats,
                'labels': anno,
                'padding': torch.ones(anno.shape[0]),
                'index': index}


"""
Code to explore the PDF and CDF of weight distributions.

We use truncated lognormals to define the distribution of excitatory connections.
We scale that by -8 for inhibitory connections.
We represent the inhibitory connections with a negative number as a convention to be consistent
with the network simulator (NEST), although technically conductances must be positive.
"""
import scipy.interpolate
import scipy.stats as st
import numpy as np

def _approx_pdf_from_cdf(cdf, vmin, vmax, n_samples=10**5):
    """numerically approximate the Probability Density Function from the cumulative"""
    x = np.linspace(vmin, vmax, n_samples)

    mid = .5 * (x[:-1] + x[1:])
    derivative = np.diff(cdf(x)) / np.diff(x)

    return scipy.interpolate.interp1d(mid, derivative, fill_value=0., bounds_error=False)

def _approx_inv_cdf_from_cdf(cdf, vmin, vmax, n_samples=10**5):
    """numerically approximate the inverse of a Cumulative Distribution Function"""
    x = np.linspace(vmin, vmax, n_samples)
    return scipy.interpolate.interp1d(cdf(x), x, fill_value=0., bounds_error=False)

class TruncatedLognormal:
    """
    Represents a truncated, and possibly scaled, lognormal distribution.
    """

    def __init__(self, loc, scale, shape, vmax, g=1):
        self.loc = loc
        self.scale = scale
        self.shape = shape
        self.vmax = vmax
        self.g = g

        self.base_lognorm = st.lognorm(
            loc=self.loc,
            scale=self.scale,
            s=self.shape)

        self.base_lognorm_cdf_vmax = self.base_lognorm.cdf(self.vmax)

        self._pdf = _approx_pdf_from_cdf(self.cdf, *self.vrange)
        self._icdf = _approx_inv_cdf_from_cdf(self.cdf, *self.vrange)

    @property
    def vrange(self) -> tuple:
        """truncated range of X"""
        vrange = 0, self.vmax * self.g

        if self.g < 0:
            vrange = vrange[1], vrange[0]

        return vrange

    def linspace(self, num=50):
        """generate samples linearly on the domain of X"""
        return np.linspace(*self.vrange, num=num)

    def cdf(self, weight):
        """Cumulative Distribution Function"""
        weight_norm = weight / self.g
        prob = np.minimum(self.base_lognorm.cdf(weight_norm) / self.base_lognorm_cdf_vmax, 1)
        if self.g < 0:
            prob = 1 - prob
        return prob

    def pdf(self, weight):
        """Probability Density Function"""
        return self._pdf(weight)

    def inv_cdf(self, prob):
        """
        Inverse of the Cumulative Distribution Function.
        Maps from probability to values.
        """
        return self._icdf(prob)

    def rev_cdf(self, prob):
        """
        Reversed Cumulative Distribution Function.
        Cumulative summation is done right-to-left.
        """
        return 1 - self.cdf(prob)

    def mean(self):
        """Estimated mean from the distribution"""
        x = self.linspace(1_000_000)
        p = self.pdf(x)
        p = p / np.sum(p)
        mean = np.sum(x * p)
        return mean

    def var(self):
        """Estimated var from the distribution"""
        mean = self.mean()
        x = self.linspace(1_000_000)
        p = self.pdf(x)
        p = p / np.sum(p)
        mean = np.sum(np.square(x - mean) * p)
        return mean

    def std(self):
        """Estimated std from the distribution"""
        return np.sqrt(self.var())

    def quantile(self, q):
        """Estimated quantile from the distribution"""
        assert 0 <= q <= 1
        return self.inv_cdf(q).item()

    def median(self):
        """Estimated median from the distribution"""
        return self.quantile(.5)

    def min(self):
        """Min value of the distribution"""
        return self.quantile(0)

    def max(self):
        """Max value of the distribution"""
        return self.quantile(1)

class ConnDist:
    """Combination of exc and inh weight distributions"""

    def __init__(self, e_weights_loc, e_weights_scale, e_weights_shape, e_weights_vmax, g):
        assert g < 0

        self.exc = TruncatedLognormal(
            e_weights_loc,
            e_weights_scale,
            e_weights_shape,
            e_weights_vmax
        )
        self.inh = TruncatedLognormal(
            e_weights_loc,
            e_weights_scale,
            e_weights_shape,
            e_weights_vmax,
            g=g,
        )

    @classmethod
    def from_batch(cls, batch):
        param_names = ['e_weights_loc', 'e_weights_scale', 'e_weights_vmax', 'e_weights_shape', 'g']
        weight_dist_params = batch.reg[param_names].drop_duplicates()
        assert len(weight_dist_params) == 1
        weight_dist_params = weight_dist_params.iloc[0]

        return cls(**weight_dist_params)


import discord
import youtube_dl
from bot_token import TOKEN

if not TOKEN:
    raise ValueError("Please add your token to bot_token.py")

client = discord.Client()

@client.event
async def on_message(message):
    if message.author== client.user :
        return
    elif message.content.startswith("*l"):
        msg = f'{message.content[3:]}Hello{message.author.mention}'
        await client.send_message(message.channel, msg)
    elif message.content.startswith("*chante"):
        url= message.content[8:]

@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')

client.run(TOKEN)


from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views.generic import View
from django_redis import get_redis_connection
from redis import StrictRedis

from apps.goods.models import GoodsSKU
from utils.common import LoginRequiredViewMixin, BaseCartView

class CartAddView(BaseCartView):

    def post(self, request, command='add'):
        """添加商品到购物车"""

        params = super().post(request, command)

        # 接受数据:user_id,sku_id,count
        user_id, sku_id, count, sku = params['user_id'], \
                                 params['sku_id'], \
                                 params['count'], \
                                 params['sku']

        # print(user_id, sku_id, count)
        # print('+'*50)

        # 添加商品到购物车,如果redis中已有该商品的id,那么就增加它的数量
        strict_redis = get_redis_connection()
        # strict_redis = StrictRedis()
        key = 'cart_%s' % user_id
        val = strict_redis.hget(key, sku_id)
        if val:
            count += int(val)

        # 库存逻辑判断
        if count > sku.stock:
            return JsonResponse({'code':5, 'errmsg':'库存不足'})

        # 操作redis数据库存储商品到购物车
        strict_redis.hset(key, sku_id, count)

        total_count = 0
        vals = strict_redis.hvals(key)
        for val in vals:
            total_count += int(val)

        context = {
            'code':0,
            'total_count':total_count,
        }

        return JsonResponse(context)

class CartInfoView(LoginRequiredViewMixin, View):
    """购物车显示界面:需要先登录"""

    def get(self, request):
        # 查询当前登录用户添加到购物车中的所有商品
        strict_redis = get_redis_connection()
        key = 'cart_%s' % request.user.id
        # 获取购物车中所有商品,返回一个字典,包含sku_id和对应的数量count
        cart_dict = strict_redis.hgetall(key)

        # 保存购物车中所有的商品对象
        skus = []
        # 商品总数量
        total_count = 0
        # 商品总金额
        total_amount = 0

        for sku_id, count in cart_dict.items():

            try:
                # 根据sku_id获取sku对象
                sku = GoodsSKU.objects.get(id=sku_id)
                # 列表中新增一个商品对象
                skus.append(sku)
            except Exception as e:
                print(e)

            # sku对象动态新增一个实例属性:count
            sku.count = int(count)
            # sku对象动态新增一个实例属性:amount
            sku.amount = sku.price * sku.count

            # 累加购物车中所有商品的数量和总金额
            total_count += sku.count
            total_amount += sku.amount

        context = {
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
        }

        return render(request, 'cart.html', context)

class CartUpdateView(LoginRequiredViewMixin, BaseCartView):

    def post(self, request, command='update'):
        """修改购物车商品数量"""

        # print(CartUpdateView.mro())
        # print('-' * 50)

        params = super().post(request, command)
        sku_id = params['sku_id']
        count = params['count']

        # print(sku_id)
        # print(count)
        # print('-' * 50)

        # todo:业务处理：保存购物车商品数量
        strict_redis = get_redis_connection()
        key = 'cart_%s' % request.user.id
        strict_redis.hset(key, sku_id, count)

        # 响应json
        return JsonResponse({'code': 0, 'message': '修改商品数量成功',})

class CartDeleteView(LoginRequiredViewMixin, BaseCartView):

    def post(self, request, command='delete'):
        """删除购物车中的商品"""

        # 获取请求参数:sku_id
        sku_id = super().post(request, command)['sku_id']

        # 业务处理:从redis中删除商品
        strict_redis = get_redis_connection()
        key = 'cart_%s' % request.user.id
        strict_redis.hdel(key, sku_id)

        # 响应请求
        return JsonResponse({'code':0, 'message':'删除成功!'})


# -*- coding: utf-8 -*-
"""
Created on Fri Mar 22 11:51:37 2019

@author: javie
"""
import plotly_express as px
from plotly.offline import plot

def pl(df, r, var):
    tmp = df[df.randomSeed.isin(r)]
    plot(px.line(tmp, height=300 * len(r), x="tick",
             y = var,
             color="FirmNumID",
             line_dash="scenario",
             facet_row="randomSeed"
             ))

# Several variables melting columns
def plMelt(df, r, vars, id_vars=["randomSeed","scenario","tick","FirmNumID"]):
    tmp = df[df.randomSeed.isin(r)]
    tmp = tmp.melt(id_vars=id_vars, value_vars=vars)

    plot(px.line(tmp, height=300 * len(r), x="tick",
             y= "value",
             color="FirmNumID",
             line_dash="scenario",
             facet_col="variable",
             facet_row="randomSeed"
             ))


from app.custom_queue import CustomQueue
from app.logger import get_logger
from datetime import datetime, timedelta

LOGGER = get_logger(__name__)
QUEUE_MAX_SIZE = 20

class Queues():
    def __init__(self):
        self.LS = CustomQueue(QUEUE_MAX_SIZE, 'LeftSingle')
        self.LT = CustomQueue(QUEUE_MAX_SIZE, 'LeftTriple')
        self.RT = CustomQueue(QUEUE_MAX_SIZE, 'RightTriple')
        self.RS = CustomQueue(QUEUE_MAX_SIZE, 'RightSingle')

        self.starting_time = datetime.now()

        self.Total_time = self.starting_time

    def add_time(self, queue: CustomQueue, time: timedelta):
        self.Total_time += time
        queue.time += time
        queue.count += 1

    def add_to_LS(self, skyer):
        self.add_to(self.LS, skyer)

    def add_to_LT(self, skyer):
        self.add_to(self.LT, skyer)

    def add_to_RT(self, skyer):
        self.add_to(self.RT, skyer)

    def add_to_RS(self, skyer):
        self.add_to(self.RS, skyer)

    def add_to(self, queue: CustomQueue, skyer):
        queue.put(skyer)
        LOGGER.debug(f'Esquiador entrou na fila: {queue.name}')

    def normalize_time(self):
        self.Total_time -= self.starting_time
        self.LS.time -= self.starting_time
        self.LT.time -= self.starting_time
        self.RT.time -= self.starting_time
        self.RS.time -= self.starting_time

    def report_queue_time(self):
        self.normalize_time()

        total_count = self.LS.count + self.LT.count + self.RT.count + self.RS.count

        if total_count:
            LOGGER.info(f'Total time = {self.Total_time/total_count}')
        else:
            LOGGER.info('ninguem saiu de qualquer fila')

        if self.LS.count:
            LOGGER.info(f'{self.LS.name} time = {self.LS.time/self.LS.count}')
        else:
            LOGGER.info(f'ninguem saiu da fila {self.LS.name}')

        if self.LT.count:
            LOGGER.info(f'{self.LT.name} time = {self.LT.time/self.LT.count}')
        else:
            LOGGER.info(f'ninguem saiu da fila {self.LT.name}')

        if self.RT.count:
            LOGGER.info(f'{self.RT.name} time = {self.RT.time/self.RT.count}')
        else:
            LOGGER.info(f'ninguem saiu da fila {self.RT.name}')

        if self.RS.count:
            LOGGER.info(f'{self.RS.name} time = {self.RS.time/self.RS.count}')
        else:
            LOGGER.info(f'ninguem saiu da fila {self.RS.name}')

    def queue_sizes(self):
        LS_size = self.LS.qsize()
        LT_size = self.LT.qsize()
        RT_size = self.RT.qsize()
        RS_size = self.RS.qsize()
        return [LS_size, LT_size, RT_size, RS_size]

    def count_queues_lenght(self):
        LS_size, LT_size, RT_size, RS_size = self.queue_sizes()
        LOGGER.debug(
            f"""count_queues_lenght()
            {'###'*3}
            >Filas agora<
            LeftSingle: {LS_size}
            LeftTriple: {LT_size}
            RightTriple: {RT_size}
            RightSingle: {RS_size}
            {'###'*3}
            """)