"""Interaction energy functionals.

Implements field--particle interaction energy functionals depending on the
field configuration. Extending HyMD with a new Hamiltonian is done by
subclassing the :code:`Hamiltonian` superclass with logic intialized in the
constructor.

The grid-independent filtering function is defined in the :code:`Hamiltonian`
superclass constructor. Hijack :code:`self.H` in a subclass to change the
filter.
"""
import numpy as np
import sympy

class Hamiltonian:
    """Interaction energy functional superclass"""

    def __init__(self, config):
        """Constructor

        Parameters
        ----------
        config : Config
            Configuration object.

        See also
        --------
        hymd.input_parser.Config : Configuration dataclass handler.
        """
        self.config = config
        self._setup()

    def _setup(self):
        """Superclass setup

        Sets up the grid-independent filtering function :code:`H`, and the
        SymPy logic for symbolically differentiating interaction energy
        functionals in Hamiltonian subclasses.
        """
        if not hasattr(self.config, "simulation_volume"):
            self.config.simulation_volume = np.prod(np.asarray(self.config.box_size))
        if not self.config.barostat:
            self.config.rho0 = self.config.n_particles / self.config.simulation_volume
            self.config.a = self.config.rho0
        if not self.config.rho0:
            self.config.rho0 = self.config.n_particles / self.config.simulation_volume
        self.phi = sympy.var("phi:%d" % (self.config.n_types))
        k = sympy.var("k:%d" % (3))

        # electrostatics variables
        self.psi = sympy.var("psi")
        self.phi_q = sympy.var("phi_q")
        if not self.config.self_energy:
            self.config.self_energy = 0.0

        def fourier_space_window_function(k):
            return sympy.functions.elementary.exponential.exp(
                -0.5
                * self.config.sigma**2
                * (k0**2 + k1**2 + k2**2)  # noqa: F821, E501
            )

        self.window_function_lambda = sympy.lambdify(
            [k], fourier_space_window_function(k)
        )

        def H(k, v):
            return v * self.window_function_lambda(k)

        self.H = H

class SquaredPhi(Hamiltonian):
    """Simple squared density interaction energy functional

    The interaction energy density takes the form

    .. math::

        w[\\tilde\\phi] = \\frac{1}{2\\kappa\\rho_0}
            \\left(
                \\sum_k \\tilde\\phi_k
            \\right)^2,

    where :math:`\\kappa` is the compressibility and :math:`rho_0` is the
    average density of the fully homogenous system. Expressing the species
    densities in terms of fluctuations from the average,

    .. math::

        \\mathrm{d}\\tilde\\phi_k = \\rho_0 - \\tilde\\phi_k,

    it is evident that this interaction energy functional is a slight change of
    the :code:`DefaultNoChi` Hamiltonian, as the expanded interaction energy
    density becomes

    .. math::

        w[\\tilde\\phi] = \\frac{1}{2\\kappa\\rho_0}
            \\left(
                6\\rho_0\\left[
                    \\sum_k \\mathrm{d}\\tilde\\phi_k
                \\right]
                +
                9\\rho_0^2
                +
                \\sum_k \\mathrm{d}\\tilde\\phi_k^2
                +
                \\prod_{k\\not=l}
                    \\mathrm{d}\\tilde\\phi_k \\mathrm{d}\\tilde\\phi_l
            \\right),

    identical to :code:`DefaultNoChi` apart from a constant energy shift
    :math:`9\\rho_0^2`(which does not impact dynamics) and the
    :math:`\\rho_0`--:math:`\\mathrm{d}\\tilde\\phi_k` cross-terms. These
    cross-terms constitute contributions to the energy linear in
    :math:`\\mathrm{d}\\tilde\\phi_k` absent in :code:`DefaultNoChi`, which has
    only quadratic terms present.

    See also
    --------
    hymd.hamiltonian.DefaultNoChi
    """

    def __init__(self, config):
        """Constructor

        Parameters
        ----------
        config : Config
            Configuration object.

        See also
        --------
        hymd.input_parser.Config : Configuration dataclass handler.
        """
        super(SquaredPhi, self).__init__(config)
        super(SquaredPhi, self)._setup()
        self.setup()

    def setup(self):
        """Setup the interaction energy potential and the external potential"""

        def w(phi, kappa=self.config.kappa, rho0=self.config.rho0):
            return 0.5 / (kappa * rho0) * (sum(phi)) ** 2

        def w_elec(
            phi_q,
            psi,
            volume=self.config.simulation_volume,
            self_energy=self.config.self_energy,
        ):
            self_energy /= volume
            return 0.5 * phi_q * psi - self_energy

        def V_bar_0(
            phi,
            k,
            kappa=self.config.kappa,
            rho0=self.config.rho0,
        ):
            V_incompressibility = 1 / (kappa * rho0) * sum(phi)
            V_interaction = 0
            return V_interaction + V_incompressibility

        def V_bar_elec(
            psi,
            t,
            type_charges=self.config.type_charges,
        ):
            return type_charges[t] * psi

        self.V_bar_0 = [
            sympy.lambdify(
                [(self.phi)], V_bar_0(self.phi, t)
            )
            for t in range(self.config.n_types)
        ]

        self.V_bar = [
            sympy.lambdify(
                [(self.phi, self.psi)], V_bar_0(self.phi, t) + V_bar_elec(self.psi, t)
            )
            for t in range(self.config.n_types)
        ]

        self.v_ext = [
            sympy.lambdify([self.phi], sympy.diff(w(self.phi), self.phi[i]))
            for i in range(self.config.n_types)
        ]

        self.w_0 = sympy.lambdify([self.phi], w(self.phi))
        self.w_elec = sympy.lambdify(
            [(self.phi_q, self.psi)], w_elec(self.phi_q, self.psi)
        )

        if self.config.coulombtype == "PIC_Spectral":
            self.w = sympy.lambdify(
                [(self.phi, self.phi_q, self.psi)],
                w(self.phi) + w_elec(self.phi_q, self.psi),
            )
        else:
            self.w = self.w_0

class DefaultNoChi(Hamiltonian):
    """Incompressibility-only interaction energy functional

    The interaction energy density takes the form

    .. math::

        w[\\tilde\\phi] = \\frac{1}{2\\kappa} \\left(
            \\sum_k \\tilde\\phi_k - a
        \\right)^2,

    where :math:`\\kappa` is the compressibility and :math:`a=\\rho_0` for
    NVT runs where :math:`\\rho_0` is the average density of the fully
    homogenous system. In case of NPT runs, :math:`a` is a calibrated
    parameter to obtain the correct average density at the target temperature
    and pressure. The :code:`SquaredPhi` Hamiltonian implements a similar
    functional with an additional linear term component depending on

    .. math::

        \\mathmr{d}\\tilde\\phi_k = \\tilde\\phi_k - \\rho_0

    and not :math:`\\mathrm{d}\\tilde\\phi_k^2`. No explicit inter-species
    interaction is present apart from the indirect interaction through the
    incompressibility.

    See also
    --------
    hymd.hamiltonian.DefaultNoChi
    hymd.input_parser.Config :
        Configuration dataclass handler.
    """

    def __init__(self, config):
        """Constructor

        Parameters
        ----------
        config : Config
            Configuration object.

        See also
        --------
        hymd.input_parser.Config : Configuration dataclass handler.
        """
        super(DefaultNoChi, self).__init__(config)
        super(DefaultNoChi, self)._setup()
        self.setup()

    def setup(self):
        """Setup the interaction energy potential and the external potential"""

        def w(phi, kappa=self.config.kappa, rho0=self.config.rho0, a=self.config.a):
            return 0.5 / (kappa * rho0) * (sum(phi) - a) ** 2

        def w_elec(
            phi_q,
            psi,
            volume=self.config.simulation_volume,
            self_energy=self.config.self_energy,
        ):
            self_energy /= volume
            return 0.5 * phi_q * psi - self_energy

        def V_bar_0(
            phi,
            k,
            kappa=self.config.kappa,
            rho0=self.config.rho0,
            a=self.config.a,
        ):
            V_incompressibility = 1 / (kappa * rho0) * (sum(phi) - a)
            V_interaction = 0
            return V_interaction + V_incompressibility

        def V_bar_elec(
            psi,
            t,
            type_charges=self.config.type_charges,
        ):
            return type_charges[t] * psi

        self.V_bar_0 = [
            sympy.lambdify(
                [(self.phi)], V_bar_0(self.phi, t)
            )
            for t in range(self.config.n_types)
        ]

        self.V_bar = [
            sympy.lambdify(
                [(self.phi, self.psi)], V_bar_0(self.phi, t) + V_bar_elec(self.psi, t)
            )
            for t in range(self.config.n_types)
        ]

        self.v_ext = [
            sympy.lambdify([self.phi], sympy.diff(w(self.phi), self.phi[i]))
            for i in range(self.config.n_types)
        ]

        self.w_0 = sympy.lambdify([self.phi], w(self.phi))
        self.w_elec = sympy.lambdify(
            [(self.phi_q, self.psi)], w_elec(self.phi_q, self.psi)
        )

        if self.config.coulombtype == "PIC_Spectral":
            self.w = sympy.lambdify(
                [(self.phi, self.phi_q, self.psi)],
                w(self.phi) + w_elec(self.phi_q, self.psi),
            )
        else:
            self.w = self.w_0

