import json
import logging
import math
import pathlib
from typing import Dict, Union

from control import data
from dataclass_utils import asdict
from helpermodules.pub import Pub
from helpermodules import timecheck

# alte Daten: Startzeitpunkt der Ladung, Endzeitpunkt, Geladene Reichweite, Energie, Leistung, Ladedauer, LP-Nummer,
# Lademodus, RFID-Tag
# json-Objekt: {"chargepoint": {"id": 1, "name": "Hof", "rfid": 1234},
# "vehicle": { "id": 1, "name":"Model 3", "chargemode": "pv_charging", "prio": True },
# "time": { "begin":"27.05.2021 07:43", "end": "27.05.2021 07:50", "time_charged": "1:34",
# "data": {"range_charged": 34, "imported_since_mode_switch": 3400, "imported_since_plugged": 5000,
#          "power": 110000, "costs": 3,42} }}

log = logging.getLogger(__name__)

def collect_data(chargepoint):
    """
    Parameter
    ---------
    chargepoint: class
        Ladepunkt, dessen Logdaten gesammelt werden
    """
    try:
        log_data = chargepoint.data.set.log
        charging_ev = chargepoint.data.set.charging_ev_data
        if chargepoint.data.get.plug_state:
            # Zählerstand beim Einschalten merken
            if log_data.imported_at_plugtime == 0:
                log_data.imported_at_plugtime = chargepoint.data.get.imported
                log.debug(f"imported_at_plugtime {chargepoint.data.get.imported}")
            # Bisher geladene Energie ermitteln
            log_data.imported_since_plugged = chargepoint.data.get.imported - log_data.imported_at_plugtime
            if log_data.imported_at_mode_switch == 0:
                log_data.imported_at_mode_switch = chargepoint.data.get.imported
                log.debug(f"imported_at_mode_switch {chargepoint.data.get.imported}")
            # Bei einem Wechsel das Lademodus wird ein neuer Eintrag erstellt.
            if chargepoint.data.get.charge_state:
                if log_data.timestamp_start_charging is None:
                    log_data.timestamp_start_charging = timecheck.create_timestamp()
                    if charging_ev.data.control_parameter.submode == "time_charging":
                        log_data.chargemode_log_entry = "time_charging"
                    else:
                        log_data.chargemode_log_entry = charging_ev.data.control_parameter.chargemode.value
                log_data.imported_since_mode_switch = chargepoint.data.get.imported - log_data.imported_at_mode_switch
                log.debug(f"imported_since_mode_switch {log_data.imported_since_mode_switch} "
                          f"counter {chargepoint.data.get.imported}")
                log_data.range_charged = log_data.imported_since_mode_switch / \
                    charging_ev.ev_template.data.average_consump * 100
                log_data.time_charged, _ = timecheck.get_difference_to_now(log_data.timestamp_start_charging)
            Pub().pub(f"openWB/set/chargepoint/{chargepoint.num}/set/log", asdict(log_data))
    except Exception:
        log.exception("Fehler im Ladelog-Modul")

def save_data(chargepoint, charging_ev, immediately: bool = True, reset: bool = False):
    """ json-Objekt für den Log-Eintrag erstellen, an die Datei anhängen und die Daten, die sich auf den Ladevorgang
    beziehen, löschen.

    Parameter
    ---------
    chargepoint: class
        Ladepunkt
    charging_ev: class
        EV, das an diesem Ladepunkt lädt. (Wird extra übergeben, da es u.U. noch nicht zugewiesen ist und nur die
        Nummer aus dem Broker in der LP-Klasse hinterlegt ist.)
    reset: bool
        Wenn die Daten komplett zurückgesetzt werden, wird nicht der Zwischenzählerstand für
        imported_at_mode_switch notiert. Sonst schon, damit zwischen save_data und dem nächsten collect_data keine
        Daten verloren gehen.
    """
    try:
        log_data = chargepoint.data.set.log
        # Es wurde noch nie ein Auto zugeordnet
        if charging_ev == -1:
            return
        if log_data.timestamp_start_charging is None:
            # Die Daten wurden schon erfasst.
            return
        if not immediately:
            if chargepoint.data.get.power != 0:
                return
        # Daten vor dem Speichern nochmal aktualisieren, auch wenn nicht mehr geladen wird.
        log_data.imported_since_plugged = chargepoint.data.get.imported - log_data.imported_at_plugtime
        log_data.imported_since_mode_switch = chargepoint.data.get.imported - log_data.imported_at_mode_switch
        log_data.range_charged = log_data.imported_since_mode_switch / charging_ev.ev_template.data.average_consump*100
        log_data.time_charged, duration = timecheck.get_difference_to_now(log_data.timestamp_start_charging)
        power = 0
        if duration > 0:
            power = log_data.imported_since_mode_switch / duration
        costs = data.data.general_data.data.price_kwh * log_data.imported_since_mode_switch / 1000
        new_entry = {
            "chargepoint":
            {
                "id": chargepoint.num,
                "name": chargepoint.data.config.name,
            },
            "vehicle":
            {
                "id": charging_ev.num,
                "name": charging_ev.data.name,
                "chargemode": log_data.chargemode_log_entry,
                "prio": charging_ev.data.control_parameter.prio,
                "rfid": chargepoint.data.set.rfid
            },
            "time":
            {
                "begin": log_data.timestamp_start_charging,
                "end": timecheck.create_timestamp(),
                "time_charged": log_data.time_charged
            },
            "data":
            {
                "range_charged": truncate(log_data.range_charged, 2),
                "imported_since_mode_switch": truncate(log_data.imported_since_mode_switch, 2),
                "imported_since_plugged": truncate(log_data.imported_since_plugged, 2),
                "power": truncate(power, 2),
                "costs": truncate(costs, 2)
            }
        }

        # json-Objekt in Datei einfügen
        (pathlib.Path(__file__).resolve(
        ).parents[2] / "data"/"charge_log").mkdir(mode=0o755, parents=True, exist_ok=True)
        filepath = str(
            pathlib.Path(__file__).resolve().parents[2] / "data" / "charge_log" /
            (timecheck.create_timestamp_YYYYMM() + ".json"))
        try:
            with open(filepath, "r", encoding="utf-8") as json_file:
                content = json.load(json_file)
        except FileNotFoundError:
            # with open(filepath, "w", encoding="utf-8") as jsonFile:
            #     json.dump([], jsonFile)
            # with open(filepath, "r", encoding="utf-8") as jsonFile:
            #     content = json.load(jsonFile)
            content = []
        content.append(new_entry)
        with open(filepath, "w", encoding="utf-8") as json_file:
            json.dump(content, json_file)
        log.debug(f"Neuer Ladelog-Eintrag: {new_entry}")

        _reset_data_regarding_chargemode(chargepoint, reset)
        Pub().pub(f"openWB/set/chargepoint/{chargepoint.num}/set/log", asdict(log_data))
    except Exception:
        log.exception("Fehler im Ladelog-Modul")

def get_log_data(request: Dict):
    """ json-Objekt mit gefilterten Logdaten erstellen

    Parameter
    ---------
    request: dict
        Infos zum Request: Monat, Jahr, Filter
    """
    log_data = {"entries": [], "totals": {}}
    try:
        # Datei einlesen
        filepath = str(
            pathlib.Path(__file__).resolve().parents[2] / "data" / "charge_log" /
            (str(request["year"]) + str(request["month"]) + ".json"))
        try:
            with open(filepath, "r", encoding="utf-8") as json_file:
                charge_log = json.load(json_file)
        except FileNotFoundError:
            log.debug("Kein Ladelog für %s gefunden!" % (str(request)))
            return log_data
        # Liste mit gefilterten Einträgen erstellen
        for entry in charge_log:
            if len(entry) > 0:
                if (
                    "id" in request["filter"]["chargepoint"] and
                    len(request["filter"]["chargepoint"]["id"]) > 0 and
                    entry["chargepoint"]["id"] not in request["filter"]["chargepoint"]["id"]
                ):
                    log.debug(
                        "Verwerfe Eintrag wegen Ladepunkt ID: %s != %s" %
                        (str(entry["chargepoint"]["id"]), str(request["filter"]["chargepoint"]["id"]))
                    )
                    continue
                if (
                    "id" in request["filter"]["vehicle"] and
                    len(request["filter"]["vehicle"]["id"]) > 0 and
                    entry["vehicle"]["id"] not in request["filter"]["vehicle"]["id"]
                ):
                    log.debug(
                        "Verwerfe Eintrag wegen Fahrzeug ID: %s != %s" %
                        (str(entry["vehicle"]["id"]), str(request["filter"]["vehicle"]["id"]))
                    )
                    continue
                if (
                    "rfid" in request["filter"]["vehicle"] and
                    len(request["filter"]["vehicle"]["rfid"]) > 0 and
                    entry["vehicle"]["rfid"] not in request["filter"]["vehicle"]["rfid"]
                ):
                    log.debug(
                        "Verwerfe Eintrag wegen RFID Tag: %s != %s" %
                        (str(entry["vehicle"]["rfid"]), str(request["filter"]["vehicle"]["rfid"]))
                    )
                    continue
                if (
                    "chargemode" in request["filter"]["vehicle"] and
                    len(request["filter"]["vehicle"]["chargemode"]) > 0 and
                    entry["vehicle"]["chargemode"] not in request["filter"]["vehicle"]["chargemode"]
                ):
                    log.debug(
                        "Verwerfe Eintrag wegen Lademodus: %s != %s" %
                        (str(entry["vehicle"]["chargemode"]), str(request["filter"]["vehicle"]["chargemode"]))
                    )
                    continue
                if (
                    "prio" in request["filter"]["vehicle"] and
                    request["filter"]["vehicle"]["prio"] is not entry["vehicle"]["prio"]
                ):
                    log.debug(
                        "Verwerfe Eintrag wegen Priorität: %s != %s" %
                        (str(entry["vehicle"]["prio"]), str(request["filter"]["vehicle"]["prio"]))
                    )
                    continue

                # wenn wir hier ankommen, passt der Eintrag zum Filter
                log_data["entries"].append(entry)

        if len(log_data["entries"]) > 0:
            # Summen bilden
            duration = "00:00"
            range_charged = 0
            mode = 0
            power = 0
            costs = 0
            for entry in log_data["entries"]:
                duration = timecheck.duration_sum(
                    duration, entry["time"]["time_charged"])
                range_charged += entry["data"]["range_charged"]
                mode += entry["data"]["imported_since_mode_switch"]
                power += entry["data"]["power"]
                costs += entry["data"]["costs"]
            power = power / len(log_data["entries"])
            log_data["totals"] = {
                "time_charged": duration,
                "range_charged": range_charged,
                "imported_since_mode_switch": mode,
                "power": power,
                "costs": costs,
            }
    except Exception:
        log.exception("Fehler im Ladelog-Modul")
    return log_data

