"""
Nick/user tracking

Author:
    - linuxdaemon <linuxdaemon@snoonet.org>
"""

import asyncio
import datetime
import re
import string
from collections import defaultdict
from contextlib import suppress

import sqlalchemy.exc
from sqlalchemy import Table, Text, Column, DateTime, PrimaryKeyConstraint, Boolean, and_

from cloudbot import hook
from cloudbot.event import EventType
from cloudbot.util import database
from cloudbot.util.async_util import wrap_future, create_future
from cloudbot.util.backoff import Delayer

address_table = Table(
    'addrs',
    database.metadata,
    Column('nick', Text),
    Column('addr', Text),
    Column('created', DateTime),
    Column('seen', DateTime),
    Column('reg', Boolean, default=False),
    Column('nick_case', Text),
    PrimaryKeyConstraint('nick', 'addr')
)

hosts_table = Table(
    'hosts',
    database.metadata,
    Column('nick', Text),
    Column('host', Text),
    Column('created', DateTime),
    Column('seen', DateTime),
    Column('reg', Boolean, default=False),
    Column('nick_case', Text),
    PrimaryKeyConstraint('nick', 'host')
)

masks_table = Table(
    'masks',
    database.metadata,
    Column('nick', Text),
    Column('mask', Text),
    Column('created', DateTime),
    Column('seen', DateTime),
    Column('reg', Boolean, default=False),
    Column('nick_case', Text),
    PrimaryKeyConstraint('nick', 'mask')
)

RFC_CASEMAP = str.maketrans(dict(zip(
    string.ascii_uppercase + "[]\\",
    string.ascii_lowercase + "{}|"
)))

def update_user_data(db, table, column_name, now, nick, value):
    """
    :type db: sqlalchemy.orm.Session
    :type table: Table
    :type column_name: str
    :type now: datetime.datetime
    :type nick: str
    :type value: str
    """

    def _insert_or_update():
        try:
            db.execute(table.insert().values(**args))
        except sqlalchemy.exc.IntegrityError:
            db.rollback()
            db.execute(table.update().values(seen=now, nick_case=nick).where(clause))
        finally:
            db.commit()

    nick_cf = rfc_casefold(nick)
    clause = and_(table.c.nick == nick_cf, getattr(table.c, column_name) == value)

    args = {
        'nick': nick_cf,
        column_name: value,
        'created': now,
        'seen': now,
        'reg': False,
        'nick_case': nick
    }

    delayer = Delayer(2)
    while True:
        with delayer:
            try:
                _insert_or_update()
            except sqlalchemy.exc.TimeoutError:
                pass
            else:
                break

def _set_result(fut, result):
    if not fut.done():
        fut.set_result(result)

def get_regex_cache(conn):
    try:
        cache = conn.memory["sherlock"]["re_cache"]
    except LookupError:
        conn.memory.setdefault("sherlock", {})["re_cache"] = cache = {}

    return cache

def get_regex(conn, name):
    cache = get_regex_cache(conn)
    try:
        regex = cache[name.lower()]
    except LookupError:
        conf = conn.config["plugins"]["sherlock"]["regex"][name.lower()]
        cache[name.lower()] = regex = re.compile(conf)

    return regex

def rfc_casefold(text):
    return text.translate(RFC_CASEMAP)

def _handle_who_response(irc_paramlist):
    return irc_paramlist[5], irc_paramlist[3]

def _handle_userhost_response(irc_paramlist):
    response = irc_paramlist[1].lstrip(':')
    nick, _, ident_host = response.partition('=')
    ident_host = ident_host[1:]  # strip the +/-
    nick = nick.rstrip('*')  # strip the * which indicates oper status
    ident, _, host = ident_host.partition('@')
    return nick, host

def _handle_whowas(irc_paramlist):
    return irc_paramlist[1], irc_paramlist[3]

def _handle_whowas_host(irc_paramlist):
    nick = irc_paramlist[1]
    hostmask = irc_paramlist[-1].strip().rsplit(None, 1)[1]
    host = hostmask.split('@', 1)[1]
    return nick, host

response_map = {
    '352': ("user_mask", _handle_who_response),
    '302': ("user_host", _handle_userhost_response),
    '340': ("user_ip", _handle_userhost_response),  # USERIP responds with the same format as USERHOST
    '314': ("user_whowas_mask", _handle_whowas),
    '379': ("user_whowas_host", _handle_whowas_host),
}

@asyncio.coroutine
def await_response(fut):
    return (yield from asyncio.wait_for(fut, 60))

@asyncio.coroutine
def await_command_response(conn, name, cmd, nick):
    futs = conn.memory["sherlock"]["futures"][name]
    nick_cf = rfc_casefold(nick)
    try:
        fut = futs[nick_cf]
    except LookupError:
        futs[nick_cf] = fut = create_future(conn.loop)
        conn.cmd(cmd, nick)

    try:
        res = yield from await_response(fut)
    finally:
        with suppress(KeyError):
            del futs[nick_cf]

    return res

@asyncio.coroutine
def get_user_host(conn, nick):
    return (yield from await_command_response(conn, "user_host", "USERHOST", nick))

@asyncio.coroutine
def get_user_ip(conn, nick):
    return (yield from await_command_response(conn, "user_ip", "USERIP", nick))

@asyncio.coroutine
def get_user_mask(conn, nick):
    return (yield from await_command_response(conn, "user_mask", "WHO", nick))

@asyncio.coroutine
def get_user_whowas(conn, nick):
    nick_cf = rfc_casefold(nick)
    futs = conn.memory["sherlock"]["futures"]
    send_command = False
    try:
        mask_fut = futs["user_whowas_mask"][nick_cf]
    except LookupError:
        send_command = True
        futs["user_whowas_mask"][nick_cf] = mask_fut = create_future(conn.loop)

    try:
        host_fut = futs["user_whowas_host"][nick_cf]
    except LookupError:
        send_command = True
        futs["user_whowas_host"][nick_cf] = host_fut = create_future(conn.loop)

    if send_command:
        conn.cmd("WHOWAS", nick)

    try:
        return (yield from await_response(asyncio.gather(mask_fut, host_fut)))
    except asyncio.TimeoutError:
        return None, None

@hook.on_start
def clear_regex_cache(bot):
    for conn in bot.connections.values():
        get_regex_cache(conn).clear()

@hook.on_start
def init_futures(bot):
    for conn in bot.connections.values():
        conn.memory["sherlock"] = {
            "futures": defaultdict(dict),
        }

@hook.event(EventType.notice)
@asyncio.coroutine
def on_notice(db, nick, chan, conn, event):
    try:
        server_info = conn.memory["server_info"]
    except LookupError:
        return

    if chan.casefold() != nick.casefold():
        # This isn't a PM / Private notice, ignore it
        return

    if nick.casefold() != server_info["server_name"]:
        # This message isn't from the server, ignore it
        return

    yield from handle_snotice(db, event)

@hook.irc_raw(response_map.keys())
@asyncio.coroutine
def handle_response_numerics(conn, irc_command, irc_paramlist):
    try:
        name, handler = response_map[irc_command]
    except LookupError:
        return

    nick, value = handler(irc_paramlist)

    futs = conn.memory["sherlock"]["futures"][name]
    try:
        fut = futs.pop(rfc_casefold(nick))
    except LookupError:
        return

    _set_result(fut, value.strip())

@asyncio.coroutine
def handle_snotice(db, event):
    conn = event.conn
    content = event.content
    for name, handler in HANDLERS.items():
        regex = get_regex(conn, name)
        match = regex.match(content)
        if match:
            yield from handler(db, event, match)

            break

@asyncio.coroutine
def set_user_data(event, db, table, column_name, now, nick, value_func, conn=None):
    value = yield from value_func(event.conn if conn is None else conn, nick)
    yield from event.async_call(update_user_data, db, table, column_name, now, nick, value)

@asyncio.coroutine
def delay_call(coro, timeout):
    yield from asyncio.sleep(timeout)
    return (yield from coro)

@asyncio.coroutine
def on_nickchange(db, event, match):
    conn = event.conn
    old_nick = match.group('oldnick')
    new_nick = match.group('newnick')
    now = datetime.datetime.now()

    old_nick_cf = rfc_casefold(old_nick)
    new_nick_cf = rfc_casefold(new_nick)

    futures = conn.memory["sherlock"]["futures"]

    data_futs = futures["data"]
    nick_change_futs = futures["nick_changes"]

    futs = {
        'addr': create_future(conn.loop),
        'host': create_future(conn.loop),
        'mask': create_future(conn.loop),
    }

    data_futs[new_nick_cf] = futs

    try:
        old_futs = data_futs.pop(old_nick_cf)
    except LookupError:
        nick_change_futs[old_nick_cf] = fut = create_future(conn.loop)
        try:
            old_futs = yield from asyncio.wait_for(fut, 30)
        except asyncio.TimeoutError:
            old_futs = {}
        finally:
            with suppress(LookupError):
                del nick_change_futs[old_nick_cf]

    try:
        nick_fut = nick_change_futs.pop(new_nick_cf)
    except LookupError:
        pass
    else:
        _set_result(nick_fut, futs)

    @asyncio.coroutine
    def _handle_set(table, name, value_func):
        try:
            value = yield from value_func(event.conn, new_nick)
        except (asyncio.TimeoutError, asyncio.CancelledError):
            value = yield from asyncio.wait_for(futs[name], 300)

        del futs[name]

        with suppress(LookupError):
            _set_result(old_futs[name], value)

        yield from asyncio.gather(
            event.async_call(update_user_data, db, table, name, now, old_nick, value),
            event.async_call(update_user_data, db, table, name, now, new_nick, value)
        )

    @asyncio.coroutine
    def _do_mask():
        yield from _handle_set(masks_table, 'mask', get_user_mask)

    @asyncio.coroutine
    def _timeout_whowas():
        try:
            yield from asyncio.gather(
                _handle_set(hosts_table, 'host', get_user_host),
                _do_mask(),
            )
        except (asyncio.TimeoutError, asyncio.CancelledError):
            mask, host = yield from get_user_whowas(event.conn, new_nick)
            if mask and host:
                with suppress(KeyError):
                    _set_result(old_futs['host'], host)

                with suppress(KeyError):
                    _set_result(old_futs['mask'], mask)

                yield from asyncio.gather(
                    event.async_call(update_user_data, db, hosts_table, 'host', now, old_nick, host),
                    event.async_call(update_user_data, db, hosts_table, 'host', now, new_nick, host),

                    event.async_call(update_user_data, db, masks_table, 'mask', now, old_nick, mask),
                    event.async_call(update_user_data, db, masks_table, 'mask', now, new_nick, mask),
                )

    yield from asyncio.gather(
        _handle_set(address_table, 'addr', get_user_ip),
        _timeout_whowas(),
    )

    with suppress(KeyError):
        del data_futs[new_nick_cf]