class DefaultWithChi(Hamiltonian):
    """Incompressibility and :math:`\\chi`-interactions energy functional

    The interaction energy density takes the form

    .. math::

        w[\\tilde\\phi] =
            \\frac{1}{2\\rho_0}
                \\sum_{k,l}\\chi_{kl} \\tilde\\phi_k \\tilde\\phi_l
            +
            \\frac{1}{2\\kappa} \\left(
                \\sum_k \\tilde\\phi_k - a
            \\right)^2,

    where :math:`\\kappa` is the compressibility and :math:`a=\\rho_0` for
    NVT runs where :math:`\\rho_0` is the average density of the fully
    homogenous system. In case of NPT runs, :math:`a` is a calibrated
    parameter to obtain the correct average density at the target temperature
    and pressure. :math:`\\chi_{ij}` is the Flory-Huggins-like
    inter-species mixing energy.
    """

    def __init__(self, config, unique_names, type_to_name_map):
        """Constructor

        Parameters
        ----------
        config : Config
            Configuration object.
        unique_names : numpy.ndarray
            Sorted array of all distinct names of different species present in
            the simulation. Result of :code:`numpy.unique(all_names)`, where
            :code:`all_names` is the gathered union of all individual MPI
            ranks' :code:`names` arrays.
        type_to_name_map : dict[int, str]
            Dictionary of the mapping from type indices (integers) to type
            names.

        See also
        --------
        hymd.input_parser.Config : Configuration dataclass handler.
        """
        super(DefaultWithChi, self).__init__(config)
        super(DefaultWithChi, self)._setup()
        self.setup(unique_names, type_to_name_map)

    def setup(self, unique_names, type_to_name_map):
        """Setup the interaction energy potential and the external potential

        Parameters
        ----------
        unique_names : numpy.ndarray
            Sorted array of all distinct names of different species present in
            the simulation. Result of :code:`numpy.unique(all_names)`, where
            :code:`all_names` is the gathered union of all individual MPI
            ranks' :code:`names` arrays.
        type_to_name_map : dict[int, str]
            Dictionary of the mapping from type indices (integers) to type
            names.
        """
        self.type_to_name_map = type_to_name_map
        self.chi_type_dictionary = {
            tuple(sorted([c.atom_1, c.atom_2])): c.interaction_energy
            for c in self.config.chi
        }
        self.phi_laplacian = [
            sympy.var("phi_laplacian%d(0:%d)" % (t, 3))
            for t in range(self.config.n_types)
        ]

        def w(
            phi,
            kappa=self.config.kappa,
            rho0=self.config.rho0,
            a=self.config.a,
            chi=self.config.chi,
            type_to_name_map=self.type_to_name_map,
            chi_type_dictionary=self.chi_type_dictionary,
        ):
            interaction = 0.0
            for i in range(self.config.n_types):
                for j in range(i + 1, self.config.n_types):
                    ni = type_to_name_map[i]
                    nj = type_to_name_map[j]
                    names = sorted([ni, nj])
                    c = chi_type_dictionary[tuple(names)]

                    interaction += c * phi[i] * phi[j] / rho0
            incompressibility = 0.5 / (kappa * rho0) * (sum(phi) - a) ** 2
            return incompressibility + interaction

        def w_elec(
            phi_q,
            psi,
            volume=self.config.simulation_volume,
            self_energy=self.config.self_energy,
        ):
            self_energy /= volume
            return 0.5 * phi_q * psi - self_energy

        def V_bar_0(
            phi,
            t,
            kappa=self.config.kappa,
            rho0=self.config.rho0,
            a=self.config.a,
            chi=self.config.chi,
            type_to_name_map=self.type_to_name_map,
            chi_type_dictionary=self.chi_type_dictionary,
        ):
            V_incompressibility = 1 / (kappa * rho0) * (sum(phi) - a)

            V_interaction = 0.0
            nk = type_to_name_map[t]
            for i in range(self.config.n_types):
                ni = type_to_name_map[i]
                names = sorted([nk, ni])
                if ni != nk:
                    c = chi_type_dictionary[tuple(names)]
                else:
                    c = 0.0
                # uncomment to count diagonal chi terms:
                # c = chi_type_dictionary[tuple(names)]
                V_interaction += c * phi[i] / rho0
            return V_interaction + V_incompressibility

        def V_bar_elec(
            psi,
            t,
            type_charges=self.config.type_charges,
        ):
            return type_charges[t] * psi

        self.V_bar_0 = [
            sympy.lambdify(
                [(self.phi)], V_bar_0(self.phi, t)
            )
            for t in range(self.config.n_types)
        ]

        self.V_bar = [
            sympy.lambdify(
                [(self.phi, self.psi)], V_bar_0(self.phi, t) + V_bar_elec(self.psi, t)
            )
            for t in range(self.config.n_types)
        ]

        self.v_ext = [
            sympy.lambdify([self.phi], sympy.diff(w(self.phi), self.phi[t]))
            for t in range(self.config.n_types)
        ]

        self.w_0 = sympy.lambdify([self.phi], w(self.phi))
        self.w_elec = sympy.lambdify(
            [(self.phi_q, self.psi)], w_elec(self.phi_q, self.psi)
        )

        if self.config.coulombtype == "PIC_Spectral":
            self.w = sympy.lambdify(
                [(self.phi, self.phi_q, self.psi)],
                w(self.phi) + w_elec(self.phi_q, self.psi),
            )
        else:
            self.w = self.w_0

def get_hamiltonian(config):
    """Return appropriate Hamiltonian object based on the
    config.hamiltonian string.

    Parameters
    ----------
    config : Config
        Configuration object.

    Returns
    ----------
    hamiltonian : Hamiltonian
        Hamiltonian object.
    """
    if config.hamiltonian.lower() == "defaultnochi":
        hamiltonian = DefaultNoChi(config)
    elif config.hamiltonian.lower() == "defaultwithchi":
        hamiltonian = DefaultWithChi(
            config, config.unique_names, config.type_to_name_map
        )
    elif config.hamiltonian.lower() == "squaredphi":
        hamiltonian = SquaredPhi(config)

    return hamiltonian


"""
Задание на закрепление знаний по модулю yaml. Написать скрипт, автоматизирующий сохранение данных в файле YAML-формата.
Для этого:

a. Подготовить данные для записи в виде словаря, в котором первому ключу соответствует список, второму — целое число,
третьему — вложенный словарь, где значение каждого ключа — это целое число с юникод-символом, отсутствующим в кодировке
ASCII (например, €);

b. Реализовать сохранение данных в файл формата YAML — например, в файл file.yaml. При этом обеспечить стилизацию файла
с помощью параметра default_flow_style, а также установить возможность работы с юникодом: allow_unicode = True;

c. Реализовать считывание данных из созданного файла и проверить, совпадают ли они с исходными.
"""
import os
import sys
import json
import yaml

PACKAGE_PARENT = '../..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from homework.common.printer import print_task

CURRENT_DIR = os.path.dirname(__file__)

ORDERS_JSON = 'orders.json'

def get_data() -> dict:
    """
    Читает JSON-файл с заказами и выдает данные

    :return: словарь данных
    """
    filepath = f'{CURRENT_DIR}\\{ORDERS_JSON}'
    with open(filepath) as f:
        return json.load(f)

def save_and_verify(filename: str, data: dict = None):
    """
    Сохраняет принятые данные в указанный yaml документ в папке скрипта

    :param filename: имя или путь к файлу в папке скрипта
    :param data: словарь данных
    """
    filepath = f'{CURRENT_DIR}\\{filename if ".yaml" in filename else f"{filename}.yaml"}'

    with open(filepath, 'w') as f:
        yaml.dump(data, f, default_flow_style=False, allow_unicode=True)

    print(f'* Прочитанный файл {filepath}:\r\n')
    with open(filepath) as f:
        print(f.read())

def main():
    print_task(3)
    save_and_verify('file', get_data())

if __name__ == '__main__':
    main()


import torch
import torch.nn as nn
import numpy as np
import torch.nn.functional as F
import math