def reset_data(chargepoint, charging_ev, immediately: bool = True):
    """nach dem Abstecken Log-Eintrag erstellen und alle Log-Daten zurücksetzen.

    Parameter
    ---------
    chargepoint: class
        Ladepunkt
    charging_ev: class
        EV, das an diesem Ladepunkt lädt. (Wird extra übergeben, da es u.U. noch nicht zugewiesen ist und nur die
        Nummer aus dem Broker in der LP-Klasse hinterlegt ist.)
    immediately: bool
        Soll sofort ein Eintrag erstellt werden oder gewartet werden, bis die Ladung beendet ist.
    """
    try:
        log_data = chargepoint.data.set.log
        if charging_ev == -1:
            # Es wurde noch nie ein Auto zugeordnet.
            return
        if not immediately:
            if chargepoint.data.get.power != 0:
                return
        save_data(chargepoint, charging_ev, immediately, reset=True)

        log_data.imported_at_plugtime = 0
        log_data.imported_since_plugged = 0
        _reset_data_regarding_chargemode(chargepoint, True)
        Pub().pub(f"openWB/set/chargepoint/{chargepoint.num}/set/log", asdict(log_data))
    except Exception:
        log.exception("Fehler im Ladelog-Modul")

def _reset_data_regarding_chargemode(chargepoint, reset: bool = False) -> None:
    log_data = chargepoint.data.set.log
    log_data.timestamp_start_charging = None
    if reset:
        log_data.imported_at_mode_switch = 0
    else:
        log_data.imported_at_mode_switch = chargepoint.data.get.imported
    log_data.chargemode_log_entry = "_"
    log_data.imported_since_mode_switch = 0
    log_data.range_charged = 0
    log_data.time_charged = "00:00"

def truncate(number: Union[int, float], decimals: int = 0):
    """
    Returns a value truncated to a specific number of decimal places.
    """
    try:
        if not isinstance(decimals, int):
            raise TypeError("decimal places must be an integer.")
        elif decimals < 0:
            raise ValueError("decimal places has to be 0 or more.")
        elif decimals == 0:
            return math.trunc(number)

        factor = 10.0 ** decimals
        return math.trunc(number * factor) / factor
    except Exception:
        log.exception("Fehler im Ladelog-Modul")


#!/usr/bin/env python3
import random
from re import sub,search,match
from sys import argv,exit,stderr
from math import floor,log10,ceil,floor,inf
from multiprocessing import Pool,cpu_count
from time import sleep,time
from pylib.du import ptb
from pylib.du import dd
from pprint import pprint
from operator import methodcaller
from types import FunctionType
from copy import deepcopy
from pylib.electronic.resistor_utils import resistor_string_to_float,flatten_thing,is_iterable

used_list=[]

class SingleIndex(int):
    def make_double(self,i):
        return DoubleIndex(self,i)

class DoubleIndex(tuple):

    def __new__(cls, *z, **zz):
        return tuple.__new__(cls,z,**zz)

    def __getnewargs__(self):
        return self

    def __lt__(self,i):
        lt=True
        for s in self:
            if not s < i:
                lt=False
        return lt

    def __ge__(self,i):
        ge=True
        for s in self:
            if not s >= i:
                ge=False
        return ge

class Values(list):
    """
    allow getting values by double index
    """
    def __getitem__(self,*z,**zz):
        if type(z[0])is DoubleIndex:
            l=[]
            for i in z[0]:
                if type(i) is tuple:
                    print("thing: \"{}\" type: {}".format(z[0],type(z[0])))
                    raise Exception("ERROR: wrong type, got tuple want int")
                l.append(super().__getitem__(i,**zz))
            return l
        else:
            return super().__getitem__(*z,**zz)

def test_0():
    """
    Test Values and DoubleIndex
    """
    values=gen_values()
    v=Values(values)
    il=[DoubleIndex(4,5),6]
    for i in il:
        print(v[i])
    il=[4,5,6]
    for i in il:
        print(v[i])

def test_1():
    """
    test single index \"make_double\" function
    """
    i=SingleIndex(5)
    d=i.make_double(3)
    values=gen_values()
    v=Values(values)
    print("single index:",i)
    print("double index:",d)
    dd(v[i])
    dd(v[d])
    dd(v[d[0]])
    dd(v[d[1]])

def testing():
    #import types
    #print(dir(types))
    test_1()
    pass

def init_random():
    pass
    with open("/dev/urandom",'rb') as f:
        if args.verbose:
            print("# {} adding randomness ".format(time()))
        data=f.read(64)
    random.seed(data)

def get_base_values(norm='EIA E12'):
    """
    10% Standard Values (EIA E12)
    Decade multiples are available from 10 Ω through 1 MΩ
    """
    supported_norms=['EIA E12']
    if norm.lower() == supported_norms[0].lower():
        return [ 10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82 ]
    else:
        raise Exception("ERROR: Norm \""+norm+"\" not supported.\nsupported norms: "+str(supported_norms))

def gen_values():
    exp=[-2,-1,0,1,2,3,4,5]
    values=[]
    for e in exp:
        for i in get_base_values():
            values.append(i*10**e)
    return values

def print_values(values,start='[',sep=', ',end=']\n',format=False):
    lv=len(values)
    rs=start+end
    for i in range(lv):
        v=values[i]
        s0="{:.3f}".format(v)
        s=s0
        s=sub("([.][0-9]*[1-9]+)[0]*$",'\\1',s)
        s=sub("[.][0]*$",'',s)
        s=sub("000000$",'M',s)
        s=sub("000$",'K',s)
        s=sub('([1-9])([1-9])[0][0]$','\\1.\\2K',s)
        s=sub('([1-9])([1-9])[0][0]K$','\\1.\\2M',s)
        rs=rs+s+(sep if i != (lv-1) else end)
    print(rs,end='')

def res_p(resistor_values):
    """
    calc parallel resistance
    """
    r=0
    for v in resistor_values:
        r+=1/v
    return 1/r

def res_s(resistor_values):
    """
    calc serial resistance
    """
    return sum_it(resistor_values)

def sum_it(thing):
    if is_iterable(thing):
        return(sum(thing))
    return thing

def res_sp(resistor_values):
    _resistor_values=[]
    for v in resistor_values:
        _resistor_values.append(res_s(v))
    return res_p(_resistor_values)

def res_sp_from_indexes(indexes):
    global values
    try:
        if type(values) is list:
            raise Exception('ERROR: wrong type')
        try:
            rp= res_sp([values[i] for i in indexes])
        except IndexError:
            print(indexes)
            raise
    except IndexError as e:
        print('INDEX ERROR: len values={} indexes={}'.format(len(values),indexes),file=stderr)
        raise e
    return rp

def get_nearest_index(val):
    global values
    r=0
    for i in range(len(values)):
        if values[i] > val:
            above=i
            break
    if i>0 and values[i] - val > values[i-1] - val:
        return i-1
    return i

def calc_max_step(indexes):
    lv=len(values)
    mstep=lv
    for i in indexes:
        mstep=min(mstep,lv-i-1)
        mstep=min(mstep,i)
    return mstep

def has_dupes(l):
    flat=flatten_thing(l)
    ll=len(flat)
    for i in range(ll):
        for j in range(ll):
            if i != j:
                if flat[i] == flat[j]:
                    return True
    return False

def has_reserved_ones(l):
    global used_list
    if any(thing in used_list for thing in l):
        return True
    return False

def mark_used(v):
    global used_list
    used_list.append(v)

is_better_counter=0
def is_better(val,new_indexes,delta):
    global is_better_counter
    is_better_counter+=1
    new=abs(calc_delta(val,new_indexes))
    old=abs(delta)
    if args.verbose and is_better_counter % 100000 == 0:
        print("WI = {}  CI= {:20.20} DN = {:3.2f}  DO = {:3.2f}".format(Worker_index,str(new_indexes),new,old))
    return new < old

def indexes_not_to_high(indexes,length):
    for i in indexes:
        if type(i) is DoubleIndex:
            for j in i:
                if type(j) is list:
                    print("indexes: {}".format(indexes))
                    raise Exception("wrong type")
                if j >= length:
                    return False
        if type(i) is list:
            print("indexes: {}".format(indexes))
            raise Exception("wrong type")
        if i >= length:
            return False
    return True