@asyncio.coroutine
def on_user_connect(db, event, match):
    nick = match.group('nick')
    ident = match.group('ident')
    host = match.group('host')
    addr = match.group('addr')

    now = datetime.datetime.now()

    nick_cf = rfc_casefold(nick)
    conn = event.conn

    mask_fut = create_future(conn.loop)

    futs = {
        'mask': mask_fut,
    }

    data_futs = conn.memory["sherlock"]["futures"]["data"]

    data_futs[nick_cf] = futs

    @asyncio.coroutine
    def _handle_set(table, name, value_func):
        try:
            value = yield from value_func(event.conn, nick)
        except (asyncio.TimeoutError, asyncio.CancelledError):
            value = yield from futs[name]

        del futs[name]

        yield from event.async_call(update_user_data, db, table, name, now, nick, value)

    @asyncio.coroutine
    def _do_mask():
        yield from _handle_set(masks_table, 'mask', get_user_mask)

    yield from asyncio.gather(
        event.async_call(update_user_data, db, hosts_table, 'host', now, nick, host),
        event.async_call(update_user_data, db, address_table, 'addr', now, nick, addr),
        _do_mask(),
    )

    with suppress(LookupError):
        del data_futs[nick_cf]

@asyncio.coroutine
def on_user_quit(db, event, match):
    nick = match.group('nick')
    ident = match.group('ident')
    host = match.group('host')
    addr = match.group('addr')

    now = datetime.datetime.now()

    nick_cf = rfc_casefold(nick)
    conn = event.conn

    futures = conn.memory["sherlock"]["futures"]

    data_futs = futures["data"]
    nick_change_futs = futures["nick_changes"]

    try:
        old_futs = data_futs.pop(nick_cf)
    except LookupError:
        nick_change_futs[nick_cf] = fut = create_future(conn.loop)
        try:
            old_futs = yield from asyncio.wait_for(fut, 30)
        except asyncio.TimeoutError:
            old_futs = {}
        finally:
            with suppress(LookupError):
                del nick_change_futs[nick_cf]

    with suppress(KeyError):
        _set_result(old_futs['host'], host)

    with suppress(KeyError):
        _set_result(old_futs['addr'], addr)

    @asyncio.coroutine
    def _do_whowas():
        mask, _ = yield from get_user_whowas(event.conn, nick)
        if mask:
            with suppress(KeyError):
                _set_result(old_futs['mask'], mask)

            yield from event.async_call(update_user_data, db, masks_table, 'mask', now, nick, mask)

    yield from asyncio.gather(
        event.async_call(update_user_data, db, hosts_table, 'host', now, nick, host),
        event.async_call(update_user_data, db, address_table, 'addr', now, nick, addr),
        _do_whowas(),
    )

HANDLERS = {
    'nick': on_nickchange,
    'connect': on_user_connect,
    'quit': on_user_quit,
}

@asyncio.coroutine
def ignore_timeout(coro):
    try:
        return (yield from coro)
    except (asyncio.TimeoutError, asyncio.CancelledError):
        pass

@hook.irc_raw('352')
@asyncio.coroutine
def on_who(conn, irc_paramlist):
    try:
        lines, fut = conn.memory["sherlock"]["futures"]["who_0"][0]
    except LookupError:
        return

    if not fut.done():
        lines.append(irc_paramlist[1:])

@hook.irc_raw('315')
@asyncio.coroutine
def on_who_end(conn, irc_paramlist):
    name = irc_paramlist[1]
    if name != "0":
        return

    try:
        lines, fut = conn.memory["sherlock"]["futures"]["who_0"][0]
    except LookupError:
        return

    _set_result(fut, lines)

@hook.on_start
@asyncio.coroutine
def get_initial_data(bot, loop, db, event):
    wrap_future(asyncio.gather(
        *[get_initial_connection_data(conn, loop, db, event) for conn in bot.connections.values() if conn.connected]
    ))

@hook.irc_raw('376')
@hook.command("getdata", permissions=["botcontrol"], autohelp=False)
@asyncio.coroutine
def get_initial_connection_data(conn, loop, db, event):
    """
    - Update all user data

    :type conn: cloudbot.client.Client
    :type loop: asyncio.AbstractEventLoop
    :type db: sqlalchemy.orm.Session
    :type event: cloudbot.event.Event
    """
    if conn.nick.endswith('-dev') and not hasattr(event, 'triggered_command'):
        # Ignore initial data update on development instances
        return

    fut = create_future(loop)
    try:
        lines, fut = conn.memory["sherlock"]["futures"]["who_0"][0]
    except LookupError:
        pass
    else:
        if not fut.done():
            return "getdata command already running"

    conn.memory["sherlock"]["futures"]["who_0"][0] = ([], fut)

    yield from asyncio.sleep(10)

    now = datetime.datetime.now()
    conn.send("WHO 0")
    try:
        lines = yield from asyncio.wait_for(fut, 30 * 60)
    except asyncio.TimeoutError:
        return "Timeout reached"
    finally:
        with suppress(LookupError):
            del conn.memory["sherlock"]["futures"]["who_0"][0]

    users = []
    for line in lines:
        chan, ident, host, server, nick, status, realname = line
        num_hops, _, realname = realname.partition(' ')
        users.append((nick, host))

    futs = [
        wrap_future(event.async_call(update_user_data, db, masks_table, 'mask', now, nick, mask))
        for nick, mask in users
    ]

    for nick, mask in users:
        yield from asyncio.gather(
            ignore_timeout(set_user_data(event, db, hosts_table, 'host', now, nick, get_user_host, conn)),
            ignore_timeout(set_user_data(event, db, address_table, 'addr', now, nick, get_user_ip, conn))
        )

    yield from asyncio.gather(*futs)

    return "Done."


from django import forms

from applications.base.models import Comuna, Pais, Region
from applications.base.utils import validarRut
from applications.empresa.models import Afp, Apv, Banco, CajasCompensacion, MutualSecurity, Salud
from applications.remuneracion.models import Concept

class BanksForm(forms.ModelForm):

    tags_input_general = {
        'class': 'form-control',
    }

    ban_nombre = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    ban_codigo = forms.CharField(label="Código", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    ban_activo = forms.ChoiceField(initial='S', label='Banco Activo?', choices=Banco.OPCIONES,
                                   widget=forms.Select(attrs=tags_input_general), required=False)

    class Meta:
        model = Banco
        fields = (
            "ban_nombre", "ban_codigo", "ban_activo"
        )

class CountryForm(forms.ModelForm):

    tags_input_general = {
        'class': 'form-control',
    }

    tags_input_readonly = {
        'class': 'form-control',
        'readonly': 'readonly'
    }

    pa_nombre = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_readonly), required=True)
    pa_codigo = forms.IntegerField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_readonly), required=True)

    class Meta:
        model = Pais
        fields = (
            "pa_nombre", "pa_codigo"
        )

class RegionForm(forms.ModelForm):

    tags_input_readonly = {
        'class': 'form-control',
        'readonly': 'readonly'
    }

    tags_input_select2_readonly = {
        'class': 'form-control select2-show-search',
        'readonly': 'readonly'
    }

    re_nombre = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_readonly), required=True)
    pais = forms.ModelChoiceField(label="País", required=True,
                                  queryset=Pais.objects.all(), widget=forms.Select(attrs=tags_input_select2_readonly))
    re_numeroregion = forms.CharField(label="Sigla", widget=forms.TextInput(
        attrs=tags_input_readonly), required=False)
    re_numero = forms.IntegerField(label="N° región", widget=forms.TextInput(
        attrs=tags_input_readonly), required=True)

    class Meta:
        model = Region
        fields = (
            "re_nombre", "pais", "re_numeroregion", "re_numero"
        )

class CommuneForm(forms.ModelForm):

    tags_input_readonly = {
        'class': 'form-control',
        'readonly': 'readonly'
    }

    tags_input_select2_readonly = {
        'class': 'form-control select2-show-search',
        'readonly': 'readonly'
    }

    com_nombre = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_readonly), required=True)
    com_numero = forms.IntegerField(label="N° comuna", widget=forms.TextInput(
        attrs=tags_input_readonly), required=True)
    region = forms.ModelChoiceField(label="Región", required=True,
                                    queryset=Region.objects.all(), widget=forms.Select(attrs=tags_input_select2_readonly))

    class Meta:
        model = Comuna
        fields = (
            "com_nombre", "com_numero", "region"
        )