class MatAtt(nn.Module):

    def __init__(self, input_dim, output_dim, opt, batch_size=32):
        super(MatAtt, self).__init__()

        self.input_dim = input_dim
        self.output_dim = output_dim
        #self.opt = opt
        #self.batch_size = batch_size
        #self.opt =opt
        self.W_ct = nn.Parameter(torch.FloatTensor(input_dim, output_dim))
        self.W_tc = nn.Parameter(torch.FloatTensor(input_dim, output_dim))
        self.w_c1 = nn.Linear(input_dim,output_dim, bias=True)
        self.w_c2 = nn.Linear(input_dim, 1, bias=True)
        self.w_a1 = nn.Linear(input_dim, output_dim, bias=True)
        self.w_a2 = nn.Linear(input_dim, 1, bias=True)
        self.w_final = nn.Linear(2*input_dim, 2*output_dim, bias=True)
        self.w_a = nn.Parameter(torch.FloatTensor(input_dim,output_dim))
        self.w_c = nn.Parameter(torch.FloatTensor(input_dim,output_dim))
        self.W = nn.Parameter(torch.FloatTensor(input_dim,output_dim))
        #self.b_c = nn.Parameter(torch.FloatTensor(batch_size,))

        nn.init.uniform_(self.W_ct, -0.1, 0.1)
        nn.init.uniform_(self.W_tc, -0.1, 0.1)
        nn.init.uniform_(self.w_a, -0.1, 0.1)
        nn.init.uniform_(self.w_c, -0.1, 0.1)
        nn.init.uniform_(self.W, -0.1,0.1)

    def reset_parameters(self):
        stdv = 1. / math.sqrt(self.input_dim)
        if self.weight is not None:
            self.weight.data.uniform_(-stdv, stdv)

    def cdp(self,aspect, context):
        temp = torch.relu(torch.matmul(aspect, self.W))
        aspect = temp * context
        return aspect

    def forward(self, aspect, context):
         #batch_size = text.shape[0]
         batch_size = aspect.shape[0]
         context_len = context.shape[1]
         aspect_len = aspect.shape[1]
         #for i in range(batch_size):
         H_ct = torch.matmul(context, self.W_ct)# [batch_size, aspect_leq, 2*hidden] * [2*hidden, 2*hidden] = [batch_size,context_leq,2*hidden]
         H_ct = torch.matmul(H_ct,aspect.transpose(1,2))#[batch,context,aspect]
         H_tc = torch.matmul(aspect, self.W_tc)
         #属性词矩阵，上下文矩阵
         h_context = torch.matmul(H_ct, aspect) #[batch,context,aspect] * [batch,aspect,2*hidden] = [ba
         H_tc = torch.matmul(H_tc,context.transpose(1,2))#[batch, aspect, context]tch,context_len,2*hidden]
         h_aspect = torch.matmul(H_tc, context)#[batch, aspect_len, 2*hidden]
         #获得上下文和属性词向量 self-attention
         #score_c = torch.matmul(h_context,self.W_1c)#[batch,context,hidden]*[hidden,hidden]->[batch,context,hidden]
         #两层的mlp
         score_c_matrix = torch.relu(self.w_c1(h_context))#[batch,context,hidden]
         score_c_matrix = torch.relu(self.w_c2(score_c_matrix))#[batch,context,1]
         score_a_matrix = torch.relu(self.w_a1(h_aspect))  # [batch,aspect,hidden]
         score_a_matrix = torch.relu(self.w_a2(score_a_matrix))  # [batch,aspect,1]
         #softmax
         score_c = F.softmax(score_c_matrix,dim=1)#[batch,soft,1]
         score_a = F.softmax(score_a_matrix, dim=1)
         context_vec = torch.sum(h_context * score_c, dim=1,keepdim=True)#[batch,1,hidden]
         aspect_vec = torch.sum(h_aspect * score_a, dim=1,keepdim=True)#[batch,1,hidden]
         #print(context_vec.shape)
         # 开始交互注意力
         #context
         #b_c = torch.tensor(torch.zeros([batch_size,context_len,1])).to(self.opt.device)
         b_c = nn.Parameter(torch.FloatTensor(batch_size, context_len)).to(self.opt.device)
         b_c = nn.init.uniform_(b_c,-0.0,0.0)
         #b_c = nn.Parameter(torch.FloatTensor(batch_size,context_len)).to(self.opt.device)
         b_a = nn.Parameter(torch.FloatTensor(batch_size, aspect_len)).to(self.opt.device)
         b_a = nn.init.uniform_(b_a, -0.0, 0.0)
         #b_a = nn.Parameter(torch.FloatTensor(batch_size, aspect_len)).to(self.opt.device)
         context_att = torch.matmul(h_context, self.w_c)#batch len hidden [hidden,hidden]->[batch len hidden]
         context_att = torch.relu((torch.bmm(context_att,aspect_vec.transpose(1,2))).squeeze()+b_c)#[batch,len,hidden]*[batch hidden 1]->[batch,len,1]
         context_att = context_att.unsqueeze(dim=-1)#batch,len,1
         context_score = F.softmax(context_att,dim=1)#[batch,lensoft,1]
         context_rep = torch.sum(context_score * h_context,dim=1)#[batch,lensoft,batch] [batch,len,hidden]
         #aspect
         aspect_att = torch.matmul(h_aspect,self.w_a)
         aspect_att = torch.relu((torch.bmm(aspect_att, context_vec.transpose(1, 2))).squeeze()+b_a)
         aspect_att = aspect_att.unsqueeze(dim=-1)
         aspect_score = F.softmax(aspect_att,dim=1)
         aspect_rep = torch.sum(aspect_score * h_aspect, dim=1)
         #拼接
         #aspect_rep = self.cdp(aspect_rep, context_rep)
         final_rep = torch.cat((aspect_rep,context_rep),dim=1)
         final_rep = torch.relu(self.w_final(final_rep))

         return final_rep

    #def forward(self, aspect, context):
class Attention(nn.Module):
    def __init__(self, embed_dim, hidden_dim, out_dim=None, n_head=1, score_function='scaled_dot_product', dropout=0.1):
        ''' Attention Mechanism
        :param embed_dim:
        :param hidden_dim:
        :param out_dim:
        :param n_head: num of head (Multi-Head Attention)
        :param score_function: scaled_dot_product / mlp (concat) / bi_linear (general dot)
        :return (?, q_len, out_dim,)
        '''
        super(Attention, self).__init__()
        if hidden_dim is None:
            hidden_dim = embed_dim // n_head
        if out_dim is None:
            out_dim = embed_dim
        self.embed_dim = embed_dim
        self.hidden_dim = hidden_dim
        self.n_head = n_head
        self.score_function = score_function
        self.w_k = nn.Linear(embed_dim, n_head * hidden_dim)
        self.w_q = nn.Linear(embed_dim, n_head * hidden_dim)
        self.proj = nn.Linear(n_head * hidden_dim, out_dim)
        self.dropout = nn.Dropout(dropout)
        if score_function == 'mlp':
            self.weight = nn.Parameter(torch.Tensor(hidden_dim*2))
        elif self.score_function == 'bi_linear':
            self.weight = nn.Parameter(torch.Tensor(hidden_dim, hidden_dim))
        else:  # dot_product / scaled_dot_product
            self.register_parameter('weight', None)
        self.reset_parameters()

    def reset_parameters(self):
        stdv = 1. / math.sqrt(self.hidden_dim)
        if self.weight is not None:
            self.weight.data.uniform_(-stdv, stdv)

    def forward(self, k, q):
        if len(q.shape) == 2:  # q_len missing
            q = torch.unsqueeze(q, dim=1)
        if len(k.shape) == 2:  # k_len missing
            k = torch.unsqueeze(k, dim=1)
        mb_size = k.shape[0]  # ?
        k_len = k.shape[1]
        q_len = q.shape[1]
        # k: (?, k_len, embed_dim,)
        # q: (?, q_len, embed_dim,)
        # kx: (n_head*?, k_len, hidden_dim)
        # qx: (n_head*?, q_len, hidden_dim)
        # score: (n_head*?, q_len, k_len,)
        # output: (?, q_len, out_dim,)
        kx = self.w_k(k).view(mb_size, k_len, self.n_head, self.hidden_dim)
        kx = kx.permute(2, 0, 1, 3).contiguous().view(-1, k_len, self.hidden_dim)
        qx = self.w_q(q).view(mb_size, q_len, self.n_head, self.hidden_dim)
        qx = qx.permute(2, 0, 1, 3).contiguous().view(-1, q_len, self.hidden_dim)
        if self.score_function == 'dot_product':
            kt = kx.permute(0, 2, 1)#(-1,hidden,len)
            score = torch.bmm(qx, kt)#(-1,len,hidden)*(-1,hidden,len)->(-1,q_len,k_len)
        elif self.score_function == 'scaled_dot_product':
            kt = kx.permute(0, 2, 1)
            qkt = torch.bmm(qx, kt)
            score = torch.div(qkt, math.sqrt(self.hidden_dim))
        elif self.score_function == 'mlp':
            kxx = torch.unsqueeze(kx, dim=1).expand(-1, q_len, -1, -1)
            qxx = torch.unsqueeze(qx, dim=2).expand(-1, -1, k_len, -1)
            kq = torch.cat((kxx, qxx), dim=-1)  # (n_head*?, q_len, k_len, hidden_dim*2)
            # kq = torch.unsqueeze(kx, dim=1) + torch.unsqueeze(qx, dim=2)
            score = F.tanh(torch.matmul(kq, self.weight))
        elif self.score_function == 'bi_linear':
            qw = torch.matmul(qx, self.weight)
            kt = kx.permute(0, 2, 1)
            score = torch.bmm(qw, kt)
        else:
            raise RuntimeError('invalid score_function')
        score = F.softmax(score, dim=-1)#(-1,q_len,k_len)*(-1,k_len,hidden)->(-1,len,hidden)
        output = torch.bmm(score, kx)  # (n_head*?, q_len, hidden_dim)
        output = torch.cat(torch.split(output, mb_size, dim=0), dim=-1)  # (?, q_len, n_head*hidden_dim)
        output = self.proj(output)  # (?, q_len, out_dim)
        output = self.dropout(output)
        return output, score

class AM_Attention(nn.Module):
    def __init__(self, in_size, hidden_size):
        super(AM_Attention, self).__init__()
        self.project = nn.Sequential(
            nn.Linear(in_size, hidden_size),
            nn.Tanh(),
            nn.Linear(hidden_size, 1, bias=False)
        )

    def forward(self, z):
        w = self.project(z)
        #print('w shape is ',w.shape)
        beta = torch.softmax(w, dim=1)
        #print('beta shape is',beta.shape)
        return (beta * z).sum(1), beta