def combine(val,max_p=3,precision=0.01,add_resistor_factor=2,random_jump_lock=200,nodupes=False,disable_pool=False,serial=True):
    global values
    bases = []
    dividers = []
    for i in range(max_p-1):
        bases.append(val*(i+2))
        dividers.append(i+2)
    print("# start values: "+str(bases))
    next_base_factor = add_resistor_factor
    lb=len(bases)
    _cpu_count=cpu_count()
    pool=Pool(_cpu_count)
    #pool=Pool(1)
    for bi in range(lb):
        #print("bi = {}".format(bi))
        divider=dividers[bi]
        nearest=get_nearest_index(bases[bi])
        indexes=[SingleIndex(nearest)]*divider
        indexes_parts = dividelist(list(range(len(values))),pool._processes)
        indexes_full  = set(list(range(len(values))))
        results=[]
        r=None
        while calc_factor(bases[bi],indexes) < next_base_factor or bi==lb-1:
            delta=calc_delta(val,indexes)
            e=abs(((val+delta)/val) - 1)
            if  e <= precision:
                dupes_ok=True
                if nodupes:
                    if has_dupes(indexes) or has_reserved_ones(indexes):
                        dupes_ok=False
                if dupes_ok:
                    if nodupes:
                        for i in indexes:
                            mark_used(i)
                    ##############
                    ##  return  ##
                    ##############
                    #for i in indexes:
                    #    print("index: {} val: {}".format(i,values[i]))
                    return [values[i] for i in indexes],e
                else:
                    # in case precision is ok but dupes not ok
                    # need to set delta high
                    # to prevent attempts improving the the delta
                    delta=inf
            any_ready=any([i.ready() for i in results])
            if not any_ready:
                for i in range(pool._processes):
                    exclude = indexes_full - set(indexes_parts[i])
                    poolargs = [val,indexes,delta,random_jump_lock,nodupes,exclude,i,serial]
                    if not disable_pool:
                        r = pool.apply_async(calc_better_v2,poolargs)
                        results.append(r)
                sleep(0.01)
            done=False
            if disable_pool:
                done=True
                indexes=calc_better_v2(val,indexes,delta,random_jump_lock,nodupes,set([]),-1)
            while not done:
                for res_i in range(len(results)):
                    if results[res_i].ready():
                        indexes=results[res_i].get()
                        results.pop(res_i)
                        done=True
                        pool.terminate()
                        pool.join()
                        pool.close()
                        pool=Pool(_cpu_count)
                        break
                sleep(0.01)

def calc_better_v2(val,indexes,delta,random_jump_lock,nodupes,exclude,worker_index,serial):
    counter=0
    random_jump=1
    _random_jump=0
    block_jump=20
    value_index_set=set(range(len(values)))-exclude
    done=False
    global Worker_index
    Worker_index=worker_index
    while not done:
        li=len(indexes)
        for i in range(li):
            for j in value_index_set:
                if i == 0:
                    if li > 1:
                        _indexes = [j] + indexes[1:]
                    else:
                        _indexes = [j]
                elif i == li-1:
                    if li > 1:
                        _indexes = indexes[:-1] + [j]
                    else:
                        _indexes = [j]
                elif li > 2:
                    _indexes = indexes[:i] + [j] + indexes[i+1:]
                else:
                    raise Exception("ERROR: unexpected case")
                if block_jump > 0:
                    _random_jump=0
                else:
                    _random_jump = random_jump
                better = calc_better_v3(val,_indexes,delta,_random_jump, nodupes, worker_index,block_jump,serial,fix=[i])
                if _random_jump > 0:
                    block_jump = 100
                else:
                    block_jump-=1
                if better is None:
                    pass
                else:
                    ##############
                    ##  return  ##
                    ##############
                    return better

        counter+=1
        random_jump=min(random_jump+1,int(len(values)/2))
        if counter%10000==0:
            init_random()

def find_index_near_val(val):
    min_dist=inf
    min_i = None
    for i in range(len(values)):
        dist=abs(val - values[i])
        if dist < min_dist:
            min_i = i
            min_dist = dist
        if dist > min_dist:
            break # sorted values
    return min_i

def calc_better_v3(val,indexes,delta,random_jump,nodupes,worker_index,block_jump,serial,fix=[]):
    """
    """
    def gen_modify_func(start_index):
        def modify_func(thing,distance):
            if type(thing) is int:
                thing=SingleIndex(thing)
            # -distance , because need lower value
            if type(thing) is SingleIndex:
                # make double, no distance yet
                min_dist_index = find_index_near_val(val/2)
                ret=thing.make_double( min_dist_index )
            elif type(thing) is DoubleIndex:
                i=random.randint(0,len(thing)-1)
                _thing=[thing[0],thing[1]]
                _thing[i]+=distance
                thing=DoubleIndex(*_thing)
                ret=thing
            return ret
        return modify_func
    lv=len(values)
    for k in range(1,random_jump+2):

        #
        #  make a list of possible modification types
        #  but do not set the extent of the modification yet
        #
        li=len(indexes)
        choices1=[ -1, +1 ]                                             # adding/subtracting
        choices=[]
        for i in range(li):
            a = choices1
            if serial:
                a += [ gen_modify_func ]
            choices.append( a )    # 2 serial connected resistors out of one resistor

        #
        #  make plan of how much to alter the index "i"
        #
        for i in range(li):
            lci=len(choices[i])
            for j in range(lci):
                ri = random.randint(1,k)
                if serial and type(choices[i][j]) is FunctionType:
                    if choices[i][j].__name__=="gen_modify_func":
                        try:
                            cij=choices[i][j]
                            # generates modify func with start index ri ("random jump")
                            choices[i][j]=choices[i][j](ri)
                        except TypeError as e:
                            cij=choices[i][j]
                            raise e
                else:
                    choices[i][j]*=ri
        #
        # modify the indexes
        #
        for i in range(li):
            lci=len(choices[i])
            if lci > 0 and not i in fix:
                befor = indexes[i]
                choice=random.randint(0,lci-1)
                if type(choices[i][choice]) is int and type(indexes[i]) is int:
                    # add int
                    indexes[i] += choices[i][choice]
                elif type(choices[i][choice]) is FunctionType:
                    # replace with return value
                    indexes[i] = choices[i][choice](indexes[i],choice)

                #
                # check whether the modification
                # meets the requirements
                #
                if indexes_not_to_high(indexes,lv):
                    if not any([j<0 for j in indexes]):
                        if is_better(val,indexes,delta):
                            if not nodupes or not has_dupes(indexes):
                                # got new indexes at this point
                                return indexes
                indexes[i] = befor
                choices[i].pop(choice)

def check_indexes(indexes):
    raise Exception("ERRROR: check unwanted")
    fail=False
    if not indexes_not_to_high(indexes,len(values)):
        fail_reason="one of indexes to high"
        fail=True
    for i in indexes:
        if type(i) is DoubleIndex:
            # test copy
            ii=deepcopy(i)
            if not i==ii or i is ii:
                fail_reason="copy test failed {} != {}".format(i,ii)
                print(DoubleIndex(i))
                print(DoubleIndex(*i))
                fail=True
            for j in i:
                if type(j) is list:
                    fail_reason="DoubleIndex contains list"
                    fail=True
                    break
            if fail:
                break
    if fail:
        raise Exception("ERROR:index check failed. indexes: {}\nFail reason: {}".format(indexes,fail_reason))

def calc_delta(val,indexes):
    return res_sp_from_indexes(indexes) - val

def calc_factor_1(base,i):
    global values
    vi=values[i]
    f=vi/base
    ff=f-1
    fff=abs(ff)
    return fff

def calc_factor(base,indexes):
    f=0
    for i in indexes:
        if type(i) is DoubleIndex:
            l=[calc_factor_1(base,j) for j in i]
        else:
            l=[calc_factor_1(base,i)]
        f=max(l)
    return f

def dividelist(l,parts):
    ll=len(l)
    parts=min(ll,parts)
    lll=[]
    dil=[0]
    for i in range(1,parts):
        di=round(i*ll/parts)
        lll.append(l[dil[-1]:di])
        dil.append(di)
    lll.append(l[dil[-1]:])
    return lll

def print_e(e,end=" ",format=False):
    plog=abs(ceil(log10(args.precision)))+1
    formatstr='e = {:.' + str(plog) + 'f}'
    s=formatstr.format(e)
    if format:
        return s+end
    else:
        print(s,end=end)

def parse_args():
    from argparse import ArgumentParser
    ap=ArgumentParser()
    ap.add_argument("-p","--precision",type=float,default=0.01,help="Factor of how much the combined value is allowed to diff from the target value.")
    ap.add_argument("-n","--max-resistor-count",type=int,default=3,help="How many branches/resistors in \"parallel\" you want to use at max to combine to one target value.")
    ap.add_argument("-a","--add-resistor-factor",type=float,default=1,help='Factor of how much the values in the set of the combination of resistors can diff from each other befor the length of the set is enlarged and another place for a resistor is added to the search.')
    ap.add_argument("-D","--do-not-add-default-resistor-values",action="store_true",default=False,help="Implicitly selects \"--no-reuse-value\" and no default values are added.")
    ap.add_argument("-R","--no-reuse-value",action="store_true",default=False, help="Implicitly enabled if also -D selected. No values will be used more than once. This is for use with a custom value list in contrast to use a default list.")
    ap.add_argument("-v","--verbose",action="store_true",default=True)
    ap.add_argument("--testing",action="store_true",default=False)
    ap.add_argument("-o","--python-output",action="store_true",default=True,help="produce output suitable for the \"-r\" option")
    ap.add_argument("--debug",action="store_true",default=True)
    ap.add_argument("-P","--disable_pool",action="store_true",default=False)
    ap.add_argument("-s","--serial",action="store_true",default=False,help="additionally use serial resistor combinations")
    ap.add_argument(dest="target_values",nargs="+",type=str,help='possible syntax := \"5k 10K 2x1k 2000.5 50.3k 5x2.3M 2.3m\". Whereby \"2x\" means two times the following thing (no space). EXAMPLE CALL:\"./rcombine.py -DR -f ./my_available_resistors -n2 -p0.01 -u ./found_resistors_combinations_that_will_not_be_used_in_the_search 2x5.0k 5x10.0K\"')
    ap.add_argument("--add",dest="add_values",nargs='*',type=float,default=[])
    ap.add_argument("-f","--value-file",help="These are the values that you want to use to be combined to the target values/value . Specify a file with values in a python list. The syntax is python syntax.",default=None)
    ap.add_argument("--print-values-and-exit",action="store_true",help="Print the values that are available to be combined to the target values. The output depends on the the other options that affect the available values. Use this if you want to check the list of values to find out if the the program understands your input as desired.")
    ap.add_argument("-u","--in-use-value-file",type=str,help="File that is python \"eval-able\" and contains a list with already consumed/used values. Paste the output of this program with the -o option into this file. The values from this file will not be used in the search of combinations.")
    global args
    args=ap.parse_args()
    if args.do_not_add_default_resistor_values:
        args.no_reuse_value = True