class AfpForm(forms.ModelForm):

    tags_input_general = {
        'class': 'form-control',
    }

    afp_codigoprevired = forms.CharField(label="Código Previred", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    afp_nombre = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    afp_tasatrabajadordependiente = forms.FloatField(label="Tasa trabajador Dependiente", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    afp_sis = forms.FloatField(label="Seguro de Invalidez y Sobrevivencia (SIS)", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    afp_tasatrabajadorindependiente = forms.FloatField(label="Tasa trabajador independiente", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    afp_activo = forms.ChoiceField(initial='S', label='Afp Activa?', choices=Afp.OPCIONES,
                                   widget=forms.Select(attrs=tags_input_general), required=False)

    class Meta:
        model = Afp
        fields = (
            "afp_codigoprevired", "afp_nombre", "afp_tasatrabajadordependiente", "afp_sis", "afp_tasatrabajadorindependiente", "afp_activo"
        )

class ApvForm(forms.ModelForm):

    tags_input_general = {
        'class': 'form-control',
    }

    apv_nombre = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_general), required=True)

    apv_nombrerazonsocial = forms.CharField(label="Razón Social", widget=forms.TextInput(
        attrs=tags_input_general), required=False)

    class Meta:
        model = Apv
        fields = (
            "apv_nombre", "apv_nombrerazonsocial"
        )

class SaludForm(forms.ModelForm):

    tags_input_readonly = {
        'class': 'form-control',
        'readonly': 'readonly'
    }

    tags_input_general = {
        'class': 'form-control',
    }

    sa_nombre = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    sa_codigo = forms.CharField(label="Código", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    sa_tipo = forms.ChoiceField(initial='F', label="Tipo Entidad?", choices=Salud.TIPO,
                                widget=forms.Select(attrs=tags_input_general), required=True)
    sa_activo = forms.ChoiceField(initial='S', label='Entidad de Salud Activa?', choices=Salud.OPCIONES,
                                  widget=forms.Select(attrs=tags_input_general), required=False)

    class Meta:
        model = Salud
        fields = (
            "sa_nombre", "sa_codigo", "sa_tipo", "sa_activo"
        )

class CajasCompensacionForm(forms.ModelForm):

    tags_input_readonly = {
        'class': 'form-control',
        'readonly': 'readonly'
    }

    tags_input_general = {
        'class': 'form-control',
    }

    cc_nombre = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    cc_codigo = forms.CharField(label="Código", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    cc_rut = forms.CharField(label="Rut", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    cc_activo = forms.ChoiceField(initial='S', label='Caja de Compensacion Activa?', choices=CajasCompensacion.OPCIONES,
                                  widget=forms.Select(attrs=tags_input_general), required=False)

    def clean_cc_rut(self):
        data = self.cleaned_data["cc_rut"]

        if not validarRut(data):
            self.add_error('cc_rut', "El rut no es valido")
        return data

    class Meta:
        model = CajasCompensacion
        fields = (
            "cc_nombre", "cc_codigo", "cc_rut", "cc_activo"
        )

class MutualSecurityForm(forms.ModelForm):

    tags_input_general = {
        'class': 'form-control',
    }

    ms_name = forms.CharField(label="Nombre", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    ms_rut = forms.CharField(label="Rut", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    ms_codeprevired = forms.CharField(label="Código", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    ms_active = forms.ChoiceField(initial='S', label='Activa?', choices=MutualSecurity.OPTIONS,
                                  widget=forms.Select(attrs=tags_input_general), required=False)

    def clean_ms_rut(self):
        data = self.cleaned_data["ms_rut"]

        if not validarRut(data):
            self.add_error('ms_rut', "El rut no es valido")
        return data

    class Meta:
        model = MutualSecurity
        fields = (
            "ms_name", "ms_rut", "ms_codeprevired", "ms_active"
        )

class ConceptsForm(forms.ModelForm):

    tags_input_general = {
        'class': 'form-control',
    }

    tags_input_select = {
        'class': 'form-control select2-one',
    }

    conc_name = forms.CharField(label="Nombre Concepto", widget=forms.TextInput(
        attrs=tags_input_general), required=True)
    conc_typeconcept = forms.ChoiceField(label="Tipo concepto", choices=Concept.TYPE_CLASSIFICATION,
                                widget=forms.Select(attrs=tags_input_select), required=True)
    conc_clasificationconcept = forms.ChoiceField(label="Clasificación concepto", choices=Concept.CLASSIFICATION,
                                widget=forms.Select(attrs=tags_input_select), required=True)
    conc_search_field = forms.ChoiceField(label="Tipo de entidad", help_text="** Este campo solo se debe usar para el caso de los descuentos de salud y afp", choices=Concept.SEARCH_FIELDS,
                                widget=forms.Select(attrs=tags_input_select), required=False)
    conc_remuneration_type = forms.ChoiceField(label="Tipo de remuneración", choices=Concept.REMUNERATION_TYPE,
                                widget=forms.Select(attrs=tags_input_select), required=False)

    class Meta:
        model = Concept
        fields = (
            "conc_name", "conc_typeconcept", "conc_clasificationconcept", "conc_search_field", "conc_remuneration_type"
        )


import os
import resource
import time

from collectors.lib import utils
from collectors.lib.collectorbase import CollectorBase

class ProcessTerminatedError(Exception):
    pass

class Process(object):
    def __init__(self, pid):
        self.pid = pid

    def stat(self):
        """ Returns /proc/[pid]/stat as dict.

            The dict only contains the values that are currently used, but can
            be extended easily.
            If the process already terminated ProcessTerminatedError is raised.
        """

        path = "/proc/%s/stat" % self.pid
        try:
            with open(path) as f:
                spl = f.readline().split()
        except IOError:
            raise ProcessTerminatedError()

        rv = {"pid": spl[0], "comm": spl[1], "ppid": spl[3],
                "utime": spl[13], "stime": spl[14], "cutime": spl[15],
                "cstime": spl[16], "vsize": spl[22], "rss": spl[23]}
        # supported since Kernel 2.6.24
        if len(spl) > 43:
                rv.update({"guest_time": spl[42],
                           "cguest_time": spl[43]})
        return rv

class Cwagent(CollectorBase):
    def __init__(self, config, logger, readq):
        super(Cwagent, self).__init__(config, logger, readq)
        pid = os.getpid()
        self.log_info("cloudwiz agent pid %d", pid)
        self.process = Process(pid)

    def __call__(self):
        with utils.lower_privileges(self._logger):
            cpu_time = 0

            try:
                s = self.process.stat()
            except ProcessTerminatedError:
                self.log_warn("process terminated, abort")
                return

            cpu_time += int(s["utime"])
            cpu_time += int(s["cutime"])
            cpu_time += int(s["stime"])
            cpu_time += int(s["cstime"])
            cpu_time += int(s["guest_time"])
            cpu_time += int(s["cguest_time"])

            ts = int(time.time())
            self._readq.nput("cloudwiz-agent.cputime %s %s" % (ts, cpu_time))
            self._readq.nput("cloudwiz-agent.mem_bytes %s %s type=vsize" % (ts, s["vsize"]))
            self._readq.nput("cloudwiz-agent.mem_bytes %s %s type=rss" % (ts, int(s["rss"]) * resource.getpagesize()))

if __name__ == "__main__":
    cwagent_inst = Cwagent(None, None, utils.TestQueue())
    cwagent_inst()


import torch

def batch_jacobian(outputs, inputs, create_graph=False):
    """Computes the jacobian of outputs with respect to inputs

    :param outputs: tensor for the output of some function
    :param inputs: tensor for the input of some function (probably a vector)
    :param create_graph: set True for the resulting jacobian to be differentible
    :returns: a tensor of size (outputs.size() + inputs.size()) containing the
        jacobian of outputs with respect to inputs
    """
    jac = outputs.new_zeros(outputs.size() + inputs.size()
                            ).view((-1,) + inputs.size())
    for i, out in enumerate(outputs.view(-1)):
        col_i = torch.autograd.grad(out, inputs, retain_graph=True,
                              create_graph=create_graph, allow_unused=True)[0]
        if col_i is None:
            # this element of output doesn't depend on the inputs, so leave gradient 0
            continue
        else:
            jac[i] = col_i

    if create_graph:
        jac.requires_grad_()

    return jac.view(outputs.size() + inputs.size())

def parametriser_regulariser(x, h, theta, g, num_concepts=5):
    batch_size = x.shape[0]
    grad_f = torch.zeros(batch_size, num_concepts, 1, 28, 28)
    for i in range(num_concepts):
        grad_f[:, i] = torch.autograd.grad(g[:, i].sum(), x, retain_graph=True)[0].data
    # grad_f = torch.autograd.grad(g, x)
    jacob_h = batch_jacobian(h, x)
    # theta_times_jacob_h = torch.einsum('boi,bo->bi', jacob_h, theta)
    theta_times_jacob_h = torch.einsum('ijiklm,ij->ijklm', jacob_h, theta)
    reg = torch.sum((grad_f.cuda() - theta_times_jacob_h.cuda()) ** 2)
    return reg


import matplotlib as mpl
import matplotlib.pyplot as plt

def get_counter_plot(counter, plot_name):
    mpl.rcParams['figure.figsize'] = (6, 6)

    sorted_x, sorted_y = zip(*counter.most_common(15))

    plt.bar(range(len(sorted_x)), sorted_y, width=0.75, align='center')
    plt.xticks(range(len(sorted_x)), sorted_x, rotation=90)
    plt.axis('tight')
    plt.tight_layout()
    plt.savefig(plot_name)
    plt.show()


from django import forms
from . import models

class CommentForm(forms.ModelForm):
    class Meta:
        model = models.Comment
        fields = (
            "comment",
        )

    def __init__(self, *args, **kwargs):
        # 폼 안에 class를 만들어주는 역할
        super(CommentForm, self).__init__(*args, **kwargs)
        self.fields['comment'].widget.attrs['placeholder'] = '댓글을 남기세요'
        for visible in self.visible_fields():
            visible.field.widget.attrs['class'] = 'comment_form'


#!/usr/bin/env python3

import sys, collections
from omada import Omada

FIELDDEF = collections.OrderedDict([
	('name',        ('USERNAME',     20)),
	('ip',          ('IP ADDRESS',   16)),
	('active',      ('STATUS',       12)),
	('networkName', ('SSID/NETWORK', 16)),
	('port',        ('AP/PORT',      16)),
	('activity',    ('ACTIVITY',     12)),
	('trafficDown', ('DOWNLOAD',     10)),
	('trafficUp',   ('UPLOAD',       10)),
	('uptime',      ('UPTIME',       16)),
])

def format_status( active ):
	return 'CONNECTED' if active else '--'

def format_port( switch, port ):
	return f'{switch} Port {port}'

def format_size( size, suffix='B' ):
	for unit in ['K','M','G','T','P','E','Z']:
		size /= 1000.0
		if abs( size ) < 1000.0:
			return f'{size:.1f} {unit}{suffix}'
	return f'{size:.1f} Y{suffix}'

def format_time( time ):
	d = time // (3600 * 24)
	h = time // 3600 % 24
	m = time % 3600 // 60
	s = time % 3600 % 60
	if d > 0: return f'{d}d {h}:{m:02d}:{s:02d}'
	if h > 0: return f'{h}:{m:02d}:{s:02d}'
	if m > 0: return f'{m:02d}:{s:02d}'
	if s > 0: return f'{s:02d}'
	return '--'

def print_header():

	if sys.stdout.isatty():
		sys.stdout.write( '\33[1m' )

	for key in FIELDDEF:
		text,width = FIELDDEF[key]
		sys.stdout.write( text.ljust(abs(width)) )

	if sys.stdout.isatty():
		sys.stdout.write( '\33[0m' )

	sys.stdout.write( '\n' )

def print_client( client ):

	for key in client:

		if key == 'active':
			client[key] = format_status( client['active'] )

		elif key == 'port':
			client[key] = format_port( client['switchName'], client['port'] )

		elif key == 'activity':
			client[key] = format_size( client['activity'], 'B/s' )

		elif key == 'trafficDown':
			client[key] = format_size( client['trafficDown'], 'B' )

		elif key == 'trafficUp':
			client[key] = format_size( client['trafficUp'], 'B' )

		elif key == 'uptime':
			client[key] = format_time( client['uptime'] )

	if client['connectDevType'] == 'ap':
		client['networkName'] = client['ssid']
		client['port'] = client['apName']

	for key in FIELDDEF:

		text = client[key] if key in client else '--'
		if not isinstance(text,str): text = str(text)

		width = FIELDDEF[key][1]

		if len(text) >= abs(width):
			text = text[0:abs(width)-4] + '... '
		elif width > 0:
			text = text.ljust(abs(width))
		else:
			text = text.rjust(abs(width)-1)

		sys.stdout.write( text )

	sys.stdout.write( '\n' )

def main():
	omada = Omada()
	omada.login()

	print_header()

	for client in omada.getSiteClients():
		print_client( client )

	omada.logout()

if __name__ == '__main__':
	main()


from multiprocessing import Process
import os

def info(title):
    print(title)
    print('module name:', __name__)
    print('parent process:', os.getppid())
    print('process id:', os.getpid())

def func(name):
    print("name:" +name)
    info('function f')

if __name__ == '__main__':
    info('main line')
    p = Process(target=func, args=('bob',))
    p2 = Process(target=func, args=('allice',))
    p.start()
    p2.start()
    p2.join()
    p.join()


#!/usr/bin/env python
# coding=utf-8

import logging
from eventlet.green import os
from storm.locals import create_database, Store

import runtime.path
from runtime import env

_database = None
_store = None
logger = logging.getLogger(__name__)

db_uri = os.path.abspath(runtime.path.join(env.get('dir_data'), 'core.db'))
logger.debug("database path: `%s'" % db_uri)

def get_store():
    global _database, _store
    if not _database:
        _database = create_database('sqlite:///%s' % db_uri)
    if not _store:
        _store = Store(_database)

    return _store

def init():
    import sqlite3
    logger.debug('create tables.')
    with open(runtime.path.resources_path('schema.sql')) as fp:
        conn = sqlite3.connect(db_uri)
        conn.executescript(fp.read())


import unittest
import torch
import torch_testing as tt
from all import nn
from all.core import StateArray
from all.approximation import VNetwork, FeatureNetwork
from all.memory import NStepAdvantageBuffer

class NStepAdvantageBufferTest(unittest.TestCase):
    def setUp(self):
        torch.manual_seed(1)
        self.features = FeatureNetwork(nn.Linear(1, 2), None)
        self.v = VNetwork(nn.Linear(2, 1), None)

    def _compute_expected_advantages(self, states, returns, next_states, lengths):
        return (
            returns
            + (0.5 ** lengths.float()) * self.v.eval(self.features.eval(next_states))
            - self.v.eval(self.features.eval(states))
        )

    def test_rollout(self):
        buffer = NStepAdvantageBuffer(self.v, self.features, 2, 3, discount_factor=0.5)
        actions = torch.ones((3))
        states = StateArray(torch.arange(0, 12).unsqueeze(1).float(), (12,))
        buffer.store(states[0:3], actions, torch.zeros(3))
        buffer.store(states[3:6], actions, torch.ones(3))
        states, _, advantages = buffer.advantages(states[6:9])

        expected_states = StateArray(torch.arange(0, 6).unsqueeze(1).float(), (6,))
        expected_next_states = StateArray(
            torch.cat((torch.arange(6, 9), torch.arange(6, 9))).unsqueeze(1).float(), (6,)
        )
        expected_returns = torch.tensor([
            0.5, 0.5, 0.5,
            1, 1, 1
        ]).float()
        expected_lengths = torch.tensor([
            2., 2, 2,
            1, 1, 1
        ])

        self.assert_states_equal(states, expected_states)
        tt.assert_allclose(advantages, self._compute_expected_advantages(
            expected_states, expected_returns, expected_next_states, expected_lengths
        ))

    def test_rollout_with_dones(self):
        buffer = NStepAdvantageBuffer(self.v, self.features, 3, 3, discount_factor=0.5)
        done = torch.tensor([False] * 12)
        done[5] = True
        done[7] = True
        done[9] = True
        states = StateArray(torch.arange(0, 12).unsqueeze(1).float(), (12,), done=done)
        actions = torch.ones((3))
        buffer.store(states[0:3], actions, torch.zeros(3))
        buffer.store(states[3:6], actions, torch.ones(3))
        buffer.store(states[6:9], actions, 2 * torch.ones(3))
        states, actions, advantages = buffer.advantages(states[9:12])

        expected_states = StateArray(torch.arange(0, 9).unsqueeze(1).float(), (9,), done=done[0:9])
        expected_next_done = torch.tensor([True] * 9)
        expected_next_done[5] = False
        expected_next_done[7] = False
        expected_next_done[8] = False
        expected_next_states = StateArray(torch.tensor([
            9, 7, 5,
            9, 7, 11,
            9, 10, 11
        ]).unsqueeze(1).float(), (9,), done=expected_next_done)
        expected_returns = torch.tensor([
            1, 0.5, 0,
            2, 1, 2,
            2, 2, 2
        ]).float()
        expected_lengths = torch.tensor([
            3, 2, 1,
            2, 1, 2,
            1, 1, 1
        ]).float()

        self.assert_states_equal(states, expected_states)
        tt.assert_allclose(advantages, self._compute_expected_advantages(
            expected_states, expected_returns, expected_next_states, expected_lengths
        ))

    def test_multi_rollout(self):
        buffer = NStepAdvantageBuffer(self.v, self.features, 2, 2, discount_factor=0.5)
        raw_states = StateArray(torch.arange(0, 12).unsqueeze(1).float(), (12,))
        actions = torch.ones((2))
        buffer.store(raw_states[0:2], actions, torch.ones(2))
        buffer.store(raw_states[2:4], actions, torch.ones(2))

        states, actions, advantages = buffer.advantages(raw_states[4:6])
        expected_states = StateArray(torch.arange(0, 4).unsqueeze(1).float(), (4,))
        expected_returns = torch.tensor([1.5, 1.5, 1, 1])
        expected_next_states = StateArray(torch.tensor([4., 5, 4, 5]).unsqueeze(1), (4,))
        expected_lengths = torch.tensor([2., 2, 1, 1])
        self.assert_states_equal(states, expected_states)
        tt.assert_allclose(advantages, self._compute_expected_advantages(
            expected_states,
            expected_returns,
            expected_next_states,
            expected_lengths
        ))

        buffer.store(raw_states[4:6], actions, torch.ones(2))
        buffer.store(raw_states[6:8], actions, torch.ones(2))

        states, actions, advantages = buffer.advantages(raw_states[8:10])
        expected_states = StateArray(torch.arange(4, 8).unsqueeze(1).float(), (4,))
        self.assert_states_equal(states, expected_states)
        tt.assert_allclose(advantages, self._compute_expected_advantages(
            expected_states,
            torch.tensor([1.5, 1.5, 1, 1]),
            StateArray(torch.tensor([8, 9, 8, 9]).unsqueeze(1).float(), (4,)),
            torch.tensor([2., 2, 1, 1])
        ))

    def assert_array_equal(self, actual, expected):
        for i, exp in enumerate(expected):
            self.assertEqual(actual[i], exp, msg=(
                ("\nactual: %s\nexpected: %s") % (actual, expected)))

    def assert_states_equal(self, actual, expected):
        tt.assert_almost_equal(actual.observation, expected.observation)
        tt.assert_equal(actual.mask, expected.mask)

if __name__ == '__main__':
    unittest.main()


import os
import cv2 as cv
import yaml
import aircv as ac
import requests
import threading
import re
import easyocr

reader = easyocr.Reader(['en'], gpu=False)

file = open("config.yaml", 'r', encoding="utf-8")
file_data = file.read()
file.close()
data = yaml.load(file_data, Loader=yaml.FullLoader)

def findLocation():
    threshold = 0.5
    try:
        imsch = ac.imread('search_mob.png')
        result = ac.find_all_template(ac.imread('screen.jpg'), imsch, threshold)
        return result
    except Exception as e:
        print('error', e)
        return None

def callback(fee,out_trade_no):
    payload = {
        'fee': fee,
        'out_trade_no':out_trade_no
    }
    r = requests.post("%spay/callback" % data['apiurl'], data=payload)
    print(r.json())
def noteMe():
    try:
        payload = {
        }
        r = requests.get("http://noteapi.yoyolife.fun/api/sms/task/exxxx08396/8", data=payload) #换成自己的id
        print(r.json())
    except Exception as e:
        print(e)

lastCheck = 0
loopCount = 0
if __name__ == '__main__':
    os.system("adb shell settings put system screen_brightness_mode 0")
    os.system("adb shell settings put system screen_brightness 0")
    while True:
        # 方法6
        os.system("adb shell input tap 484 133")
        os.system("adb exec-out screencap -p > screen.jpg")
        img = cv.imread('screen.jpg')
        try:
            loca = findLocation()

            if len(loca) > 0:

                obj = 0
                if len(loca) == 1:
                    obj = loca[-1]
                else:
                    for objSub in loca:
                        if objSub['result'][1] > 1000:
                            obj = objSub
                            break
                i = 0
                #
                if obj != None and obj['confidence'] > 0.95:
                    x = int(obj['result'][0])
                    y = int(obj['result'][1])
                    # print(x,y)
                    cv.rectangle(img, (x + 20, y + 230), (x + 590, y + 350), color=(0, 0, 255),
                                 thickness=2)
                    cv.rectangle(img, (x-140, y + 50), (x + 190, y + 110), color=(0, 0, 255),
                                 thickness=2)
                    imgPrice = img[y + 230:y + 350, x + 20:x + 590]
                    imgData = img[y + 50:y + 110, x -140:x + 190]
                    result = reader.readtext(imgPrice, detail=0)
                    num = re.sub("\D", "", result[-1])
                    resultData = reader.readtext(imgData, detail=0)
                    numID = re.sub("\D", "", resultData[-1])
                    numID = int(float(numID))

                    fee = int(float(num))
                    with open('last.log') as f:
                        lastCheck = f.read()
                        if lastCheck != '':
                            lastCheck = int(lastCheck)
                    if lastCheck != numID:
                        f = open("last.log", 'w')
                        f.write(str(numID))
                        f.close()
                        t = threading.Thread(target=callback, args=(fee,lastCheck,))
                        t.start()
                        print(i, fee,numID)
                    i += 1
            cv.imshow('result', img)
        except Exception as e:
            print(e)
        if loopCount >= 60:
            print('loopCount',loopCount)
            loopCount = 0
            t = threading.Thread(target=noteMe)
            t.start()
        else:
            loopCount += 1
        if ord("q") == cv.waitKey(1):
            break


import argparse
import csv

from XL.columns import *
from XL.column_data import *
from XL.parse_files import *

parser = argparse.ArgumentParser(description='process csv and excel files.')
parser.add_argument('-csv', '--csv1', help='CSV file containing data', required=True)
parser.add_argument('--csv2', help='CSV file containing data', required=False)
parser.add_argument('-xl', '--xl1', help='excel file containing data', required=False)
parser.add_argument('--xl2', help='excel file containing data', required=False)

args = vars(parser.parse_args())
print(args)

csv1 = parse_csv(args['csv1'])
if args['csv2'] is not None:
    csv2 = parse_csv(args['csv2'])
if args['xl1'] is not None:
    xl1 = parse_excel(args['xl1'])
if args['xl2'] is not None:
    xl2 = parse_excel(args['xl2'])

def columns():
    cols = get_columns(csv1)

def write_csv():
    data = list(zip(get_columns(csv1), get_first_row_data(csv1)))
    df = pd.DataFrame(data)
    header = ("Columns", "First row vals")
    df.columns = header
    df.to_csv('output.csv', index=False)

write_csv()

def write_csv_np(zip_obj):
    """
    function to write the csv using csv module instead of pandas
    :param zip_obj:
    :return:
    """
    csv_columns = ['A', 'B', 'C']
    with open('output.csv', 'w') as f:
        writer = csv.writer(f)
        writer.writerow(csv_columns)
        writer.writerows(zip_obj)


from datetime import date
print(f'{20*"-"}\n{"VOTAÇÃO":^20}\n{20*"-"}')

def voto(ano):
    print(30*'-')
    idade = date.today().year - ano
    print(f'Com {idade} anos, ', end='')
    if idade >= 70 or 16 <= idade <= 17:
        return opcoes[1]
    elif idade < 16:
        return opcoes[2]
    else:
        return opcoes[0]

opcoes = ('O VOTO É OBRIGATÓRIO!', 'O VOTO É OPCIONAL!', 'O VOTO É NEGADO!')
votacao = voto(int(input('Em que ano você nasceu ? ')))
print(votacao)


from pathlib import Path
import re

space =  '    '
branch = '│   '
tee =    '├── '
last =   '└── '

with open(Path(__file__).parent.parent / '.gitignore', 'r') as f:
	lines = f.read().splitlines()

new_lines = []
for line in lines:
    if len(line) > 0 and line[0] not in ['#']:
        new_line = str(line)

        # if new_line[0] == '\\':
        #     new_line = '/' + new_line[1:]
        # elif new_line[0] != '/':
        #     new_line = '/' + new_line

        new_line = new_line.replace('/','\/').replace('.','\.')

        if new_line[-1] == '*':
            new_lines.append(new_line.replace('*','.*'))
        else:
            new_lines.append(new_line.replace('*','.*?'))

ret = '\/(' + '|'.join(new_lines) + ')'
matcher = re.compile(ret)

class Tree():
    def __init__(self, dir_path: Path, only_dirs: bool=False, ignore_dirs: list=[], level: int=-1):
        self.only_dirs = only_dirs
        self.dir_path = dir_path
        self.ignore_dirs = set(ignore_dirs) | set(['/.git','media/','plots/'])
        self.level = level

        self.files = 0

    def generate(self):
        ret = [self.dir_path.name or '.']
        ret.extend(self.__make__())

        return ret

    def __make__(self, prefix: str=''):
        if not self.level:
            return

        if self.only_dirs:
            contents = []
            for d in self.dir_path.iterdir():
                if d.is_dir() and d.name not in self.ignore_dirs:
                    contents.append(d)
        else:
            contents = []
            for d in self.dir_path.iterdir():
                m = str(d)
                m = '/' + m[0:] if m[0] != '/' else m
                ignore = any([g in m for g in self.ignore_dirs])
                match = matcher.search(m)
                if match is None and not ignore:
                    contents.append(d)

        pointers = [tee] * (len(contents) - 1) + [last]

        for pointer, path in zip(pointers, contents):
            if path.is_dir():
                yield prefix + pointer + path.name

                if pointer == tee:
                    extension = branch
                else:
                    extension = space

                self.dir_path = path
                self.level = self.level-1
                yield from self.__make__(prefix=prefix+extension)
            elif not self.only_dirs:
                yield prefix + pointer + path.name
                self.files += 1

if __name__ == '__main__':
    tree = Tree(Path(__file__).parent.parent)
    pretty = tree.generate()
    print('\n'.join(pretty))


import os
import numpy as np
import matplotlib

import matplotlib.pyplot as plt

from .tools import *

def show(block=True):
    plt.show(block)

def save(fig, legend, fileName, fileFormat='pdf', overwrite=False):
    fullFileName = fileName + '.' + fileFormat if not fileName.endswith(fileFormat) else fileName
    if not overwrite and os.path.exists(fullFileName):
        warn("Output file %s exists already! Not overwriting!" % fullFileName)
        return

    print("Writing plot to " + fullFileName)
    extra = ()
    if legend:
        extra = (legend,)

    fig.savefig(fullFileName, bbox_inches='tight', format=fileFormat)

def plotMultiDelays(x, delays, xLabel, labels=None, title=None, markersize=1.5, fileName=None, overwrite=None, colors=None, block=False, show=False):
    if not colors:
        defaultColors = ['r', 'g', 'b']
        colors = list(reversed(defaultColors[:len(delays)]))

    yLabel = "offset [msec]"

    import matplotlib.gridspec as gridspec

    figsize = (5, 2.5)

    breakX = False

    def plotMyDelays(ax):
        xA = np.array(x, dtype=float)
        xA = xA - min(xA[~np.isnan(xA)])
        if labels:
            for i, (d, l) in enumerate(zip(delays, labels)):
                assert(len(xA) == len(d))
                ax.plot(xA, np.asarray(d) * 1000, linestyle='-', marker='.', markersize=markersize, label=l, color=colors[i])
        else:
            for i, d in enumerate(delays):
                assert(len(xA) == len(d))
                ax.plot(xA, np.asarray(d) * 1000, linestyle='-', marker='.', markersize=markersize, color=colors[i])

    fig, ax = plt.subplots(1, 1, figsize=figsize)
    plotMyDelays(ax)
    ax.set_xlabel(xLabel)
    ax.set_ylabel(yLabel)

    if title:
        ax.set_title(title)

    legend = None
    if labels:
        legend = ax.legend(loc='upper right', shadow=False)

    if fileName:
        save(fig, legend, fileName, overwrite=overwrite)

    if show:
      show(block)
    return fig


import numpy as np
import matplotlib.pyplot as plt
import re
import os
os.makedirs('./plots/', exist_ok=True)

def add_entry(runtime_dict, px, py, size, time):
    if (px, py, size) not in runtime_dict:
        runtime_dict[(px, py, size)] = []
    runtime_dict[(px, py, size)].append(time)

if __name__ == '__main__':
    with open('./times.txt', 'r') as f:
        content = f.readlines()

    runtimes1D = {}
    runtimes2D = {}
    for line in content:
        result = re.search(r"configuration px = (\d*), py = (\d*), size = (\d*), runtime 1D = (\d*.?\d*), runtime 2D = (\d*.?\d*)", line)
        px, py, size, runtime1D, runtime2D = [float(i) for i in result.groups()]

        add_entry(runtimes1D, px, py, size, runtime1D)
        add_entry(runtimes2D, px, py, size, runtime2D)

    boxplot_1d_runtimes = []
    boxplot_2d_runtimes = []
    boxplot_small_1d = []
    boxplot_small_2d = []
    for i, (config, val) in enumerate(runtimes1D.items()):
        boxplot_1d_runtimes.append(val)
        if config[-1] == 4096:
            boxplot_small_1d.append(val)    # for just size 4096

    for i, (config, val) in enumerate(runtimes2D.items()):
        boxplot_2d_runtimes.append(val)
        if config[-1] == 4096:
            boxplot_small_2d.append(val)    # for just size 4096

    # plot of all values
    bp1 = plt.boxplot(boxplot_1d_runtimes, positions=[1,2,1,2], patch_artist=True, boxprops=dict(facecolor="C0"))
    bp2 = plt.boxplot(boxplot_2d_runtimes, positions=[1,2,1,2], patch_artist=True, boxprops=dict(facecolor="C2"))

    plt.xticks(ticks = range(3), labels = ["", (2,2), (2,4)], rotation = 30)  # required to fix label alignment issue
    plt.xlabel("Configurations")
    plt.ylabel("Runtime in seconds")
    plt.legend([bp1["boxes"][0], bp2["boxes"][0]], ['1D', '2D'], bbox_to_anchor = (1,1))
    plt.title("Configuration Vs Runtime")
    plt.tight_layout()

    plt.savefig('./plots/runtimes.png', dpi=300)
    plt.close()

    # plot of just size=4096 values
    bp1 = plt.boxplot(boxplot_small_1d, positions=[1,2], patch_artist=True, boxprops=dict(facecolor="C0"))
    bp2 = plt.boxplot(boxplot_small_2d, positions=[1,2], patch_artist=True, boxprops=dict(facecolor="C2"))

    plt.xticks(ticks = range(3), labels = ["", (2,2), (2,4)], rotation = 30)  # required to fix label alignment issue
    plt.xlabel("Configurations")
    plt.ylabel("Runtime in seconds")
    plt.legend([bp1["boxes"][0], bp2["boxes"][0]], ['1D', '2D'], bbox_to_anchor = (1,1))
    plt.title("Configuration Vs Runtime for data size = 4096")
    plt.tight_layout()

    plt.savefig('./plots/runtimes_size_4096.png', dpi=300)
    plt.close()


#!/usr/bin/env python3
import sys

import pybullet as p
import pybullet_data

model_fn = 'stompy.urdf'
if len(sys.argv) > 1:
    model_fn = sys.argv[1]

c = p.connect(p.GUI)
p.setPhysicsEngineParameter(enableFileCaching=0)
p.setAdditionalSearchPath(pybullet_data.getDataPath()) #used by loadURDF
p.setGravity(0,0,-9.8)
planeId = p.loadURDF("plane.urdf")
if 'sdf' in model_fn:
    rid = p.loadSDF(model_fn)
elif 'urdf' in model_fn:
    cubeStartPos = [0,0,1]
    cubeStartOrientation = p.getQuaternionFromEuler([0,0,0])
    rid = p.loadURDF(model_fn,cubeStartPos, cubeStartOrientation)
p.setRealTimeSimulation(True)
#p.stepSimulation()
nj = p.getNumJoints(rid)
# store joint ids for all leg joints
legs = {}
print("N joints: %s" % (nj, ))
for ji in range(nj):
    print("Joint %i" % (ji, ))
    info = p.getJointInfo(rid, ji)
    name = info[1].decode('ascii')
    ts = name.split('_')
    if ts[2] == 'body':  # hip joint
        ln = ts[4]
        jn = 'hip'
    else:
        ln = ts[2]
        if ts[-1] == 'thigh':
            jn = 'thigh'
        elif ts[-1] == 'upper':
            jn = 'knee'
        elif ts[-1] == 'lower':
            jn = 'calf'
        else:
            jn = None
    print("\t%s" % (info, ))
    if jn is None:
        continue
    if ln not in legs:
        legs[ln] = {}
    legs[ln][jn] = ji
print("")
print("Joint IDs:", legs)

# move hips
i = input("any key to move knees")
jids = [legs[ln]['knee'] for ln in legs]
p.setJointMotorControlArray(
    rid, jids, p.POSITION_CONTROL, targetPositions=[-0.5] * len(jids))
i = input("any key to move knees")
p.setJointMotorControlArray(
    rid, jids, p.POSITION_CONTROL, targetPositions=[-0.0] * len(jids))

i = input("any key to move thighs")
jids = [legs[ln]['thigh'] for ln in legs]
p.setJointMotorControlArray(
    rid, jids, p.POSITION_CONTROL, targetPositions=[0.5] * len(jids))
i = input("any key to move thighs")
p.setJointMotorControlArray(
    rid, jids, p.POSITION_CONTROL, targetPositions=[0.0] * len(jids))

i = input("any key to move hips")
jids = [legs[ln]['hip'] for ln in legs]
p.setJointMotorControlArray(
    rid, jids, p.POSITION_CONTROL, targetPositions=[0.5] * len(jids))
i = input("any key to move hips")
p.setJointMotorControlArray(
    rid, jids, p.POSITION_CONTROL, targetPositions=[0.0] * len(jids))

# move thighs
# move knees

i = input("any key to exit")
# move joints with setJointMotorControl2/Array
#p.setJointMotorControlArray(
#    rid, indices, p.POSITION_CONTROL,
#    targetPositions=[0.1] * 6
p.disconnect()


#import libraries

import lightgbm as lgb
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
import streamlit as st
import pickle
import bz2file as bz2
import altair as alt

from Antuns.prediction_LGBM import Prediction_LGBM
from Antuns.p1_import_csv import upload_csv
from Antuns.p2_plotting_data import curve_plot
from Antuns.page_setting import page_intro

page_intro()
#-----------------------------------------------------------------
#ignore version warnings
import warnings
warnings.filterwarnings("ignore")

#Global variables
THRESHOLD_GLOBAL = 0.75

#All wells to be trained
wells_name = ["01-97-HXS-1X", "15-1-SN-1X", "15-1-SN-2X", "15-1-SN-3XST", "15-1-SN-4X", "15-1-SNN-1P",
              "15-1-SNN-2P", "15-1-SNN-3P", "15-1-SNN-4P", "15-1-SNS-1P", "15-1-SNS-2P", "15-1-SNS-4P"]
#Obtain data and label of wells
name_features = ["GR", "LLD", "LLS", "NPHI", "RHOB", "DTC", "DTS"]
#-----------------------------------------------------------------

# Calculate the confusion matrix of applying model on dataframe (including features and label) df with threshold
def calculate_confusion_matrix (model = None, df= None, threshold=None):
    model_prediction = [model]
    # Apply model on dataframe
    proba = Prediction_LGBM(trained_models=model_prediction, data = df, feature_names=name_features)
    proba_well = proba.loc[:, "model_0"]
    # Apply threshold
    if threshold==None: threshold = 0.5
    # Get label from dataframe df
    well_proba = proba_well.apply(lambda x: 1 if x >= threshold else 0)
    return well_proba

#------------------------------------------------------------------
# Load any compressed pickle file
file = "models/LightGBM_0.45.pbz2"
def decompress_pickle(file):
    data = bz2.BZ2File(file, 'rb')
    data = pickle.load(data)
    return data
# model_best = decompress_pickle(file)

# Loading Modeling
model_best = lgb.Booster(model_file="models/LGBM_20221125.json")

#-------------------------------------------------------------------------------------------------

col_1, col_2, col_3, col_4, col_5, = st.columns(5)
# with col_3:
    # st.image("https://i.ibb.co/Yd42K98/LogoVPI.png", width=250)
    # st.header("Welcome to Fracture Prediction Dashboard!")

#Loading data from browser:----------------------------------------
st.subheader("1. Load CSV input file:")
wells_df_predict = upload_csv()
st.write('---')
if wells_df_predict is not None:
    wells_df_predict = wells_df_predict.replace({-9999: np.nan}).dropna(how='any', subset = ["FRACTURE_ZONE"])

    st.write("Data Input:")
    st.dataframe(wells_df_predict.sort_index(), width=1400, height=300)
    st.write('---')
    st.write("Selected Prediction Model:")
    st.write(model_best)
#------------------------------------------------------------------
    feature_names = [col for col in wells_df_predict.columns if col not in ["WELL", "DEPTH","FRACTURE_ZONE"]]
    # Full data for export data
    st.session_state.pred = st.button("Predict Fracture Zone")
    if st.session_state.pred:
        threshold = 0.23
        #Make label Prediction
        predictions = (model_best.predict(wells_df_predict[feature_names])> threshold).astype(int)
        wells_df_predict['FRACTURE_ZONE_PRED'] = predictions
        st.dataframe(wells_df_predict, width=1400, height=300)
#Plot Data------------------------------------------------------------------
        plotting_curves = [c for c in wells_df_predict.columns.unique() if c not in ["DEPTH", "WELL", "TVD", "FRACTURE_ZONE", "FRACTURE_ZONE_PRED", "DCALI_FINAL", "INCL", "AZIM_TN"]]
        plotting_curves.sort()
        if "FRACTURE_ZONE_PRED" in wells_df_predict.columns.unique():
            plotting_curves.append("FRACTURE_ZONE_PRED")
        for well in wells_df_predict.WELL.unique():
            st.write('---')
            st.write(f"{well} Logs: \n")
            well_plot = wells_df_predict[wells_df_predict.WELL == well]
            charts_dict={}
            for i, c in enumerate(plotting_curves):
                charts_dict[i] = curve_plot(data=well_plot,filted_data=None, x_column=c)
    #Show Curve-----------------------------------------------------------------------
            st.write(alt.concat(*charts_dict.values()).configure(autosize='fit'))
    # Download --------------------------------------------------------------
        st.write('---')
        st.write("Download final result to csv file")

        st.download_button(label='Download All Wells',
                        data = wells_df_predict.to_csv(),
                        file_name='FracturePredictionALL.csv',
                        mime='text/csv')


from flask import Flask, render_template, request
from flask_cors import CORS, cross_origin
import pickle
from sklearn.preprocessing import StandardScaler as scaler

app = Flask(__name__)

@app.route('/',methods=['GET'])
def homepage():
    return render_template("index.html")

@app.route('/predict', methods=['POST','GET'])
@cross_origin()
def index():
    if request.method == 'POST':
        try:
            #reading the inputs given by user
            gre_score = float(request.form['gre_score'])
            toefl_score = float(request.form['toefl_score'])
            university_rating = float(request.form['university_rating'])
            sop = float(request.form['sop'])
            lor = float(request.form['lor'])
            cgpa = float(request.form['cgpa'])
            is_research = request.form['research']
            if(is_research=='yes'):
                research=1
            else:
                research=0
            filename = 'finalized_model_linear_regression_nonscaled.pickle'
            loaded_model = pickle.load(open(filename, 'rb'))#loading the model
            prediction = loaded_model.predict([[gre_score,toefl_score,university_rating,sop,lor,cgpa,research]])
            print(f"prediction is {prediction}")

            return render_template('result.html',prediction=round(100*prediction[0]))
        except Exception as e:
            print("the exception message is ", e)
            return 'something is wrong'
    else:
        return render_template('index.html')

if __name__ == "__main__":
    app.run(debug=True)


#setup
'START BLOCK'
import pygame
import keyboard
import math

from sprites import *
from map import *

pygame.init()

screen = pygame.display.set_mode((1200,600))

running = True

clock = pygame.time.Clock()

font = pygame.font.Font(None,32)
'END BLOCK'

#environment
'START BLOCK'
groundshift = 0

#should only be used for rendering, not collisions or anything else
#IMPORTANT - THIS IS LITERALLY USED TO RENDER EVERYTHING IN THE ENTIRE GAME
camX = 600
#literally used for nothing
camY = 0

time = 0
day = 1
daycolor = (200,200,250)
'END BLOCK'

#players
'START BLOCK'
class player1:
    X = 0
    Y = 455

    direction = 'left'
    move = 'none'

    class sword:
        sprite = sword #not actually used

        sword = 0
        length = 0
        state = 'none'

        rect = sprite.get_rect()

    sprite = p1
    rect = sprite.get_rect()
    rect.topleft = (X,Y)

class player2:
    X = 0
    Y = 455

    direction = 'left'
    move = 'none'

    class sword:
        sprite = sword

        sword = 0
        length = 0
        state = 'none'

        rect = sprite.get_rect()

    sprite = p2
    rect = sprite.get_rect()
    rect.topleft = (X,Y)

screenX = 0

bothmoving = False

speed = 3

health = 100
'END BLOCK'

#enemies
'START BLOCK'
enemies = []

enemytimer = 500
'END BLOCK'

#main loop
while running:

    #quit
    'START BLOCK'
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    'END BLOCK'

    #environment
    'START BLOCK'
    #sky
    screen.fill(daycolor)

    time = time + 0.1

    #sunrise
    if time > 0 and time < 200:
        daycolor = (0+time,0+time,50+time)
    #day
    if time > 200 and time < 1000:
        daycolor = (200,200,250)
    #sunset
    if time > 1000 and time < 1200:
        daycolor = (200-time+1000,200-time+1000,250-time+1000)
    #night
    if time > 1200 and time < 2000:
        daycolor = (0,0,50)
    if time > 2000:
        time = 0
        day = day + 1

    #ground
    for i in range (17):
        if bothmoving:
            groundshift = camX%80
        screen.blit(ground,(-80+i*80+groundshift,camY+500))

    #houses
    for houseX in houseXs:
        screen.blit(house,(camX+houseX,camY+400))
    for doorX in doorXs:
        screen.blit(doorsprite,(camX+doorX,camY+450))

    #grass
    for grass in grassdata:
        if camX+grass['X'] > -100 and camX+grass['X'] < 1300:
            if grass['type'] == 0:
                grasssprite = grass1
            if grass['type'] == 1:
                grasssprite = grass2
            screen.blit(grasssprite,(camX+grass['X'],camY+490))
    'END BLOCK'

    #die
    'START BLOCK'
    if health <= 0:
        running = False
    'END BLOCK'

    #movement
    'START BLOCK'
    #p1
    a = keyboard.is_pressed('a')
    d = keyboard.is_pressed('d')

    #p2
    left = keyboard.is_pressed('left')
    right = keyboard.is_pressed('right')

    #p1
    if a != d:
        if a:
            player1.X = player1.X - speed
            player1.move = 'left'
            player1.direction = 'left'
        if d:
            player1.X = player1.X + speed
            player1.move = 'right'
            player1.direction = 'right'

    else:
        player1.move = 'none'

    #p2
    if left != right:
        if left:
            player2.X = player2.X - speed
            player2.direction = 'left'
            player2.move = 'left'
        if right:
            player2.X = player2.X + speed
            player2.move = 'right'
            player2.direction = 'right'

    else:
        player2.move = 'none'

    #p1
    if camX+player1.X < 50:
        player1.X = 50 - camX
    if camX+player1.X > 1130:
        player1.X = 1130 - camX

    #p2
    if camX+player2.X < 50:
        player2.X = 50 - camX
    if camX+player2.X > 1130:
        player2.X = 1130 - camX

    #rect used for collisions
    player1.rect = player1.sprite.get_rect()
    player1.rect.topleft = (player1.X,player1.Y)

    player2.rect = player2.sprite.get_rect()
    player2.rect.topleft = (player2.X,player2.Y)

    #camera
    if player1.move == player2.move:
        if player1.move == 'left':
            camX = camX + 3
        if player1.move == 'right':
            camX = camX - 3

        if not player1.move == 'none':
            bothmoving = True

    if player1.direction == 'right':
        screen.blit(pygame.transform.scale(player1.sprite,(20,45)),(camX+player1.X,camY+player1.Y))
    if player1.direction == 'left':
        screen.blit(pygame.transform.flip(pygame.transform.scale(player1.sprite,(20,45)),True,False),(camX+player1.X,camY+player1.Y))
    if player2.direction == 'right':
        screen.blit(pygame.transform.scale(player2.sprite,(20,45)),(camX+player2.X,camY+player2.Y))
    if player2.direction == 'left':
        screen.blit(pygame.transform.flip(pygame.transform.scale(player2.sprite,(20,45)),True,False),(camX+player2.X,camY+player2.Y))
    'END BLOCK'

    #sword
    'START BLOCK'
    #p1
    if player1.sword.sword > 0:
        player1.sword.sword = player1.sword.sword - 1

    if player1.sword.sword < 0:
        player1.sword.sword = player1.sword.sword + 1
        if player1.sword.sword == 0:
            player1.sword.sword = 30

    if keyboard.is_pressed('w'):
        if player1.sword.sword == 0:
            player1.sword.sword = -30
            player1.sword.length = 0
            player1.sword.state = 'out'

    if player1.sword.sword < 0:
        if player1.sword.state == 'out':
            player1.sword.length = player1.sword.length + 1
            if player1.sword.length == 15:
                player1.sword.state = 'in'

        if player1.sword.state == 'in':
            player1.sword.length = player1.sword.length - 1

        if player1.direction == 'left':
            screen.blit(sword,(camX+player1.X-20-player1.sword.length,camY+player1.Y+10))
            player1.sword.rect.topleft = (player1.X-20-player1.sword.length,player1.Y+10)
        if player1.direction == 'right':
            screen.blit(pygame.transform.flip(sword,True,False),(camX+player1.X+10+player1.sword.length,camY+player1.Y+10))
            player1.sword.rect.topleft = (player1.X+10+player1.sword.length,player1.Y+10)

    #p2
    if player2.sword.sword > 0:
        player2.sword.sword = player2.sword.sword - 1

    if player2.sword.sword < 0:
        player2.sword.sword = player2.sword.sword + 1
        if player2.sword.sword == 0:
            player2.sword.sword = 30

    if keyboard.is_pressed('up'):
        if player2.sword.sword == 0:
            player2.sword.sword = -30
            player2.sword.length = 0
            player2.sword.state = 'out'

    if player2.sword.sword < 0:
        if player2.sword.state == 'out':
            player2.sword.length = player2.sword.length + 1
            if player2.sword.length == 15:
                player2.sword.state = 'in'

        if player2.sword.state == 'in':
            player2.sword.length = player2.sword.length - 1

        if player2.direction == 'left':
            screen.blit(sword,(camX+player2.X-20-player2.sword.length,camY+player2.Y+10))
            player2.sword.rect.topleft = (player2.X-20-player2.sword.length,camY+player2.Y+10)
        if player2.direction == 'right':
            screen.blit(pygame.transform.flip(sword,True,False),(camX+player2.X+10+player2.sword.length,camY+player2.Y+10))
            player2.sword.rect.topleft = (player2.X+10+player2.sword.length,camY+player2.Y+10)
    'END BLOCK'

    #enemy spawning
    'START BLOCK'
    enemytimer = enemytimer - 1

    #spawn enemies
    if enemytimer < 1:
        if random.randint(0,1) == 1:
            enemyX = -100
        else:
            enemyX = 1300

        enemies.append({'type':'normal',
                        'X':enemyX-camX,'Y':460+camY,'direction':'left','knockback':0,
                        'target':'none','targettimer':0,
                        'health':2,'hurttimer':0,
                        'attacktimer':0,'damage':1})

        enemytimer = random.randint(200,350)

    #clear dead enemies
    for enemy in enemies:
        if enemy['health'] < 1:
            enemies.remove(enemy)
    'END BLOCK'

    #enemy AI
    'START BLOCK'
    for enemy in enemies:

        if enemy['type'] == 'normal':
            enemyrect = zombie1.get_rect()
            enemyrect.topleft = (enemy['X'],enemy['Y'])

            #whether or not the zombie can take damage
            if enemy['hurttimer'] > 0:
                enemy['hurttimer'] = enemy['hurttimer'] - 1

            #targeting
            if enemy['targettimer'] > 0:
                enemy['targettimer'] = enemy['targettimer'] - 1

            if enemy['targettimer'] == 0:
                if math.dist(enemyrect.center,player1.rect.center) > math.dist(enemyrect.center,player2.rect.center):
                    enemy['target'] = '2'
                    enemy['targettimer'] = 120
                if math.dist(enemyrect.center,player2.rect.center) > math.dist(enemyrect.center,player1.rect.center):
                    enemy['target'] = '1'
                    enemy['targettimer'] = 120

            #chase
            if enemy['target'] == '1' and not abs(enemyrect.centerx-player1.rect.centerx) < 1:
                if enemyrect.centerx > player1.rect.centerx:
                    enemy['X'] = enemy['X'] - 1
                    enemy['direction'] = 'left'
                if enemyrect.centerx < player1.rect.centerx:
                    enemy['X'] = enemy['X'] + 1
                    enemy['direction'] = 'right'

            if enemy['target'] == '2' and not abs(enemyrect.centerx-player2.rect.centerx) < 15:
                if enemyrect.centerx > player2.rect.centerx:
                    enemy['X'] = enemy['X'] - 1
                    enemy['direction'] = 'left'
                if enemyrect.centerx < player2.rect.centerx:
                    enemy['X'] = enemy['X'] + 1
                    enemy['direction'] = 'right'

            #when hit
            if (enemyrect.colliderect(player1.sword.rect) and player1.sword.sword < 0) or (enemyrect.colliderect(player2.sword.rect) and player2.sword.sword < 0):
                if enemy['hurttimer'] == 0:
                    enemy['health'] = enemy['health'] - 1
                    enemy['knockback'] = 7
                    enemy['hurttimer'] = 40

            #takes knockback
            if enemy['knockback'] > 0:
                if enemy['direction'] == 'left':
                    enemy['X'] = enemy['X'] + enemy['knockback']
                if enemy['direction'] == 'right':
                    enemy['X'] = enemy['X'] - enemy['knockback']

                enemy['knockback'] = enemy['knockback'] - 1

            #attack
            if enemy['target'] == '1':
                if abs(enemyrect.centerx-player1.rect.centerx) < 30:
                    if enemy['attacktimer'] == 0:
                        enemy['attacktimer'] = 40
                    else:
                        enemy['attacktimer'] = enemy['attacktimer'] - 1
                        if enemy['attacktimer'] == 0:
                            health = health - enemy['damage']

            if enemy['target'] == '2':
                if abs(enemyrect.centerx-player2.rect.centerx) < 30:
                    if enemy['attacktimer'] == 0:
                        enemy['attacktimer'] = 40
                    else:
                        enemy['attacktimer'] = enemy['attacktimer'] - 1
                        if enemy['attacktimer'] == 0:
                            health = health - enemy['damage']

            #draws the sprite
            if enemy['direction'] == 'left':
                screen.blit(pygame.transform.flip(zombie1,True,False),(camX+enemy['X'],camY+enemy['Y']))
            if enemy['direction'] == 'right':
                screen.blit(zombie1,(camX+enemy['X'],camY+enemy['Y']))
    'END BLOCK'

    #displays
    'START BLOCK'
    healthdisplay = font.render(str(health),True,(0,0,0))
    screen.blit(heart,(30,30))
    screen.blit(healthdisplay,(60,30))
    'END BLOCK'

    #necessary stuff
    'START BLOCK'
    pygame.display.update()
    clock.tick(60)
    'END BLOCK'

#quit
pygame.quit()


from datetime import datetime

from content.surfline.Spots import Spot
from .Report import Report

def get_sunlights(request, spots):
    report_type = request.get('queryResult').get('parameters').get("type")
    date = request.get('queryResult').get('parameters').get("date-time")
    city = request.get('queryResult').get('parameters').get("geo-city")
    substate = request.get('queryResult').get('parameters').get("geo-sub-state")
    state = request.get('queryResult').get('parameters').get("geo-state")
    country = request.get('queryResult').get('parameters').get("geo-country")

    spot = Spot(place=city, subregion=substate, region=state, country=country)
    value = spots.check_place(spot)
    print(report_type, date, city, substate, state, country)

    if value:
        messages = []
        text = "so, i m getting the sunlights for today"
        messages.append({"text": {"text": [text]}})
        sunlights = Report(spot, spots).get_sunLights()
        print(sunlights)

        now = datetime.now()

        if sunlights["dawn"] > now:
            print(sunlights["dawn"])
            text = "the first light today will be at {}".format(sunlights["dawn"])
            messages.append({"text": {"text": [text]}})
        if sunlights["sunrise"] > now:
            print(sunlights["sunrise"])
            text = "the sunrise will be at ".format(sunlights["sunrise"])
            messages.append({"text": {"text": [text]}})
        if sunlights["sunset"] > now:
            print(sunlights["sunset"])
            text = "the sunset will be at {}".format(sunlights["sunset"])
            messages.append({"text": {"text": [text]}})
        if sunlights["dusk"] > now:
            print(sunlights["dusk"])
            text = "the last light of sun today will be at {}".format(sunlights["dusk"])
            messages.append({"text": {"text": [text]}})

        if len(messages) == 1:
            text = "it is already night, come back tomorrow"
            messages = [{"text": {"text": [text]}}]

        return {
            "fulfillmentText": text,
            "fulfillmentMessages": messages
        }

    text = "i didn't find your spot.. can you be more precise or look at the list"
    return {
        "fulfillmentText": text,
    }


# ID 1 -> 海防艦 -> Coastal Defence Ship (?)
# ID 2 -> 駆逐艦 -> Destroyer
# ID 3 -> 軽巡洋艦 -> Light Cruiser
# ID 4 -> 重雷装巡洋艦 -> Torpedo Cruiser
# ID 5 -> 重巡洋艦 -> Heavy Cruiser
# ID 6 -> 航空巡洋艦 -> Aviation Cruiser
# ID 7 -> 軽空母 -> Light Aircraft Carrier
# ID 8 -> 戦艦 -> Battleship
# ID 9 -> Also battleship
# ID 10 -> 航空戦艦 -> Aviation battleship
# ID 11 -> 正規空母 -> Aircraft carrier
# ID 12 -> 超弩級戦艦 -> Super Dreadnought
# ID 13 -> 潜水艦 -> Submarine
# ID 14 -> 潜水空母 -> Submarine Aircraft Carrier
# ID 15 -> 補給艦 -> Supply Vessel/Replenishment Oiler?
# ID 16 -> 水上機母艦 -> Seaplane Carrier
# ID 17 -> 揚陸艦 -> amphibious assault ship
# ID 18 -> 装甲空母 -> Armored aircraft carrier
# ID 19 -> 工作艦 -> Repair Ship
# ID 20 -> 潜水母艦 -> Submarine Tender
# ID 21 -> 練習巡洋艦 -> Practice Cruiser
# from db import db,Dock
import random

from flask import abort
from flask import g
from sqlalchemy import text

from db import Kanmusu, db
from . import MemberHelper

def calculate_repair_time(kanmusu: Kanmusu):
    # {Total repair time} = {HP loss} * {base repair time} * {ship type} + {30 seconds}
    # Our modified formula: Total = HP Loss * ((Build Time**0.6) + Level)
    return (kanmusu.ship.max_stats.hp - kanmusu.current_hp) * ((kanmusu.ship.buildtime**0.6) + kanmusu.level)

def get_ship_from_recipe(fuel: int=30, ammo: int=30, steel: int=30, baux: int=30) -> int:

    ship_t = text("""select ship_id, chance from recipe
      join recipe__resources min on recipe.min_resources_id = min.id
      join recipe__resources max on recipe.max_resources_id = max.id
      where
      :fuel between min.fuel and max.fuel and
      :ammo between min.ammo and max.ammo and
      :steel between min.steel and max.steel and
      :baux between min.baux and max.baux;
    """)

    ships = db.session.execute(ship_t, {"fuel": fuel, "ammo": ammo, "steel": steel, "baux": baux})

    if not ships:
        return None

    ship_choices = [[x[0]] * x[1] for x in ships]
    ship_choices = [item for sublist in ship_choices for item in sublist]
    return random.choice(ship_choices)

def get_and_remove_ship_kdock(dockid: int):
    admiral = g.admiral
    try:
        dock = admiral.docks_craft[dockid]
    except IndexError:
        abort(404)
        return None

    if dock.kanmusu is None:
        # ....
        abort(400)
        return

    dock.kanmusu.active = True

    api_data = {
        "api_ship_id": dock.kanmusu.ship.api_id,
        "api_kdock": MemberHelper.dock_data([dock], False),
        "api_id": dock.kanmusu.number,
        "api_slotitem": [], # TODO: Equipment!
        "api_ship": MemberHelper.kanmusu(kanmusu=dock.kanmusu)
    }
    # Update dock data.
    db.session.add(dock.kanmusu)
    dock.update(None)
    db.session.add(dock)
    db.session.commit()
    return api_data

def craft_ship(fuel: int, ammo: int, steel: int, baux: int, dockid: int):
    admiral = g.admiral
    ship = get_ship_from_recipe(fuel, ammo, steel, baux)
    if ship:
        nship = Kanmusu(ship)
        nship.active = False
        nship.number = len(g.admiral.kanmusu)
    else:
        print("Something bad happened. Where are your recipes?")
        abort(404)
        return

    # Change dock data.
    try:
        dock = admiral.docks_craft[dockid]
    except IndexError:
        abort(404)
        return

    if dock.kanmusu is not None:
        # wat
        abort(400)
        return

    dock = dock.update(nship, fuel, ammo, steel, baux, True)

    admiral.resources.sub(fuel, ammo, steel, baux)

    db.session.add(dock)
    admiral.add_kanmusu(nship)
    db.session.add(admiral)
    api_data = {
        "api_ship_id": nship.ship.api_id,
        "api_kdock": MemberHelper.dock_data([dock], False),
        "api_id": nship.number,
        "api_slotitem": [],
        "api_ship": MemberHelper.kanmusu(kanmusu=dock.kanmusu)
    }
    db.session.commit()
    return api_data


# -*- coding: utf-8 -*-
"""
@Time ： 2023/3/5 16:41
@Auth ： Yin yanquan
@File ：criterion.py
@IDE ：PyCharm
@Motto：ABC(Always Be Coding)
"""

import numpy as np
import cv2
from PIL import Image
from PIL import ImageChops

def cal_IOU(image1, image2):
    """
    计算重叠度
    :param image1: 图片1
    :param image2: 图片2
    :return: None（TP）
    """
    gt_mask = cv2.imread(image1, cv2.IMREAD_GRAYSCALE)
    out_mask = cv2.imread(image2, cv2.IMREAD_GRAYSCALE)
    size = gt_mask.shape
    w = size[1]  # 宽度
    h = size[0]  # 高度
    IOU_mask = np.zeros((h, w), dtype=int)
    # print(size,w,h)
    for i in range(h):
        for j in range(w):
            if int(gt_mask[i][j]) > 240 and int(out_mask[i][j]) > 240:
                IOU_mask[i][j] = 255
    cv2.imwrite('./IOU.jpg', IOU_mask)
    return IOU_mask

def compare_images(image1, image2, save_path):
    """
    比较图片，如果有不同则生成展示不同的图片
    :param image1: 第一张图片的路径
    :param image2: 第二张图片的路径
    :param save_path: 不同图的保存路径
    :return: None （FP+FN）
    """
    image_one = Image.open(image1)
    image_two = Image.open(image2)
    try:
        diff = ImageChops.difference(image_one, image_two)

        if diff.getbbox() is None:
            print("No difference between the two pictures")
        else:
            diff.save(save_path)
    except ValueError as e:
        text = ("表示图片大小和box对应的宽度不一致，参考API说明：Pastes another image into this image."
                "The box argument is either a 2-tuple giving the upper left corner, a 4-tuple defining the left, upper, "
                "right, and lower pixel coordinate, or None (same as (0, 0)). If a 4-tuple is given, the size of the pasted "
                "image must match the size of the region.使用2纬的box避免上述问题")
        print("【{0}】{1}".format(e, text))

def cal_criterion(ground_truth_mask, output_mask):
    """
    计算对抗样本输入模型后的mask与ground truth的比值
    :param ground_truth_mask: 原图片对应的gt_mask
    :param output_mask: 对抗样本输入模型后的mask与gt_mask的差值
    :return: 两者的比率， output_mask的非黑像素数量，gt_mask的非黑像素数量，攻击是否成功
    """

    gt_mask = cv2.imread(ground_truth_mask, cv2.IMREAD_GRAYSCALE)
    gt_pixels = cv2.countNonZero(gt_mask)

    out_mask = cv2.imread(output_mask, cv2.IMREAD_GRAYSCALE)
    out_pixels = cv2.countNonZero(out_mask)

    attack_rate = out_pixels / gt_pixels

    return attack_rate, out_pixels, gt_pixels

def precision(public_mask, output_mask):
    """
    计算准确率
    :param public_mask: 图片公共部分
    :param output_mask: 模型输出图片
    :return: 准确率
    """
    # p_mask = cv2.imread(public_mask, cv2.IMREAD_GRAYSCALE)
    # p_pixels = cv2.countNonZero(p_mask)
    p_pixels = cv2.countNonZero(public_mask)

    out_mask = cv2.imread(output_mask, cv2.IMREAD_GRAYSCALE)
    out_pixels = cv2.countNonZero(out_mask)

    pre_rate = p_pixels / out_pixels
    return pre_rate

def recall(public_mask, ground_truth_mask):
    """
    计算召回率
    :param public_mask: 图片公共部分
    :param ground_truth_mask: 原图片对应的gt_mask
    :return: 召回率
    """
    # p_mask = cv2.imread(public_mask, cv2.IMREAD_GRAYSCALE)
    # p_pixels = cv2.countNonZero(p_mask)
    p_pixels = cv2.countNonZero(public_mask)

    gt_mask = cv2.imread(ground_truth_mask, cv2.IMREAD_GRAYSCALE)
    gt_pixels = cv2.countNonZero(gt_mask)

    re_rate = p_pixels / gt_pixels
    return re_rate

def f_score(precision_rate, recall_rate, beta=2):
    """
    计算F分数
    :param precision_rate: 准确率
    :param recall_rate: 召回率
    :param beta: 计算权重
    :return: F分数
    """
    numerator = precision_rate * recall_rate
    denominator = ((beta ** 2) * precision_rate) + recall_rate
    ratio = 1 + (beta ** 2)
    if denominator < 0.001:
        score = 0
    else:
        score = ratio * numerator / denominator
    return score

def usage(ground_truth_mask, output_mask, beta=2):
    """
    具体图片计算方法
    :param ground_truth_mask: 原图片对应的gt_mask
    :param output_mask: 模型输出图片
    :param beta: 计算权重
    :return: F分数，准确率，召回率
    """
    public_mask = cal_IOU(ground_truth_mask, output_mask)
    pre_rate = precision(public_mask, output_mask)
    re_rate = recall(public_mask, ground_truth_mask)
    # print(pre_rate, re_rate)
    F_score = f_score(pre_rate, re_rate, beta=beta)
    # print(F_score)
    return F_score, pre_rate, re_rate

if __name__ == '__main__':
    img1 = '../example_gt.png'
    img2 = '../output/fgsm/3_fgsm_output_eps_0.1.jpg'
    # cal_IOU(img1, img2)
    # pre_rate = precision(img3, img2)
    # re_rate = recall(img3, img1)
    # print(pre_rate, re_rate)
    # F_score = f_score(pre_rate, re_rate)
    # print(F_score)
    F_score, _, _ = usage(img1, img2, beta=2)
    print(F_score)


import matplotlib.pyplot as plt
import numpy as np

def test_classification(model, test_data, test_target, index):
    img = test_data[index].reshape(8,8)
    pred = model.predict_proba(test_data[index:index+1]).squeeze()
    fig, (ax1, ax2) = plt.subplots(figsize=(6,9), ncols=2)

    ax1.imshow(img, cmap='gray')
    ax1.set_title('Actual: ' + str(test_target[index]))
    ax1.axis('off')

    ax2.barh(np.arange(10), pred)
    ax2.set_aspect(0.1)
    ax2.set_yticks(np.arange(10))
    ax2.set_yticklabels(np.arange(10))
    ax2.set_title('Model Prediction')
    ax2.set_xlim(0, 1.1)
    ax2.invert_yaxis()

    plt.tight_layout()