from __future__ import print_function
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from models import *

def clear_grad(model):
    for p in model.parameters():
        if p.grad is not None:
            p.grad.detach_()
            p.grad.zero_()

class Flatten(nn.Module):
    def forward(self, input):
        return input.view(input.size(0), -1)

def test(args, atkmodel, scratchmodel, testoptimizer, device, train_loader,
         test_loader, epoch, labeltransform=None):
    test_loss = 0
    val_loss = 0
    correct = 0
    correct_val = 0
    correct_tgt = 0
    atkmodel.eval()
    targetlist = []
    predlist = []
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        testoptimizer.zero_grad()
        with torch.no_grad():
            noise = atkmodel(data) * args.eps
            atkdata = torch.clamp(data + noise, 0, 1)
            # atkdata = data + noise
        output = scratchmodel(atkdata)
        loss = F.cross_entropy(output, target)
        with torch.no_grad():
            output2 = scratchmodel(data)
            loss2 = F.cross_entropy(output2, target)
        loss.backward()
        testoptimizer.step()
        if batch_idx % args.log_interval * 100 == 0:
            print(
                'Test_train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}\tNatLoss: {:.6f}'.format(
                    epoch, batch_idx * len(data), len(train_loader.dataset),
                           100. * batch_idx / len(train_loader), loss.item(),
                    loss2.item()
                ))

    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = scratchmodel(data)
            test_loss += F.cross_entropy(output, target,
                                         reduction='sum').item()  # sum up batch loss
            pred = output.max(1, keepdim=True)[
                1]  # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item()
            if labeltransform is not None:
                correct_tgt += pred.eq(labeltransform(target)
                                       .view_as(pred)).sum().item()
            predlist = predlist + pred.cpu().numpy().reshape(-1).tolist()
            targetlist = targetlist + target.cpu().numpy().tolist()

    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            noise = atkmodel(data) * args.eps
            atkdata = torch.clamp(data + noise, 0, 1)
            output = scratchmodel(atkdata)
            val_loss += F.cross_entropy(output, target,
                                        reduction='sum').item()  # sum up batch loss
            pred = output.max(1, keepdim=True)[
                1]  # get the index of the max log-probability
            correct_val += pred.eq(target.view_as(pred)).sum().item()

    test_loss /= len(test_loader.dataset)

    print(
        '\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.02f}%), '
        'Accuracy_tgt: {}/{} ({:.02f}%), Accuracy_adv: {}/{} ({:.02f}%)\n'
        .format(
            test_loss, correct, len(test_loader.dataset),
            100. * correct / len(test_loader.dataset),
            correct_tgt, len(test_loader.dataset),
            100. * correct_tgt / len(test_loader.dataset),
            correct_val, len(test_loader.dataset),
            100. * correct_val / len(test_loader.dataset),
        ))
    return 100. * correct / len(test_loader.dataset)

def main():
    # Training settings
    parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
    parser.add_argument('--batch-size', type=int, default=64, metavar='N',
                        help='input batch size for training (default: 64)')
    parser.add_argument('--test-batch-size', type=int, default=1000,
                        metavar='N',
                        help='input batch size for testing (default: 1000)')
    parser.add_argument('--epochs', type=int, default=2, metavar='N',
                        help='number of epochs to train (default: 10)')
    parser.add_argument('--lr', type=float, default=0.01, metavar='LR',
                        help='learning rate (default: 0.01)')
    parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
                        help='SGD momentum (default: 0.5)')
    parser.add_argument('--no-cuda', action='store_true', default=False,
                        help='disables CUDA training')
    parser.add_argument('--seed', type=int, default=1, metavar='S',
                        help='random seed (default: 1)')
    parser.add_argument('--log-interval', type=int, default=100, metavar='N',
                        help='how many batches to wait before '
                             'logging training status')
    parser.add_argument('--eps', type=float, default=0.3,
                        help='epsilon for data poisoning')
    parser.add_argument('--path', type=str, required=True,
                        help='resume from checkpoint')
    parser.add_argument('--targeted', action='store_true', default=False)
    parser.add_argument('--modelsize', choices=['small', 'normal', 'large'],
                        help='choose different CNNs')
    args = parser.parse_args()
    use_cuda = not args.no_cuda and torch.cuda.is_available()

    torch.manual_seed(args.seed)

    args.device = torch.device("cuda" if use_cuda else "cpu")

    kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}
    train_loader = torch.utils.data.DataLoader(
        datasets.MNIST('data', train=True, download=True,
                       transform=transforms.Compose([
                           transforms.ToTensor()
                       ])),
        batch_size=args.batch_size, shuffle=True, **kwargs)
    test_loader = torch.utils.data.DataLoader(
        datasets.MNIST('data', train=False, transform=transforms.Compose([
            transforms.ToTensor()
        ])),
        batch_size=args.test_batch_size, shuffle=True, **kwargs)

    atkmodel = Autoencoder().to(args.device)
    atkmodel.load_state_dict(torch.load(args.path))
    print('load from ' + args.path)
    if args.modelsize=='normal':
        scratchmodel = create_net().to(args.device)
    elif args.modelsize=='small':
        scratchmodel = create_small_net().to(args.device)
    elif args.modelsize=='large':
        scratchmodel = create_large_net().to(args.device)
    testoptimizer = optim.Adam(scratchmodel.parameters(), lr=args.lr)
    for epoch in range(1, args.epochs + 1):
        acc = test(args, atkmodel, scratchmodel, testoptimizer, args.device,
                   train_loader, test_loader, epoch,
                   labeltransform=((lambda x: (x + 1) % 10)
                   if args.targeted else None))

if __name__ == '__main__':
    main()


import numpy as np

class Vector(np.ndarray):
    def __new__(cls, input_array):
        # Input array is an already formed ndarray instance
        # We first cast to be our class type

        if len(input_array) == 2:
            obj = np.insert(input_array, 2, 0.0, axis=0).view(cls)

        else:
            obj = np.asarray(input_array).view(cls)
        # Finally, we must return the newly created object:
        return obj

    def __array_finalize__(self, obj):
        # see InfoArray.__array_finalize__ for comments
        if obj is None: return
        self.unit = getattr(obj, 'unit', None)

class Vectors(Vector):
    def __new__(cls, input_array):
        # Input array is an already formed ndarray instance
        # We first cast to be our class type

        if len(input_array[input_array.shape[-1]]) == 2:
            obj = np.insert(input_array, input_array.shape[-1], 0.0, axis=len(input_array.shape) - 1).view(cls)
        else:
            obj = np.asarray(input_array).view(cls)
        return obj

class vector(np.ndarray):
    def __new__(cls, input_array):
        # Input array is an already formed ndarray instance
        # We first cast to be our class type
        __a = np.asarray(input_array)
        if len(__a.shape) > 1:
            obj = Vectors(__a)
        else:
            obj = Vector(__a)
        # add the new attribute to the created instance
        obj.unit = (obj / np.linalg.norm(obj)).view(cls)
        # Finally, we must return the newly created object:
        return obj


import os
from kafka import KafkaConsumer
import json

kafka_broker = os.environ.get("KAFKA_BROKER_URL", "localhost:9093")
kafka_topic = os.environ.get("KAFKA_TOPIC", "posts")

consumer = KafkaConsumer(
    kafka_topic,
    bootstrap_servers=[kafka_broker],
    auto_offset_reset="earliest",
    value_deserializer=lambda m: json.loads(m.decode("utf-8")),
)
print(f"Listening for messages on topic '{kafka_topic}'...")

for message in consumer:
    print(f"Received message: {message.value}")


def toString(n_variables,restricciones,objetivo,maxmin):
    """
    Función que convierte a string un problema para ser impreso

    :param n_restricciones: número de restricciones del problema
    :param n_variables:  número de variables del problema
    :param restricciones: una lista de listas donde cada lista interna es una restriccione
    :param objetivo: una lsita con los coeficientes de la función objetivo
    :param relaciones: una lista con valores del 1 al 3, donde 1 es "=", 2 es "<=" y 3 es ">="
    :param maxmin: int que indica si el problema es de maximización o minimización
    :return problema: un string representando el problema
    """
    problema = "z = "

    if maxmin == 0:
        problema = f"max z = "
    elif maxmin == 1:
        problema = "min z = "
    problema += coefToString(objetivo) + "\n"
    y =1
    for (pos,rest) in enumerate(restricciones):
        if rest[1] == 1:
            restS = coefToString(rest[0])
            if rest[-1] != 0:
                restS += f" + {rest[-1]}s{y}"
                y+=1
            problema += restS+" = "+str(rest[-2])+"\n"
        elif rest[1] == 2:
            restS = coefToString(rest[0])
            if rest[-1] != 0:
                restS += f" + {rest[-1]}s{y}"
                y += 1
            problema += restS+ " <= " + str(rest[-2]) + "\n"
        elif rest[1] == 3:
            restS = coefToString(rest[0])
            if rest[-1] != 0:
                restS += f" + {rest[-1]}s{y}"
                y += 1
            problema += restS + " >= " + str(rest[-2]) + "\n"
    return problema

def coefToString(coefs):
    cadena = ""
    for coef in range(len(coefs)):
        if coefs[coef] == 0:
            continue
        if coef != 0:
            if coefs[coef] > 0:
                cadena += " + "
        cadena += str(coefs[coef]) + f"x{coef+1}"
    return cadena

def imprimirTabla(variables, tabla):
    base = list(tabla.keys())
    tam_col = 10

    vbls =""
    for var in variables.values(): #cada variable
        vbls += var + (" "*(tam_col-len(var)))
    print("\t\t  " +vbls)
    reng = ""
    for var in base: ##cada renglon
        reng += var + "        "
        for valor in list(tabla[var]):
            reng += str(valor) + (" "*(tam_col-len(str(valor))))
        reng += "\n"
    print(reng)

def mult_rest_menos_uno(rest):
    nueva_rest =[]
    nvos_coefs = []
    for coef in rest[0]:
        nvos_coefs.append(coef * -1)
    nueva_rest.append(nvos_coefs)
    if rest[1] == 2:
        nueva_rest.append(3)
    elif rest[1] == 3:
        nueva_rest.append(2)
    else:
        nueva_rest.append(1)
    nueva_rest.append(rest[2] * -1)
    return nueva_rest

def genFila(rest,vars,posfila):
    """
        Recibe
            rest: (list) [{"X1": 1, "X2": 2, ...}, ...] El diccionario con las variables iniciales
            vars: (dict) {0: "X1", 1: "X2", ...} Todas las variables
    """
    fila = []
    for var in vars.values():
        if var[0] == "X":
            fila.append(rest[0][var])
        elif posfila == int(var[1]) and var[0] == "S":
            fila.append(rest[3])
        elif posfila == int(var[1]) and var[0] == "Y":
            fila.append(rest[4])
        else:fila.append(0)
    fila.append(rest[2])
    return fila

def genFilaObjetivo(variables,obj):
    """
        Recibe
            variables: (dict) {0:x1,1:x2...} un diccionario con las variables del tableau ordenadas
            obj: (dict) {x1: 1, y1: -1, ...} un diccionario con los coefs de la f.o.
        Regresa
            fila [list] [0,1,1,...] una lista que representa la fila objetivo
    """
    fila = []
    for var in variables.values():
        if obj.get(var) != None:
            fila.append(obj[var])
        else:
            fila.append(0)
    fila.append(0) # z inicial es cero
    return fila