def remove_indexes(indexes,thing):
    _thing=thing
    thing=_thing.__class__()
    for i in range(len(_thing)):
        if not i in indexes:
            thing.append(_thing[i])
    return thing

def prepare_target_values(values,enable_mult=True):
    _values=[]
    for v in values:
        _values.append( resistor_string_to_float(  v, enable_mult=True ))
    values=[]
    for v in _values:
        if hasattr(v,'__iter__'):
            values+=prepare_target_values(v)
        else:
            values.append(v)
    return values

def main():
    global values
    parse_args()
    if args.testing:
        testing()
        exit()
    init_random()
    if not args.value_file is None:
        with open(args.value_file) as f:
            _file_values = eval(f.read())
            file_values=[]
            for v in _file_values:
                float_or_floats=resistor_string_to_float(v)
                if hasattr(float_or_floats,'__iter__'):
                    if not type(float_or_floats) is list:
                        float_or_floats=list(float_or_floats)
                        file_values+=float_or_floats
                else:
                    file_values.append(float_or_floats)
    else:
        file_values=[]

    if not args.do_not_add_default_resistor_values:
        add_values=[resistor_string_to_float(v) for v in args.add_values]
        values=gen_values()+args.add_values+file_values
    else:
        values = args.add_values + file_values
    values.sort()
    values=Values(values)

    if not args.in_use_value_file is None:
        global used_list
        with open(args.in_use_value_file) as f:
            used_values = eval(f.read())
            used_values = [ resistor_string_to_float(v) for v in used_values ]
            for v in used_values:
                try:
                    i=values.index(v)
                    used_list.append(i)
                except ValueError:
                    pass # no need to remove not existing
        in_use_values=[ values[i] for i in used_list ]
        values=remove_indexes(used_list,values)
        used_list=[] # reset is ok, all values are removed

    if args.print_values_and_exit:
        print("resistor values:")
        print("=============")
        print(values)
        print("In-use values:")
        print("=============")
        pprint(in_use_values)
        exit(0)

    if args.python_output:
        print("[")

    target_values=prepare_target_values(args.target_values,enable_mult=True)
    for target_value in target_values:
        print("# target_value = "+str(target_value))
        vals,e=combine  (
                        target_value,
                        precision=args.precision,
                        max_p=args.max_resistor_count,
                        add_resistor_factor=args.add_resistor_factor,
                        nodupes=args.no_reuse_value,
                        disable_pool=args.disable_pool,
                        serial=args.serial,
                        )
        if args.python_output:
            flat=flatten_thing(vals)
            print(", ".join(str(v) for v in flat)+",")
        print_result(vals,e)
    if args.python_output:
        print("]")

def print_result(vals,e):
    lines=[]
    lines.append( [print_e(e,format=True),str(vals)])
    lines.append( [("final combined value = {:.3f} [Ohm]".format(res_sp(vals)))])
    width=0
    for line in lines:
        line_width=0
        for thing in line:
            line_width+=len(thing)
        line_width+=len(line)-1
        width=max(line_width,width)
    print("#"*(width+12))
    for line in lines:
        fs='###   {:'+str(width)+"."+str(width)+'}   ###'
        print(fs.format(" ".join(line)))
    print("#"*(width+12))

if __name__ == '__main__':
    main()

# vim: set foldnestmax=1 foldlevel=0 foldmethod=indent :


import logging
import random
from argparse import ArgumentParser
from itertools import chain
from pprint import pformat
import warnings

import torch
import torch.nn.functional as F

from transformers import OpenAIGPTLMHeadModel, OpenAIGPTTokenizer, GPT2LMHeadModel, GPT2Tokenizer
from train import SPECIAL_TOKENS, build_input_from_segments, add_special_tokens_
from utils import get_dataset, download_pretrained_model

PERSONA_KEYWORDS = {
    "fans": "ariana",
    "armenian": "kim",
    "airport": "kylie",
    "mexico": "trump",
    "youtuber": "shane",
    "virgo": "zendaya",
    "humble": "justin"
}

dataset_path = ""
dataset_cache = "./dataset_cache_OpenAIGPTTokenizer"
this_model = "openai-gpt"
max_history = 2
this_device = "cpu"
max_length = 20
min_length = 1
seed = 0
temperature = 0.7
top_k = 0
top_p = 0.9
no_sample = False

# tokenizer and model
model = None
tokenizer = None

def get_persona_key(persona):
    for p in PERSONA_KEYWORDS.keys():
        if p in persona:
            return PERSONA_KEYWORDS[p]

def initialise():
    global tokenizer
    global model
    model_checkpoint = download_pretrained_model()
    tokenizer_class, model_class = (OpenAIGPTTokenizer, OpenAIGPTLMHeadModel)
    tokenizer = tokenizer_class.from_pretrained(model_checkpoint)
    model = model_class.from_pretrained(model_checkpoint)
    model.to(this_device)
    add_special_tokens_(model, tokenizer)

    return 'OK'

def get_personality():
    dataset = torch.load(dataset_cache)
    personalities = [dialog["personality"] for dataset in dataset.values() for dialog in dataset]
    personality = random.choice(personalities)
    persona_key = get_persona_key(tokenizer.decode(chain(*personality)))
    return tokenizer.decode(chain(*personality)), personality, persona_key

def reply(input_text, history, personality):
    history.append(tokenizer.encode(input_text))
    with torch.no_grad():
        out_ids = sample_sequence(personality, history)
    history.append(out_ids)
    history = history[-(2*max_history+1):]
    out_text = tokenizer.decode(out_ids, skip_special_tokens=True)
    return out_text, history

def top_filtering(logits, top_k=0., top_p=0.9, threshold=-float('Inf'), filter_value=-float('Inf')):
    """ Filter a distribution of logits using top-k, top-p (nucleus) and/or threshold filtering
        Args:
            logits: logits distribution shape (vocabulary size)
            top_k: <=0: no filtering, >0: keep only top k tokens with highest probability.
            top_p: <=0.0: no filtering, >0.0: keep only a subset S of candidates, where S is the smallest subset
                whose total probability mass is greater than or equal to the threshold top_p.
                In practice, we select the highest probability tokens whose cumulative probability mass exceeds
                the threshold top_p.
            threshold: a minimal threshold to keep logits
    """
    assert logits.dim() == 1  # Only work for batch size 1 for now - could update but it would obfuscate a bit the code
    top_k = min(top_k, logits.size(-1))
    if top_k > 0:
        # Remove all tokens with a probability less than the last token in the top-k tokens
        indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None]
        logits[indices_to_remove] = filter_value

    if top_p > 0.0:
        # Compute cumulative probabilities of sorted tokens
        sorted_logits, sorted_indices = torch.sort(logits, descending=True)
        cumulative_probabilities = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1)

        # Remove tokens with cumulative probability above the threshold
        sorted_indices_to_remove = cumulative_probabilities > top_p
        # Shift the indices to the right to keep also the first token above the threshold
        sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
        sorted_indices_to_remove[..., 0] = 0

        # Back to unsorted indices and set them to -infinity
        indices_to_remove = sorted_indices[sorted_indices_to_remove]
        logits[indices_to_remove] = filter_value

    indices_to_remove = logits < threshold
    logits[indices_to_remove] = filter_value

    return logits

def sample_sequence(personality, history, current_output=None):
    special_tokens_ids = tokenizer.convert_tokens_to_ids(SPECIAL_TOKENS)
    if current_output is None:
        current_output = []

    for i in range(max_length):
        instance = build_input_from_segments(personality, history, current_output, tokenizer, with_eos=False)

        input_ids = torch.tensor(instance["input_ids"], device=this_device).unsqueeze(0)
        token_type_ids = torch.tensor(instance["token_type_ids"], device=this_device).unsqueeze(0)

        logits = model(input_ids, token_type_ids=token_type_ids)
        if isinstance(logits, tuple):  # for gpt2 and maybe others
            logits = logits[0]
        logits = logits[0, -1, :] / temperature
        logits = top_filtering(logits, top_k=top_k, top_p=top_p)
        probs = F.softmax(logits, dim=-1)

        prev = torch.topk(probs, 1)[1] if no_sample else torch.multinomial(probs, 1)
        if i < min_length and prev.item() in special_tokens_ids:
            while prev.item() in special_tokens_ids:
                if probs.max().item() == 1:
                    warnings.warn("Warning: model generating special token with probability 1.")
                    break  # avoid infinitely looping over special token
                prev = torch.multinomial(probs, num_samples=1)

        if prev.item() in special_tokens_ids:
            break
        current_output.append(prev.item())

    return current_output


# -*- coding: UTF-8 -*-
import re;

from bs4 import BeautifulSoup;

import GetWebContent
import GetHTML

href_home = ['http://games.ifeng.com/',
             'http://games.ifeng.com/yejiehangqing/index.shtml'];

def catchGames(cursor, conn):
    for href in href_home:
        htmlcode =GetHTML.getHtml(href);
        soup = BeautifulSoup(htmlcode, "html.parser");
        list1 = soup.find_all('a', href=re.compile('http://games.ifeng.com/a/'));
        for item in list1:
            if unicode(item.get("href"))[0] == 'h':
                #print 'Games:',item.get("href");
                GetWebContent.catch(unicode(item.get('href')), 'Games', cursor, conn);


import matplotlib
matplotlib.use('Agg')

import matplotlib.pyplot as pl
from matplotlib import rc

matplotlib.rc('text', usetex=True)
pl.rcParams['text.latex.preamble'] = [
    r'\usepackage{tgheros}',
    r'\usepackage[eulergreek]{sansmath}',
    r'\sansmath',
    r'\usepackage{siunitx}',
    r'\sisetup{detect-all}'
]

import sys, os, itertools, pickle, utils