import pygame
from pygame.locals import *
import enemigos
import piloto
import numpy as np
from PIL import Image
import sys
import os

myDir = os.getcwd()
sys.path.append(myDir)
class Jugar:
    def __init__(self,x,px,py,ancho,velocidad):
        self.x = x
        self.px = px
        self.py = py
        self.ancho = ancho
        self.velocidad = velocidad

    def main(self):
        #print(I.size)
        I = Image.open("recursos/fondos/Jugar/jugarP.png")
        pygame.init()
        principal_img = pygame.image.load("recursos/fondos/Jugar/jugarP.png")
        ventana = pygame.display.set_mode(I.size)
        ventana.blit(principal_img,(0,0))
        pygame.display.set_caption('Play')
        pygame.display.update()
        clock=pygame.time.Clock()
        Jugar.personaje(ventana,self)

    def personaje(ventana,self):
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                if event.type == pygame.KEYDOWN and event.key == K_SPACE:
                    ins = enemigos.Enemi(ventana,900,340,True,10,0,0)
                    ins2 = piloto.Pilot(ventana,1500,178,True,10,0,0)
                    Jugar.camina(self,ventana,ins,ins2)

    def camina(self,ventana,ins,ins2):
        caminar = [pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (1).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (2).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (3).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (4).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (5).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (6).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (7).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (8).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (9).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (10).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (11).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (12).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (13).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (14).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Walk (15).png'),(100,100))]

        salta = [pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (1).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (2).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (3).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (4).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (5).png'),(100,100)),
				 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (6).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (7).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (8).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (9).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (10).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (11).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (12).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (13).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (14).png'),(100,100)),
                 pygame.transform.scale(pygame.image.load('recursos/sprites/jugador/Jump (15).png'),(100,100))]

        camina = Jugar(0,94,335,30,5)

        # Control de FPS
        reloj = pygame.time.Clock()

        # Variables salto
        salto = False
        # Contador de salto
        cuentaSalto = 10

        # Variables dirección
        izquierda = False
        derecha = False

        # Pasos
        cuentaPasos = 0
        # Movimiento
        def recarga_pantalla(cuentaPasos):
            fondo = pygame.image.load("recursos/fondos/Jugar/jugar.png")
            # Fondo en movimiento
            x_relativa = camina.x % fondo.get_rect().width
            ventana.blit(fondo, (x_relativa - fondo.get_rect().width, 0))
            if x_relativa < 999:
                ventana.blit(fondo, (x_relativa, 0))
            camina.x -= 5

            # Movimiento a la derecha
            if derecha:
                ventana.blit(caminar[cuentaPasos//1], (camina.px, camina.py))
            # Movimiento a la izquierda
            elif izquierda:
                ventana.blit(pygame.transform.flip(caminar[cuentaPasos//1],True,False), (camina.px, camina.py))
            elif derecha and izquierda == False and salto == False :
                ventana.blit(caminar[cuentaPasos // 1], (camina.px, camina.py))

        ejecuta = True

        # Bucle de acciones y controles

        while True:
            cir_per = pygame.draw.circle(ventana,(0,0,255),(camina.px+40,camina.py+50),20)
            ins.ene()
            ins2.ene()
            # FPS
            reloj.tick(20)
            # Bucle del juego
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    vent(0)

            # Opción tecla pulsada
            keys = pygame.key.get_pressed()
            # Contador de pasos
            if cuentaPasos + 1 >= 15:
                cuentaPasos = 0
            # Tecla - Moviemiento a la izquierda
            elif keys[pygame.K_LEFT] and camina.px > camina.velocidad:
                camina.px -= camina.velocidad-1
                izquierda = True
                derecha = False
                cuentaPasos += 1

            # Tecla - Moviemiento a la derecha
            elif keys[pygame.K_RIGHT] and camina.px < 900 - camina.velocidad - camina.ancho:
                camina.px += camina.velocidad
                izquierda = False
                derecha = True
                cuentaPasos += 1

            elif keys[pygame.K_ESCAPE]:
                vent(0)

            # Personaje quieto
            else:
                izquierda = False
                derecha = True
                cuentaPasos += 1

            # Tecla SPACE - Salto
            if not salto:
                if keys[pygame.K_UP]:
                    salto = True
                    izquierda = False
                    derecha = False
                    cuentaPasos = 0

            else:
                if cuentaSalto >= -10:
                    camina.py -= (cuentaSalto * abs(cuentaSalto)) * 0.5
                    ventana.blit(salta[cuentaPasos // 1], (camina.px, camina.py))
                    cuentaSalto -= 1
                else:
                    cuentaSalto = 10
                    salto = False

            # print("bx: ",camina.px)
            # print("by: ",camina.py)
            if ins.choque(cir_per) == True:
                vent(0)
            if ins2.choque_pilot(cir_per) == True:
                vent(0)
            # Actualización de la ventana
            pygame.display.update()
            #Llamada a la función de actualización de la ventana
            recarga_pantalla(cuentaPasos)

def credit(self):
    I = Image.open("recursos/fondos/creditos/creditos.png")
    #print(I.size)while True:
    pygame.init()
    ventana = pygame.display.set_mode(I.size)
    principal_img = pygame.image.load("recursos/fondos/creditos/creditos.png")
    ventana.blit(principal_img,(0,0))
    pygame.display.set_caption('Creditos')
    pygame.display.update()
    clock=pygame.time.Clock()
    while True:
        for eventos in pygame.event.get():
            if eventos.type == pygame.QUIT:
                pygame.quit()
            if eventos.type==pygame.MOUSEBUTTONDOWN:
                (x,y) = pygame.mouse.get_pos()
                if x>=987 and y>=580 and x<=1294 and y<=734:
                    vent(self)

def vent(self):
    I = Image.open("recursos/fondos/principal/fondo.png")
    #print(I.size)
    pygame.init()
    ventana = pygame.display.set_mode(I.size)
    principal_img = pygame.image.load("recursos/fondos/principal/fondo.png")
    ventana.blit(principal_img,(0,0))
    pygame.display.set_caption('Game plataform')
    pygame.display.update()
    clock=pygame.time.Clock()
    while True:
        for eventos in pygame.event.get():
            if eventos.type == pygame.QUIT:
                pygame.quit()
            if eventos.type==pygame.MOUSEBUTTONDOWN:
                (x,y) = pygame.mouse.get_pos()
                if x>=987 and y>=580 and x<=1294 and y<=734:
                    sys.exit()
                if x>=558 and y>=580 and x<=867 and y<=734:
                    credit(self)
                if x>=104 and y>=580 and x<=408 and y<=734:
                    Jugar.main(self)


'''Load data and build generators.'''

from data_preprocesser import normalize_image, random_crop_image, center_crop_image
from data_preprocesser import resize_image, horizontal_flip_image
# from data_preprocesser import ImageDataGenerator
from keras.preprocessing.image import ImageDataGenerator
import random,cv2
import numpy as np
def train_preprocessing(x, size_target=(244, 244)):
    '''Preprocessing for train dataset image.

    Args:
        x: input image.
        size_target: a tuple (height, width) of the target size.

    Returns:
        Preprocessed image.
    '''
    return normalize_image(
        center_crop_image(
            horizontal_flip_image(
                resize_image(
                    x,
                    size_target=size_target,
                    flg_keep_aspect=True
                )
            )
        ),
        mean=[123.82988033, 127.3509729, 110.25606303]
    )

def valid_preprocessing(x, size_target=(244, 244)):
    '''Preprocessing for validation dataset image.

    Args:
        x: input image.
        size_target: a tuple (height, width) of the target size.

    Returns:
        Preprocessed image.
    '''
    return normalize_image(
        center_crop_image(
            resize_image(
                x,
                size_target=size_target,
                flg_keep_aspect=True
            )
        ),
        mean=[123.82988033, 127.3509729, 110.25606303]
    )
def random_crop(img,w = 244,h = 244):
    #随机生成多边形并填充
    n = random.randint(5, 10)  # n个点
    # img = np.zeros((w, h, 3), np.int32)
    # img = np.asarray(img, np.int32)
    point = np.zeros((n, 2))
    for i in range(n):
        x = random.randint(int(0), int(w  ))
        y = random.randint(int(0 ), int(h  ))
        point[i][0] = x
        point[i][1] = y
        # print(x, y)
    point = np.asarray(point, np.int32)
    # plt.imshow(img)
    color = [random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)]
    res=cv2.fillPoly(img, [point], color)
    img = np.asarray(res.get(), np.int32)
    # print(res)

    # plt.imshow(img)
    # plt.show()
    # sys.exit(0)
    return res.get()
def build_generator(
        train_dir=None,
        valid_dir=None,
        batch_size=128
    ):
    '''Build train and validation dataset generators.

    Args:
        train_dir: train dataset directory.
        valid_dir: validation dataset directory.
        batch_size: batch size.

    Returns:
        Train generator and validation generator.
    '''

    results = []
    if train_dir:
        train_datagen = ImageDataGenerator(
            preprocessing_function=random_crop,
            rescale = 1./255,
            samplewise_center=True,
            samplewise_std_normalization=True,
            rotation_range=100,
            width_shift_range=0.4,
            height_shift_range=0.4,
            shear_range=0.4,
            zoom_range=0.4,
            horizontal_flip=True,
            fill_mode='constant',
            cval=0
        )
        train_generator = train_datagen.flow_from_directory(
            train_dir,
            target_size=(244, 244),
            batch_size=batch_size,
            class_mode='categorical'
        )
        results += [train_generator]

    if valid_dir:
        valid_datagen = ImageDataGenerator(
            preprocessing_function=random_crop,
            rescale = 1./255,
            samplewise_center=True,
            samplewise_std_normalization=True,
            rotation_range=100,
            width_shift_range=0.4,
            height_shift_range=0.4,
            shear_range=0.4,
            zoom_range=0.4,
            horizontal_flip=True,
            fill_mode='constant',
            cval=0
        )
        valid_generator = valid_datagen.flow_from_directory(
            valid_dir,
            target_size=(244, 244),
            batch_size=batch_size,
            class_mode='categorical'
        )
        results += [valid_generator]

    return results

if __name__ == "__main__":
    pass


from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
import os

D = pd.read_csv('param_file_new.csv')

filename = '%s/%s.36500000.0_days_sca_node.csv' % (D.prefix[0],D.prefix[0])

D1 = pd.read_csv(filename)
xvec = np.arange(D.min_x[0],D.max_x[0],D.dx[0])
yvec = np.arange(D.min_y[0],D.max_y[0],D.dy[0])
zvec = np.arange(0,D.upper_numlayers[0]+D.middle_numlayers[0]+D.lower_numlayers[0],1)
XX,YY,ZZ = np.meshgrid(xvec,yvec,zvec)

D1['ZZtemp'] = ZZ.flatten(order='F')
D_temp = D1[D1.ZZtemp==12]

plt.scatter(D_temp[' X coordinate (m)'], D_temp[' Y coordinate (m)'],c = D_temp[' Temperature (deg C)'])
plt.colorbar()
plt.show()


from django import forms
from shared.models import *

class Form(forms.Form):
    case_id = forms.IntegerField(widget=forms.HiddenInput)
    case_name = forms.CharField(widget=forms.HiddenInput)

class ContactForm(forms.Form):
    case_id = forms.IntegerField(label='Case ID', widget=forms.HiddenInput)
    case_name = forms.CharField(label='Case Name', widget=forms.HiddenInput)
    contact_name = forms.CharField(label='Contact Name', max_length=256)
    contact_phone_num = forms.CharField(label='Contact Phone number', max_length=13)
    contact_email = forms.EmailField(label='Contact Email')
    place_of_contact = forms.CharField(label='Address of place of contact', max_length=256)
    postcode = forms.CharField(label='Postcode', max_length=8)

    # find if a person already exists in the database. Enter them if not and return the pk.
    def lookup_person(self):
        person = People.objects.filter(name__exact=self.cleaned_data['contact_name'],
                                       phone_num__exact=self.cleaned_data['contact_phone_num'],
                                       email__exact=self.cleaned_data['contact_email'])
        assert (person.count() <= 1)
        if person.count() == 0:
            # add person to model
            # check if address exists
            possibleAddress = Addresses.objects.filter(addr__exact=self.cleaned_data['place_of_contact'],
                                                       postcode=self.cleaned_data['postcode'])
            if possibleAddress.count() == 0:
                location = Addresses(addr=self.cleaned_data['place_of_contact'], postcode=self.cleaned_data['postcode'])
                location.save()
                # bit weird because persons address gets saved as the place of contact, which is not necessarily accurate, also their date of birth will be the default
                # TODO: Check this doesn't effect the stats
                p = People(
                    name=self.cleaned_data['contact_name'],
                    phone_num=self.cleaned_data['contact_phone_num'],
                    email=self.cleaned_data['contact_email'],
                    location=Addresses.objects.get(pk=location.pk)
                )
            else:
                p = People(
                    name=self.cleaned_data['contact_name'],
                    phone_num=self.cleaned_data['contact_phone_num'],
                    email=self.cleaned_data['contact_email'],
                    location=possibleAddress.first()
                )
            p.save()
            return p.pk
        else:
            return person.first().pk

    # find if an address already exists in the database. Enter it if not and return the pk.
    def lookup_address(self):
        address = Addresses.objects.filter(addr__exact=self.cleaned_data['place_of_contact'],
                                       postcode__exact=self.cleaned_data['postcode'])
        assert (address.count() <= 1)
        if address.count() == 0:
            location = Addresses(addr=self.cleaned_data['place_of_contact'], postcode=self.cleaned_data['postcode'])
            location.save()
            return location.pk
        else:
            return address.first().pk

    # assumes that the test has not already been input
    def input_contact(self, contactID, location):
        t = Contact(
            positive_case = Test.objects.get(pk=self.cleaned_data['case_id']),
            case_contact = People.objects.get(pk=contactID),
            location = Addresses.objects.get(pk=location)
        )
        t.save()

    def add_contact(self):
        # process the data in self.cleaned_data as required
        person = self.lookup_person()
        location = self.lookup_address()
        self.input_contact(person, location)

FINISHED_CHOICES = [(True, "Yes"), (False, "No")]

# a form for updating TestContacted if successful
class TestContactedForm(forms.Form):
    case_id = forms.IntegerField(label='Case ID', widget=forms.HiddenInput)
    success = forms.ChoiceField(widget=forms.RadioSelect, choices=FINISHED_CHOICES, label='Successfully contacted')

    def confirm_call(self):
        if self.cleaned_data['success']:
            case = Test.objects.get(pk=self.cleaned_data['case_id'])
            c = TestContacted(
                case=case
            )
            c.save()

# a form for updating ContactContacted if successful
class ContactContactedForm(forms.Form):
    contact_id = forms.IntegerField(label='Contact ID', widget=forms.HiddenInput)
    success = forms.ChoiceField(widget=forms.RadioSelect, choices=FINISHED_CHOICES, label='Successfully contacted')

    def confirm_call(self):
        if self.cleaned_data['success']:
            contact = Contact.objects.get(pk=self.cleaned_data['contact_id'])
            c = ContactContacted(
                contact=contact
            )
            c.save()


from django.urls import path, include
from rest_framework import permissions
from .views import DirectionApiView, DisciplineApiView, StudyGroupApiView, StudentApiView, get_report, report_status
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
   openapi.Info(
      title="University Cervice API",
      default_version='v1',
      description="",
   ),
   public=True,
   permission_classes=[permissions.IsAuthenticated],
)

urlpatterns = [
    path('api/v1/report/', get_report),
    path('api/v1/report-status/', report_status),
    path('api/v1/diretions/', DirectionApiView.as_view()),
    path('api/v1/diretions/<int:id>/', DirectionApiView.as_view()),
    path('api/v1/disciplines/', DisciplineApiView.as_view()),
    path('api/v1/disciplines/<int:id>/', DisciplineApiView.as_view()),
    path('api/v1/studygroups/', StudyGroupApiView.as_view()),
    path('api/v1/studygroups/<int:id>/', StudyGroupApiView.as_view()),
    path('api/v1/students/', StudentApiView.as_view()),
    path('api/v1/students/<int:id>/', StudentApiView.as_view()),
    path('api/v1/drf-auth/', include('rest_framework.urls')),
    path('api/v1/docs/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]


"""Add Oauth table to support social sign in

Revision ID: 65bab22d239a
Revises: 2ab89177fcba
Create Date: 2022-09-16 07:44:54.929466

"""
import sqlalchemy as sa
from alembic import op
from fastapi_users_db_sqlalchemy import GUID

# revision identifiers, used by Alembic.
revision = "65bab22d239a"
down_revision = "2ab89177fcba"
branch_labels = None
depends_on = None

def upgrade() -> None:
    op.create_table(
        "oauth_account",
        sa.Column("oauth_name", sa.String(length=100), nullable=False),
        sa.Column("access_token", sa.String(length=1024), nullable=False),
        sa.Column("expires_at", sa.Integer(), nullable=True),
        sa.Column("refresh_token", sa.String(length=1024), nullable=True),
        sa.Column("account_id", sa.String(length=320), nullable=False),
        sa.Column("account_email", sa.String(length=320), nullable=False),
        sa.Column("id", GUID(), nullable=False),
        sa.Column("user_id", GUID(), nullable=False),
        sa.ForeignKeyConstraint(("user_id",), ["user.id"], ondelete="cascade"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(
        op.f("ix_oauth_account_account_id"),
        "oauth_account",
        ["account_id"],
        unique=False,
    )
    op.create_index(
        op.f("ix_oauth_account_oauth_name"),
        "oauth_account",
        ["oauth_name"],
        unique=False,
    )
    op.add_column(
        "user",
        sa.Column(
            "has_real_password", sa.Boolean(), server_default="t", nullable=False
        ),
    )

def downgrade() -> None:
    op.drop_index(op.f("ix_oauth_account_oauth_name"), table_name="oauth_account")
    op.drop_index(op.f("ix_oauth_account_account_id"), table_name="oauth_account")
    op.drop_table("oauth_account")
    op.drop_column("user", "has_real_password")


"""
This module provides a function to retrieve city data from a MongoDB database and the NOAA API, and
write the data to a CSV file.

Functions:
    get_cities_data() -> None
        Retrieves data on cities from the NOAA API and writes it to a CSV file. Filters the API
        results to only include cities already present in the database.
        API documentation: https://www.ncdc.noaa.gov/cdo-web/webservices/v2#locations

Example usage:
    # Call from command line:
    # python get_city_id.py

Notes:
    This module requires the following libraries to be installed:
    requests, csv, os, dotenv, pymongo.
    The module also requires a .env file to be present in the root directory, containing the
    following variable: NCEI_TOKEN.
    The get_database function is imported from a separate module, which should contain the necessary
    code to establish a connection to the MongoDB database.
"""

import requests
import os
import csv
from dotenv import load_dotenv

import sys
sys.path.insert(0, '../..')  # Add parent directory to sys.path

from get_database import get_database

# Load environment variables
load_dotenv()

# Get NCEI API token from environment variables
NCEI_TOKEN = os.getenv('NCEI_TOKEN')

# Get database and cities collection
dbname = get_database()
cities_collection = dbname["cities"]

def get_cities_data() -> None:
    """
    Retrieves data for all cities available from the NOAA API and saves it to a CSV file.
    Continuously updates the API's offset parameter until all available data has been retrieved.

    Parameters:
        None

    Returns:
        None

    Raises:
        HTTPError: If the initial API call fails, or if subsequent calls return an HTTP error.
    """

    # Get a list of all cities in the database
    cities = cities_collection.distinct('city')

    # Set up the initial API parameters for the first request
    url = "https://www.ncdc.noaa.gov/cdo-web/api/v2/locations"
    params = {
        'datasetid': 'GHCND',  # Only get data from this dataset
        'locationcategoryid': 'CITY',  # Only get data for cities
        'limit': 1000,  # Get up to 1000 results per request
        'offset': 0  # Start with the first result
    }

    while True:
        # Make the API request
        response = requests.get(url, params=params, headers={
            'token': NCEI_TOKEN}, timeout=20)

        # Get the data from the response
        data = response.json().get("results", [])

        # If no data is returned, we've got all the data and can break out of the loop
        if not data:
            break

        # Write the data to the CSV file
        with open('csv/cities.csv', mode='a', newline='', encoding='UTF-8') as csv_file:
            writer = csv.writer(csv_file)

            for result in data:
                name = result['name']
                split_name = name.split(',')
                city = split_name[0]

                # Only write the city if it exists in the DB
                if city in cities:
                    mindate = result['mindate']
                    maxdate = result['maxdate']
                    city_id = result['id']
                    writer.writerow([mindate, maxdate, name, city, city_id])

        # Update the offset for the next request
        params['offset'] += len(data)

if __name__ == "__main__":
    get_cities_data()


from motor_typing import TYPE_CHECKING
import functools
from .lr0path import LR0PathItem

class LR0Node(object):

    def __init__(self, item_set, item, predecessor=None, parent=None):
        # type: (LR0ItemSet, LR0Item, Optional[Tuple[int, "LR0Node"]], Optional[LR0Node]) -> None
        self._item_set = item_set
        self._item = item

        if predecessor is not None:
            self._predecessor_lookahead = predecessor[0] # type: Optional[int]
            self._predecessors = [predecessor[1]]        # type: List[LR0Node]
        else:
            self._predecessor_lookahead = None
            self._predecessors = []
        self._successor = None                           # type: Optional[LR0Node]

        self._direct_parents = []      # type: List[LR0Node]
        self._direct_children = []     # type: List[LR0Node]
        if parent is not None:
            self._direct_parents.append(parent)
            parent._direct_children.append(self)

    def expand_empty_recursive(self):
        # type: () -> LR0Path
        # expand the first item of the path to build empty productions
        if self._item._index == self._item.len:
            return LR0PathItem(self._item)
        assert self._successor is not None
        for child in self._direct_children:
            if -1 not in child._item._first:
                continue
            if child._successor is None:
                result = LR0PathItem(child._item) # type: LR0Path
                result = result.derive_from(self._item)
                queue = self._successor.expand_empty_recursive()
                return result.expand_next(queue)
            else:
                if -1 in child._item._follow:
                    p = child._successor.expand_empty()
                    result = child.expand_empty()
                    result = result.expand_next(p)
                    result = result.derive_from(self._item)
                    queue = self._successor.expand_empty_recursive()
                    return result.expand_next(queue)
        raise ValueError()

    def expand_empty(self):
        # type: () -> LR0Path
        # expand the first item of the path to build empty productions
        if self._item._index == self._item.len:
            return LR0PathItem(self._item)
        for child in self._direct_children:
            if -1 not in child._item._first:
                continue
            if child._successor is None:
                result = LR0PathItem(child._item) # type: LR0Path
                result = result.derive_from(self._item)
                return result
            else:
                if -1 in child._item._follow:
                    p = child._successor.expand_empty()
                    result = child.expand_empty()
                    result = result.expand_next(p)
                    result = result.derive_from(self._item)
                    return result
        raise ValueError()

    def expand_lookahead(self, lookahead):
        # type: (Set[int]) -> LR0Path
        # expand the first item of the path until it starts with the lookahead
        queue = [(self, [[]])]     # type: List[Tuple[LR0Node, List[List[LR0Path]]]]
        seen = set()

        while queue:
            node, paths = queue.pop(0)
            if node in seen:
                continue
            seen.add(node)

            if node._item != node._item._last:
                following_symbol = node._item.rule.production[node._item._index]
                if following_symbol in lookahead:
                    previous = None
                    paths[-1].append(LR0PathItem(node._item))
                    while paths:
                        child_paths = paths.pop(-1)
                        if previous is not None:
                            child_paths[-1] = child_paths[-1].expand_next(previous)
                        merge_children = lambda x, y: x.derive_from(y._items[0][1])
                        result = functools.reduce(merge_children, child_paths[::-1])
                        previous = result
                    return result
                else:
                    if not lookahead.isdisjoint(node._item._first):
                        for child in node._direct_children:
                            queue.append((child, paths[:-1] + [paths[-1] + [LR0PathItem(node._item)]]))
                    if -1 in node._item._first and node._successor is not None:
                        empty_path = node.expand_empty()
                        queue.append((node._successor, paths[:-1] + [paths[-1] + [empty_path]] + [[]]))
        raise ValueError()

    def filter_node_by_lookahead(self, path, lookahead):
        # type: (LR0Path, Set[int]) -> LR0Path
        following_symbol = self._item.rule.production[self._item._index + 1]
        assert self._successor is not None
        if following_symbol in lookahead:
            return path
        elif not lookahead.isdisjoint(self._successor._item._first):
            try:
                successor_path = self._successor.expand_lookahead(lookahead)
            except ValueError:
                successor_path = self._successor.expand_lookahead(lookahead)
            return path.expand_next(successor_path)
        elif -1 in self._successor._item._first:
            successor_path = self._successor.expand_empty()
            p = self._successor.filter_node_by_lookahead(successor_path, lookahead)
            result = path.expand_next(p)
            return result
        else:
            raise ValueError()

    def backtrack_up(self, path, lookahead, seen):
        # type: (LR0Path, Set[int], Set[Union[Tuple["LR0Node", bool], LR0ItemSet]]) -> List[Tuple["LR0Node", LR0Path, Set[int], Optional[int]]]
        queue = [(self, path, lookahead)]
        result = []                # type: List[Tuple["LR0Node", LR0Path, Set[int], Optional[int]]]
        state_path_seen = set()    # type: Set[Tuple[LR0ItemSet, int]]

        seen.add(self._item_set)

        while queue:
            node, path, lookahead = queue.pop(0)

            for parent in node._direct_parents:
                if (parent, bool(lookahead)) in seen:
                    continue
                seen.add((parent, bool(lookahead)))
                item = parent._item
                if lookahead:
                    if not lookahead.isdisjoint(item._follow):
                        p = parent.filter_node_by_lookahead(path.derive_from(parent._item), lookahead)
                        result.append((parent, p, set(), None))
                        queue.append((parent, p, set()))
                    if -1 in item._follow:
                        if item != item._last:
                            assert parent._successor is not None
                            empty_path = parent._successor.expand_empty_recursive()
                            p = path.derive_from(parent._item).expand_next(empty_path)
                            queue.append((parent, p, lookahead))
                        else:
                            queue.append((parent, path.derive_from(parent._item), lookahead))
                else:
                    queue.append((parent, path.derive_from(parent._item), lookahead))
            for predecessor in node._predecessors:
                if lookahead:
                    if (predecessor._item_set, predecessor._item._symbol) in state_path_seen:
                        continue
                    state_path_seen.add((predecessor._item_set, predecessor._item._symbol))
                assert node._predecessor_lookahead is not None
                result.append((predecessor, path.extend(predecessor._item), lookahead, node._predecessor_lookahead))

        return result

    def backtrack_to_any(self, path, nodes):
        # type: (LR0Path, List["LR0Node"]) -> Tuple["LR0Node", LR0Path]
        if self in nodes:
            return self, path
        queue = [(self, path)]
        seen = set()
        seen.add(self)
        while queue:
            node, path = queue.pop(0)

            for parent in node._direct_parents:
                if parent in seen:
                    continue
                seen.add(parent)
                if parent in nodes:
                    return parent, path.derive_from(parent._item)
                else:
                    queue.append((parent, path.derive_from(parent._item)))

        raise ValueError()

if TYPE_CHECKING:
    from motor_typing import Dict, List, Optional, Set, Tuple, Union
    from .lr0item import LR0Item
    from .lr0path import LR0Path
    from .lr0itemset import LR0ItemSet


import random
import sys

import pyautogui
import pyperclip
import time
pyautogui.PAUSE = 0
def get_board():
    t = time.time()
    pyautogui.moveTo(1281, 188)
    pyautogui.click()
    pyautogui.hotkey('ctrl', 'c')
    coldic = {'red': 'RE', 'lightblue': 'LB', 'purple': 'PU', 'green': 'GR', 'pink': 'PN', 'orange': 'OG', 'maroon': 'MR', 'teal': 'TL', 'yellow': 'YL', 'brown': 'BR', 'blue': 'BL', 'purpleblue': 'PB', '': ''}
    html = pyperclip.paste()
    lines = []
    current_line = []
    html = html[:html.find('
')]
    if 'alert center' in html:
        return '', True
    for i, item in enumerate(html):
        if html[i:].startswith('")+1:]
            if '<' in number:
                number = number[:number.find('<')]
            if number != '':
                number = int(number.replace("%", ""))
            else:
                number = 0
            name = ''
            for q in scanned:
                if q == '"':
                    add = not add
                    if add:
                        continue
                    else:
                        break
                if add:
                    name += q
            namelm = name.split(' ')
            namel = []
            owner = ''
            for thing in namelm:
                if thing != 'attackable':
                    namel.append(thing)
            if namel[-1] in ['large', 'small', 'tiny']:
                namel = namel[:-1]
            if namel == ['mountain']:
                name = 'MTN'
            if 'neutral' in namel[1:]:
                name = 'n'
                owner = coldic[namel[0]]
            if 'city' in namel[1:]:
                name = 'c'
                owner = coldic[namel[0]]
            if namel == ['fog']:
                name = '?'
            if namel == ['fog', 'obstacle']:
                name = 'M?'
            if 'general' in namel:
                name = 'g'
                owner = coldic[namel[0]]
            if namel == ['']:
                name = 'n'
            current_line.append([owner, name, number])
        if html[i:].startswith('
'):
            lines.append(current_line)
            current_line = []
    return lines, False
print(get_board())
def move_space(startx, starty, direction, board, g_c):
    for a, l in enumerate(board):
        for b, m in enumerate(l):
            if m[0] == 'RE' and m[1] == 'g':
                board_general = (b, a)
                break
    general_coords = g_c
    pyautogui.click(1, 1)
    assert direction in ['up', 'left', 'right', 'down']
    pyautogui.click(general_coords)
    xmove = startx - board_general[0]
    ymove = starty - board_general[1]
    wait = 0.1
    with pyautogui.hold('shift'):
        if xmove < 0:
            for _ in range(abs(xmove)):
                pyautogui.press('left')
                time.sleep(wait)
        else:
            for _ in range(abs(xmove)):
                pyautogui.press('right')
                time.sleep(wait)
        if ymove > 0:
            for _ in range(abs(ymove)):
                pyautogui.press('down')
                time.sleep(wait)
        else:
            for _ in range(abs(ymove)):
                pyautogui.press('up')
                time.sleep(wait)
    pyautogui.press(direction)


import sqlite3
db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
sql=db.cursor()
db.row_factory=sqlite3.Row
# вставлять везде этот обработчик ошибок
# db = None
# try:
# except sqlite3.Error as e:
#     if db: db.rollback()
#     print (e)
# finally:
#     db.commit()
#     if db: db.close()

#функция проверки зарегистрирован ли ползователь
def check_registration(username):
    db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
    sql=db.cursor()
    db = None
    try:
        sql.execute(f"SELECT name FROM worker WHERE username == '{username}'")
        from_worker = sql.fetchone()
        sql.execute(f"SELECT name FROM client WHERE username == '{username}'")
        from_client = sql.fetchone()
        if from_worker != None or from_client != None:
            return True
        else:
            return False
    except sqlite3.Error as e:
        if db: db.rollback()
        print (e)
    finally:
        if db: db.close()

#функция проверки роли пользователя
def check_role(username):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT 'worker' as source, username FROM worker WHERE username='{username}' UNION ALL SELECT 'client' as source, username FROM client WHERE username='{username}'")
        rows = sql.fetchone()
        # print(rows)
        return rows[0]
    except:
        return 'Пользователь не найден'

#запись работника в бд
def reg_worker(date, username):
    db = None

    worker_information = date[username]
    username = worker_information['username'].replace(' ', '_')
    first_name = worker_information['first_name'].replace(' ', '_')
    resume = worker_information['resume'].replace(' ', '_')
    phone = worker_information['phone'].replace(' ', '_')
    age = worker_information['age']
    chat_id = worker_information['chat_id']
    if resume == '/next': #обработка пропуска
        resume = 'Не указано'
    try:
        db = sqlite3.connect('DataBases/workers.db')
        sql = db.cursor()

        sql.execute(f"INSERT INTO worker (username , name , specialization, phone_number, age, rate, chat_id) VALUES('{username}', '{first_name}','{resume}','{phone}', '{age}', '{0}', '{chat_id}')")
        sql.execute(f"UPDATE main_info SET workers_count = workers_count + 1")

    except sqlite3.Error as e:
        if db: db.rollback()
        print (e)

    finally:
        db.commit()
        if db: db.close()

def reg_client(client_info,username):               #функция записи заказчика в базу данных, принимает словарь и имя пользователя
    username=client_info[username]['username']
    chat_id=client_info[username]['chat_id']
    phone_number=client_info[username]['phone_number']
    name=client_info[username]['name']
    try:
        sql.execute(f"INSERT INTO client(name,phone_number,chat_id,username) VALUES('{name}','{phone_number}','{chat_id}','{username}')")
        sql.execute(f"UPDATE main_info SET client_count = client_count + 1")
    except sqlite3.Error as e:
        if db: db.rollback()
        print (e)
    finally:
        db.commit()
        db.close()

#изменение имени у работника
def worker_change_name_bd(username, new_username):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"UPDATE worker SET name = '{new_username}' WHERE username = '{username}'")
        return f'Успешно, ваше имя измененно на {new_username}'
    except sqlite3.Error as e:
        if db: db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()
#изменение описания у работника
def worker_change_description_bd(username, new_description):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"UPDATE worker SET specialization = '{new_description}' WHERE username = '{username}'")
        return f'Успешно, ваше описание измененно'
    except sqlite3.Error as e:
        if db: db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()
#изменение номера телефона у работника
def worker_change_phone_bd(username, new_phone_namber):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"UPDATE worker SET phone_number = '{new_phone_namber}' WHERE username = '{username}'")
        return f'Успешно, ваш номер успешно изменен на {new_phone_namber}'
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()
#изменение возраста у работника
def worker_change_age_bd(username, new_age):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"UPDATE worker SET age = '{new_age}' WHERE username = '{username}'")
        return f'Успешно, ваш возраст успешно изменен на{new_age}'
    except sqlite3.Error as e:
        if db: db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

#изменение профиля у заказчика
#изменение имени у заказчика
def client_change_name_bd(username, new_username):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"UPDATE client SET name = '{new_username}' WHERE username = '{username}'")
        print ('name(1)')
        return f'Успешно, ваше имя измененно на {new_username}'
    except sqlite3.Error as e:
        if db: db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()
#изменение номера телефона у заказчика
def client_change_phone_bd(username, new_phone_namber):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"UPDATE client SET phone_number = '{new_phone_namber}' WHERE username = '{username}'")
        db.commit()
        return f'Успешно, ваш номер успешно изменен на {new_phone_namber}'
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

def all_vacancy_find_work_db():
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT id, client, title, description, adress, workers_count, age, price FROM 'order' WHERE status = '1'") #достаю все записи из двух столбцов
        all_vacancy = sql.fetchall()
        return all_vacancy
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

# print(all_vacancy_find_work_db())

#Добавление записи в таблицу черновая работа
def add_work_black(work_dict,username):               #функция записи заказчика в базу данных, принимает словарь и имя пользователя
    # username=client_info[username]['username']
    # chat_id=client_info[username]['chat_id']
    # phone_number=client_info[username]['phone_number']
    # name=client_info[username]['name']
    username=username
    type_work=title=work_dict[username]['type']
    title=work_dict[username]['title']
    description=work_dict[username]['description']
    adress=work_dict[username]['adress']
    count_workers=work_dict[username]['workers_count']
    age=work_dict[username]['age']
    price=work_dict[username]['price']

    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT id FROM client WHERE username=='{username}'")
        client=sql.fetchone()[0]
        print(client)

        sql.execute(f"INSERT INTO 'order' (client,title,description,adress,workers_count,age,price,type,status) VALUES('{client}','{title}','{description}','{adress}',{count_workers},'{age}','{price}','{type_work}',0)")
        sql.execute(f"UPDATE main_info SET orders_count = orders_count + 1")
        sql.execute(f"UPDATE main_info SET orders_sum = orders_sum + {price}")
        last_id = sql.execute('SELECT last_insert_rowid()').fetchone()[0]
        return last_id
    except sqlite3.Error as e:
        if db: db.rollback()
        print (e)
    finally:
        db.commit()
        db.close()

# add_work_black({'Hzorhz': {'type': 'Почасовая', 'title': 'название', 'description': 'Описание', 'adress': 'адрес', 'workers_count': 6, 'age': 12, 'price': 1789}},'Hzorhz')

def profile_worker_db(username):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT name, specialization, phone_number, age FROM worker WHERE username = '{username}'")
        date_worker = sql.fetchone()
        print(date_worker)
        return date_worker
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()
profile_worker_db('Alexei0212022')

def profile_client_db(username):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT name, phone_number FROM client WHERE username = '{username}'")
        date_client = sql.fetchone()
        return date_client
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

# print (profile_client_db('Alexei0212022'))

#достает chatid заказчика для пересылки ему отклика работника
def find_chatid_client_for_worker_db(id_order):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT client FROM 'order' WHERE id = '{id_order}'")
        client_id = sql.fetchone()[0]
        sql.execute(f'SELECT chat_id FROM client WHERE id = {client_id}')
        chatid_client = sql.fetchone()[0]
        return chatid_client
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

        db.close()

#Функция, которая возвращает чат айди админа

def select_admin_chat_id():
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT chat_id FROM admin")
        admin_chat_id = sql.fetchone()[0]

        return admin_chat_id
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

        db.close()
#Функция одобрения работы и перевода ее в активное состояние. Также возвращает чат айди клиента, чтобы отправить ему сообщение о том, что заявка опубликована
def accept_work_db(order_id):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"UPDATE 'order' SET status = 1 WHERE id = {order_id}")
        client_id=sql.execute(f"SELECT client FROM 'order' WHERE id = {order_id}").fetchone()[0]

        chat_id=sql.execute(f"SELECT chat_id FROM 'client' WHERE id = {client_id}").fetchone()[0]

        return chat_id
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

#Функция удаления работы из бд, если админ отклонил ее
def reject_work_db(order_id):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()

        client_id=sql.execute(f"SELECT client FROM 'order' WHERE id = {order_id}").fetchone()[0]

        chat_id=sql.execute(f"SELECT chat_id FROM 'client' WHERE id = {client_id}").fetchone()[0]

        sql.execute(f"DELETE FROM 'order' WHERE id ={order_id}")
        return chat_id
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

def select_worker_chat_id(username):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT chat_id FROM worker WHERE username = '{username}'")
        worker_chatid = sql.fetchone()[0]
        return worker_chatid
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

def full_info_order(order_id):
    try:
        db=sqlite3.connect('DataBases/workers.db',check_same_thread=False)
        sql=db.cursor()
        sql.execute(f"SELECT * FROM 'order' WHERE id = {order_id}")
        order_info = sql.fetchone()
        return order_info
    except sqlite3.Error as e:
        db.rollback()
        print (e)
        return 'Упс, что то пошло не так'
    finally:
        db.commit()
        db.close()

print(full_info_order(1))


import os
import shutil
from os.path import join, dirname

from django import test
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.management import call_command
from django.conf import settings

from image_helper.tests.test_app.models import TestModel
from image_helper.fields import _get_thumbnail_filename

class SizedImageFieldTests(test.TestCase):
    def setUp(self):
        call_command("migrate", verbosity=0)

    def tearDown(self):
        test_images_path = os.path.join(settings.MEDIA_ROOT, "test_images")
        if os.path.exists(test_images_path):
            shutil.rmtree(test_images_path)

    def _get_simple_uploaded_file(self):
        return SimpleUploadedFile(
            "sample_photo.png",
            open(join(dirname(__file__), "test_app/sample_photo.png"),
                 'rb').read(),
            content_type="image/png")

    def _save_image_model(self):
        upload_file = self._get_simple_uploaded_file()
        m = TestModel(image=upload_file)
        m.save()
        return m

    def test_saves_image_and_thumbnail(self):
        upload_file = self._get_simple_uploaded_file()
        m = TestModel(image=upload_file)
        m.save()

        model = TestModel.objects.get(pk=1)
        self.assertEqual("test_images/sample_photo.png", model.image.name)
        self.assertEqual("{}test_images/sample_photo.png".format(
            settings.MEDIA_URL), model.image.url)
        self.assertEqual("{}/test_images/sample_photo.png".format(
            settings.MEDIA_ROOT), model.image.path)
        self.assertEqual(True, os.path.exists(model.image.path))

        self.assertEqual("test_images/sample_photo-thumbnail.png",
                         model.image.thumbnail.name)
        self.assertEqual("{}test_images/sample_photo-thumbnail.png".format(
            settings.MEDIA_URL), model.image.thumbnail.url)
        self.assertEqual("{}/test_images/sample_photo-thumbnail.png".format(
            settings.MEDIA_ROOT), model.image.thumbnail.path)
        self.assertEqual(True, os.path.exists(model.image.thumbnail.path))

    def test_saves_appropriately_when_finding_valid_image_name(self):
        # Thumbnail should be named the same as image, just with the -thumbnail piece.
        self._save_image_model()
        self._save_image_model()

        model = TestModel.objects.get(pk=2)
        self.assertTrue(
            model.image.name.startswith("test_images/sample_photo"))
        self.assertNotEqual("test_images/sample_photo.png", model.image.name)
        self.assertEqual("{}{}".format(settings.MEDIA_URL, model.image.name),
                         model.image.url)
        self.assertEqual("{}/{}".format(settings.MEDIA_ROOT, model.image.name),
                         model.image.path)
        self.assertEqual(True, os.path.exists(model.image.path))

        expected_thumbnail_name = _get_thumbnail_filename(model.image.name)
        self.assertEqual(expected_thumbnail_name, model.image.thumbnail.name)
        self.assertEqual("{}{}".format(settings.MEDIA_URL,
                                       expected_thumbnail_name),
                         model.image.thumbnail.url)
        self.assertEqual("{}/{}".format(settings.MEDIA_ROOT,
                                        expected_thumbnail_name),
                         model.image.thumbnail.path)
        self.assertEqual(True, os.path.exists(model.image.thumbnail.path))

class GetThumbnailFilenameTests(test.TestCase):
    def test_get_thumbnail_filename(self):
        thumbnail_name = _get_thumbnail_filename("my_image.jpg")
        self.assertEqual("my_image-thumbnail.jpg", thumbnail_name)

    def test_allows_customized_append_text(self):
        thumbnail_name = _get_thumbnail_filename(
            "my_image.jpg", append_text="-small")
        self.assertEqual("my_image-small.jpg", thumbnail_name)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#!/usr/bin/python3
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import json
import pprint
#import mysql.connector
#from mysql.connector import (connection)
import re
import codecs
import myTokenizer as mt
import openpyxl

def processText(ith, mainText):
	ret = ""
	ret += "Câu hỏi " + str(int(ith)) + ":\n"
	x = mt.MyTokenizer(mainText)
	words = x.printOut()
	for i in words:
		ret += "\t" + i + "\n"
	return ret

def readFileXlsx():
	book = openpyxl.load_workbook('testTableTraining.xlsx')
	sheet = book.active
	f = open('vnTokenizer.txt', "w")
	for row in range(2, 102):
		ith = sheet.cell(row = row, column = 1).value
		mainText = sheet.cell(row = row, column = 2).value
		ret = processText(ith, mainText)
		f.write(ret)
readFileXlsx()

def printFileXlsx():
	book = openpyxl.load_workbook('testTableTraining.xlsx')
	sheet = book.active
	f = open('question.txt', "w")
	for row in range(2, 102):
		#ith = sheet.cell(row = row, column = 1).value
		mainText = sheet.cell(row = row, column = 2).value
		#ret = processText(ith, mainText)
		#f.write(ret)
		f.write("Question " + str(row  - 1) + ":\n")
		f.write(mainText + "\n")
printFileXlsx()


import json
from bot.common.threads.thread_builder import (
    BaseThread,
    BaseStep,
    StepKeys,
    ThreadKeys,
    Step,
)

# from bot.common.threads.utils import get_jump_thread
from bot.common.threads.shared_steps import SelectGuildEmojiStep
from bot.config import Redis

class OverrideThreadStep(BaseStep):
    """A step that overwrites the current thread
    This step gets the name of the jump thread from
    the cache metadata and then overwrites the current
    steps in memory with the new threads steps.
    """

    name = StepKeys.OVERRIDE_THREAD.value

    def __init__(self, cls):
        self.parent_thread = cls

    async def send(self, message, user_id):
        thread = await get_jump_thread(self.parent_thread, message, user_id)
        return await thread.step.current.send(message, user_id)

class GuildSelect(BaseThread):
    """A thread that sets the guild_id for another thread
    This thread is typically called from a command which
    will set the next thread to jump to on the next step
    and responds with an emoji prompt for a user to set
    guild_id.
    """

    name = ThreadKeys.GUILD_SELECT.value

    def __await__(self):
        async def init(self):
            await self._init_steps()
            key_vals = await Redis.get(self.user_id)
            if key_vals:
                self.command_name = (
                    json.loads(key_vals).get("metadata").get("thread_name")
                )
            return self

        return init(self).__await__()

    async def get_steps(self):
        steps = Step(current=SelectGuildEmojiStep(cls=self)).add_next_step(
            OverrideThreadStep(self)
        )
        return steps.build()

# avoid circular dependency
from bot.common.threads.utils import get_jump_thread  # noqa: E402