def generaProblema(problema):
    if problema == 0:
        return(3,2, [[{"X1":1,"X2": 0},2,5,0,0],[{"X1":1,"X2": 1},2,8,0,0],[{"X1":0, "X2":1},2,4,0,0]],{"X1":1,"X2":3},0)
    if problema == 1:
        return(2, 2, [[{"X1":1, "X2":1}, 3, 4, 0,0], [{"X1":1, "X2":2}, 2, 2, 0,0]], {"X1":1, "X2":1}, 0)

def generarVariables(restricciones):
    """
        Devuelve
            vars: (dict) {0: "x1", 1: "x2",...}  todas las variables ordenadas
    """
    vars = {}
    clave = 0
    for i in range(len(restricciones[0][0])):
        clave += 1
        vars[i] = f'X{i+1}'
    for i,rest in enumerate(restricciones):
        if rest[3] != 0:
            vars[clave] = f'S{i+1}'
            clave += 1
    for i,rest in enumerate(restricciones):
        if rest[4] != 0:
            vars[clave] = f'Y{i+1}'
            clave += 1
    return vars

def getPosDict(dict, clave):
    for pos,valor in dict.items():
        if valor == clave:
            return pos
    return -1


import pandas as pd
import sys, getopt
import numpy as np
from sklearn import metrics
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
data=pd.read_excel('features.xlsx')

feature_cols=['DAY','TEMP','CLOUD','RAIN','WIND','PUHD','SCHD','PRSA','Seasons']
X=data[feature_cols];
y=data['Sales']
y_gunther=data['PRSA']          # PREDICTIVE SALES OF GUNTHER
lr=LinearRegression()

min_rmse=10000
lr_opt=LinearRegression()

print("\n=======Iterating for 15 times splitting randomly to find the best fitting LR model ==========")
for i in range(1,15):
    X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.8)
    lr.fit(X_train,y_train)
    y_pred=lr.predict(X_test)
    rmse=np.sqrt(metrics.mean_squared_error(y_test,y_pred))
    if min_rmse > rmse:
        min_rmse=rmse
        lr_opt=lr

print("\nOur training intercept ",lr_opt.intercept_)
print("\nOur training coefficients\n")
print(feature_cols)
print(lr_opt.coef_)
print("\nThe minimum root mean square error over the iteration is \n",min_rmse)
print("==============fitting the same model for overall price predictions=============")
y_pred_all=lr_opt.predict(X)
gunther_loss = y_gunther.sum()-y.sum()
our_pred=y_pred_all.sum()-y.sum()
print("\nGunter loss from Jan 2016 to April 2017 compared to actual sales ",gunther_loss)
if our_pred <0:
    print("\nOur prediction is only ",-our_pred," less than actual sales")
else:
    print("\n Our predition is only ",our_pred," more than actual sales",)

print("\n=========== predicting the price =========== \n")
x1=float(sys.argv[1])
x2=float(sys.argv[2])
x3=float(sys.argv[3])
x4=float(sys.argv[4])
x5=float(sys.argv[5])
x6=float(sys.argv[6])
x7=float(sys.argv[7])
x8=float(sys.argv[9])
x9=float(sys.argv[9])
X_enter=[x1,x2,x3,x4,x5,x6,x7,x8,x9]
y_new_pred=lr_opt.predict(X_enter)

print("\nThe predicting price for the day is ",y_new_pred)


import argparse
from dataclasses import dataclass, field

class Instruction:
    def __init__(self, txt):
        split = txt.split(' ')
        self.cmd = split[0]
        self.arg = int(split[1])

    def apply(self, state):
        if self.cmd == "acc":
            return ProgramState(pc=state.pc + 1, acc=state.acc + self.arg)
        elif self.cmd == "jmp":
            return ProgramState(pc=state.pc + self.arg, acc=state.acc)
        elif self.cmd == "nop":
            return ProgramState(pc=state.pc + 1, acc=state.acc)

    def swap(self):
        if self.cmd == "acc":
            return False
        if self.cmd == "jmp":
            self.cmd = "nop"
            return True
        if self.cmd == "nop":
            self.cmd = "jmp"
            return True

@dataclass
class ProgramState:
    pc: int = field(default=0)
    acc: int = field(default=0)

class Executor:
    def __init__(self):
        self.state = ProgramState()

    def execute(self, program):
        visits = {}
        while self.state.pc not in visits:
            if self.state.pc == len(program):
                return True, self.state.acc
            visits[self.state.pc] = self.state.acc
            instruction = program[self.state.pc]
            self.state = instruction.apply(self.state)

        return False, self.state.acc

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("filename", default="./sample.txt")
    args = parser.parse_args()
    program = []
    with open(args.filename) as f:
        for line in f.readlines():
            program.append(Instruction(line.strip()))

    for i in range(0, len(program)):
        if (program[i].swap()):
            executor = Executor()
            success, acc = executor.execute(program)
            if success:
                print(acc)
                return
            program[i].swap()

if __name__ == '__main__':
    main()


from django.db import models
from users.models import User

from dataclasses import dataclass

class ConnectionRequest(models.Model):
    number = models.PositiveIntegerField(db_index=True, verbose_name='Номер заявки')
    client = models.ForeignKey(
        'Client', related_name='connection_requests',
        on_delete=models.PROTECT,
        verbose_name='Клиент'
    )
    status = models.ForeignKey(
        'Status', related_name='connection_requests',
        on_delete=models.PROTECT,
        verbose_name='Статус заявки'
    )
    date_entered_status = models.DateTimeField(
        verbose_name='Дата входа заявки в статус'
    )
    service = models.ForeignKey(
        'Service', related_name='connection_requests',
        on_delete=models.PROTECT,
        verbose_name='Услуга'
    )
    additional_sales_channel = models.ForeignKey(
        'AdditionalSalesChannel',
        related_name='connection_requests',
        on_delete=models.PROTECT,
        blank=True, null=True,
        verbose_name='Доп.канал продаж'
    )
    reg_date = models.DateTimeField(verbose_name='Дата регистрации')
    reg_date_for_request = models.DateTimeField(
        null=True, verbose_name='Дата регистрации под заявки'
    )
    reg_date_brigade_for_TVP = models.DateTimeField(
        null=True, verbose_name='Регистрация наряда на ТВП'
    )
    completed_by = models.ForeignKey(
        User, related_name='completed_connection_requests',
        on_delete=models.PROTECT,
        blank=True, null=True,
        verbose_name='Оператор завершивший заявку'
    )
    rejection_date = models.DateTimeField(
        null=True, verbose_name='Дата отклонения под заявки'
    )
    TVP_test_type = models.ForeignKey(
        'TVPTestType', related_name='connection_requests',
        on_delete=models.PROTECT, null=True,
        verbose_name='Тип проверки ТВП'
    )
    TVP_presence = models.ForeignKey(
        'TVPPresence', related_name='connection_requests',
        on_delete=models.PROTECT, null=True,
        verbose_name='Наличие ТВП'
    )
    completion_TVP_date = models.DateTimeField(
        null=True, verbose_name='Завершение проверки ТВП'
    )
    TVP_check_duration = models.TimeField(
        null=True, verbose_name='Длительность проверки ТВП'
    )
    agreed_connection_date = models.DateTimeField(
        blank=True, null=True, verbose_name='Согласованная дата подключения'
    )
    installer = models.ForeignKey(
        'Installer', related_name='connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Инсталлятор'
    )
    agent_installer = models.ForeignKey(
        'AgentInstaller', related_name='connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Агент-инсталлятор'
    )
    comment_TVP_ShPD = models.CharField(
        max_length=250, blank=True, verbose_name='Комментарий ТВП ШПД',
        null=True
    )
    started_by = models.ForeignKey(
        User, related_name='started_connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Оператор заводивший заявку'
    )
    id_agreement_KURS = models.CharField(
        max_length=250, blank=True, verbose_name='ID Договор КУРС',
        null=True
    )
    note = models.CharField(
        max_length=250, blank=True, verbose_name='Примечание',
        null=True
    )
    contact_phone_number = models.PositiveIntegerField(
        blank=True, null=True, verbose_name='Контактный телефон',
        default=0
    )
    contact_person = models.CharField(
        max_length=200, blank=True, verbose_name='Контактное лицо',
        null=True
    )
    TP_ShPD_price = models.DecimalField(
        max_digits=8, decimal_places=2, blank=True,
        null=True, verbose_name='Стоимость ТП (ШПД)'
    )
    TP_IPTV_price = models.DecimalField(
        max_digits=8, decimal_places=2, blank=True,
        null=True, verbose_name='Стоимость ТП (IPTV)'
    )
    contract_created_by_fio = models.CharField(
        max_length=250, blank=True,
        verbose_name='ФИО сотрудника создавшего договор',
        null=True
    )
    IPTV_tariff_plan = models.ForeignKey(
        'IPTVTariffPlan', related_name='connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Тарифный план IPTV'
    )
    access_card_number = models.PositiveIntegerField(
        blank=True, null=True, verbose_name='Номер карты доступа'
    )
    IPTV_access_card_number = models.PositiveIntegerField(
        blank=True, null=True, verbose_name='Номер карты доступа IPTV'
    )
    tariff_plan = models.ForeignKey(
        'TariffPlan', related_name='connection_requests',
        on_delete=models.PROTECT, blank=True, null=True,
        verbose_name='Тарифный план'
    )
    client_number_SUS = models.PositiveIntegerField(
        blank=True, null=True, verbose_name='№ клиентский СУС'
    )
    sending_date_APTV = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата отправки на АПТВ'
    )
    finishing_date_APTV_planned = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата окончания АПТВ планируемая'
    )
    finishing_date_APTV_actual = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата окончания АПТВ фактическая'
    )
    APTV_duration = models.DurationField(
        blank=True, null=True, verbose_name='Длительность этапа АПТВ'
    )
    sending_date_DO = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата отправки на ДО'
    )
    finishing_date_DO_planned = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата окончания ДО планируемая'
    )
    finishing_date_DO_actual = models.DateTimeField(
        blank=True, null=True, verbose_name='Дата окончания ДО фактическая'
    )
    DO_duration = models.DurationField(
        blank=True, null=True, verbose_name='Длительность этапа ДО',
    )

    class Meta:
        verbose_name = 'Заявка на подключение'
        verbose_name_plural = 'Заявки на подключение'
        ordering = ('-date_entered_status',)

    def __str__(self):
        return f"Заявка №{self.number}"

class Client(models.Model):
    title = models.CharField(max_length=250, verbose_name='Название клиента')
    INN = models.PositiveBigIntegerField(db_index=True, verbose_name='ИНН')

    class Meta:
        verbose_name = 'Клиент'
        verbose_name_plural = 'Клиенты'

    def __str__(self):
        return self.title

class Status(models.Model):
    title = models.CharField(max_length=100, verbose_name='Название')
    group = models.ForeignKey(
        'StatusGroup', related_name='statuses',
        on_delete=models.PROTECT, verbose_name='Группа'
    )

    class Meta:
        verbose_name = 'Статус заявки'
        verbose_name_plural = 'Статусы заявок'
        ordering = ('group', 'title')

    def __str__(self):
        return self.title