def test_dataref_gen():

    dpath = "./data/test/" +\
            "200410_140103_test_standard_net/" +\
            "builds/0000/raw"

    with open(dpath+'/namespace.p', 'rb') as pfile:
        nsp=pickle.load(pfile)

    fname = os.path.splitext(os.path.basename(__file__))[0]

    utils.generate_dataref_tex(nsp, '', fname)

    # fig.savefig("{}".format(fname)+'.pdf', dpi=300,
    #             bbox_inches='tight')

if __name__ == "__main__":

    test_dataref_gen()


from itertools import combinations

def resolution(clauses):
    new = set()
    while True:
        for ci,cj in combinations(clauses,2):
            resolvents = resolve(ci, cj)
            if any(len(r) == 0 for r in resolvents): return True
            new.update(resolvents)

        if new.issubset(clauses): return False
        clauses.update(new)
        new.clear()

def discard(S,x):
    return frozenset(y for y in S if not y in x)

def resolve(ci, cj):
    resolvents = set()
    u = ci.union(cj)
    for pi in ci:
        for pj in cj:
            if pi == -pj:
                res= discard(u,[pi,pj])
                resolvents.add(res)
    return resolvents

clauses = {frozenset({-1, 2}), frozenset({-2, 3,1}),frozenset({-3, 2}),frozenset({-2,}),frozenset({3,})}

if resolution(clauses): print("Query is proven")
else: print("query is not proven")


# coding: utf-8
from __future__ import absolute_import

# Standard imports
import logging

# Internal imports
from aoiktracecall.util import indent_by_level

# Debug logger.
# Initialized in `get_debug_logger`.
_DEBUG_LOGGER = None

# Info logger.
# Initialized in `get_info_logger`.
_INFO_LOGGER = None

# Error logger.
# Initialized in `get_error_logger`.
_ERROR_LOGGER = None

def set_debug_logger(logger):
    # Use global
    global _DEBUG_LOGGER

    # Set logger
    _DEBUG_LOGGER = logger

def get_debug_logger():
    # Use global
    global _DEBUG_LOGGER

    # If logger is not initialized
    if _DEBUG_LOGGER is None:
        # Get logger
        _DEBUG_LOGGER = logging.getLogger(
            'aoiktracecall.logging.DEBUG_LOGGER'
        )

        # Disable propagation
        _DEBUG_LOGGER.propagate = False

        # Set logging level
        _DEBUG_LOGGER.setLevel(logging.DEBUG)

    # Return logger
    return _DEBUG_LOGGER

def set_info_logger(logger):
    # Use global
    global _INFO_LOGGER

    # Set logger
    _INFO_LOGGER = logger

def get_info_logger():
    # Use global
    global _INFO_LOGGER

    # If logger is not initialized
    if _INFO_LOGGER is None:
        # Get logger
        _INFO_LOGGER = logging.getLogger(
            'aoiktracecall.logging.INFO_LOGGER'
        )

        # Disable propagation
        _INFO_LOGGER.propagate = False

        # Set logging level
        _INFO_LOGGER.setLevel(logging.INFO)

    # Return logger
    return _INFO_LOGGER

def set_error_logger(logger):
    # Use global
    global _ERROR_LOGGER

    # Set logger
    _ERROR_LOGGER = logger

def get_error_logger():
    # Use global
    global _ERROR_LOGGER

    # If logger is not initialized
    if _ERROR_LOGGER is None:
        # Get logger
        _ERROR_LOGGER = logging.getLogger(
            'aoiktracecall.logging.ERROR_LOGGER'
        )

        # Disable propagation
        _ERROR_LOGGER.propagate = False

        # Set logging level
        _ERROR_LOGGER.setLevel(logging.INFO)

    # Return logger
    return _ERROR_LOGGER

def print_debug(text, indent=True):
    # If have text
    if text:
        # If need indent the text
        if indent:
            # Indent the text
            text = indent_by_level(text)

        # Get logger
        logger = get_debug_logger()

        # Send text to logger
        logger.debug(text)

def print_info(text, indent=True):
    # If have text
    if text:
        # If need indent the text
        if indent:
            # Indent the text
            text = indent_by_level(text)

        # Get logger
        logger = get_info_logger()

        # Send text to logger
        logger.info(text)

def print_error(text, indent=True):
    # If have text
    if text:
        # If need indent the text
        if indent:
            # Indent the text
            text = indent_by_level(text)

        # Get logger
        logger = get_error_logger()

        # Send text to logger
        logger.error(text)


"""
@Author: Furkan Kirlangic
@Last Revision: 22.12.2021
"""

import base64
import socket
from multiprocessing import Queue

import cv2
import imutils
import numpy as np
from cv2 import cv2 as cv

SIZE = 65536  # UDP data transfer size in bytes

class Udp:
    """
    If data will be sent, the device is called server.
    If client, addr is client address
    If server, addr is client address
    """

    def __init__(self, port: int, addr: str, client=False):  # client true if receiving
        self.im_queue = Queue(10)
        self.transfer_queue = Queue(10)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, SIZE)
        self.host_ip = addr
        self.port = port
        self.socket_address = (self.host_ip, self.port)

        # self.socket.bind(self.socket_address)

        if client == True:
            while True:
                try:
                    self.socket.bind(self.socket_address)
                    print("Binded successfully")
                    break
                except:
                    pass

    """                                   Video Stream                                            """
    """-------------------------------------------------------------------------------------------"""

    def vid_stream(self, width: int, height: int, im_quality: int, cam_id: int):
        cap = cv.VideoCapture(cam_id)  # device id is left zero, will be updated later when cameras are connected
        client_addr = self.socket_address
        while cap.isOpened():
            _, frame = cap.read()
            frame = imutils.resize(frame, width=width, height=height)

            encoded, buffer = cv.imencode('.jpg', frame, [cv.IMWRITE_JPEG_QUALITY, im_quality])
            message = base64.b64encode(buffer)
            try:
                self.socket.sendto(message, client_addr)
            except:

                print('Cannot send image over UDP')
            """cv.imshow('transmitting', frame)
            key = cv.waitKey(1) & 0xFF
            if key == ord('q'):
                self.socket.close()
                break
            """

    def get_vid_stream(self):
        while True:
            packet, _ = self.socket.recvfrom(SIZE)
            data = base64.b64decode(packet, ' /')
            npdata = np.fromstring(data, dtype=np.uint8)
            frame = cv.imdecode(npdata, 1)

            try:
                self.im_queue.put(frame)

                # cv2.imshow("fram", frame)
                # cv2.waitKey(0)
            except:
                print('Cannot put frame to queue')
            """cv.imshow("receiving", frame)
            key = cv.waitKey(1) & 0xFF
            if key == ord('q'):
                self.socket.close()
                break"""

    """                                 Non-video UDP transmission                                """
    """-------------------------------------------------------------------------------------------"""

    def send_msg(self, qOut: Queue):
        while True:
            message = qOut.get()
            if type(message) != bytearray:
                message = bytearray(message)
            try:
                self.socket.sendto(message, self.socket_address)
            except:
                print('Cannot send UDP message')

    def receive_msg(self):
        while True:
            try:
                message, _ = self.socket.recvfrom(SIZE)
                if type(message) != bytearray:
                    message = bytearray(message)
                # print(list(message))
                self.transfer_queue.put(message)
            except:
                print('Cannot receive UDP message')


import numpy as np
import torch
import matplotlib.pyplot as plt
import copy

from . import densities
from . import preisach

import gpytorch

#hybrid hysteresis/GP
class HybridGP(torch.nn.Module):
    def __init__(self,
                 hysteresis_model,
                 density_model,
                 train_x, train_y, lk,
                 priors = None):

        super(HybridGP, self).__init__()

        self.h_module = Hysteresis(hysteresis_model, density_model)
        self.gp_module = ExactGP(train_x, train_y, lk)

    def forward(x):
        B = self.h_module(x)
        return self.gp_module(B)

#impliment a hysteresis module as a subclass of torch.nn
class Hysteresis(torch.nn.Module):
    def __init__(self,
                 hysteresis_model,
                 density_model,
                 priors = None):

        super(Hysteresis, self).__init__()

        #register parameters from density model
        #for name, item in density_model.params.items():
        #    self.register_parameter(name,item)

        self.density_model = density_model
        self.hysteresis_model = hysteresis_model

    def forward(self, x):
        self.hysteresis_model.set_applied_field(x)
        self.hysteresis_model.propagate_states()

        return self.hysteresis_model.calculate_magnetization(
            self.density_model).reshape(-1,1)

    def predict(self, x):
        return self.hysteresis_model.predict_magnetization(x,
                                                           self.density_model).reshape(-1,1)

class HysteresisExact(gpytorch.models.ExactGP):
    def __init__(self, train_x, train_y, lk, hyst_module):
        super(HysteresisExact, self).__init__(train_x, train_y, lk)

        self.mean_module = gpytorch.means.ConstantMean()
        self.covar_module = gpytorch.kernels.ScaleKernel(
            gpytorch.kernels.RBFKernel())

        self.hyst_module = hyst_module

    def forward(self, x):
        '''
        NOTE: remember that the argument passed to x here is a union between training and test data
              when self.training = False
        - we need to re-do the hysteresis model (call calculate_magnetization) for the training data
          but when we predict future values we need to call predict_magnetization

        '''
        if self.training:
            B = self.hyst_module(x)
        else:
            #note: to allow batch training self.train_inputs is a tuple of tensors, need first index
            # not the case for passing x!
            n_train = self.train_inputs[0].shape[0]
            #print(f'x:{x}')

            B_train = self.hyst_module(x[:n_train])
            #print(f'B_train:{B_train}')

            B_test = self.hyst_module.predict(x[n_train:]).float()
            #print(f'B_test:{B_test}')

            #concat
            B = torch.cat((B_train, B_test),axis = 0)
            #print(f'B:{B}')

        mean = self.mean_module(B)
        covar = self.covar_module(B)

        return gpytorch.distributions.MultivariateNormal(mean, covar)

    def get_manifold_model(self):
        #from this model create a copy GP that predicts from manifold space, not input space

        #get manifold inputs and outputs
        #note will not work for batch mode!
        manifold_inputs = self.hyst_module(self.train_inputs[0])
        manifold_outputs = self.train_targets

        #define new model - use deep copies so modifications to new model do not change orig model
        manifold_lk = copy.deepcopy(self.likelihood)
        manifold_model = ExactGP(manifold_inputs, manifold_outputs, manifold_lk)

        #set model cov and mean function to copy
        manifold_model.mean_module = copy.deepcopy(self.mean_module)
        manifold_model.covar_module = copy.deepcopy(self.covar_module)

        return manifold_model

class ExactGP(gpytorch.models.ExactGP):
    def __init__(self, train_x, train_y, lk):
        super(ExactGP, self).__init__(train_x, train_y, lk)

        self.mean_module = gpytorch.means.ConstantMean()
        self.covar_module = gpytorch.kernels.ScaleKernel(
            gpytorch.kernels.RBFKernel())

    def forward(self, x):
        mean = self.mean_module(x)
        covar = self.covar_module(x)

        return gpytorch.distributions.MultivariateNormal(mean, covar)

def train_model(model, likelihood, x, y, iter_steps = 250, lr = 0.1, fname = ''):
    # Find optimal model hyperparameters
    model.train()
    likelihood.train()

    # Use the adam optimizer
    for name, param in model.named_parameters():
        print(f'{name}:{param.requires_grad}')

    optimizer = torch.optim.Adam(model.parameters(), lr = lr)

    # "Loss" for GPs - the marginal log likelihood
    mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)

    best_loss = 10000
    for i in range(iter_steps):
        optimizer.zero_grad()
        output = model(x)
        loss = -mll(output, y)
        loss.backward(retain_graph=True)
        if loss.item() < best_loss:
            best_param = copy.deepcopy(model.state_dict())
            best_loss = loss.item()

        if i % 10 == 0:
            print('Iter %d - Loss: %.3f - Best loss %.3f' % (i + 1, loss.item(), best_loss))

        optimizer.step()

    #set model params to the best
    model.load_state_dict(best_param)

    torch.save(model.state_dict(), f'{fname}model.pth')


import sys
import argparse
import os
from os.path import join, dirname, isdir, isfile, exists, abspath

import torch
import torch.nn as nn
import torch.nn.functional as F

import yaml
from easydict import EasyDict
import data
import models
# import util.util as util
import util.html as html

def reset_config(args):
    this_dir = dirname(abspath(__file__))
    default_cfg_path = join(this_dir, 'configs/default_configs.yaml')
    cfg = yaml.load(open(default_cfg_path))
    cfg = EasyDict(cfg)
    # add attr from args
    for k, v in args._get_kwargs():
        if k == 'gpu_ids': v = [int(vid) for vid in v.split(',')]
        cfg[k] = v
    # add attr from model specific
    model_cfg_path = join(this_dir, 'configs/{}.yaml'.format(args.model))
    model_cfg = yaml.load(open(model_cfg_path))
    model_cfg = EasyDict(model_cfg)
    for k, v in model_cfg.items():
        cfg[k] = v

    # reset attr fixed for test
    cfg.num_threads = 0
    cfg.batch_size = 1
    cfg.serial_batches = True
    cfg.no_flip = True
    cfg.isTrain = False # test fixed
    return cfg

def create_dataset(cfg):
    dataset = eval('data.' + cfg.dataset_mode.capitalize() + 'Dataset')(cfg)
    print('dataset [{}] was created'.format(type(dataset).__name__))
    dataset_size = len(dataset)
    print('The number of training images = {}'.format(dataset_size))

    dataloader = torch.utils.data.DataLoader(
        dataset, batch_size=cfg.batch_size,
        shuffle=True if cfg.isTrain else False,
        num_workers=int(cfg.num_threads),
        drop_last=True if cfg.phase=='train' else False,
    )
    return dataloader, dataset_size

def create_model(cfg):
    model = eval('models.' + cfg.model.upper() + 'Model')(cfg)
    return model

def main(args):
    cfg = reset_config(args)
    dataset, dataset_size = create_dataset(cfg)
    model = create_model(cfg)

    vis_dir = join(cfg.results_dir, cfg.name, '{}_{}'.format(cfg.phase, cfg.epoch))
    print('creating web directory {}'.format(vis_dir))
    vispage = html.HTML(vis_dir, 'Experiment = {}, Phase = {}, Epoch = {}'.format(cfg.name, cfg.phase, cfg.epoch))

    for i, data in enumerate(dataset):
        if i == 0:
            model.data_dependent_initialize(data)
            model.setup(cfg)
            model.parallelize()
            model.eval()

        model.set_input(data)
        model.test()
        visuals = model.get_current_visuals()
        img_path = model.get_image_paths()
        if i % 5 == 0:
            print('processing (%04d)-th image... %s' % (i, img_path))
        vispage.save_images(visuals, img_path, width=cfg.display_winsize)
    vispage.save()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='argument parse for test scripts')
    parser.add_argument('--dataroot', type=str)
    parser.add_argument('--gpu_ids', default='0', type=str)
    parser.add_argument('--name', default='', type=str)
    parser.add_argument('--model', default='cut', type=str)
    parser.add_argument('--phase', default='train', type=str, help='train (or val/test) set')
    parser.add_argument('--results_dir', default='./results', type=str)
    parser.add_argument('--epoch', type=str, default='latest', help='resume model epoch')
    parser.add_argument('--verbose', action='store_true', help='True with more debug info')

    args = parser.parse_args()
    main(args)


#!/usr/bin/env python2
import cv2
import os
import sys
import numpy as np
sys.path.append('.')
import tensorflow as tf
import detect_face
import random
from mtcnn.mtcnn import MTCNN

def speeds(obstacle):
    speed = []
    for i in range(60):
        a = random.randint(45, 80)
        speed.append(round(a))
        speed.sort()
        # low is a list of speeds to slower

    #print(speed)
    #print(len(speed))
    if obstacle == False:
        return random.choice(speed)

    else:
        return 0

def main():

    video_capture = cv2.VideoCapture('sample2.mp4')

    #video_capture.set(3, 640)
    #video_capture.set(4, 480)

    minsize =30 # minimum size of face
    threshold = [ 0.6, 0.7, 0.7 ]  # three steps's threshold
    factor = 0.709 # scale factor
    detect_features = MTCNN()

    sess = tf.Session()
    with sess.as_default():
        pnet, rnet, onet = detect_face.create_mtcnn(sess, None)
        while(True):
            ret, frame = video_capture.read()
            if not ret:
                break
            # Display the resulting frame
            img = frame[:,:,0:3]
            boxes, _ = detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor)

            for i in range(boxes.shape[0]):
                result = detect_features.detect_faces(img)
                pt1 = (int(boxes[i][0]), int(boxes[i][1]))
                pt2 = (int(boxes[i][2]), int(boxes[i][3]))

                if len(result) == 0:
                        print('no pedestrians')
                        a = speeds(obstacle=False)
                        dp1 =(100, 300)
                        dp2 =(400,600)
                        cv2.rectangle(frame, dp1, dp2, thickness=-1, color=(0, 255, 0))
                        font = cv2.FONT_HERSHEY_SIMPLEX
                        num1 = 'Pedestrians: '+str(len(result))
                        cv2.putText(img,num1,(100,400), font, 1.0,(255,255,255),2,cv2.LINE_AA)
                        num2 = 'Speed: '+str(a)
                        cv2.putText(img,num2,(100,450), font, 1.0,(255,255,255),2,cv2.LINE_AA)

                else :
                        a = speeds(obstacle=True)
                        dp1 =(100, 300)
                        dp2 =(400,600)
                        cv2.rectangle(frame, dp1, dp2, thickness=-1, color=(0, 0, 255))
                        font = cv2.FONT_HERSHEY_SIMPLEX
                        num1 = 'Pedestrians: '+str(len(result))
                        cv2.putText(img,num1,(100,400), font, 1.0,(255,255,255),2,cv2.LINE_AA)
                        num2 = 'Speed: '+str(a)
                        cv2.putText(img,num2,(100,450), font, 1.0,(255,255,255),2,cv2.LINE_AA)

                for j in range(len(result)):
                        bounding_box = result[j]['box']
                        keypoints = result[j]['keypoints']
                        cv2.rectangle(frame, pt1, pt2, color=(0, 255, 0))
                        print(boxes)
                        cv2.circle(img,(keypoints['left_eye']), 2, (0,155,255), 2)
                        cv2.circle(img,(keypoints['right_eye']), 2, (0,155,255), 2)
                        cv2.circle(img,(keypoints['nose']), 2, (0,155,255), 2)
                        cv2.circle(img,(keypoints['mouth_left']), 2, (0,155,255), 2)
                        cv2.circle(img,(keypoints['mouth_right']), 2, (0,155,255), 2)

            cv2.namedWindow('Video', cv2.WINDOW_NORMAL)
            #cv2.rectangle(frame, pt1, pt2, color=(0, 255, 0))
            cv2.resizeWindow('Video', 1800,900)
            cv2.imshow('Video', frame)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                print("Ended Simulation")
                break

    video_capture.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()


from django.db import models
from utils.models import CoreModel,BaseModel
from apps.address.models import Address
from mysystem.models import Users
# Create your models here.

# ================================================= #
# ************** 商品分类 model  ************** #
# ================================================= #

class GoodsCategory(CoreModel):
    """商品类别"""
    name = models.CharField(max_length=20, verbose_name='名称')
    desc = models.CharField(max_length=255, null=True, blank=True,verbose_name='描述')
    # level = models.SmallIntegerField(default=1, verbose_name="分类层级(1：一级 2：二级)", help_text="分类层级(1：一级 2：二级)")
    default_image = models.CharField(max_length=255, null=True, blank=True, verbose_name='默认图片')  # 类别图片（单个图片）
    sort = models.PositiveSmallIntegerField(default=0, verbose_name="排序", help_text="显示顺序")
    status = models.BooleanField(default=True, verbose_name="商品类别状态", help_text="商品类别状态")
    is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")
    parent = models.ForeignKey('self', related_name='goodscategorysubs', null=True, blank=True, on_delete=models.CASCADE, verbose_name='父类别')

    class Meta:
        db_table = 'tb_goods_category'
        verbose_name = '商品类别'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