class StatusGroup(models.Model):
    title = models.CharField(max_length=30, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Группа статуса'
        verbose_name_plural = 'Группы статусов'

    def __str__(self):
        return self.title

class Service(models.Model):
    title = models.CharField(max_length=50, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Услуга'
        verbose_name_plural = 'Услуги'

    def __str__(self):
        return self.title

class AdditionalSalesChannel(models.Model):
    title = models.CharField(max_length=60, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Доп.канал продажи'
        verbose_name_plural = 'Доп.каналы продажи'

    def __str__(self):
        return self.title

class TVPTestType(models.Model):
    title = models.CharField(max_length=50, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Тип проверки ТВП'
        verbose_name_plural = 'Типы проверок ТВП'

    def __str__(self):
        return self.title

class TVPPresence(models.Model):
    title = models.CharField(max_length=50, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Наличие ТВП'
        verbose_name_plural = 'Наличие ТВП'

    def __str__(self):
        return self.title

class Installer(models.Model):
    first_name = models.CharField(max_length=50, verbose_name='Имя')
    last_name = models.CharField(max_length=50, verbose_name='Фамилия')
    surname = models.CharField(max_length=50, verbose_name='Отчество')

    class Meta:
        verbose_name = 'Инсталлятор'
        verbose_name_plural = 'Инсталляторы'

    def __str__(self):
        return f"{self.last_name} {self.first_name} {self.surname}"

class AgentInstaller(models.Model):
    title = models.CharField(max_length=250, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Агент-инсталлятор'
        verbose_name_plural = 'Агенты-инсталляторы'

    def __str__(self):
        return self.title

class IPTVTariffPlan(models.Model):
    title = models.CharField(max_length=100, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Тарифный план IPTV'
        verbose_name_plural = 'Тарифные планы IPTV'

    def __str__(self):
        return self.title

class TariffPlan(models.Model):
    title = models.CharField(max_length=100, unique=True, verbose_name='Название')

    class Meta:
        verbose_name = 'Тарифный план'
        verbose_name_plural = 'Тарифные планы'

    def __str__(self):
        return self.title

#
# class File(models.Model):
#     title = models.CharField(max_length=256, default='No title', verbose_name='Название')
#     file = models.FileField(upload_to='files', verbose_name='Файл')
#     upload_at = models.DateTimeField(auto_now_add=True, verbose_name='Дата загрузки')
#
#     class Meta:
#         verbose_name = 'Файл .xlsx с заявками'
#         verbose_name_plural = 'Файлы .xlsx с заявками'
#         ordering = ('-upload_at',)
#

@dataclass
class DataExel:
    number: int
    client: str
    inn: int
    status: str
    date_entered_status: str
    service: str
    additional_sales_channel: str
    reg_date: str
    reg_date_for_request: str
    reg_date_brigade_for_TVP: str
    completed_by: str
    rejection_date: str
    TVP_test_type: str
    TVP_presence: str
    completion_TVP_date: str
    TVP_check_duration: str
    agreed_connection_date: str
    installer: str
    agent_installer: str
    comment_TVP_ShPD: str
    started_by: str
    id_agreement_KURS: str
    number_agreement_KURS: str
    note: str
    contact_phone_number: str
    contact_person: str
    TP_ShPD_price: str
    TP_IPTV_price: str
    contract_created_by_fio: str
    IPTV_tariff_plan: str
    access_card_number: str
    IPTV_access_card_number: str
    tariff_plan: str
    client_number_SUS: str
    sending_date_APTV: str
    finishing_date_APTV_planned: str
    finishing_date_APTV_actual: str
    APTV_duration: str
    sending_date_DO: str
    finishing_date_DO_planned: str
    finishing_date_DO_actual: str
    DO_duration: str


import streamlit as st
import pandas as pd
import copy
import pickle
import matplotlib.pyplot as plt
import networkx as nx

setlist = ["volcano","earthquake","light","heat"]
rel_list = ["is a type of","is a superset of","is identical to","is disjoint from","overlaps with"]

if 'save_res' not in st.session_state:
  st.session_state.save_res = False

try:

  #phendf = pd.read_csv('phendf.csv')
  file0 = open('setdf.pkl',"rb")
  setdf = pickle.load(file0)
  file0.close()
  #phendf = phendf.loc[:,['phen1','rel','phen2']]
except:
  st.write('creating new setdf')
  setdf = pd.DataFrame()

try:
  #current_vals = pd.read_csv('currentvals.csv')
  file1 = open('current_vals_set.pkl',"rb")
  current_vals = pickle.load(file1)
  file1.close()
except:
  st.write('creating new current vals')
  current_vals = dict()
  current_vals['set1'] = setlist[0]
  current_vals['rel'] = rel_list[0]
  current_vals['set2'] = setlist[1]

if current_vals['set1'] not in setlist:
    current_vals['set1'] = setlist[0]
if current_vals['set2'] not in setlist:
    current_vals['set2'] = setlist[1]

col1,col2,col3,col4 = st.columns(4)

with col1:
  set1 = st.selectbox(label = "Choose set 1",options = setlist,index = setlist.index(current_vals['set1']))

with col2:
  rel = st.selectbox(label = "Choose relationship",options = rel_list,index=rel_list.index(current_vals['rel']))

with col3:
  set2 = st.selectbox(label = "Choose phenomenon 2",options = setlist,index=setlist.index(current_vals['set2']))

current_vals['set1'] = set1
current_vals['rel'] = rel
current_vals['set2'] = set2
file2 = open("current_vals_set.pkl", "wb")
pickle.dump(current_vals,file2)
file2.close()

st.write(set1,rel,set2)

# with col4:
#   st.button(label = "+",on_click = onclicksave)
with col4:
  st.session_state.save_res = st.button(label = "+")

st.write(st.session_state.save_res)

if st.session_state.save_res:
    #onclicksave()
  setdf = setdf.append({'set1':set1,'rel':rel,'set2':set2},ignore_index=True)
  setdf = setdf.drop_duplicates()
  file3 = open('setdf.pkl',"wb")
  pickle.dump(setdf,file3)
  file3.close()

if setdf.shape[0]>0:
  fig, ax = plt.subplots()
  G = nx.from_pandas_edgelist(setdf, 'set1', 'set2',['rel'],create_using=nx.DiGraph())
  pos = nx.planar_layout(G)
  nx.draw(G, pos, with_labels=True)
  edge_labels = nx.get_edge_attributes(G,'rel')
  nx.draw_networkx_edge_labels(G, pos, edge_labels = edge_labels)
  st.pyplot(fig)
  st.table(setdf)


import os
import datetime as dt
import joblib
import pandas as pd

from sklearn.metrics import balanced_accuracy_score, accuracy_score, mean_squared_error, mean_absolute_error

from configuration import model_dir
from src.utils.base_model import load_model, time_function, get_logger
from src.utils.db import run_query
from src.utils.general import safe_open

logger = get_logger()

class BaseModel:
    """Anything that can be used by any model goes in this class"""

    def __init__(self, model_object=None, load_trained_model=True, save_trained_model=True,
                 test_mode=False, load_model_date=None, problem_name=None, compare_models=True,
                 is_classifier=False):
        # Store all arguments passed to __init__ inside the class,
        # so we know what they were later
        self.model_object = model_object
        self.load_trained_model = load_trained_model
        self.save_trained_model = save_trained_model
        self.test_mode = test_mode
        self.load_model_date = load_model_date
        self.problem_name = problem_name
        self.compare_models = compare_models
        # The date this class was instantiated
        self.creation_date = str(dt.datetime.today().date())
        # The name of the model you want to use
        self.model_type = self.model_object.__name__
        # A unique identifier for this model
        self.model_id = "{}_{}_{}_{}".format(
            self.problem_name, self.model_type, self.creation_date, str(abs(hash(dt.datetime.today()))))
        # Store the trained model here
        self.trained_model = self.load_model(load_model_date) if load_trained_model else None
        # Load previous best model
        self.previous_model = self.load_model()
        # The name of all features in the model, specified as a list
        self.model_features = None
        # Model parameters
        self.params = None
        # A place to store predictions made by the model
        self.model_predictions = None
        # What name to give the problem the model is trying to solve
        self.problem_name = problem_name
        # A list of performance metrics (pass the functions, they must
        # take actuals, predictions as the first and second arguments
        self.performance_metrics = [balanced_accuracy_score, accuracy_score] \
            if is_classifier else [mean_squared_error, mean_absolute_error]
        # A dictionary to store the performance metrics for the trained model
        self.performance = {}
        # Name of the target variable (or variables, stored in a list)
        self.target = None
        # A query used to retrieve training data
        self.training_data_query = None
        # Store names of categorical features
        self.categorical_features = None

    def get_training_data(self) -> pd.DataFrame:
        """Retrieve training data (by querying a DB or otherwise)"""

        df = run_query(query=self.training_data_query)
        return df

    def clean_input_data(self, df):
        """Add any data cleaning steps here (before generating features)"""
        return NotImplemented

    def generate_features(self, X) -> pd.DataFrame:
        """Put code to generate features from cleaned input data here"""
        return NotImplemented

    def encode_cateogrical_features(self, X) -> pd.DataFrame:
        """One-hot encode categorical features and add them to the feature list"""

        for feature in self.categorical_features:
            X_dummies = pd.get_dummies(X[feature], prefix=feature)
            # Get encoded features
            X = pd.concat([X.drop(feature, axis=1), X_dummies], axis=1)
            # Add encoded features to the feature list
            self.model_features.append(X_dummies.columns)
        # Remove categorical features from the feature list
        self.model_features = [
            feature for feature in self.model_features if feature not in self.categorical_features]
        return X

    def preprocess(self, X) -> pd.DataFrame:
        return X

    def optimise_hyperparams(self, X, y, param_grid=None) -> None:
        return NotImplemented

    def train_model(self, X, y) -> None:
        return NotImplemented

    def predict(self, X):  # ToDo: Find out what datatype is output
        """Predict on a new set of data"""

        X = self.preprocess(X[self.model_features])
        return self.trained_model.predict(X[self.model_features])

    def save_training_data(self) -> None:
        return NotImplemented

    def save_prediction_data(self, *, cols_to_save) -> None:
        return NotImplemented

    @time_function(logger=logger)
    def save_model(self, save_to_production=False) -> None:
        """Save a trained model to the models directory"""

        if self.trained_model is None:
            logger.error("There is no model to save, aborting.")
        else:
            # Save the model ID inside the model object (so we know which
            # model made which predictions in the DB)
            self.trained_model.model_id = self.model_id
            self.trained_model.model_features = self.model_features
            self.trained_model.performance_metrics = self.performance_metrics
            self.trained_model.performance = self.performance
            file_name = self.model_id + '.joblib'
            save_dir = os.path.join(model_dir, file_name)
            logger.info("Saving model to {} with joblib.".format(save_dir))
            with safe_open(save_dir, "wb") as f_out:
                joblib.dump(self.trained_model, f_out)
            if save_to_production:
                save_dir = os.path.join(model_dir, 'in_production', file_name)
                with safe_open(save_dir, "wb") as f_out:
                    joblib.dump(self.trained_model, f_out)

    @time_function(logger=logger)
    def load_model(self, date=None) -> None:
        """Load model from the local filesystem"""

        model = load_model(self.model_type, date=date, keyword=self.problem_name)
        if model is None:
            logger.warning('No available models of type {}.'.format(self.model_type))
            return None
        else:
            # Set the attributes of the model to those of the class
            self.model_id = model.model_id
            if hasattr(model, 'params'):
                self.params = model.params
            if hasattr(model, 'model_features'):
                self.model_features = model.model_features
            if hasattr(model, 'performance_metrics'):
                self.performance_metrics = model.performance_metrics
            if hasattr(model, 'performance'):
                self.performance = model.performance
            else:
                logger.warning('The loaded model has no get_params method, '
                               'cannot load model parameters.')
            return model

    @time_function(logger=logger)
    def compare_latest_model(self) -> bool:
        """Compare the newly trained model with the previous model of the same name (if one exists).
            Return True if the new model performs best, otherwise return False """

        main_performance_metric = self.performance_metrics[0].__name__
        new_performance = self.performance.get(main_performance_metric)
        old_performance = self.previous_model.performance.get(main_performance_metric)
        if new_performance > old_performance:
            logger.info('New model beats previous model. Replacing this model')
            logger.info('{}: Previous Model: {}, New Model: {}'.format(
                main_performance_metric, old_performance, new_performance
            ))
            return True
        else:
            logger.info('New model does not beat previous model.')
            logger.info('{}: Previous Model: {}, New Model: {}'.format(
                main_performance_metric, old_performance, new_performance
            ))
            return False


import torch
import torch.nn as nn
import torch.nn.functional as F
from pytorch_lightning import LightningModule
from sklearn.metrics import f1_score
from pytorch_lightning.callbacks import LearningRateMonitor
from torch.optim.lr_scheduler import OneCycleLR

class MaskedMSELoss(nn.Module):
    def __init__(self):
        super().__init__()
        self.mse = nn.MSELoss(reduction="none")

    def forward(self, pred, target, mask):
        loss = self.mse(pred, target)
        masked_loss = loss * mask
        if mask.sum() == 0:
            return masked_loss.sum()
        return masked_loss.sum() / mask.sum()

class GRUD(LightningModule):
    def __init__(
        self,
        input_size,
        hidden_size,
        output_size=6,
        learning_rate=0.001,
        finetune=False,
    ):
        super(GRUD, self).__init__()
        self.hidden_size = hidden_size
        self.grud_cell = GRUDCell(input_size, hidden_size)
        self.fc = nn.Linear(hidden_size, output_size)
        self.loss_fn = nn.CrossEntropyLoss()
        self.learning_rate = learning_rate
        self.finetune = finetune

    def forward(self, x, x_mean, mask, delta):
        batch_size, seq_len, _ = x.size()
        h = torch.zeros(batch_size, self.hidden_size).to(x.device)
        for t in range(seq_len):
            h = self.grud_cell(
                x[:, t, :], h, x_mean[:, t, :], mask[:, t, :], delta[:, t, :]
            )
        out = self.fc(h)
        # print(out.shape)
        return out

    def training_step(self, batch, batch_idx):
        x, x_mean, mask, delta, y = batch
        pred = self.forward(x, x_mean, mask, delta)
        # y = torch.argmax(y, dim=1)
        # pred = torch.argmax(pred, dim=1)
        loss = self.loss_fn(pred, y)
        self.log("train_loss", loss)
        return loss

    def validation_step(self, batch, batch_idx):
        x, x_mean, mask, delta, y = batch
        pred = self.forward(x, x_mean, mask, delta)
        # y = torch.argmax(y, dim=1)
        loss = self.loss_fn(pred, y)

        # Calculate accuracy
        pred_classes = torch.argmax(pred, dim=1)
        acc = (pred_classes == y).float().mean()

        # Log loss and accuracy
        self.log("val_loss", loss, prog_bar=True)
        self.log("val_acc", acc, prog_bar=True)

        return loss

    def test_step(self, batch, batch_idx):
        x, x_mean, mask, delta, y = batch
        pred = self(x, x_mean, mask, delta)
        # y = torch.argmax(y, dim=1)  # convert one-hot to class indices

        # Compute loss
        loss = self.loss_fn(pred, y)

        pred = torch.argmax(
            pred, dim=1
        )  # get the class with highest predicted probability

        # Compute accuracy
        correct_predictions = (pred == y).float()
        acc = correct_predictions.sum() / len(correct_predictions)

        # Compute F1-score
        f1 = f1_score(y.detach().cpu(), pred.detach().cpu(), average="macro")

        # Log the loss, accuracy, and F1-score
        self.log("test_loss", loss, prog_bar=True)
        self.log("test_acc", acc, prog_bar=True)
        self.log(
            "test_f1", torch.tensor(f1), prog_bar=True
        )  # f1_score returns a numpy float, need to convert to tensor

        return loss

    def configure_optimizers(self):
        if self.finetune:
            # Initialize a warm up phase for the first 20% of training steps
            optimizer = torch.optim.Adam(self.parameters(), lr=0.0001)
            steps_per_epoch = len(self.train_dataloader())
            num_training_steps = steps_per_epoch * self.trainer.max_epochs
            lr_scheduler = {
                "scheduler": OneCycleLR(
                    optimizer,
                    0.001,
                    total_steps=num_training_steps,
                    anneal_strategy="linear",
                    pct_start=0.2,
                ),
                "name": "learning_rate",
                "interval": "step",
                "frequency": 1,
            }
            return [optimizer], [lr_scheduler]
        return torch.optim.Adam(self.parameters(), lr=self.learning_rate)

class APCModel(LightningModule):
    def __init__(self, input_size, hidden_size, output_size):
        super(APCModel, self).__init__()
        self.hidden_size = hidden_size
        self.grud_cell = GRUDCell(input_size, hidden_size)
        self.fc = nn.Linear(
            hidden_size, output_size
        )  # output_size is the same as input_size for APC
        self.loss_fn = MaskedMSELoss()

    def forward(self, x, x_mean, mask, delta):
        batch_size, seq_len, _ = x.size()
        h = torch.zeros(batch_size, self.hidden_size).to(x.device)
        outputs = []
        for t in range(seq_len):
            h = self.grud_cell(
                x[:, t, :], h, x_mean[:, t, :], mask[:, t, :], delta[:, t, :]
            )
            output = self.fc(h)
            outputs.append(output)
        return torch.stack(outputs, dim=1)

    def training_step(self, batch, batch_idx):
        x, x_mean, mask, delta, y = batch
        pred = self.forward(x, x_mean, mask, delta)
        pred = pred[:, -1, :]
        mask = mask[:, -1, :]
        loss = self.loss_fn(pred, y, mask)
        self.log("train_loss", loss)
        return loss

    def configure_optimizers(self):
        return torch.optim.Adam(self.parameters(), lr=0.001)

class GRUDCell(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(GRUDCell, self).__init__()
        self.input_size = input_size
        self.hidden_size = hidden_size

        # Define the parameters for the GRU-D
        self.weight_z = nn.Parameter(
            torch.Tensor(hidden_size, input_size + hidden_size)
        )
        self.weight_r = nn.Parameter(
            torch.Tensor(hidden_size, input_size + hidden_size)
        )
        self.weight_h_tilde = nn.Parameter(
            torch.Tensor(hidden_size, input_size + hidden_size)
        )

        # Define the parameters for the decay rates
        self.weight_gamma_x = nn.Parameter(torch.Tensor(input_size))
        self.weight_gamma_h = nn.Parameter(torch.Tensor(hidden_size))

        self.bias = nn.Parameter(torch.Tensor(hidden_size))

        # Initialize parameters
        self.reset_parameters()

    def reset_parameters(self):
        nn.init.xavier_uniform_(self.weight_z)
        nn.init.xavier_uniform_(self.weight_r)
        nn.init.xavier_uniform_(self.weight_h_tilde)

        # Initialize the decay rates with uniform because they have less than 2 dimensions
        nn.init.uniform_(self.weight_gamma_x, a=0.0, b=1.0)
        nn.init.uniform_(self.weight_gamma_h, a=0.0, b=1.0)
        nn.init.zeros_(self.bias)

    def forward(self, x, h_prev, x_mean, mask, delta):
        """
        x: current input
        h_prev: previous hidden state
        x_mean: the mean value of the input x
        mask: binary mask that indicates the presence of missing values
        delta: time intervals between two consecutive visits
        """

        gamma_x = torch.exp(
            -torch.max(
                torch.zeros_like(delta),
                self.weight_gamma_x * delta
                # + self.bias_gamma_x,
            )
        )
        gamma_h = torch.exp(
            -torch.max(
                torch.zeros_like(delta),
                self.weight_gamma_h * delta,
            )
        )

        x_hat = gamma_x * x + (1 - gamma_x) * mask * x_mean
        h_prev = gamma_h * h_prev

        z = torch.sigmoid(
            F.linear(
                torch.cat((x_hat, h_prev), dim=1), self.weight_z, self.bias
            )
        )
        r = torch.sigmoid(
            F.linear(
                torch.cat((x_hat, h_prev), dim=1), self.weight_r, self.bias
            )
        )
        h_tilde = torch.tanh(
            F.linear(
                torch.cat((x_hat, r * h_prev), dim=1),
                self.weight_h_tilde,
                self.bias,
            )
        )
        h_next = (1 - z) * h_prev + z * h_tilde

        return h_next


# coding: utf-8

__author__ = ["Samuel Joshua"]

import pyautogui
# to write anything to the interface, first open notepad, click on the position where you want to write then write
# to do this in a single line
pyautogui.click(100, 100);pyautogui.typewrite('Hello world!')
pyautogui.click(100, 100);pyautogui.typewrite('Hello world!', interval=0.2)

# to use keys, just pass it a list of keys to press
# so below code presses the a key, b key, then left button, left again, then caps X and Y
pyautogui.click(100, 100);pyautogui.typewrite(['a', 'b', 'left', 'left', 'X', 'Y'], interval=1)

# PRINTS ALL THE AVAILABLE KEYBOARD KEYS
print(pyautogui.KEYBOARD_KEYS)

# to press just one key
# pressing the F5 key here for example
pyautogui.press('f5')

# to open multiple keys in combination
pyautogui.click(100, 100);pyautogui.hotkey('ctrl', 'o')


class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    def get_descriptive_name(self):
        long_name = f'{self.make} {self.model} {self.year}'
        return long_name.title()

class Battery():
    """Uma tentativa simples de modelar uma bateria para um carro elétrico."""

    def __init__(self, battery_size=70):
        """Inicializa os atributos da bateria"""
        self.battery_size = battery_size

    def describe_battery(self):
        """Exibe uma frase que descreve a capacidade da bateria."""
        print(f'This car has a {self.battery_size} kWh battery.')

    def get_range(self):
        """Exibe uma frase sobre a distância que o carro é capaz de percorrer com essa bateria."""
        if self.battery_size == 70:
            range = 240
        elif self.battery_size == 85:
            range = 270

        message = f'This car can go approximately {range} miles on a full charge.'
        print(message)

class EletricCar(Car):
    "Representa aspectos especificos de veículos elétricos."

    def __init__(self, make, model, year):
        """Inicializa os atributos da classe-pai. Em seguida, inicializa os atributos especificos de um carro
        eletrico."""
        super().__init__(make, model, year)
        self.battery = Battery()

carro = Car('Honda', 'Civic', 2022)
carro_eletrico = EletricCar('Tesla', 'Model S', 2023)

print(carro.get_descriptive_name())

print(carro_eletrico.get_descriptive_name())
carro_eletrico.battery.describe_battery()
carro_eletrico.battery.get_range()


# moleculeloader.py

import pandas as pd
from rdkit import Chem
from rdkit.Chem import Descriptors

class MoleculeLoader:
    """
    A class used to load and process molecular data.
    """
    def __init__(self, datafile: str, smi_col: str, scores_col: str) -> None:
        """
        Initializes the MoleculeLoader with a data file.

        Args:
            - datafile (str): The name of the data file to load.
            - smi_col (str): The name of the column containing SMILES strings in the `DataFrame`.
            - scores_col(str): The name of the column containing the docking scores in the `DataFrame`.
        """
        self.datafile = datafile
        self.smi_col = smi_col
        self.scores_col = scores_col
        self._df = None

    def _load_data(self) -> pd.DataFrame:
        """
        Loads data from the data file into a DataFrame.

        This method is called automatically when accessing the `df` property
        if the data has not been loaded yet.

        Returns:
            - pd.DataFrame: The loaded data.
        """
        self._df = pd.read_csv(self.datafile)

    def _process_data(self):
        """
        Processes the loaded DataFrame.
        """
        if 'molecules' not in self._df.columns:
            self._df['molecules'] = self._df[self.smi_col].apply(Chem.MolFromSmiles)

        #self._df.rename(columns={self.scores_col: "scores"}, inplace=True)
        #self._df.rename(columns={self.smi_col: "SMILES"}, inplace=True)

        self._df.sort_values(by=self.scores_col)

    @property
    def df(self):
        """
        Provides access to the loaded and processed DataFrame.

        If the data has not been loaded yet, it is loaded automatically
        the first time this property is accessed.

        Returns:
            - pd.DataFrame: The loaded DataFrame.
        """
        if self._df is None:
            self._load_data()
            self._process_data()
        return self._df

    def filter_by_mol_wt(self, MolWt: int):
        if self._df is None:
            raise ValueError("DataFrame is not loaded. Please load the data using .df on your object.")

        self._df = self._df[self._df['molecules'].apply(Descriptors.MolWt) < MolWt]

        return self

    def filter_by_num_atoms(self, max_atoms: int):
        if self._df is None:
            raise ValueError("DataFrame is not loaded. Please load the data using .df on your object.")

        self._df = self._df[self._df['molecules'].apply(lambda mol: mol.GetNumAtoms()) <= max_atoms]

        return self


import matplotlib.pyplot as plt
from matplotlib import patches
import cv2 as cv

from imaging.colordetect.color_segment import ColorSegmentationResult

def get_rectangle_edges_from_pascal_bbox(bbox):
    xmin_top_left, ymin_top_left, xmax_bottom_right, ymax_bottom_right = bbox

    bottom_left = (xmin_top_left, ymax_bottom_right)
    width = xmax_bottom_right - xmin_top_left
    height = ymin_top_left - ymax_bottom_right

    return bottom_left, width, height

def draw_pascal_voc_bboxes(
        plot_ax: plt,
        bboxes,
        labels,
        confidences=None,
        get_rectangle_corners_fn=get_rectangle_edges_from_pascal_bbox,
        labels_dict=None
):
    for bbox, label, i in zip(bboxes, labels, range(len(labels))):
        bottom_left, width, height = get_rectangle_corners_fn(bbox)

        rect_1 = patches.Rectangle(
            bottom_left,
            width,
            height,
            linewidth=4,
            edgecolor="black",
            fill=False,
        )
        rect_2 = patches.Rectangle(
            bottom_left,
            width,
            height,
            linewidth=2,
            edgecolor="white",
            fill=False,
        )
        if labels_dict is not None:
            label = labels_dict[int(label)]
        if confidences is not None:
            label = f"{label} ({confidences[i]:.1%})"

        plot_ax.text(x=bottom_left[0] + width // 2,
                     y=bottom_left[1] + height - 10,
                     s=label,
                     color="white",
                     backgroundcolor="black",
                     horizontalalignment="center",
                     verticalalignment="center")
        # Add the patch to the Axes
        plot_ax.add_patch(rect_1)
        plot_ax.add_patch(rect_2)

def show_image(
        image, bboxes=None, labels=None, confidences=None, draw_bboxes_fn=draw_pascal_voc_bboxes, figsize=(10, 10),
        labels_dict=None, file_name=None
):
    fig, ax = plt.subplots(1, figsize=figsize)
    ax.imshow(image)

    if bboxes is not None:
        draw_bboxes_fn(ax, bboxes, labels, confidences=confidences, labels_dict=labels_dict)
    if file_name is not None:
        plt.savefig(file_name)
    else:
        plt.show()

def show_image_cv(
        image: cv.Mat, bboxes=None, labels=None, confidences=None, file_name=None, font_scale=2,
        thickness=1, box_color=(255, 255, 255), text_color=(255, 255, 255),
        color_results: "list[ColorSegmentationResult]" = None
):
    for bbox, label, color_res in zip(bboxes, labels,color_results):
        x0, y0, x1, y1 = map(int, bbox)
        image = cv.rectangle(image, (x0, y0), (x1, y1), color=box_color, thickness=thickness)
        cv.putText(image, label, (x0, y0), cv.FONT_HERSHEY_PLAIN, font_scale, text_color,thickness)

        cv.putText(image, "Shape", (max(0,x0-40), y1+20), cv.FONT_HERSHEY_PLAIN, font_scale, text_color,thickness, bottomLeftOrigin=False)
        cv.putText(image, "Letter", (x1, y1+20), cv.FONT_HERSHEY_PLAIN, font_scale, text_color,thickness, bottomLeftOrigin=False)

        cv.circle(image, (x0,y1), 5, color_res.shape_color.tolist(), -1)
        cv.circle(image, (x1,y1), 5, color_res.letter_color.tolist(), -1)
    if file_name is not None:
        cv.imwrite(file_name, image)
    else:
        plt.imshow(image)
        plt.show()

def compare_bboxes_for_image(
        image,
        predicted_bboxes,
        actual_bboxes,
        predicted_labels,
        actual_labels,
        confidences=None,
        draw_bboxes_fn=draw_pascal_voc_bboxes,
        figsize=(20, 20),
        labels_dict=None
):
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize)
    ax1.imshow(image)
    ax1.set_title("Prediction")
    ax2.imshow(image)
    ax2.set_title("Actual")

    draw_bboxes_fn(ax1, predicted_bboxes, predicted_labels, confidences, labels_dict=labels_dict)
    draw_bboxes_fn(ax2, actual_bboxes, actual_labels, labels_dict=labels_dict)

    plt.show()


#!/usr/bin/env python
# encoding: utf-8

"""
Waf tool for ChibiOS build
"""

from waflib import Errors, Logs, Task, Utils
from waflib.TaskGen import after_method, before_method, feature

import os
import shutil
import sys
import re
import pickle

_dynamic_env_data = {}
def _load_dynamic_env_data(bld):
    bldnode = bld.bldnode.make_node('modules/ChibiOS')
    tmp_str = bldnode.find_node('include_dirs').read()
    tmp_str = tmp_str.replace(';\n','')
    tmp_str = tmp_str.replace('-I','')  #remove existing -I flags
    # split, coping with separator
    idirs = re.split('; ', tmp_str)

    # create unique list, coping with relative paths
    idirs2 = []
    for d in idirs:
        if d.startswith('../'):
            # relative paths from the make build are relative to BUILDROOT
            d = os.path.join(bld.env.BUILDROOT, d)
        d = os.path.normpath(d)
        if not d in idirs2:
            idirs2.append(d)
    _dynamic_env_data['include_dirs'] = idirs2

@feature('ch_ap_library', 'ch_ap_program')
@before_method('process_source')
def ch_dynamic_env(self):
    # The generated files from configuration possibly don't exist if it's just
    # a list command (TODO: figure out a better way to address that).
    if self.bld.cmd == 'list':
        return

    if not _dynamic_env_data:
        _load_dynamic_env_data(self.bld)
    self.use += ' ch'
    self.env.append_value('INCLUDES', _dynamic_env_data['include_dirs'])

class upload_fw(Task.Task):
    color='BLUE'
    always_run = True
    def run(self):
        upload_tools = self.env.get_flat('UPLOAD_TOOLS')
        src = self.inputs[0]
        return self.exec_command("python '{}/px_uploader.py' '{}'".format(upload_tools, src))

    def exec_command(self, cmd, **kw):
        kw['stdout'] = sys.stdout
        return super(upload_fw, self).exec_command(cmd, **kw)

    def keyword(self):
        return "Uploading"

class set_default_parameters(Task.Task):
    color='CYAN'
    always_run = True
    def keyword(self):
        return "apj_tool"
    def run(self):
        rel_default_parameters = self.env.get_flat('DEFAULT_PARAMETERS')
        abs_default_parameters = os.path.join(self.env.SRCROOT, rel_default_parameters)
        apj_tool = self.env.APJ_TOOL
        sys.path.append(os.path.dirname(apj_tool))
        from apj_tool import embedded_defaults
        defaults = embedded_defaults(self.inputs[0].abspath())
        if not defaults.find():
            print("Error: Param defaults support not found in firmware")
            sys.exit(1)
        defaults.set_file(abs_default_parameters)
        defaults.save()

class generate_bin(Task.Task):
    color='CYAN'
    run_str="${OBJCOPY} -O binary ${SRC} ${TGT}"
    always_run = True
    def keyword(self):
        return "Generating"
    def __str__(self):
        return self.outputs[0].path_from(self.generator.bld.bldnode)

class generate_apj(Task.Task):
    color='CYAN'
    run_str="python '${UPLOAD_TOOLS}/px_mkfw.py' --image '${SRC}' --prototype '${BUILDROOT}/apj.prototype' > '${TGT}'"
    always_run = True
    def keyword(self):
        return "Generating"
    def __str__(self):
        return self.outputs[0].path_from(self.generator.bld.bldnode)

class build_abin(Task.Task):
    '''build an abin file for skyviper firmware upload via web UI'''
    color='CYAN'
    run_str='${TOOLS_SCRIPTS}/make_abin.sh ${SRC}.bin ${SRC}.abin'
    always_run = True
    def keyword(self):
        return "Generating"
    def __str__(self):
        return self.outputs[0].path_from(self.generator.bld.bldnode)

class build_intel_hex(Task.Task):
    '''build an intel hex file for upload with DFU'''
    color='CYAN'
    run_str='${TOOLS_SCRIPTS}/make_intel_hex.py ${SRC} ${FLASH_RESERVE_START_KB}'
    always_run = True
    def keyword(self):
        return "Generating"
    def __str__(self):
        return self.outputs[0].path_from(self.generator.bld.bldnode)

@feature('ch_ap_program')
@after_method('process_source')
def chibios_firmware(self):
    self.link_task.always_run = True

    link_output = self.link_task.outputs[0]

    bin_target = self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.bin').name)
    apj_target = self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.apj').name)

    generate_bin_task = self.create_task('generate_bin', src=link_output, tgt=bin_target)
    generate_bin_task.set_run_after(self.link_task)

    generate_apj_task = self.create_task('generate_apj', src=bin_target, tgt=apj_target)
    generate_apj_task.set_run_after(generate_bin_task)

    if self.env.BUILD_ABIN:
        abin_target = self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.abin').name)
        abin_task = self.create_task('build_abin', src=link_output, tgt=abin_target)
        abin_task.set_run_after(generate_apj_task)

    bootloader_bin = self.bld.srcnode.make_node("Tools/bootloaders/%s_bl.bin" % self.env.BOARD)
    if os.path.exists(bootloader_bin.abspath()) and self.bld.env.HAVE_INTEL_HEX:
        hex_target = self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.hex').name)
        hex_task = self.create_task('build_intel_hex', src=[bin_target, bootloader_bin], tgt=hex_target)
        hex_task.set_run_after(generate_bin_task)

    if self.env.DEFAULT_PARAMETERS:
        default_params_task = self.create_task('set_default_parameters',
                                               src=link_output)
        default_params_task.set_run_after(self.link_task)
        generate_bin_task.set_run_after(default_params_task)

    if self.bld.options.upload:
        _upload_task = self.create_task('upload_fw', src=apj_target)
        _upload_task.set_run_after(generate_apj_task)

def setup_can_build(cfg):
    '''enable CAN build. By doing this here we can auto-enable CAN in
    the build based on the presence of CAN pins in hwdef.dat'''
    env = cfg.env
    env.AP_LIBRARIES += [
        'AP_UAVCAN',
        'modules/uavcan/libuavcan/src/**/*.cpp',
        'modules/uavcan/libuavcan_drivers/stm32/driver/src/*.cpp'
        ]

    env.CFLAGS += ['-DUAVCAN_STM32_CHIBIOS=1',
                   '-DUAVCAN_STM32_NUM_IFACES=2']

    env.CXXFLAGS += [
        '-Wno-error=cast-align',
        '-DUAVCAN_STM32_CHIBIOS=1',
        '-DUAVCAN_STM32_NUM_IFACES=2'
        ]

    env.DEFINES += [
        'UAVCAN_CPP_VERSION=UAVCAN_CPP03',
        'UAVCAN_NO_ASSERTIONS=1',
        'UAVCAN_NULLPTR=nullptr'
        ]

    env.INCLUDES += [
        cfg.srcnode.find_dir('modules/uavcan/libuavcan/include').abspath(),
        cfg.srcnode.find_dir('modules/uavcan/libuavcan_drivers/stm32/driver/include').abspath()
        ]
    cfg.get_board().with_uavcan = True

def load_env_vars(env):
    '''optionally load extra environment variables from env.py in the build directory'''
    print("Checking for env.py")
    env_py = os.path.join(env.BUILDROOT, 'env.py')
    if not os.path.exists(env_py):
        print("No env.py found")
        return
    e = pickle.load(open(env_py, 'rb'))
    for k in e.keys():
        v = e[k]
        if k == 'ROMFS_FILES':
            env.ROMFS_FILES += v
            continue
        if k in env:
            if isinstance(env[k], dict):
                a = v.split('=')
                env[k][a[0]] = '='.join(a[1:])
                print("env updated %s=%s" % (k, v))
            elif isinstance(env[k], list):
                env[k].append(v)
                print("env appended %s=%s" % (k, v))
            else:
                env[k] = v
                print("env added %s=%s" % (k, v))
        else:
            env[k] = v
            print("env set %s=%s" % (k, v))

def configure(cfg):
    cfg.find_program('make', var='MAKE')
    #cfg.objcopy = cfg.find_program('%s-%s'%(cfg.env.TOOLCHAIN,'objcopy'), var='OBJCOPY', mandatory=True)
    cfg.find_program('arm-none-eabi-objcopy', var='OBJCOPY')
    env = cfg.env
    bldnode = cfg.bldnode.make_node(cfg.variant)
    def srcpath(path):
        return cfg.srcnode.make_node(path).abspath()

    def bldpath(path):
        return bldnode.make_node(path).abspath()
    env.AP_PROGRAM_FEATURES += ['ch_ap_program']

    kw = env.AP_LIBRARIES_OBJECTS_KW
    kw['features'] = Utils.to_list(kw.get('features', [])) + ['ch_ap_library']

    env.CH_ROOT = srcpath('modules/ChibiOS')
    env.AP_HAL_ROOT = srcpath('libraries/AP_HAL_ChibiOS')
    env.BUILDDIR = bldpath('modules/ChibiOS')
    env.BUILDROOT = bldpath('')
    env.SRCROOT = srcpath('')
    env.PT_DIR = srcpath('Tools/ardupilotwaf/chibios/image')
    env.UPLOAD_TOOLS = srcpath('Tools/ardupilotwaf')
    env.CHIBIOS_SCRIPTS = srcpath('libraries/AP_HAL_ChibiOS/hwdef/scripts')
    env.TOOLS_SCRIPTS = srcpath('Tools/scripts')
    env.APJ_TOOL = srcpath('Tools/scripts/apj_tool.py')
    env.SERIAL_PORT = srcpath('/dev/serial/by-id/*_STLink*')

    # relative paths to pass to make, relative to directory that make is run from
    env.CH_ROOT_REL = os.path.relpath(env.CH_ROOT, env.BUILDROOT)
    env.AP_HAL_REL = os.path.relpath(env.AP_HAL_ROOT, env.BUILDROOT)
    env.BUILDDIR_REL = os.path.relpath(env.BUILDDIR, env.BUILDROOT)

    mk_custom = srcpath('libraries/AP_HAL_ChibiOS/hwdef/%s/chibios_board.mk' % env.BOARD)
    mk_common = srcpath('libraries/AP_HAL_ChibiOS/hwdef/common/chibios_board.mk')
    # see if there is a board specific make file
    if os.path.exists(mk_custom):
        env.BOARD_MK = mk_custom
    else:
        env.BOARD_MK = mk_common

    if cfg.options.default_parameters:
        cfg.msg('Default parameters', cfg.options.default_parameters, color='YELLOW')
        env.DEFAULT_PARAMETERS = srcpath(cfg.options.default_parameters)

    # we need to run chibios_hwdef.py at configure stage to generate the ldscript.ld
    # that is needed by the remaining configure checks
    import subprocess

    if env.BOOTLOADER:
        env.HWDEF = srcpath('libraries/AP_HAL_ChibiOS/hwdef/%s/hwdef-bl.dat' % env.BOARD)
        env.BOOTLOADER_OPTION="--bootloader"
    else:
        env.HWDEF = srcpath('libraries/AP_HAL_ChibiOS/hwdef/%s/hwdef.dat' % env.BOARD)
        env.BOOTLOADER_OPTION=""
    hwdef_script = srcpath('libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py')
    hwdef_out = env.BUILDROOT
    if not os.path.exists(hwdef_out):
        os.mkdir(hwdef_out)
    try:
        cmd = "python '{0}' -D '{1}' '{2}' {3}".format(hwdef_script, hwdef_out, env.HWDEF, env.BOOTLOADER_OPTION)
        ret = subprocess.call(cmd, shell=True)
    except Exception:
        cfg.fatal("Failed to process hwdef.dat")
    if ret != 0:
        cfg.fatal("Failed to process hwdef.dat ret=%d" % ret)

    load_env_vars(cfg.env)
    if env.HAL_WITH_UAVCAN:
        setup_can_build(cfg)

def pre_build(bld):
    '''pre-build hook to change dynamic sources'''
    load_env_vars(bld.env)
    if bld.env.HAL_WITH_UAVCAN:
        bld.get_board().with_uavcan = True

def build(bld):
    bld(
        # build hwdef.h and apj.prototype from hwdef.dat. This is needed after a waf clean
        source=bld.path.ant_glob(bld.env.HWDEF),
        rule="python '${AP_HAL_ROOT}/hwdef/scripts/chibios_hwdef.py' -D '${BUILDROOT}' '%s' %s" % (bld.env.HWDEF, bld.env.BOOTLOADER_OPTION),
        group='dynamic_sources',
        target=[bld.bldnode.find_or_declare('hwdef.h'),
                bld.bldnode.find_or_declare('apj.prototype'),
                bld.bldnode.find_or_declare('ldscript.ld')]
    )

    bld(
        # create the file modules/ChibiOS/include_dirs
        rule="touch Makefile && BUILDDIR=${BUILDDIR_REL} CHIBIOS=${CH_ROOT_REL} AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${MAKE} pass -f '${BOARD_MK}'",
        group='dynamic_sources',
        target=bld.bldnode.find_or_declare('modules/ChibiOS/include_dirs')
    )

    common_src = [bld.bldnode.find_or_declare('hwdef.h'),
                  bld.bldnode.find_or_declare('modules/ChibiOS/include_dirs')]
    common_src += bld.path.ant_glob('libraries/AP_HAL_ChibiOS/hwdef/common/*.[ch]')
    common_src += bld.path.ant_glob('libraries/AP_HAL_ChibiOS/hwdef/common/*.mk')
    common_src += bld.path.ant_glob('modules/ChibiOS/os/hal/**/*.[ch]')
    common_src += bld.path.ant_glob('modules/ChibiOS/os/hal/**/*.mk')
    if bld.env.ROMFS_FILES:
        common_src += [bld.bldnode.find_or_declare('ap_romfs_embedded.h')]
    ch_task = bld(
        # build libch.a from ChibiOS sources and hwdef.h
        rule="BUILDDIR='${BUILDDIR_REL}' CHIBIOS='${CH_ROOT_REL}' AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} '${MAKE}' lib -f '${BOARD_MK}'",
        group='dynamic_sources',
        source=common_src,
        target=bld.bldnode.find_or_declare('modules/ChibiOS/libch.a')
    )
    ch_task.name = "ChibiOS_lib"

    bld.env.LIB += ['ch']
    bld.env.LIBPATH += ['modules/ChibiOS/']
    wraplist = ['strerror_r', 'fclose', 'freopen', 'fread']
    for w in wraplist:
        bld.env.LINKFLAGS += ['-Wl,--wrap,%s' % w]


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

import requests
from pyquery import PyQuery as pq
import openpyxl
import sys
from openpyxl.drawing.image import Image
from openpyxl.styles import Font, Alignment
import io
import PIL # 需安装pip3 install Pillow

def send_request(url):
	headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'}
	resp=requests.get(url, headers=headers)
	return resp

def get_cate(doc):
	# 获取分类数据
	catelist=doc('.homepage-cat-name').items()
	create_excel()
	for cate in catelist:
		href=url+cate.attr('href')
		catename=cate.text()
		cate_doc=pq(send_request(href).text)
		foodsList=get_food(cate_doc)
		if len(foodsList)>0:
			write_excel(foodsList,catename)
	delete_Sheet()

def get_food(cate_doc):
	# 获取美食数据
	foods=cate_doc('.category-recipe-list .list li').items()
	foodsList=[]
	for food in foods:
		name=food('.name a').text()
		s=food('.ing.ellipsis').text()
		scores=food('.stats span')
		score1=scores[0].text
		score2=scores[1].text if len(scores)>1 else '0'
		img=food('.cover.pure-u img').attr('data-src')
		href=url+food('div>a').attr('href')
		foodsList.append([name,s,score1,score2,img,href])
	return foodsList

def create_excel():
	# 创建excel
	wb=openpyxl.Workbook()
	wb.save('下厨房.xlsx')

def delete_Sheet():
	# 删除默认sheet
	wb=openpyxl.load_workbook('下厨房.xlsx')
	del wb['Sheet']
	wb.save('下厨房.xlsx')

def write_excel(list, sheetname):
	# 数据写入表格
	wb=openpyxl.load_workbook('下厨房.xlsx')
	sheet=wb.create_sheet(sheetname)
	sheet.append(['菜名','材料','评分','人气','图片','链接'])
	# 设置宽高 设置属性必须在设置数据之后，否则会独立成行
	set_styles(sheet)
	count=1
	for food in list:
		sheet.append(food)
		count+=1
		sheet.row_dimensions[count].height=120
		cell_num='E'+str(count)
		sheet[cell_num]=''			# 清空图片url
		# 插入图片
		resp=send_request(food[4])
		image_file = io.BytesIO(resp.content)
		img = Image(image_file)
		sheet.add_image(img,cell_num)
	wb.save('下厨房.xlsx')

# 整行整列设置样式失败
def set_styles(sheet):
	sheet.column_dimensions['A'].width=40
	sheet.column_dimensions['B'].width=60
	sheet.column_dimensions['E'].width=50
	sheet.column_dimensions['F'].width=50
	# sheet.column_dimensions['A'].font=Font(size=14)
	# sheet.column_dimensions['B'].font=Font(size=14)
	# sheet.column_dimensions['C'].font=Font(size=14)
	# sheet.column_dimensions['D'].font=Font(size=14)
	# sheet.column_dimensions['F'].font=Font(size=14)
	# sheet.row_dimensions[1].font=Font(size=16,bold=True)
	sheet.row_dimensions[1].height=20
	# 设置对齐方式
	# alignment=Alignment(
	# 	horizontal='left',
	# 	vertical='center'
	# 	)
	# alignment_center=Alignment(
	# 	horizontal='center',
	# 	vertical='center'
	# 	)
	# sheet.column_dimensions['A'].alignment=alignment
	# sheet.column_dimensions['B'].alignment=alignment
	# sheet.column_dimensions['C'].alignment=alignment
	# sheet.column_dimensions['D'].alignment=alignment
	# sheet.column_dimensions['E'].alignment=alignment
	# sheet.column_dimensions['F'].alignment=alignment
	# sheet.row_dimensions[1].alignment=alignment_center

def start():
	doc=pq(send_request(url).text)
	get_cate(doc)

url='https://www.xiachufang.com'
start()


"""Form Component class definition.

Todo:
    * Clean up input verification via Tkinter's `validatecommand` and `invalidcommand` `Entry` methods, which would
        also allow for less event bindings.

.. _src-components-form:
    https://github.com/hivebattery/gui/blob/master/driver/src/components/form.py

"""
from __future__ import absolute_import

import re

from react.index import StringVar, IntVar, Label, Frame, Entry, Scale, Radiobutton, Checkbutton, HORIZONTAL,\
                        END, GOLDEN_RATIO, set_immediate
from react.component import Component

from src.common.log.console_message import *
from src.common.bytes import bytes
from src.config.config import *

MAX_VALS_FREQS = [F_MIN, F_MIN * 2 ** 23]
"""list of float: The lower and upper bounds for valid frequency values.
"""

class Form(Component):
    """Form Component.

    The React Component that contains the GUI's form i.e. the entries, the radio buttons, the checkbox, and the
    scale through which the user inputs the EIS parameters.

    Attributes:
        __n_middle_bits (int): The number of bits between the lowest and the highest frequencies.
        __start_frequency_str_var (react.widget_wrappers.StringVar): Holds the input of the 'start frequency' entry.
        __end_frequency_str_var (react.widget_wrappers.StringVar): Holds the input of the 'end frequency' entry.
        __single_frequency_str_var (react.widget_wrappers.IntVar): Holds the 'single frequency' checkbox value.
        fields_frame (react.widget_wrappers.Frame): Contains the left side of the form with all the entries.
        other_frame (react.widget_wrappers.Frame): Contains the right side of the form.
        single_freq_lb (react.widget_wrappers.Label): 'Single frequency' label.
        start_frequency_lb (react.widget_wrappers.Label): 'Start frequency' label.
        end_frequency_lb (react.widget_wrappers.Label): 'End frequency' label.
        n_freqs_lb (react.widget_wrappers.Label): 'Number of frequencies' label.
        n_freqs_int (react.widget_wrappers.Label): The actual number of frequencies.
        amplitude_lb (react.widget_wrappers.Label): 'Amplitude' label.
        start_frequency_en (react.widget_wrappers.Entry): Start frequncy entry.
        end_frequency_en (react.widget_wrappers.Entry): End frequency entry.
        amplitude_en (react.widget_wrappers.Entry): End frequency entry.
        n_freqs_scale (react.widget_wrappers.Scale): Allows the user to input how many frequencies should be requested.
        amplitude_rb_v (react.widget_wrappers.Radiobutton): Allows the user to select 'Voltage'.
        amplitude_rb_c (react.widget_wrappers.Radiobutton): Allows the user to select 'Current'.
        single_freq_cb_v (react.widget_wrappers.Checkbutton): Allows the user to request a single frequency.
        entries (list of react.widget_wrappers.Entry): Provides an easy way to refer to all entries in the form at once.

    """
    def __init__(self, parent, frame=None, **props):
        """Form Component constructor.

        Args:
            parent (react.component.Component): The component that should contain the form.
            frame (react.widget_wrappers.Frame, optional): The Frame where the form should be placed. If no
                frame is specified, then the default frame is considered instead.
            **props: The props passed down to the Form component.

        """
        super(Form, self).__init__(parent, frame, **props)

        self.state = dict(single_frequency=False)

        self.__n_middle_bits = -1

        # StringVars
        self.__start_frequency_str_var = StringVar()
        self.__end_frequency_str_var = StringVar()

        # IntVars
        self.__single_frequency_int_var = IntVar()

        # Frame
        self.fields_frame = Frame(self, width=self.height, height=self.height, frame=self.parent_frame, bg=BG_COLOR)
        self.other_frame = Frame(self, width=self.height * GOLDEN_RATIO, height=self.height, frame=self.parent_frame,
                                 bg=BG_COLOR)

        # Labels
        self.single_freq_lb = Label(self, "Single frequency", frame=self.fields_frame, bg=BG_COLOR, fg=TEXT_COLOR,
                                    font=("Helvetica", 12))
        self.start_frequency_lb = Label(self, "Start frequency (mHz):", frame=self.fields_frame, bg=BG_COLOR,
                                        fg=TEXT_COLOR, font=("Helvetica", 12))
        self.end_frequency_lb = Label(self, "End frequency (mHz):", frame=self.fields_frame, bg=BG_COLOR,
                                      fg=TEXT_COLOR, font=("Helvetica", 12))
        self.n_freqs_lb = Label(self, "No. of frequencies:", frame=self.other_frame, bg=BG_COLOR, fg=TEXT_COLOR,
                                font=("Helvetica", 12), width=20)
        self.n_freqs_int = Label(self, self.props.n_freqs_str_var, frame=self.other_frame, bg=BG_COLOR, fg=TEXT_COLOR,
                                 font=("Helvetica", 12))
        self.amplitude_lb = Label(self, "Amplitude (mV):", frame=self.fields_frame, bg=BG_COLOR, fg=TEXT_COLOR,
                                  font=("Helvetica", 12))

        # Entries
        self.start_frequency_en = Entry(self, self.__start_frequency_str_var, frame=self.fields_frame)
        self.end_frequency_en = Entry(self, self.__end_frequency_str_var, frame=self.fields_frame)
        self.amplitude_en = Entry(self, self.props.amplitude_str_var, frame=self.fields_frame)

        # Scale
        self.n_freqs_scale = Scale(self, frame=self.other_frame, bg=BG_COLOR, from_=2, orient=HORIZONTAL,
                                   command=self.update_n_freqs_sc, troughcolor=FG_COLOR, sliderrelief='flat',
                                   highlightbackground=BG_COLOR, activebackground=BG_COLOR, bd=1,
                                   highlightcolor=BG_COLOR, highlightthickness=0)

        # Radiobuttons
        self.amplitude_rb_v = Radiobutton(self, "Voltage", self.props.amplitude_int_var, 0, frame=self.other_frame,
                                          command=lambda: self.on_amplitude_type_change(), bg=BG_COLOR, fg=TEXT_COLOR,
                                          font=("Helvetica", 12))
        self.amplitude_rb_c = Radiobutton(self, "Current", self.props.amplitude_int_var, 1, frame=self.other_frame,
                                          command=lambda: self.on_amplitude_type_change(), bg=BG_COLOR, fg=TEXT_COLOR,
                                          font=("Helvetica", 12))

        # Checkbuttons
        self.single_freq_cb_v = Checkbutton(self, None, self.__single_frequency_int_var, 0,
                                            frame=self.fields_frame,
                                            command=lambda: self.toggled_single_frequency(), bg=BG_COLOR, fg=BG_COLOR,
                                            activebackground=BG_COLOR, highlightcolor=BG_COLOR,
                                            highlightbackground=BG_COLOR, selectcolor=BG_COLOR,
                                            activeforeground=BG_COLOR, disabledforeground=BG_COLOR, bd=0,
                                            offrelief='flat')

        self.entries = [self.start_frequency_en, self.end_frequency_en, self.amplitude_en]

        for entry in self.entries:  #: Configure entries and set up the events they should handle.
            entry.config(background=FG_COLOR, borderwidth=0, relief='flat', foreground=TEXT_COLOR,
                         width=8, highlightthickness=1, insertbackground="white", disabledbackground=BG_COLOR,
                         selectbackground=TEXT_COLOR, selectforeground="black")
            entry.bind("<ButtonRelease-1>", self.clear_entry)
            entry.bind("<FocusIn>", self.clear_entry)
            entry.bind("<FocusOut>", self.update_n_freqs_sc)

        #: Set up all other event handling
        self.start_frequency_en.bind("<Up>", lambda e: self.pressed_key(e, 'start_frequency', 1))
        self.end_frequency_en.bind("<Up>", lambda e: self.pressed_key(e, 'end_frequency', 1))
        self.amplitude_en.bind("<Up>", lambda e: self.pressed_key(e, 'amplitude', 1))

        self.start_frequency_en.bind("<Down>", lambda e: self.pressed_key(e, 'start_frequency', -1))
        self.end_frequency_en.bind("<Down>", lambda e: self.pressed_key(e, 'end_frequency', -1))
        self.amplitude_en.bind("<Down>", lambda e: self.pressed_key(e, 'amplitude', -1))

    def component_will_receive_props(self, props):
        """Overrides Component's `component_will_receive_props`.

        Validate the form's input if the device is reconnected or blur all entries if the device has just been
        disconnected.

        Args:
            props: The new props that haven't been updated on this component.

        See Also:
            React module :py:mod:`component`.

        """
        if hasattr(props, 'is_device_connected'):
            if self.props.is_device_connected != props.is_device_connected:
                if props.is_device_connected:
                    set_immediate(self.update_n_freqs_sc)
                else:
                    set_immediate(self.parent_frame.focus)

    def on_bg_click(self):
        """Background click event handler to blur all entries.

        See Also:
            React's main module :py:mod:`react-index`

        """
        for entry in self.entries:
            entry.selection_clear()

    def pressed_key(self, e, key, direction):
        """Up and down keys handler.

        Provides the required functionality for the user to be able to navigate through each entry's input history
        using the .hive file.

        Args:
            e (Tkinter.Event): The event object generate by Tkinter when the user presses the up or down arrow keys.
            key (str): The key to match the correct entry's input history in the .hive file.
            direction (int): 1 if the user pressed the up arrow key, -1 otherwise.

        """
        new_str = str(self.props.poll_history(key, direction))

        if len(new_str) > 0:
            e.widget.delete(0, END)
            e.widget.insert(0, new_str)

    @staticmethod
    def clear_entry(e):
        """Clear all text in the entry.

        Args:
            e (Tkinter.Event): The Tkinter event object generated by the entry.

        """
        entry = e.widget
        entry.select_range(0, END)

    def toggled_single_frequency(self):
        """Enable a single frequency request.

        Sets the state of the component to the current choice of single or multiple frequencies and validates the input.

        """
        self.set_state(dict(single_frequency=bool(self.__single_frequency_int_var.get())))
        self.update_n_freqs_sc()

    def update_n_freqs_sc(self, e=None):
        """Validates form input.

        Checks all entries and user input by applying the necessary constraints to each widget. These operations happen
        in the following order:

            1) Check if the entries are empty.
            2) If the amplitude entry is not empty or all frequency entries are not empt, procced with validation:
                a) If the frequency entries are not empty, validate them and decide whether the right side of the
                    form should be displayed.
                b) If the amplitude entry is not empty, validate it.
            3) If validation was successful, configure the scale so that users may select the number of frequencies to
                request.
            4) Toggle the form reflecting the state of the validation so that this component's parent knows about the
                input.

        Args:
            e (Tkinter.Event, optional): The Tkinter event object generated by the entry. None implies the validation
                was triggered programmatically rather than by Tkinter's event loop.

        """
        is_start_freq_empty = self.start_frequency_en.is_empty()  #: Step 1
        is_end_freq_empty = self.end_frequency_en.is_empty()
        is_amplitude_empty = self.amplitude_en.is_empty()

        if e is not None and bool(re.search('entry', e if isinstance(e, str) else str(e.widget))):
            e.widget.selection_clear()

        hide_freqs = True
        form_validated = False

        #: Step 2
        if not ((is_start_freq_empty or (is_end_freq_empty and self.state.single_frequency)) and is_amplitude_empty):
            if not is_start_freq_empty and (self.state.single_frequency or not is_end_freq_empty):  #: Step 2.a
                [start_freq_code, end_freq_code, freq_range_code] = self.check_freqs()
                clean_messages = {}

                if start_freq_code == 0:
                    clean_messages[str(LATEST_ERRORS_START_FREQ)] = True

                if end_freq_code == 0:
                    clean_messages[str(LATEST_ERRORS_END_FREQ)] = True

                if freq_range_code == 0:
                    clean_messages[str(LATEST_ERRORS_RANGE)] = True

                hide_freqs = len(clean_messages) != 3

                if len(clean_messages) > 0:
                    self.props.update_latest_errors(clean_messages)

            if not is_amplitude_empty:  #: Step 2.b
                form_validated = self.check_amplitude() and not hide_freqs

        if not hide_freqs:  #: Step 3
            self.configure_scale(form_validated)

        self.props.toggle_form(form_validated)  #: Step 4

    def on_amplitude_type_change(self):
        """Validate form after selecting 'Voltage' or 'Current' with the radio buttons.

        If the amplitude entry is not empty, programmatically fire `self.update_n_freqs_sc`.

        """
        if not self.amplitude_en.is_empty():
            self.update_n_freqs_sc(None)

    def check_amplitude(self):
        """Validate amplitude entry.

        Two important checks happen during this method:

            1) Whether the user typed an integer.
            2) Whether the integer input lies within the acceptable bounds.

        In case of error, change the color of text to indicate invalid input and save these errors to the latest errors
        list tracker so that the user only gets notified about each error once. If validation was successful, change
        back the text of the entry to reflect valid input.

        Raises:
            ValueError: If the user input is not an integer.

        """
        amplitude_str = re.sub(" ", "", self.amplitude_en.get())
        args = None

        try:  #: Check 1
            amplitude_int = int(amplitude_str, 10)
            upper_bound = 30 - 10 * self.props.amplitude_int_var.get()

            if not 0 <= amplitude_int <= upper_bound:  #: Check 2
                args = "Amplitude", amplitude_int, 0, upper_bound
                code = 1

            else:
                code = 0

        except ValueError:
            args = amplitude_str, 'integer'
            code = 2

        if code != 0:
            color = ERROR_COLOR

            if self.props.latest_errors[3] != amplitude_str:
                self.props.log_messages([(args, code)], {str(LATEST_ERRORS_AMPLITUDE): amplitude_str})
        else:
            color = TEXT_COLOR
            self.props.update_latest_errors({str(LATEST_ERRORS_AMPLITUDE): True})

        self.amplitude_en.configure(foreground=color)

        return color == TEXT_COLOR

    def check_freqs(self):
        """Validate frequency entries.

        Three important checks happen during this method:

            1) Whether the user typed an integer.
            2) Whether the integer input lies within the acceptable bounds.
            3) If applicable, whether the lower bound is compatible with the upper bound.

        In case of error, change the color of text to indicate invalid input and save these errors to the latest errors
        list tracker so that the user only gets notified about each error once. If validation was successful, change
        back the text of the entry to reflect valid input.

        Raises:
            ValueError: If the user input is not an integer.

        """
        freq_en = [self.start_frequency_en]
        freqs_int = []
        codes = [None, None, 0]

        if not self.state.single_frequency:
            freq_en.append(self.end_frequency_en)
        else:
            codes[1] = 0

        args = [None for i in range(3)]
        freqs_str = [re.sub(" ", "", x.get()) for x in freq_en]
        latest_errors = {}
        messages = []

        for i in range(len(freq_en)):
            freq_var = freqs_str[i]

            try:  #: Check 1
                freq_int = int(freq_var)
                freqs_int.append(freq_int)

                if not (MAX_VALS_FREQS[0] <= freq_int <= MAX_VALS_FREQS[1]):  #: Check 2
                    args[i] = ("Start frequency" if i == 0 else "End frequency", freq_int, MAX_VALS_FREQS[0],
                               MAX_VALS_FREQS[1])
                    codes[i] = 1
                else:
                    codes[i] = 0

                i += 1

            except ValueError:
                args[i] = (freq_var, 'integer')
                codes[i] = 2

        if len(freqs_int) == 2 and freqs_int[0] > freqs_int[1]:  #: Check 3
            args[2] = ("Start frequency", freqs_int[0], "end frequency", freqs_int[1])
            codes[2] = 3

        for j in range(len(freq_en)):
            code = codes[j]

            if code != 0:
                color = ERROR_COLOR

                if self.props.latest_errors[j] != freqs_str[j]:
                    messages.append((args[j], code))
                    latest_errors[str(j)] = freqs_str[j]
            else:
                color = TEXT_COLOR

            freq_en[j].config(foreground=color)

        if codes[2] != 0:
            freq_en[0].config(foreground=ERROR_COLOR)
            freq_en[1].config(foreground=ERROR_COLOR)

            if self.props.latest_errors[2] != str(hash("#".join(freqs_str))):
                messages.append((args[2], codes[2]))
                latest_errors['2'] = str(hash("#".join(freqs_str)))

        if len(latest_errors):
            self.props.log_messages(messages, latest_errors)

        return codes

    def configure_scale(self, form_validated):
        """Display and set up scale to allow the user to select the number of frequencies.

        1) Determine the maximum number of possible frequencies.
        2) Map the input to actual values according to minimum frequency and compute the number of bits between the
            start and end frequency, if applicable.
        3) Reset the latest errors list tracker to the default.

        Args:
            form_validated (bool): True if the input was validated, False otherwise.

        """
        freqs_str = [re.sub(" ", "", x.get()) for x in [self.start_frequency_en, self.end_frequency_en]]

        if self.state.single_frequency:  #: Step 1
            n_freqs = 1
            lower_bound = bytes.get_binary_limits(int(freqs_str[0]), int(freqs_str[0]), F_MIN)[0]
            upper_bound = None
        else:
            freqs_str = [re.sub(" ", "", x.get()) for x in [self.start_frequency_en, self.end_frequency_en]]
            self.__n_middle_bits = bytes.get_num_middle_bits(int(freqs_str[0]), int(freqs_str[1]), F_MIN)  #: Step 2
            lower_bound, upper_bound = bytes.get_binary_limits(int(freqs_str[0]), int(freqs_str[1]), F_MIN)

            if self.__n_middle_bits > 0:
                n_freqs = self.n_freqs_scale.get()
            else:
                n_freqs = 2

        if form_validated:  #: Step 3
            amplitude_str = re.sub(" ", "", self.amplitude_en.get())
            self.props.clear_latest_errors()
            self.props.on_form_validated(lower_bound, upper_bound, n_freqs, int(amplitude_str))
        else:
            self.props.update_freqs(lower_bound, upper_bound, n_freqs)

    def render(self):
        """Form Component Render method.

        Determine which widgets to show according to the form validation.

        """
        self.fields_frame.place(width=self.width / GOLDEN_RATIO, height=self.height)
        self.other_frame.place(x=self.width / GOLDEN_RATIO, width=self.width / GOLDEN_RATIO ** 2, height=self.height)

        self.single_freq_lb.place(relwidth=1 / GOLDEN_RATIO, relheight=0.25)
        self.single_freq_cb_v.place(relx=1 / GOLDEN_RATIO, relwidth=1 - 1 / GOLDEN_RATIO, relheight=0.25)

        self.start_frequency_lb.place(rely=0.25, relwidth=1 / GOLDEN_RATIO, relheight=0.25)
        self.start_frequency_en.place(rely=0.33, relx=1 / GOLDEN_RATIO, relwidth=1 - 1 / GOLDEN_RATIO)

        if not self.state.single_frequency:
            prefix = 'Start f'
            self.end_frequency_lb.place(rely=0.5, relwidth=1 / GOLDEN_RATIO, relheight=0.25)
            self.end_frequency_en.place(rely=0.57, relx=1 / GOLDEN_RATIO, relwidth=1 - 1 / GOLDEN_RATIO)
        else:
            prefix = 'F'

        self.start_frequency_lb.config(text=('%srequency (mHz):' % prefix))

        self.amplitude_lb.place(rely=0.75, relwidth=1 / GOLDEN_RATIO, relheight=0.25)
        self.amplitude_en.place(rely=0.82, relx=1 / GOLDEN_RATIO, relwidth=1 - 1 / GOLDEN_RATIO)

        self.amplitude_rb_v.place(relx=0.2, relheight=0.25, relwidth=0.6)
        self.amplitude_rb_c.place(relx=0.2, rely=0.2, relheight=0.25, relwidth=0.6)

        #: Custom colors and cursor depending on the GUI's state
        if self.props.is_device_connected and self.props.hive_record_ready:
            state = 'normal'
            cursor = 'xterm'
            highlightbg = 'black'
        else:
            state = 'disabled'
            cursor = 'arrow'
            highlightbg = FG_COLOR

        if self.props.form_validated and not self.state.single_frequency and state == 'normal':
            self.n_freqs_lb.place(relx=0.095, rely=0.5, relwidth=0.7, relheight=0.25)
            self.n_freqs_int.place(rely=0.5, relx=0.78, relheight=0.25)

            if self.__n_middle_bits > 0:
                self.n_freqs_scale.config(to=2 + self.__n_middle_bits)
                self.n_freqs_scale.place(relx=0.1, rely=0.75, relwidth=0.8, relheight=0.25)

            self.props.n_freqs_str_var.set(str(self.props.n_freqs))

        for entry in self.entries:
            entry.config(state=state, cursor=cursor, highlightbackground=highlightbg)

        self.amplitude_rb_c.config(state=state)
        self.amplitude_rb_v.config(state=state)
        self.single_freq_cb_v.config(state=state)