# ================================================= #
# ************** 优惠券 model  ************** #
# ================================================= #
GOODSCOUPON_RECEIVE_TYPE = (
        (0, ""),
        (1, "手动领取"),
        (2, "新人劵"),
        (3, "后台发放"),
        (4, "邀请劵"),
    )
GOODSCOUPON_COUPONTYPE = (
        (0, "通用券"),
        (1, "商城类通用券"),
        (2, "服务类通用券"),
    )
# 通用：服务类商品+商城类商品
# 服务：仅能用于服务类商品
# 商城：仅能用于商城内商品
class GoodsCoupon(CoreModel):
    """商品优惠券(管理员创建)"""
    name = models.CharField(max_length=50, verbose_name='优惠券名称')
    caption = models.CharField(max_length=256, verbose_name='优惠券副标题', null=True, blank=True)  # 副标题
    desc = models.CharField(max_length=150, null=True, blank=True, verbose_name='描述')
    sort = models.IntegerField(default=0, verbose_name="排序", help_text="显示顺序")
    total_num = models.IntegerField(default=0, verbose_name="优惠券总数量", help_text="优惠券总数量")
    received_num = models.IntegerField(default=0, verbose_name="优惠券已领取数量", help_text="优惠券已领取数量")
    used_num = models.IntegerField(default=0, verbose_name="已被使用的数量", help_text="已被使用的数量")
    is_permanent = models.BooleanField(default=True, verbose_name="是否无限张数", help_text="是否无限张数")
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='优惠券面值',default=0)
    is_condition = models.BooleanField(default=False, verbose_name="有无门槛", help_text="有无门槛")#0无门槛 1有门槛
    use_min_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='最低消费多少金额可用优惠券',default=0)#有无门槛,0表示无门槛
    start_time = models.DateField(null=True, blank=True, help_text="优惠券领取开启时间", verbose_name="优惠券领取开启时间")
    end_time = models.DateField(null=True, blank=True, help_text="优惠券领取结束时间",verbose_name="优惠券领取结束时间")
    valid_begin_date = models.DateField(verbose_name="有效期开始时间", blank=True, null=True)
    valid_end_date = models.DateField(verbose_name="有效结束时间", blank=True, null=True)
    coupon_expiretime = models.IntegerField(default=0, verbose_name="优惠券有效期限（单位：天）", help_text="优惠券有效期限（单位：天）")#领取后几天有效，自券被领时开始算起
    receive_type = models.SmallIntegerField(choices=GOODSCOUPON_RECEIVE_TYPE, default=0, verbose_name="优惠券发送方式",help_text="优惠券发送方式")
    coupon_type = models.SmallIntegerField(choices=GOODSCOUPON_COUPONTYPE,default=0, verbose_name="优惠券类型（2）", help_text="优惠券类型（2）")
    is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")
    status = models.BooleanField(default=True, verbose_name="状态", help_text="状态")#0关闭 1正常

    class Meta:
        db_table = 'tb_goods_coupon'
        verbose_name = '商品优惠券'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

class CouponRecord(CoreModel):
    """优惠券发放、消费纪录 - 面向用户（用户领取卷）"""
    # 跟优惠券生成规则是一对多的关系 - 一种优惠券有30张，则发放记录就有30条
    coupon = models.ForeignKey("GoodsCoupon", on_delete=models.CASCADE,verbose_name="关联优惠券")
    number = models.CharField(max_length=64,verbose_name="用来计数",null=True,blank=True)
    # 一对多,一个用户有多张优惠券,一张优惠券只能给一个用户
    user = models.ForeignKey(Users,verbose_name="拥有者", on_delete=models.CASCADE,related_name='couponuser1')
    status_choices = ((0, '未领取'),(1, '未使用'), (2, '已使用'), (3, '已过期'), (4, '已撤回'))
    status = models.SmallIntegerField(choices=status_choices, default=0)
    used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用时间")
    receive_time = models.DateTimeField(blank=True, null=True, verbose_name="领取时间")
    is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")

    class Meta:
        db_table = 'tb_goods_coupon_record'
        verbose_name = '用户持券表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '%s-%s-%s'%(self.user,self.coupon,self.get_status_display())

# ================================================= #
# ************** 商品品牌 model  ************** #
# ================================================= #
class GoodsBrand(CoreModel):
    """ 商品所属品牌 """
    category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE,related_name="brands", verbose_name="所属分类", help_text="所属分类")
    name = models.CharField(max_length=30, verbose_name="品牌名", help_text="品牌名")
    desc = models.TextField(blank=True, max_length=200,default="",  verbose_name="品牌描述", help_text="品牌描述")
    default_image = models.CharField(max_length=255, null=True, blank=True, verbose_name='品牌logo')  #（单个图片）
    sort = models.PositiveSmallIntegerField(default=0, verbose_name="排序")

    class Meta:
        db_table = "tb_goods_brand"
        ordering = ["-sort"]
        verbose_name = "商品品牌"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name
# ================================================= #
# ************** 商品 model  ************** #
# ================================================= #
class SPU(CoreModel):
    """商品SPU"""
    SPU_SPEC_TYPE = (
        (0, "单规格"),
        (1, "多规格")
    )
    name = models.CharField(max_length=60, verbose_name='标题')
    sub_name = models.CharField(max_length=60, blank=True,null=True, default="", verbose_name="副标题")#副标题
    category1 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat1_spu', verbose_name='一级类别')
    # category2 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat2_spu',null=True, blank=True, verbose_name='二级类别')
    # category3 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat3_spu', null=True, blank=True, verbose_name='三级类别')
    brand = models.ForeignKey(GoodsBrand, on_delete=models.PROTECT, related_name="brands", blank=True, null=True,verbose_name="品牌")
    spec_type = models.PositiveIntegerField(choices=SPU_SPEC_TYPE, default=0, verbose_name="规格类型")#默认单规格
    default_image = models.CharField(max_length=255, null=True, blank=True, verbose_name='商品主图')  #（单个图片）
    image_list = models.CharField(max_length=2000, null=True, blank=True, verbose_name='商品轮播图')  # （多个图片）
    price = models.DecimalField(max_digits=10, decimal_places=2,default=0, verbose_name="售价")#sku中选择一个最低的售价写入
    # market_price = models.DecimalField(max_digits=10, decimal_places=2,default=0, verbose_name="市场价")
    # cost_price = models.DecimalField(max_digits=10, decimal_places=2,default=0, verbose_name="成本价")
    sales = models.IntegerField(default=0, verbose_name='销量')
    stock = models.IntegerField(default=0, verbose_name="库存")
    unit = models.CharField(max_length=30, default="", blank=True,null=True,verbose_name="商品单位")
    comments = models.IntegerField(default=0, verbose_name='评论量',null=True, blank=True)
    desc_detail = models.TextField(default='', verbose_name='详细介绍',null=True, blank=True)#商品详情
    desc_pack = models.TextField(default='', verbose_name='包装信息',null=True, blank=True)
    desc_service = models.TextField(default='', verbose_name='售后服务',null=True, blank=True)
    is_launched = models.BooleanField(default=True, verbose_name='是否上架销售')
    is_tuijian = models.BooleanField(default=False, verbose_name='是否推荐')#自定义字段，可删掉
    sort = models.PositiveSmallIntegerField(default=0, verbose_name="排序")
    is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")

    class Meta:
        db_table = 'tb_goods_spu'
        verbose_name = '商品SPU'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

class SKU(CoreModel):
    """商品SKU"""
    name = models.CharField(max_length=60, verbose_name='标题',null=True, blank=True)
    spu = models.ForeignKey(SPU, on_delete=models.CASCADE, verbose_name='商品SPU',related_name='skus')
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='商品单价')
    shop_price = models.DecimalField(max_digits=10, decimal_places=2, default=0,null=True, blank=True, verbose_name="售价")
    market_price = models.DecimalField(max_digits=10, decimal_places=2, default=0,null=True, blank=True, verbose_name="市场价")
    cost_price = models.DecimalField(max_digits=10, decimal_places=2, default=0,null=True, blank=True, verbose_name="成本价")
    stock = models.IntegerField(default=0, verbose_name='商品库存')
    unite = models.CharField(max_length=20, verbose_name='商品单位',null=True, blank=True)
    sales = models.IntegerField(default=0, verbose_name='商品销量',null=True, blank=True)
    default_image = models.CharField(max_length=255, null=True, blank=True, verbose_name='默认图片')#商品主图(单张)
    is_launched = models.BooleanField(default=True, verbose_name='是否上架销售')
    is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")

    class Meta:
        ordering = ["create_datetime"]
        db_table = 'tb_goods_sku'
        verbose_name = '商品SKU'
        verbose_name_plural = verbose_name

    def __str__(self):
        return f'{self.spu.name}的SKU'

class SKUImage(CoreModel):
    """SKU图片"""
    sku = models.ForeignKey(SKU, on_delete=models.CASCADE, verbose_name='商品sku',related_name='goods_imagelist')
    image = models.CharField(max_length=255,verbose_name='图片')
    sort = models.PositiveSmallIntegerField(default=0, verbose_name="排序")

    class Meta:
        ordering=  ["sort"]
        db_table = 'tb_goods_sku_image'
        verbose_name = 'SKU图片'
        verbose_name_plural = verbose_name

class SPUSpecification(CoreModel):
    """商品SPU规格名"""
    spu = models.ForeignKey(SPU, on_delete=models.CASCADE, related_name='spu_specs', verbose_name='商品SPU')
    name = models.CharField(max_length=20, verbose_name='规格名称')

    class Meta:
        ordering = ["create_datetime"]
        db_table = 'tb_goods_spu_specification'
        verbose_name = '商品SPU规格'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

class SPUSpecificationOption(CoreModel):
    """商品SPU规格选项值"""
    spec = models.ForeignKey(SPUSpecification, related_name='options', on_delete=models.CASCADE, verbose_name='规格')
    value = models.CharField(max_length=20, verbose_name='选项值')

    class Meta:
        ordering = ["create_datetime"]
        db_table = 'tb_goods_spu_specification_option'
        verbose_name = '规格选项'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.value

class SKUSpecification(CoreModel):
    """SKU具体规格"""
    sku = models.ForeignKey(SKU, related_name='specs', on_delete=models.CASCADE, verbose_name='sku')
    spec = models.ForeignKey(SPUSpecification, on_delete=models.CASCADE, verbose_name='规格名称')
    option = models.ForeignKey(SPUSpecificationOption, on_delete=models.CASCADE, verbose_name='规格值')

    class Meta:
        ordering = ["create_datetime"]
        db_table = 'tb_goods_sku_specification'
        verbose_name = 'SKU规格'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '%s: %s - %s' % (self.sku, self.spec.name, self.option.value)

class GoodsSpecTemplate(CoreModel):
    """商品规格模板(供添加商品时选择使用)"""
    spec = models.CharField(max_length=100,  verbose_name='规格名称')
    option = models.CharField(max_length=255, verbose_name='规格值')

    class Meta:
        db_table = 'tb_goods_spec_template'
        verbose_name = '商品规格模板'
        verbose_name_plural = verbose_name

# ================================================= #
# ************** 商品订单model  ************** #
# ================================================= #
class OrderInfo(CoreModel):
    """订单信息"""
    PAY_METHOD_CHOICES = (
        (0, ""),
        (1, "货到付款"),
        (2, "微信"),
        (3, "支付宝"),

    )
    ORDER_STATUS_CHOICES = (
        (1, "待支付"),
        (2, "待发货"),
        (3, "待收货"),
        (4, "待评价"),
        (5, "已完成"),
        (6, "已取消"),
    )
    ORDER_PAY_STATUS_CHOICES = (
        (0, "待支付"),
        (1, "已支付"),
        (2, "退款中"),
        (3, "退款失败"),
        (4, "已退款"),
    )
    order_id = models.CharField(max_length=64, verbose_name="订单号",unique=True)#内部
    trade_id = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name="支付编号")#外部
    user = models.ForeignKey(Users, on_delete=models.PROTECT,related_name='createorderuser1' ,verbose_name="下单用户")
    address_name = models.CharField(max_length=50, null=True, blank=True, verbose_name="收货人姓名")
    address_mobile = models.CharField(max_length=20, null=True, blank=True, verbose_name="收货人手机号")
    address_place = models.CharField(max_length=100, null=True, blank=True, verbose_name="收货详细地址")
    couponrecord_id = models.CharField(max_length=60, unique=True, null=True, blank=True, verbose_name="用户优惠券id")
    couponrecord_price = models.DecimalField(max_digits=10, decimal_places=2, default=0,null=True, blank=True, verbose_name="优惠券面值")
    total_count = models.IntegerField(default=1, verbose_name="商品总数")
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="实付商品总金额",default=0)
    total_amount_pay = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="订单总金额",default=0)
    freight = models.DecimalField(max_digits=10, decimal_places=2,null=True, blank=True,verbose_name="运费",default=0)
    logistics_id = models.CharField(max_length=100, verbose_name="物流单号",null=True, blank=True)#该商城项目特有，其他项目可去掉
    send_time = models.DateTimeField(null=True, blank=True, help_text="发货时间", verbose_name="发货时间")#该商城项目特有，其他项目可去掉
    logistics_company = models.CharField(max_length=90, verbose_name="物流公司", null=True, blank=True)#该商城项目特有，其他项目可去掉
    pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=0, verbose_name="支付方式")
    pay_time = models.CharField(max_length=64,null=True, blank=True, verbose_name="支付时间", help_text="支付时间")
    remark = models.CharField(max_length=100, verbose_name="订单备注",null=True,blank=True)
    cancel_reason = models.CharField(max_length=100, verbose_name="订单取消原因", null=True, blank=True)
    status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="订单状态")
    pay_status = models.SmallIntegerField(choices=ORDER_PAY_STATUS_CHOICES, default=0, verbose_name="支付状态")
    is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")

    class Meta:
        db_table = "tb_mall_order_info"
        verbose_name = '订单基本信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.order_id

class OrderGoods(CoreModel):
    """订单商品"""
    SCORE_CHOICES = (
        (0, '0分'),
        (1, '20分'),
        (2, '40分'),
        (3, '60分'),
        (4, '80分'),
        (5, '100分'),
    )
    order = models.ForeignKey(OrderInfo, related_name='ordergoodsskus', on_delete=models.CASCADE, verbose_name="订单")
    spu = models.ForeignKey(SPU, on_delete=models.PROTECT,blank=True, null=True, verbose_name="订单商品")
    sku = models.ForeignKey(SKU, on_delete=models.PROTECT,blank=True, null=True, verbose_name="订单规格")
    count = models.IntegerField(default=1, verbose_name="数量")
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="sku单价")
    comment = models.TextField(verbose_name="评价信息",null=True,blank=True)
    score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5, verbose_name='满意度评分')
    is_anonymous = models.BooleanField(default=False, verbose_name='是否匿名评价')
    is_commented = models.BooleanField(default=False, verbose_name='是否评价了')

    class Meta:
        db_table = "tb_mall_order_goods"
        verbose_name = '订单商品'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.spu.name

class OrderRefunds(CoreModel):
    """订单退款"""
    ORDER_STATUS_CHOICES = (
        (0, "待支付"),
        (1, "已支付"),
        (2, "退款中"),
        (3, "退款失败"),
        (4, "已退款"),
    )
    order_no= models.CharField(max_length=64, verbose_name="订单号", unique=True)  # 内部
    order = models.ForeignKey(OrderInfo, related_name='orderrefunds', on_delete=models.CASCADE, verbose_name="要退款的订单")
    refund_id = models.CharField(max_length=64, verbose_name="退款单号", unique=True)  # 外部返回
    amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="退款金额")
    reason = models.CharField(max_length=64, verbose_name="退款失败原因", null=True,blank=True)  # 失败原因
    status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=2, verbose_name="退款状态")

    class Meta:
        db_table = "tb_mall_order_refunds"
        verbose_name = '商城订单退款'
        verbose_name_plural = verbose_name


# -*- coding: utf-8 -*-
import unittest
from securetea.lib.log_monitor.system_log.failed_login import FailedLogin
from securetea.logger import SecureTeaLogger

try:
    # if python 3.x.x
    from unittest.mock import patch
except ImportError:  # python 2.x.x
    from mock import patch

class TestFailedLogin(unittest.TestCase):
    """
    Test class for FailedLogin.
    """

    def setUp(self):
        """
        Setup class for FailedLogin.
        """
        self.os = "debian"

    @patch.object(FailedLogin, "update_user_dict")
    @patch('securetea.lib.log_monitor.system_log.failed_login.utils')
    def test_parse_log_file(self, mock_utils, mock_failed_login):
        """
        Test parse_log_file.
        """
        mock_utils.categorize_os.return_value = self.os
        # Create FailedLogin object
        self.failedlogin_obj = FailedLogin()
        mock_utils.open_file.return_value = ["Jun  3 18:31:08 adam su[13086]: pam_unix(su:auth): \
                                              authentication failure; logname= uid=1000 euid=0 \
                                              tty=/dev/pts/2 ruser=username rhost=  user=root"]
        mock_utils.get_epoch_time.return_value = 1
        self.failedlogin_obj.parse_log_file()
        mock_utils.get_epoch_time.assert_called_with('Jun', '3', '18:31:08')
        mock_failed_login.assert_called_with("username", "Jun 3", 1, 1)

    @patch('securetea.lib.log_monitor.system_log.failed_login.utils')
    def test_update_user_dict(self, mock_utils):
        """
        Test update_user_dict.
        """
        mock_utils.categorize_os.return_value = self.os
        # Create FailedLogin object
        self.failedlogin_obj = FailedLogin()
        self.failedlogin_obj.update_user_dict("username", "Jun 3", 1, 1)
        hashed_username = "username" + self.failedlogin_obj.SALT + "Jun 3"
        self.assertTrue(self.failedlogin_obj.user_to_count.get(hashed_username))
        temp_dict = {
            "date": "Jun 3",
            "last_time": 1,
            "count": 1
        }
        self.assertEqual(self.failedlogin_obj.user_to_count[hashed_username],
                         temp_dict)

    @patch('securetea.lib.log_monitor.system_log.failed_login.utils')
    @patch.object(SecureTeaLogger, "log")
    @patch('securetea.lib.log_monitor.system_log.failed_login.time')
    def test_check_brute_force(self, mock_time, mock_log, mock_utils):
        """
        Test check_brute_force.
        """
        mock_utils.categorize_os.return_value = self.os
        # Create FailedLogin object
        self.failedlogin_obj = FailedLogin()
        self.failedlogin_obj.update_user_dict("username", "Jun 3", 1, 1)
        mock_time.time.return_value = 2
        self.failedlogin_obj.THRESHOLD = -10  # Set THRESHOLD to negative to trigger alarm
        self.failedlogin_obj.check_brute_force()
        mock_log.assert_called_with('Too much failed login attempts: username on: Jun 3 failed attempts: 1',
                                    logtype='warning')


from typing import List

def get_elves(lines: List[str]) -> List[int]:
    current = 0
    elves = []
    for line in lines:
        line=line.strip()
        if not line:
            elves.append(current)
            current = 0
            continue
        current += int(line)

    return elves

def read_file(path: str) -> List[str]:
    with open(path, "r") as file:
        return file.readlines()

def main():
    lines= read_file("./data/one.txt")
    elves = get_elves(lines)
    elves_by_calories=sorted(elves)
    top_three = elves_by_calories[-3:]
    print(sum(top_three))

if __name__ == "__main__":
    main()