import math

from typing import List

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

from .data import tokenize, tokenize_batch
from .two_hot_encoding import NGramsEmbedding

class RNNModel(nn.Module):
    """Container module with an encoder, a recurrent module, and a decoder."""

    def __init__(
        self,
        dictionary,
        nlayers: int,
        ngrams: int,
        hidden_size: int,
        unk_t: int,
        nout=None,
        embedding_size: int = 100,
        is_forward_lm=True,
        document_delimiter: str = "\n",
        dropout=0.1,
    ):
        super(RNNModel, self).__init__()

        self.ntoken = len(dictionary)

        self.encoder = NGramsEmbedding(len(dictionary), embedding_size)
        self.ngrams = ngrams
        self.unk_t = unk_t
        self.dictionary = dictionary
        self.nlayers = nlayers
        self.is_forward_lm = is_forward_lm
        self.nout = nout
        self.document_delimiter = document_delimiter
        self.hidden_size = hidden_size
        self.embedding_size = embedding_size
        self.dropout = dropout

        if nlayers == 1:
            self.rnn = nn.LSTM(embedding_size, hidden_size, nlayers)
        else:
            self.rnn = nn.LSTM(embedding_size, hidden_size, nlayers, dropout=dropout)

        self.drop = nn.Dropout(dropout)
        self.decoder = nn.Linear(hidden_size, len(dictionary))
        if nout is not None:
            self.proj = nn.Linear(hidden_size, nout)
            self.initialize(self.proj.weight)
            self.decoder = nn.Linear(nout, len(dictionary))
        else:
            self.proj = None
            self.decoder = nn.Linear(hidden_size, len(dictionary))

        self.init_weights()

    @staticmethod
    def initialize(matrix):
        in_, out_ = matrix.size()
        stdv = math.sqrt(3.0 / (in_ + out_))
        matrix.detach().uniform_(-stdv, stdv)

    def init_weights(self):
        initrange = 0.1
        nn.init.uniform_(self.encoder.weight, -initrange, initrange)
        nn.init.zeros_(self.decoder.weight)
        nn.init.uniform_(self.decoder.weight, -initrange, initrange)

    def forward(self, input, hidden):
        # [#ngram, #seq_len, #batch_size]
        emb = self.encoder(input)
        emb = self.drop(emb)
        output, hidden = self.rnn(emb, hidden)
        decoded = self.decoder(output)
        decoded = decoded.view(-1, self.ntoken)

        return decoded, hidden

    def forward2(self, input, hidden, ordered_sequence_lengths=None):

        encoded = self.encoder(input)
        encoded = self.drop(encoded)

        self.rnn.flatten_parameters()

        output, hidden = self.rnn(encoded, hidden)

        if self.proj is not None:
            output = self.proj(output)

        decoded = self.decoder(
            output.view(output.size(0) * output.size(1), output.size(2))
        )

        return (
            decoded.view(output.size(0), output.size(1), decoded.size(1)),
            output,
            hidden,
        )

    def init_hidden(self, bsz):
        weight = next(self.parameters()).detach()
        return (
            weight.new(self.nlayers, bsz, self.hidden_size).zero_().clone().detach(),
            weight.new(self.nlayers, bsz, self.hidden_size).zero_().clone().detach(),
        )

    def __getstate__(self):

        # serialize the language models and the constructor arguments (but nothing else)
        model_state = {
            "state_dict": self.state_dict(),
            "dictionary": self.dictionary,
            "is_forward_lm": self.is_forward_lm,
            "hidden_size": self.hidden_size,
            "nlayers": self.nlayers,
            "embedding_size": self.embedding_size,
            "nout": self.nout,
            "document_delimiter": self.document_delimiter,
            "dropout": self.dropout,
            "ngrams": self.ngrams,
            "unk_t": self.unk_t,
        }

        return model_state

    def __setstate__(self, d):

        # special handling for deserializing language models
        if "state_dict" in d:

            # re-initialize language model with constructor arguments
            language_model = RNNModel(
                dictionary=d["dictionary"],
                nlayers=d["nlayers"],
                ngrams=d["ngrams"],
                hidden_size=d["hidden_size"],
                unk_t=d["unk_t"],
                nout=d["nout"],
                embedding_size=d["embedding_size"],
                is_forward_lm=d["is_forward_lm"],
                document_delimiter=d["document_delimiter"],
                dropout=d["dropout"],
            )

            language_model.load_state_dict(d["state_dict"])

            # copy over state dictionary to self
            for key in language_model.__dict__.keys():
                self.__dict__[key] = language_model.__dict__[key]

            # set the language model to eval() by default (this is necessary since FlairEmbeddings "protect" the LM
            # in their "self.train()" method)
            self.eval()

        else:
            self.__dict__ = d

    def save(self, file):
        model_state = {
            "state_dict": self.state_dict(),
            "dictionary": self.dictionary,
            "is_forward_lm": self.is_forward_lm,
            "hidden_size": self.hidden_size,
            "nlayers": self.nlayers,
            "embedding_size": self.embedding_size,
            "nout": self.nout,
            "document_delimiter": self.document_delimiter,
            "dropout": self.dropout,
            "ngrams": self.ngrams,
            "unk_t": self.unk_t,
        }

        torch.save(model_state, str(file), pickle_protocol=4)

    def get_representation(
        self,
        strings: List[str],
        start_marker: str,
        end_marker: str,
        chars_per_chunk: int = 512,
    ):

        len_longest_str: int = len(max(strings, key=len))

        # pad strings with whitespaces to longest sentence
        padded_strings: List[str] = []

        for string in strings:
            if not self.is_forward_lm:
                string = string[::-1]

            padded = f"{start_marker}{string}{end_marker}"
            padded_strings.append(padded)

        # cut up the input into chunks of max charlength = chunk_size
        chunks = []
        splice_begin = 0
        longest_padded_str: int = len_longest_str + len(start_marker) + len(end_marker)
        for splice_end in range(chars_per_chunk, longest_padded_str, chars_per_chunk):
            chunks.append([text[splice_begin:splice_end] for text in padded_strings])
            splice_begin = splice_end

        chunks.append(
            [text[splice_begin:longest_padded_str] for text in padded_strings]
        )

        hidden = self.init_hidden(len(chunks[0]))

        batches: List[torch.Tensor] = []

        # push each chunk through the RNN language model
        for chunk in chunks:
            len_longest_chunk: int = len(max(chunk, key=len))
            sequences_as_char_indices: List[torch.Tensor] = []

            for string in chunk:
                chars = list(string) + [" "] * (len_longest_chunk - len(string))

                chars = ["".join(chars)]

                # [ngram, 1, sequence]
                n_gram_char_indices = tokenize_batch(
                    self.dictionary, chars, self.ngrams, otf=True).unsqueeze(dim=1)

                sequences_as_char_indices.append(n_gram_char_indices)

            # [ngram, batch_size, sequence]
            batches.append(torch.cat(sequences_as_char_indices, dim=1))

        output_parts = []
        for batch in batches:
            # [ngram, sequence, batch_size]
            batch = batch.transpose(1, 2).to(flair.device)

            _, rnn_output, hidden = self.forward2(batch, hidden)

            output_parts.append(rnn_output)

        # concatenate all chunks to make final output
        output = torch.cat(output_parts)

        return output

# Temporarily leave PositionalEncoding module here. Will be moved somewhere else.
class PositionalEncoding(nn.Module):
    r"""Inject some information about the relative or absolute position of the tokens in the sequence.
        The positional encodings have the same dimension as the embeddings, so that the two can be summed.
        Here, we use sine and cosine functions of different frequencies.
    .. math:
        \text{PosEncoder}(pos, 2i) = sin(pos/10000^(2i/d_model))
        \text{PosEncoder}(pos, 2i+1) = cos(pos/10000^(2i/d_model))
        \text{where pos is the word position and i is the embed idx)
    Args:
        d_model: the embed dim (required).
        dropout: the dropout value (default=0.1).
        max_len: the max. length of the incoming sequence (default=5000).
    Examples:
        >>> pos_encoder = PositionalEncoding(d_model)
    """

    def __init__(self, d_model, dropout=0.1, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=dropout)

        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(
            torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)
        )
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer("pe", pe)

    def forward(self, x):
        r"""Inputs of forward function
        Args:
            x: the sequence fed to the positional encoder model (required).
        Shape:
            x: [sequence length, batch size, embed dim]
            output: [sequence length, batch size, embed dim]
        Examples:
            >>> output = pos_encoder(x)
        """

        x = x + self.pe[: x.size(0), :]
        return self.dropout(x)

class TransformerModel(nn.Module):
    """Container module with an encoder, a recurrent or transformer module, and a decoder."""

    def __init__(
        self,
        dictionary,
        embedding_size,
        nhead,
        nhid,
        nlayers,
        ngrams,
        unk_t,
        is_forward_lm=True,
        document_delimiter="\n",
        dropout=0.5,
    ):
        super(TransformerModel, self).__init__()
        try:
            from torch.nn import TransformerEncoder, TransformerEncoderLayer
        except:
            raise ImportError(
                "TransformerEncoder module does not exist in PyTorch 1.1 or lower."
            )

        self.ntoken = len(dictionary)
        self.dictionary = dictionary
        self.is_forward_lm = is_forward_lm
        self.ngrams = ngrams
        self.unk_t = unk_t
        self.nlayers = nlayers
        self.document_delimiter = document_delimiter
        self.dropout = dropout

        self.hidden_size = nhid
        self.nhead = nhead

        self.model_type = "Transformer"
        self.src_mask = None
        self.pos_encoder = PositionalEncoding(embedding_size, dropout)
        encoder_layers = TransformerEncoderLayer(
            embedding_size, nhead, self.hidden_size, dropout
        )
        self.transformer_encoder = TransformerEncoder(encoder_layers, nlayers)
        self.encoder = NGramsEmbedding(self.ntoken, embedding_size)
        self.embedding_size = embedding_size
        self.decoder = nn.Linear(embedding_size, self.ntoken)

        self.init_weights()

    def _generate_square_subsequent_mask(self, sz):
        mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)
        mask = (
            mask.float()
            .masked_fill(mask == 0, float("-inf"))
            .masked_fill(mask == 1, float(0.0))
        )
        return mask

    def init_weights(self):
        initrange = 0.1
        nn.init.uniform_(self.encoder.weight, -initrange, initrange)
        nn.init.zeros_(self.decoder.bias)
        nn.init.uniform_(self.decoder.weight, -initrange, initrange)

    def forward(self, src, has_mask=True):
        if has_mask:
            device = src.device
            if self.src_mask is None or self.src_mask.size(0) != len(src):
                mask = self._generate_square_subsequent_mask(src.size(1)).to(device)
                self.src_mask = mask
        else:
            self.src_mask = None
        src = self.encoder(src) * math.sqrt(self.embedding_size)
        src = self.pos_encoder(src)
        output = self.transformer_encoder(src, self.src_mask)
        output = self.decoder(output)
        return F.log_softmax(output, dim=-1)

    def __getstate__(self):

        # serialize the language models and the constructor arguments (but nothing else)
        model_state = {
            "state_dict": self.state_dict(),
            "dictionary": self.dictionary,
            "is_forward_lm": self.is_forward_lm,
            "hidden_size": self.hidden_size,
            "nlayers": self.nlayers,
            "embedding_size": self.embedding_size,
            "document_delimiter": self.document_delimiter,
            "dropout": self.dropout,
            "ngrams": self.ngrams,
            "unk_t": self.unk_t,
            "nhead": self.nhead
        }

        return model_state

    def __setstate__(self, d):

        # special handling for deserializing language models
        if "state_dict" in d:

            # re-initialize language model with constructor arguments
            language_model = TransformerModel(
                dictionary=d["dictionary"],
                nlayers=d["nlayers"],
                ngrams=d["ngrams"],
                nhid=d["hidden_size"],
                unk_t=d["unk_t"],
                # nout=d["nout"],
                embedding_size=d["embedding_size"],
                is_forward_lm=d["is_forward_lm"],
                document_delimiter=d["document_delimiter"],
                dropout=d["dropout"],
                nhead=d["nhead"]
            )

            language_model.load_state_dict(d["state_dict"])

            # copy over state dictionary to self
            for key in language_model.__dict__.keys():
                self.__dict__[key] = language_model.__dict__[key]

            # set the language model to eval() by default (this is necessary since FlairEmbeddings "protect" the LM
            # in their "self.train()" method)
            self.eval()

        else:
            self.__dict__ = d

    def save(self, file):
        # TODO: Can we make this flair compatible?
        model_state = {
            "state_dict": self.state_dict(),
            "dictionary": self.dictionary,
            "is_forward_lm": self.is_forward_lm,
            "hidden_size": self.hidden_size,
            "nlayers": self.nlayers,
            "embedding_size": self.embedding_size,
            # "nout": self.nout,
            "document_delimiter": self.document_delimiter,
            "dropout": self.dropout,
            "ngrams": self.ngrams,
            "unk_t": self.unk_t,
            "nhead": self.nhead
        }

        torch.save(model_state, str(file), pickle_protocol=4)

    def forward2(self, input, ordered_sequence_lengths=None):

        encoded = self.encoder(input) * math.sqrt(self.embedding_size)
        encoded = self.pos_encoder(encoded)

        output = self.transformer_encoder(encoded, self.src_mask)
        decoded = self.decoder(output)

        # if self.proj is not None:
        #     output = self.proj(output)

        # decoded = self.decoder(
        #     output.view(output.size(0) * output.size(1), output.size(2))
        # )

        return decoded, output

    def get_representation(
        self,
        strings: List[str],
        start_marker: str,
        end_marker: str,
        chars_per_chunk: int = 512,
    ):

        len_longest_str: int = len(max(strings, key=len))

        # pad strings with whitespaces to longest sentence
        padded_strings: List[str] = []

        for string in strings:
            if not self.is_forward_lm:
                string = string[::-1]

            padded = f"{start_marker}{string}{end_marker}"
            padded_strings.append(padded)

        # cut up the input into chunks of max charlength = chunk_size
        chunks = []
        splice_begin = 0
        longest_padded_str: int = len_longest_str + len(start_marker) + len(end_marker)
        for splice_end in range(chars_per_chunk, longest_padded_str, chars_per_chunk):
            chunks.append([text[splice_begin:splice_end] for text in padded_strings])
            splice_begin = splice_end

        chunks.append(
            [text[splice_begin:longest_padded_str] for text in padded_strings]
        )

        batches: List[torch.Tensor] = []

        # push each chunk through the RNN language model
        for chunk in chunks:
            len_longest_chunk: int = len(max(chunk, key=len))
            sequences_as_char_indices: List[torch.Tensor] = []

            for string in chunk:
                chars = list(string) + [" "] * (len_longest_chunk - len(string))

                chars = ["".join(chars)]

                # [ngram, 1, sequence]
                n_gram_char_indices = tokenize_batch(
                    self.dictionary, chars, self.ngrams, otf=True, device=flair.device
                ).unsqueeze(dim=1)

                sequences_as_char_indices.append(n_gram_char_indices)

            # [ngram, batch_size, sequence]
            batches.append(torch.cat(sequences_as_char_indices, dim=1))

        output_parts = []
        for batch in batches:
            # [ngram, sequence, batch_size]
            batch = batch.transpose(1, 2)

            _, transformer_output = self.forward2(batch)

            output_parts.append(transformer_output)

        # concatenate all chunks to make final output
        output = torch.cat(output_parts)

        return output

{'TransformerEncoder': 'torch.nn.TransformerEncoder', 'TransformerEncoderLayer': 'torch.nn.TransformerEncoderLayer'}


import discord

client = discord.Client()

@client.event
async def on_ready():
    print('We have logged in as {0.user}'.format(client))
    for guild in client.guilds:
        for channel in guild.channels:
            print(channel, channel.id)
    while True:
        channel = client.get_channel(int(input("Entrez l'id du channel...")))
        print("\n\n===============================================\n\n")
        print("MESSAGES DU SALON", channel.name)
        messages = await channel.history().flatten()
        messages.reverse()
        for mes in messages:
            print("[" + mes.author.name, mes.created_at.strftime("%d/%m/%Y, %H:%M:%S") + "]   ", mes.content)
        print("\n\n===============================================\n\n")

client.run('SECRET-BOT_TOCKEN')


# importing necessary libraries
import numpy as np
from scipy import linalg
import pickle
import sys
import getopt

# defining a function to run the Randomized Kaczmarz (RK) algorithm
def run_RK(A, E, F, b, e, n_run, n_iter, eta, sigma_A, sigma_b, folder):

    """
    The arguments for the run_RK() function are the following:
    A            : The non noisy matrix
    E            : The multiplicative left-hand noise to the matrix A
    F            : The multiplicative right-hand noise to the matrix A
    b            : The non noisy right-hand side vector  (Ax=b)
    e            : The noise added to the vector b
    n_run        : numbre of runs of the RK algorithm to be performed
    n_iter       : numbre of iterations in each run
    eta          : The learning rate
    sigma_A      : The left-hand noise magnitude
    sigma_b      : The right-hand noise magnitude
    folder       : Foldre to store results

    """

    noiseE = sigma_A*E
    noiseF = sigma_A*F
    noiseb = sigma_b*e

    A_tld = np.linalg.multi_dot([np.identity(m)+noiseE, A, np.identity(n)+noiseF])   # The noisy matrix
    b_tld = b+noiseb      # The noisy right-hand side vector

    print("cond(A_tld):  ",np.linalg.cond(A_tld))

    # computing R_tld
    R = (np.linalg.norm(np.linalg.pinv(A_tld), ord=2)*np.linalg.norm(A_tld, 'fro'))**2

    # compute the min singular value of A_tld: lambda_min
    U, s, Vt = np.linalg.svd(A_tld)
    lambda_min = min(s)

    # computing the horizon of the theoretical bound
    horizon = (np.linalg.norm( (noiseE @ A + A @ noiseF + noiseE @ A @ noiseF) @ x_ls - noiseb, ord=2) / lambda_min)**2

    # generating probabilities of choosing the rows
    probas = []
    frob_norm_Atld = np.linalg.norm(A_tld, ord='fro')
    for i in range(A_tld.shape[0]):
        probas.append((np.linalg.norm(A_tld[i], ord=2)**2)/(frob_norm_Atld**2))

    # lists to store results
    distance_to_x_ls = [[] for i in range(int(n_run))]
    bound = [[] for i in range(int(n_run))]

    # generate starting point x_0, must be in the column space of Atld^T
    x_0 = np.transpose(A_tld) @ np.random.normal(size=(m,))

    # runing the RK algorithm
    for r in range(int(n_run)):

        # starting point
        x = x_0

        distance_to_x_ls[r].append(np.linalg.norm(x - x_ls)**2)
        if r==0:
            bound[r].append(np.linalg.norm(x_0 - x_ls, ord=2)**2+ horizon)

        for i in range(int(n_iter)):
            #row_idx = np.random.randint(0,m)
            row_idx = int(np.random.choice(m, 1, p=probas))
            if np.linalg.norm(A_tld[row_idx,:])==0:
                continue
            else:
                x = x + eta*(b_tld[row_idx] - np.dot(A_tld[row_idx,:],x))/((np.linalg.norm(A_tld[row_idx,:], ord=2))**2)*A_tld[row_idx,:]

                distance_to_x_ls[r].append(np.linalg.norm(x - x_ls)**2)
                if r==0:
                    bound[r].append(((1-1/R)**(i+1))*(np.linalg.norm(x_0 - x_ls, ord=2)**2) + horizon)

        print("end run", r)

    # saving results
    name = folder + 'sigmaA_{}_sigmab_{}'.format(sigma_A,sigma_b)
    with open(name+'_distance_to_x_ls', "wb") as fp: pickle.dump(distance_to_x_ls,fp)
    with open(name+'_bound', "wb") as fp: pickle.dump(bound,fp)

def main(argv):

    n_iter = None
    n_run = None
    eta = None
    zeroF = None
    zeroE = None

    try:
        opts, args = getopt.getopt(argv[1:], '', ["n_iter=", "n_run=", "eta=", "zeroF=", "zeroE=" ])
    except:
        print("Error")

    for opt, arg in opts:
        if opt in ['--n_iter']:
            n_iter = arg
        elif opt in ['--n_run']:
            n_run = arg
        elif opt in ['--eta']:
            eta = arg
            eta = float(eta)
        elif opt in ['--zeroF']:
            zeroF = arg
        elif opt in ['--zeroE']:
            zeroE = arg

    # generating matrix A
    global m,n
    m = 500     # numbre of rows of A
    n = 300     # numbre of columns of A
    r = 300     # rank of A

    sigma_min = 1     # minimum singular value of A
    sigma_max = 10    # maximum singular value of A

    singular_values = np.linspace(sigma_min,sigma_max,r)

    U = linalg.orth(np.random.randn(m,r))

    V = linalg.orth(np.random.randn(n,r))

    D = np.diag(singular_values)

    A = np.linalg.multi_dot([U, D, np.transpose(V)])

    print("cond(A):  ",np.linalg.cond(A))

    # generating vector b
    x_opt = np.random.randn(n,)
    b = np.dot(A,x_opt)

    # checking consistency of noise free system
    print("rank(A)  ",np.linalg.matrix_rank(A))
    aug = np.column_stack((A,b))
    print("rank(A|b)  ",np.linalg.matrix_rank(aug))
    print("Noisless linear system is consistent:  ", np.linalg.matrix_rank(A)==np.linalg.matrix_rank(aug))

    # compute x_ls
    global x_ls
    x_ls = np.dot(np.linalg.pinv(A),b)

    # generating the noises
    E = np.random.normal(loc=[0.]*m, scale=[1.]*m, size=(m,m))
    F = np.random.normal(loc=[0.]*n, scale=[1.]*n, size=(n,n))
    e = np.random.randn(m)

    # save generated data and noise
    with open("Results/multiplicative_noise/Matrix_A", "wb") as fp: pickle.dump(A,fp)
    with open("Results/multiplicative_noise/vector_b", "wb") as fp: pickle.dump(b,fp)
    with open("Results/multiplicative_noise/noiseE", "wb") as fp: pickle.dump(E,fp)
    with open("Results/multiplicative_noise/noiseF", "wb") as fp: pickle.dump(F,fp)
    with open("Results/multiplicative_noise/e", "wb") as fp: pickle.dump(e,fp)

    # runing RK with different noise magnitudes
    if zeroF == True:     # case F = 0
        run_RK(A, E, np.zeros((n,n)), b, e, n_run, n_iter, eta, 1, 1, 'Results/multiplicative_noise/ZeroF/')
        run_RK(A, E, np.zeros((n,n)), b, e, n_run, n_iter, eta,  0.5, 0.5, 'Results/multiplicative_noise/ZeroF/')
        run_RK(A, E, np.zeros((n,n)), b, e, n_run, n_iter, eta, 0.05, 0.05, 'Results/multiplicative_noise/ZeroF/')
        run_RK(A, E, np.zeros((n,n)), b, e, n_run, n_iter, eta,  0.1, 0.1, 'Results/multiplicative_noise/ZeroF/')
        run_RK(A, E, np.zeros((n,n)), b, e, n_run, n_iter, eta,  10, 10, 'Results/multiplicative_noise/ZeroF/')
        run_RK(A, E, np.zeros((n,n)), b, e, n_run, n_iter, eta,  0.005, 0.005, 'Results/multiplicative_noise/ZeroF/')

    elif zeroE == True:     # case E = 0
        run_RK(A, np.zeros((m,m)), F, b, e, n_run, n_iter, eta, 0.005, 0.005, 'Results/multiplicative_noise/ZeroE/')
        run_RK(A, np.zeros((m,m)), F, b, e, n_run, n_iter, eta, 0.01, 0.01, 'Results/multiplicative_noise/ZeroE/')
        run_RK(A, np.zeros((m,m)), F, b, e, n_run, n_iter, eta,  0.5, 0.5, 'Results/multiplicative_noise/ZeroE/')

    elif (zeroE == True and zeroF == True):
        print("ERROR, E or F should not be zero")
    else:                 # general case
        run_RK(A, E, F, b, e, n_run, n_iter, eta, 0.005, 0.005, 'Results/multiplicative_noise/GeneralCase/')
        run_RK(A, E, F, b, e, n_run, n_iter, eta,  0.01, 0.01, 'Results/multiplicative_noise/GeneralCase/')
        run_RK(A, E, F, b, e, n_run, n_iter, eta,  0.1, 0.1, 'Results/multiplicative_noise/GeneralCase/')

if __name__ == "__main__":
    main(sys.argv)


from django.db import models

class Sauceproduct(models.Model):
    sauces = models.ForeignKey(
        'sauce.Sauce', on_delete=models.SET_NULL, null=True, blank=True)
    product = models.ForeignKey(
        'products.Product', on_delete=models.SET_NULL, null=True, blank=True)
    description = models.CharField(max_length=100, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.sauces


# Send a heartbeat every 5 minutes to Slack
# This uses the slack-cli library: https://github.com/rockymadden/slack-cli
from requests import get
import time
import subprocess
import json
import datetime

def get_date_time():
    return str(datetime.datetime.now())

def send_slack():
    try:
        query = ["../../slack", "chat", "send", "-tx", f'Heartbeat start: {get_date_time()}', "-ch", '#pi']
        res_json = subprocess.check_output(query) # Call slack process
        res = json.loads(res_json) # Parse json
        print(res)
        assert res["ok"] # Make sure we got ok as response

        timestamp = res["ts"]
        channel = res["channel"]

        return timestamp, channel

    except subprocess.CalledProcessError:
        print("Subprocess call failed!")
        print(f"Query: {' '.join(query)}")
        raise subprocess.CalledProcessError()

    except AssertionError:
        print("Assertion 'ok == True' failed...")
        print(f"Query: {' '.join(query)}")
        print(res)
        raise AssertionError()

def update_slack(timestamp, channel):
    try:
        query = ["../../slack", "chat", "update", "-tx", f'Heartbeat update: {get_date_time()}', "-ch", f"{channel}", "-ts", f'{timestamp}']
        res_json = subprocess.check_output(query) # Call slack process
        res = json.loads(res_json) # Parse json

        assert res["ok"] # Make sure we got ok as response

    except subprocess.CalledProcessError:
        print("Subprocess call failed!")
        print(f"Query: {' '.join(query)}")
        raise subprocess.CalledProcessError()

    except AssertionError as e:
        print("Assertion 'ok == True' failed...")
        print(f"Query: {' '.join(query)}")
        print(res)
        raise AssertionError()

def main():
    print("Sending first message to Slack...")
    timestamp, channel = send_slack()
    print("Done sending first message. Sleeping...")

    while True:
        time.sleep(10*60) # Sleep for 10 minutes
        print("Updating Slack...")
        update_slack(timestamp, channel)
        print("Done updating Slack! Sleeping...")

if __name__ == "__main__":
    main()


import sys
import socket
import time
from variables import ACTION, PRESENCE, TIME, USER, ACCOUNT_NAME, RESPONSE
from utils import port_check, addres, get_message, send_message

def create_presence(name: str = 'Guest'):
    message = {
        ACTION: PRESENCE,
        TIME: time.time(),
        USER: {
            ACCOUNT_NAME: name
        }
    }
    return message

def answer(message):
    if RESPONSE in message:
        if message[RESPONSE] == 200:
            return '200 : OK'
        if message[RESPONSE] == 400:
            return '400 : BAD REQUEST'
    else:
        raise ValueError

def main():
    addr = addres(sys.argv)
    port = port_check(sys.argv)

    messenger = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    messenger.connect((addr, port))
    send_message(messenger, create_presence())
    try:
        ans = get_message(messenger)
        mes = answer(ans)
        print(mes)
    except ValueError:
        print('Не удалось прочитать сообщение сервера')

if __name__ == '__main__':
    main()


# Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=12475

### Products API ###

from fastapi import APIRouter

router = APIRouter(prefix="/products",
                   tags=["products"],
                   responses={404: {"message": "No encontrado"}})

products_list = ["Producto 1", "Producto 2",
                 "Producto 3", "Producto 4", "Producto 5"]

@router.get("/")
async def products():
    return products_list

@router.get("/{id}")
async def products(id: int):
    return products_list[id]


import gzip
import json
import networkx as nx

def writeobj(filename, obj):
    with gzip.open(filename, 'wb') as f:
        f.write(json.dumps(obj, indent=4))

def readobj(filename):
    with gzip.open(filename, 'r') as f:
        return json.loads(f.read())

def mkdict(obj, key='id'):
    return dict((x[key], x) for x in obj)

def cosponsors():
    'Return a graph of cosponsors'
    ret = nx.Graph()

    bills = mkdict(readobj('bills-113.json.gz'))
    people = mkdict(readobj('people.json.gz'))
    cosponsorships = readobj('cosponsorship.json.gz')

    for bill in cosponsorships:
        bill_id = bill['bill']
        if bill_id not in bills:
            continue

        author_id = bills[bill_id]['sponsor']['id']
        author = people[author_id]['name']
        cosponsor = people[bill['person']]['name']

        if ret.has_edge(cosponsor, author):
            ret[cosponsor][author]['weight'] += 1
        else:
            ret.add_edge(cosponsor, author, weight=1)
    return ret


import time, yaml
from operator import itemgetter
from .keys import *
from .helpers import *

def flags_compile(flags):
    first = flags[0]
    faction = {
        "id": f"compile_flags_{len(flags)}",
        "do": "flags",
        "from": first["from"],
        "flags":  flags,
    }
    return faction

class ActionTimer:
    def __init__(self, times):
        self.times = times
        self.reset()

    def reset(self):
        self.start = time.perf_counter()
        self.end = self.start

    def update(self, action):
        self.end = time.perf_counter()
        self.times[action['id']] = self.end - self.start
        self.start = self.end

#
# CQML Virtual Machine
#

class VM:
    def __init__(self, yaml, spark):
        self.spark = spark
        self.yaml = yaml
        self.actions= yaml["actions"]
        self.cactions = []
        self.macros = {}
        self.compile(self.actions)
        self.last = self.cactions[0]
        self.debug = False
        self.skip_errors = False
        self.df = {}
        self.sizes = {}
        self.times = {}
        self.pkg = None

    def key_actions(self, key):
      return {a['id']: a[key] for a in self.cactions if (key in a) and (kSkip not in a)}

    def saveable(self):
      saves = self.key_actions(kSave)
      return saves

    def save(self, id, df, type):
        size = df.count()
        action = {
            "id": id,
            "do": kSave,
            "size": size,
            kSkip: True
        }
        if size > 0:
          action[kSave] = type
        #print(action)
        self.cactions[:0] = [action]
        self.df[id] = df
        return df

    def log(self, str, name=False):
      if self.debug:
         if name: print(name)
         print(str)

    def macro(self, todo, action):
        mdef = todo.split("|")
        mcall = todo.split(".")

        if len(mdef) > 1:
            action['do'] = mdef[1]
            self.macros[action['id']] = yaml.dump(action)
            return 0
        key = mcall[1]
        template = self.macros[key]
        expanded = template.format(**action)
        #print(expanded)
        dict = yaml.safe_load(expanded)
        dict['id'] = action['id']
        self.cactions.append(dict)
        return 1

    def reload(self, yaml_file):
        with open(yaml_file) as data:
            raw_yaml = yaml.full_load(data)
            self.actions = raw_yaml["actions"]
            self.log(self.actions)
            self.compile(self.actions)

    def compile(self, action_dict):
        flags = []
        for id, action in action_dict.items():
            action['id'] = id
            todo = action['do']

            if (todo=='flag') and (action['from'] == "$id"):
                flags.append(action)
            elif len(flags) > 0:
                faction = flags_compile(flags)
                self.cactions.append(faction)
                self.cactions.append(action)
                flags = []
            elif 'macro' in todo:
                self.macro(todo, action)
            else:
                self.cactions.append(action)

        if len(flags) > 0:
            faction = flags_compile(flags)
            self.cactions.append(faction)
        return self.cactions

    def run(self, only=None):
      out = None
      timer = ActionTimer(self.times)
      for action in self.cactions:
          self.log(f"run[{action['id']}]: action['do']")
          if kSkip not in action:
            #if only and action['do'] == only:
              out = self.perform(action)
              timer.update(action)
      return out

    def get_key(self, name):
        key = self.last[name[1:]] if name[0] == '$' else name
        #self.log(f"get_key: {name} -> {key}")
        return key

    def get_frame(self, name):
        key = self.get_key(name)
        return self.df[key]

    def set_frame(self, name, frame):
        key = self.get_key(name)
        self.df[key] = frame

    def test_action(self, n, show=False):
        action = self.cactions[n]
        id = action['id']
        return test_id(self, id, show)

    def test_id(self, id, show=False):
        action = self.actions[id]
        self.log(f"# {id}: {action}")
        self.perform(action)
        df = self.df[id]
        if show and not isinstance(df, dict):
            df.show()
        return df

    def ensure_unique(self, df, key):
        all = df.select(key)
        #print(all)
        unique = all.distinct()
        #print(unique)
        n_dupes = all.count() - unique.count()
        if (n_dupes != 0):
          msg = f"ensure_unique.{key}[{n_dupes}] = {all.count()} - {unique.count()}"
          self.log(msg)
          if not self.skip_errors:
            raise Exception("FAIL."+msg)
        return df

    def perform(self, action):
        id, do = itemgetter('id', 'do')(action)
        print(f'*perform[{do}]: {id}')
        method = getattr(self, f'do_{do}')
        df = method(action)
        if not isinstance(df, dict):
            self.sizes[id] = df.count()
            df = df if kKeepIndistinct in action else df.distinct()
            df = self.ensure_unique(df, action[kUniq]) if kUniq in action else df
            df = df.sort(get_sort(action), ascending=False)
        self.set_frame(id, df)
        self.last = action
        return df


import pyautogui
import socket
import logging
#import sys

import threading
import time

#todo: might need refactoring
def log(msg):
    #will always get a reference to an existing logger
    #with the name indicated
    logger=logging.getLogger("log")
    logger.info(msg)

class MySocket(object):
    def __init__(self, host, port, maxlen):
        log("Initializing socket")
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_address = (host, port)
        self.max_connections = 5
        self.MAXLEN = maxlen
        #this is used in Loops to indicate
        #if the program should stop or keep listening
        self.listen=True

    def start_listening(self):
        log("Starting up on %s port %s" % self.server_address)
        self.sock.bind(self.server_address)
        self.sock.listen(self.max_connections)

        #main loop
        while self.listen:
            log('waiting for a new connection')
            clientsocket, address= self.sock.accept()
            log( 'connection from %s at %s '% address)
            self.process_connection(clientsocket, address)
            log('finished processing connection :)')

        log('listening stopped!')

    #todo: refactor this shit!
    def process_connection(self, connection, addr):
        try:
            msg = ""
            #todo: not sure about this shit!
            while True:
                data = connection.recv(self.MAXLEN)
                msg+=data
                log('received "%s"' % data)
                if not MySocket.msg_received(msg):
                    pass
                processed_msg = MySocket.process_msg(msg)
                if processed_msg is None:
                    log('unsupported message type!')
                    return
                log('no more data from %s at %s' % addr)
                log('the full message is "%s"' % msg)
                log('the extracted message is "%s"' % processed_msg)
                log('sending ACK to client...')
                log('pressing "playpause"...')
                pyautogui.press(processed_msg)
                #todo: put this into a variable
                connection.sendall("0")
                return

        except KeyboardInterrupt:
            log('Interrupted!')
        finally:
            connection.close()

    #removes the length indicator from the received message
    @staticmethod
    def process_msg(msg):
        extracted_msg = msg.split(',')[1]
        if extracted_msg not in ['playpause','prevtrack', 'nexttrack', 'volumeup', 'volumedown' ]:
            return None
        return extracted_msg

    #checks the length of message and returns True if
    #it's been delivered completely. The msg would be
    #in the format: "7,message"
    @staticmethod
    def msg_received(msg):
        #we wait until we get a comma because that's the separator
        if not ',' in msg:
            return False
        split = msg.split(',')
        return int(split[0]) == len(split[1])

    def stop_listening(self):
        log('stopping listening on connections...')
        self.listen=False

if __name__ == '__main__':
    # setting logging message level
    logging.basicConfig(level=logging.INFO)
    s=MySocket('',10000, 64)
    #t=threading.Thread(target=s.start_listening)
    s.start_listening()


import os
from matplotlib.pyplot import imread
import random
import numpy as np

# set seed:
seed_value = 1
os.environ['PYTHONHASHSEED']=str(seed_value)
random.seed(seed_value)
np.random.seed(seed_value)

def getListOfFiles(dirName):
    # create a list of file and sub directories
    # names in the given directory
    listOfFile = os.listdir(dirName)
    allFiles = list()
    # Iterate over all the entries
    for entry in listOfFile:
        # Create full path
        fullPath = os.path.join(dirName, entry)
        # If entry is a directory then get the list of files in this directory
        if os.path.isdir(fullPath):
            allFiles = allFiles + getListOfFiles(fullPath)
        elif fullPath.endswith('.png'):
            allFiles.append(fullPath)
    return allFiles

def main(dir):
    all_files = getListOfFiles(dir)
    random.shuffle(all_files)
    n = len(all_files)
    data = []
    # sub sample 1/3 of the database
    for i in range(n//3):
        im = imread(all_files[i])[:,:,:3]
        data.append(im)
    return data


from flask import Flask, render_template
from flask import url_for

app = Flask(__name__)

@app.route('/')
@app.route('/list_prof/<list>')
def list_prof(list):
    jobs_list = ['Капитан', 'Штурман', 'Врач', 'Солдат', 'Гей']

    return render_template('list_prof.html', list=list, jobs=jobs_list)

if __name__ == '__main__':
    app.run(port=8080, host='127.0.0.1')

# http://127.0.0.1:8080/list_prof/ol


import re;
import collections;

warnings = [];
classStack = [];

def arrayJoin(arr, delim = " "):
	result = "";
	first = True;
	for line in arr:
		if len(line) == 0:
			continue;
		if not first:
			result += delim;
		first = False;
		result += line;
	return result;

def warning(message):
	warnings.append(arrayJoin(classStack, ".") + message);

class FunctionParam:
	def __init__(self, type, name):
		self.type = type;
		self.name = name;
		self.comment = "";
		self.commentJoin = [];
		self.optional = None;

	def finished(self):
		if len(self.commentJoin) == 0 and self.type != "nil":
			warning(str(self) + " has no comment");
		self.comment = arrayJoin(self.commentJoin);
		self.commentJoin = None;

	def __str__(self):
		s = "(" + self.type;
		if self.name:
			s += " " + self.name;
		if self.optional:
			s += " [" + self.optional + "]";
		s += ")";
		if self.comment:
			s += " : " + self.comment;
		return s;

# Represents a single function signature for a potentially overloaded function.
# Contains a comment block, list of input paramters and returns.
# As well as if the signature is for a static function and a list of 'see also's.
class FunctionInstance:
	commentLineSplit = re.compile('/\*\*+(.*)|\s*\*?/?(.*)');
	metaMatch = re.compile('@\S+');
	whitespaceSplit = re.compile('\s+');
	def __init__(self):
		self.comment = "";
		self.params = [];
		self.returns = [];
		self.isStatic = False;
		self.parsing = None;
		self.alsoSee = [];
		self.inCode = False;
		self.isPrivate = False;
	def addParam(self, param):
		self.params.append(param)

	def idList(self):
		s = "";
		first = True;

		if len(self.params) == 0:
			s = "Void";
		else:
			for param in self.params:
				if first:
					first = False;
				else:
					s += "_";
				s += param.type + "_" + param.name;
		s += "__";
		if len(self.returns) == 0:
			s += "Void";
		else:
			first = True;
			for ret in self.returns:
				if first:
					first = False;
				else:
					s += "_";
				s += ret.type;

		return s;
	# Parses a single comment line.
	# Deals with looking for metatags such as @static, @param, @returns and @see.
	# Also replaces
's with newlines.
	def parseLine(self, line):
		matchIter = FunctionInstance.metaMatch.finditer(line);
		for match in matchIter:
			meta = str(match.group()).lower();

			line = line.strip();

			if meta == "@static":
				self.isStatic = True;
				return "";
			if meta == "@private":
				self.isPrivate = True;
				return "";
			if meta == "@param":
				# A param line can be in either format of
				# @param Type Name [Optional] Comment (Splits into 4)
				# or
				# @param Type Name Comment (Splits into 3)
				# So we need to split it into 4 and then combine 3 and 4
				# to make the whole comment if there is no optional.
				split = FunctionInstance.whitespaceSplit.split(line, 4);
				optional = None;
				type = split[1];
				comment = "";
				name = split[2];
				# Check for optional
				if name[0] == "[" and name[len(name) - 1] == "]":
					# Grab the optional from the square brackets.
					optional = name[1:len(name) - 1];
					name = split[3];
					if len(split) > 4:
						comment = split[4];
				else:
					# There is no optional so combine 3 and 4 if they are available.
					if len(split) > 3:
						comment = split[3];
						if len(split) > 3:
							comment += " " + split[4];

				param = FunctionParam(type, name);
				self.params.append(param);
				param.optional = optional;
				self.parsing = param;
				if len(split) > 3:
					return self.parseLine(comment);
				else:
					return "";

			if meta == "@returns":
				# Return tag has the format
				# @return Type Comment
				# So splitting is fairly simple.
				split = FunctionInstance.whitespaceSplit.split(line, 2);
				returnParam = FunctionParam(split[1], None);
				self.returns.append(returnParam);
				self.parsing = returnParam;
				if len(split) > 2:
					return self.parseLine(split[2]);
				else:
					return "";

			if meta == "@see":
				# See tag has the format
				# @see Type
				split = FunctionInstance.whitespaceSplit.split(line, 2);
				self.alsoSee.append(split[1]);
				# We don't need to include this line in the comments
				return "";

		code = line.find("
");
		if code >= 0:
			self.inCode = True;
		code = line.find("
");
		if code >= 0:
			self.inCode = False;

		if self.inCode:
			line = line + "\n";

		return line.replace("
", "\n");

	# Takes an array of unparsed comment lines and parses them into
	# the main comment block and the function parameters and returns.
	def parseComment(self, lines):
		commentJoin = [];
		for line in lines:
			for match in FunctionInstance.commentLineSplit.finditer(line):
				group = match.group(1) if match.group(1) else match.group(2);
				if group:
					s = self.parseLine(str(group));
					if len(s) > 0:
						if not self.parsing:
							commentJoin.append(s);
						else:
							self.parsing.commentJoin.append(s);

		self.comment = arrayJoin(commentJoin);

		for param in self.params:
			param.finished();

		for returnParam in self.returns:
			returnParam.finished();

		if len(self.comment) == 0 and not self.isPrivate:
			warning("." + str(self) + " has no comment");

		self.parsing = None;

	def __str__(self):
		s = "(";
		first = True;
		for param in self.params:
			if not first:
				s += ", ";
			first = False;
			s += param.type + " " + param.name;
			if param.optional:
				s += " [" + param.optional + "]";
		s += ") -> (";
		first = True;
		for returnParam in self.returns:
			if not first:
				s += ", ";
			first = False;
			s += returnParam.type;
		s += ")";
		return s;

# Represents a function with it's Lua name, C++ Name and all the overloaded
# function signatures it can have.
# Also stores if it's a special function like a constructor, destructor or operator.
class FunctionDescription:
	specialFuncNames = dict({"new":1, "__gc":1, "__eq":1});
	def __init__(self, name, cppName):
		self.name = name;
		self.cppName = cppName;
		self.instances = [];
		if name in FunctionDescription.specialFuncNames:
			self.isSpecial = True;
		else:
			self.isSpecial = False;

	def addInstance(self, instance):
		self.instances.append(instance);

	def parseComment(self, comment):
		instance = FunctionInstance();
		lines = comment.splitlines(False);
		classStack.append(self.name);
		# Parse lines for anything that affects all of the function instances.
		instance.parseComment(lines);
		self.instances.append(instance);
		classStack.pop();

	def __str__(self):
		return self.name + " (" + self.cppName + ")"

# Stores a representation of a class.
# This class can have a comment block, a name, a namespace and a list
# of all the functions and operators that this class has.
class ClassDescription:
	wrapperRegex = re.compile('"([^"]+)"[^,]*,\s*([^}]+)}');
	commentSplitter = re.compile("(/\*\*.*?\*/)|(int \w+\(lua_State[^\)]+\))", re.S);
	charParse = re.compile("int (\w+)\(lua_State");

	def __init__(self, name):
		self.name = name;
		self.classComment = "";
		self.namespace = None;
		# Special functions refer to ctor, dtor and operators
		self.specialFuncs = collections.OrderedDict();
		self.funcs = collections.OrderedDict();
		self.cppLookups = collections.OrderedDict();
		self.fileContents = "";
		self.wrappers = "";
		self.inCode = False;

	def addFunction(self, funcDesc):
		self.cppLookups[funcDesc.cppName] = funcDesc;
		if funcDesc.isSpecial:
			self.specialFuncs[funcDesc.name] = funcDesc;
		else:
			self.funcs[funcDesc.name] = funcDesc;

	# Parses a C++ wrapper file.
	# Looks for the luaL_Reg structure which contains all the mappings between
	# Lua functions and the C++ function names.
	# Then splits the file up into comments and function signatures and parses
	# comments to functions.
	def parseFile(self, filename):
		classStack.append(self.name);
		file = open(filename);
		self.fileContents = file.read();
		luaRegIndex = re.search("luaL_Reg", self.fileContents).start();
		bracketStart = self.fileContents.find("{", luaRegIndex);
		bracketEnd = self.fileContents.find("};", luaRegIndex);
		self.wrappers = self.fileContents[bracketStart + 1:bracketEnd];

		self.parseWrappers(self.wrappers);

		self.parseComments();

		classStack.pop();

	# Parses the luaL_Reg structure for mappings between the Lua function names
	# and the C++ function names.
	def parseWrappers(self, content):
		for match in ClassDescription.wrapperRegex.finditer(content):
			func = FunctionDescription(match.group(1), match.group(2).strip())
			self.addFunction(func);

	def parseClassLine(self, line):
		matchIter = FunctionInstance.metaMatch.finditer(line);
		for match in matchIter:
			meta = str(match.group()).lower();
			if meta == "@class":
				return "";

		code = line.find("
");
		if code >= 0:
			self.inCode = True;
		code = line.find("
");
		if code >= 0:
			self.inCode = False;

		if self.inCode:
			line = line + "\n";

		return line.replace("
", "\n");

	def parseClassComment(self, comment):
		commentJoin = [];
		for line in comment.splitlines(False):
			for match in FunctionInstance.commentLineSplit.finditer(line):
				group = match.group(1) if match.group(1) else match.group(2);
				if group:
					commentJoin.append(self.parseClassLine(str(group)));

		self.classComment = arrayJoin(commentJoin);
	# Splits the file into comments and function signatures.
	def parseComments(self):
		comments = [];
		for match in ClassDescription.commentSplitter.finditer(self.fileContents):
			line = match.group();
			index = line.find("/*");
			if index == 0:
				if line.find("@class") > 0:
					self.parseClassComment(line);
				else:
					comments.append(line);
			else:
				cppName = ClassDescription.charParse.match(line).group(1);

				if not cppName in self.cppLookups:
					continue

				func = self.cppLookups[cppName];

				if len(comments) == 0:
					warning("." + func.name + " has no comments");

				for comment in comments:
					func.parseComment(comment);
				comments = [];

		if len(self.classComment) == 0:
			warning(" has not class comment");

	def __str__(self):
		s = "Special functions\n"
		for k,v in self.specialFuncs.items():
			s += str(v) + "\n"
		s += "Normal functions\n"
		for k,v in self.funcs.items():
			s += str(v) + "\n"

		return s

class Documentation:
	whitespaceSplit = re.compile('\s+');
	def __init__(self):
		self.classes = collections.OrderedDict();

	def parseClass(self, className, filepath):
		classDesc = ClassDescription(className);
		classDesc.parseFile(filepath);
		self.classes[className] = classDesc;

	def parseList(self, listPath):
		basePath = "";
		file = open(listPath);
		contents = file.read();
		lines = contents.splitlines(False);
		for line in lines:
			#line = line.strip();
			if len(line) == 0 or line.find("//") == 0:
				continue;

			split = Documentation.whitespaceSplit.split(line, 2);
			if split[0] == "__basePath":
				basePath = split[1];
			else:
				classDesc = ClassDescription(split[0]);
				classDesc.parseFile(basePath + split[1]);
				self.classes[split[0]] = classDesc;


# -*- coding: utf-8 -*-
"""
@author: Florian Koch
@license: All rights reserved
"""
import pandas as pd
import json

with open('../../data/Öffentliche Beleuchtung der Stadt Zürich/beleuchtung.json') as data_file:
  data = json.load(data_file)
  df = pd.io.json.json_normalize(data, ['features', ['geometry', 'coordinates']],['name', ])
  df.columns = ['E', 'N', 'name']
  df.name = 'illumination'

df.to_csv('../../data/prepared/illumination.csv')


# =========================================================================
# Copyright (C) 2022. Huawei Technologies Co., Ltd. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =========================================================================

from collections import OrderedDict
import io
import os
import logging
import json

class FeatureMap(object):
    def __init__(self, dataset_id, data_dir):
        self.data_dir = data_dir # must keep to be used in embedding layer for pretrained emb
        self.dataset_id = dataset_id
        self.num_fields = 0
        self.total_features = 0
        self.input_length = 0
        self.features = OrderedDict()
        self.labels = []
        self.column_index = dict()
        self.group_id = None
        self.default_emb_dim = None

    def load(self, json_file, params):
        logging.info("Load feature_map from json: " + json_file)
        with io.open(json_file, "r", encoding="utf-8") as fd:
            feature_map = json.load(fd) #, object_pairs_hook=OrderedDict
        if feature_map["dataset_id"] != self.dataset_id:
            raise RuntimeError("dataset_id={} does not match feature_map!".format(self.dataset_id))
        self.num_fields = feature_map["num_fields"]
        self.labels = feature_map.get("labels", [])
        self.total_features = feature_map.get("total_features", 0)
        self.input_length = feature_map.get("input_length", 0)
        self.group_id = feature_map.get("group_id", None)
        self.default_emb_dim = params.get("embedding_dim", None)
        self.features = OrderedDict((k, v) for x in feature_map["features"] for k, v in x.items())
        if params.get("use_features", None):
            self.features = OrderedDict((x, self.features[x]) for x in params["use_features"])
        if params.get("feature_specs", None):
            self.update_feature_specs(params["feature_specs"])
        self.set_column_index()

    def update_feature_specs(self, feature_specs):
        for col in feature_specs:
            namelist = col["name"]
            if type(namelist) != list:
                namelist = [namelist]
            for name in namelist:
                for k, v in col.items():
                    if k != "name":
                        self.features[name][k] = v

    def save(self, json_file):
        logging.info("Save feature_map to json: " + json_file)
        os.makedirs(os.path.dirname(json_file), exist_ok=True)
        feature_map = OrderedDict()
        feature_map["dataset_id"] = self.dataset_id
        feature_map["num_fields"] = self.num_fields
        feature_map["total_features"] = self.total_features
        feature_map["input_length"] = self.input_length
        feature_map["labels"] = self.labels
        if self.group_id is not None:
            feature_map["group_id"] = self.group_id
        feature_map["features"] = [{k: v} for k, v in self.features.items()]
        with open(json_file, "w") as fd:
            json.dump(feature_map, fd, indent=4)

    def get_num_fields(self, feature_source=[]):
        if type(feature_source) != list:
            feature_source = [feature_source]
        num_fields = 0
        for feature, feature_spec in self.features.items():
            if feature_spec["type"] == "meta":
                continue
            if len(feature_source) == 0 or feature_spec.get("source") in feature_source:
                num_fields += 1
        return num_fields

    def sum_emb_out_dim(self, feature_source=[]):
        if type(feature_source) != list:
            feature_source = [feature_source]
        total_dim = 0
        for feature, feature_spec in self.features.items():
            if feature_spec["type"] == "meta":
                continue
            if len(feature_source) == 0 or feature_spec.get("source") in feature_source:
                total_dim += feature_spec.get("emb_output_dim",
                                              feature_spec.get("embedding_dim",
                                                               self.default_emb_dim))
        return total_dim

    def set_column_index(self):
        logging.info("Set column index...")
        idx = 0
        for feature, feature_spec in self.features.items():
            if "max_len" in feature_spec:
                col_indexes = [i + idx for i in range(feature_spec["max_len"])]
                self.column_index[feature] = col_indexes
                idx += feature_spec["max_len"]
            else:
                self.column_index[feature] = idx
                idx += 1
        self.input_length = idx
        for label in self.labels:
            self.column_index[label] = idx
            idx += 1

    def get_column_index(self, feature):
        if feature not in self.column_index:
            self.set_column_index()
        return self.column_index[feature]


import argparse
from pwm import main as pwm_main
from pwm import *

'''
-m pour le fichier contenant la matrice (option longue --pfm, pas de valeur par défaut) ;
-t pour le seuil de score de matrice (option longue --threshold, pas de valeur par défaut) ;
-l pour la longueur du promoteur (option longue --promotor-length, par défaut 1000) ;
-w pour la longueur de la fenêtre glissante (option longue --window-size, par défaut 40) ;
-s pour le seuil de score de fenêtre (option longue --window-threshold, pas de valeur par défaut) ;
-p pour la valeur du pseudo-poids (option longue --pseudocount, valeur par défaut 0.1).
'''
def main(args):
    parser = argparse.ArgumentParser()
    parser.parse_args()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-m", "--pfm", help="le fichier contenant la matrice")
    parser.add_argument("-t", "--threshold", help="The threshold of the results", type=int)
    parser.add_argument("-l", "--promotor-length", help="The lengh of the promotor", type=int, default=1000)
    parser.add_argument("-w", "--window-size", help="the size of the sliding window", type=int, default=40)
    parser.add_argument("-s", "--window-threshold", type=int)
    parser.add_argument("-p", "--pseudocount", help="le seuil de poids", type=int, default=0.1)

    parser.add_argument("-v", "--verbosity", help="increases the verbosity", action="store_true")
    args = parser.parse_args()
    if (args.verbosity):
        print("verbosity turned on")

    nb_occurences = scan_sequence()
    score_de_fenetre = score_window()

    pwm_main()


#!/usr/bin/env python
import os
from posixpath import split
import pygame
import numpy as np
from eden.core import Eden
import platform
if platform.system() == 'Windows':
    import ctypes
    ctypes.windll.user32.SetProcessDPIAware()
from pygame.transform import scale as surf_scale
from typing import List, Tuple

asset_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'assets')

FONT = os.path.join(asset_dir, 'consola.ttf')
FONT_SIZE = 16
FONT_WHITE = (255, 255, 255)
FONT_BLACK = (0, 0, 0)
FONT_RED   = (200, 0, 0)
FONT_GREEN = (0, 200, 0)
FONT_BLUE  = (0, 0, 200)

PIC_SIZE= 32

BLOCK_BORDER     = 0
BLOCK_SYNTHESIZE = 1
BLOCK_BACKPACK   = 2
BLOCK_EQUIPMENT  = 3
BLOCK_MAP        = 4
BLOCK_ATTRIBUTE  = 5

BLOCK_ASSET_NAME = {
    BLOCK_BORDER:     'border',
    BLOCK_SYNTHESIZE: 'synthesize',
    BLOCK_BACKPACK:   'slot_bp',
    BLOCK_EQUIPMENT:  'slot_eq',
    BLOCK_MAP:        'background',
    BLOCK_ATTRIBUTE:  'background'
}
FOG_ASSET_NAME = ['fog_black', 'fog_white']
TYPE_NAME = ["agent", "being", "item", "resource", "buff", "weather", "landform", "attribute"]

ACTION_IDLE       = 0
ACTION_ATTACK     = 1
ACTION_COLLECT    = 2
ACTION_PICKUP     = 3
ACTION_CONSUME    = 4
ACTION_EQUIP      = 5
ACTION_SYNTHESIZE = 6
ACTION_DISCARD    = 7
ACTION_MOVE       = 8

class Render:
    def __init__(self, env:Eden, display_size:int=20) -> None:
        assert display_size >= 16, "display_size is supposed to be >= 16"
        self.env = env
        self.n_agent = env.backend.agent_count
        self.current_agent = 0
        self.action = [[]] * self.n_agent

        self.display_size = display_size
        self.info_linewidth = display_size - 7
        self.backpack_line_n   = int(np.ceil(self.env.backpack_size / 10))
        self.equipment_line_n  = int(np.ceil(self.env.equipment_size / 10))
        self.synthesize_line_n = int(np.ceil(len(self.env.synthesize_list) / 10))
        self.attribute_line_n  = int(np.ceil(len(env.attribute_name) / 2))

        self.window_x = int(1 + self.display_size + 1 + 10 + 1) # border map border slot border
        self.window_y = int(1 + self.display_size + 1 + 6  + 1) # border map border info border
        self.window_y = max(
            self.window_y,
            1 + self.backpack_line_n +     # backpack
            1 + self.equipment_line_n +    # equipment
            1 + self.synthesize_line_n + 1 # synthesize
        )

        self.is_daytime = True
        self.current_vision_range = 0
        self.ui_info = None
        self.assets = {}
        self.block_size = PIC_SIZE
        self.block = np.zeros((self.window_x, self.window_y), dtype=int) # record block_type of every block
        self.nameint = np.zeros_like(self.block, dtype=int) - 1          # used in click support for [backpack, equipment, synthesize]
        self.mouse_info = ""
        self.block_x = -1
        self.block_y = -1
        self._init_display()

    def ui_run(self):
        while self.fresh():
            self.clock.tick(15)
        pygame.quit()

    def fresh(self) -> bool:
        '''
        Fresh the ui. Return False if ui window is closed else True
        '''
        self._draw_ui()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                action = self._handle_mouse_click(event)
                if len(action) > 0:
                    self.action[self.current_agent] = action
                    self.current_agent += 1
                    if self.current_agent >= self.n_agent:
                        self.current_agent = 0
                        self.env.step(self.action)
            elif event.type == pygame.MOUSEMOTION:
                self._handle_mouse_motion(event)
            elif event.type == pygame.VIDEORESIZE:
                self.block_size = np.floor(min(event.w / self.window_x, event.h / self.window_y))
                self.font = pygame.font.Font(FONT, int(self.block_size // 2))
                self.attr_font = pygame.font.Font(FONT, int(self.block_size // 4))
        return True

    def _draw_ui(self):
        self.ui_info = self.env.backend.ui(self.current_agent)
        self._draw_border()
        self._draw_info()
        self._draw_synthesize_list()
        cursor = self._draw_map()
        cursor = self._draw_attribute(cursor)
        cursor = self._draw_backpack(cursor)
        cursor = self._draw_equipment(cursor)
        pygame.display.flip()

    def _handle_mouse_motion(self, event):
        cursor_x, cursor_y = pygame.mouse.get_pos()
        self.block_x = int(cursor_x // self.block_size)
        self.block_y = int(cursor_y // self.block_size)
        # mouse info
        x = self.block_x
        y = self.block_y
        if x < 0 or x >= self.window_x:
            return []
        if y < 0 or y >= self.window_y:
            return []
        target_0, target_1 = self._get_target_param()
        if self.block[x, y] == BLOCK_MAP:
            cursor = 1 + (target_0 * self.env.map_size_x + target_1) * 6
            if self.ui_info[cursor + 1] < 0: # not occupied, record lanform name
                self.mouse_info = self.env.run_script(f"get.landform.{target_0}-{target_1}")
            else: # occupied, record object info
                self.mouse_info = self.env.run_script(f"get.map.{target_0}-{target_1}|get.info.$0")
        elif self.block[x, y] == BLOCK_BACKPACK:
            row = y - 1
            col = x - 2 - self.display_size
            slot = row * 10 + col
            name_id = self.env.run_script(f"get.agent.{self.current_agent}|get.backpack.$0.{slot}")
            if name_id != "":
                self.mouse_info = self.env.run_script(f"get.info.{name_id}")
            else:
                self.mouse_info = "Empty Backpack Slot"
        elif self.block[x, y] == BLOCK_EQUIPMENT:
            row = y - 2 - self.backpack_line_n
            col = x - 2 - self.display_size
            slot = row * 10 + col
            name_id = self.env.run_script(f"get.agent.{self.current_agent}|get.equipment.$0.{slot}")
            if name_id != "":
                self.mouse_info = self.env.run_script(f"get.info.{name_id}")
            else:
                self.mouse_info = "Empty Equipment Slot"
        elif self.block[x, y] == BLOCK_SYNTHESIZE:
            row = y - 3 - self.backpack_line_n - self.equipment_line_n
            col = x - 2 - self.display_size
            slot = row * 10 + col
            name = self.env.backend_cfg.typeid2name[f"item:{self.nameint[x, y]}"]
            self.mouse_info = f"[{name}] " + self.env.run_script(f"get.synthesize_table.{name}")

    def _handle_mouse_click(self, event) -> List[float]:
        if event.button not in [pygame.BUTTON_LEFT, pygame.BUTTON_RIGHT]:
            return []
        x = self.block_x
        y = self.block_y
        if x < 0 or x >= self.window_x:
            return []
        if y < 0 or y >= self.window_y:
            return []
        target_0, target_1 = self._get_target_param()
        if self.block[x, y] == BLOCK_MAP:
            cursor = 1 + (target_0 * self.env.map_size_x + target_1) * 6
            if self.ui_info[cursor + 1] < 0: # not occupied, move here
                return [ACTION_MOVE, target_0, target_1]
            else: # occupied, take action accordingly
                type_name = TYPE_NAME[int(self.ui_info[cursor + 1])]
                if type_name == 'agent':
                    return [ACTION_IDLE, -1, -1]
                elif type_name == 'being':
                    return [
                        ACTION_COLLECT if event.button == pygame.BUTTON_LEFT else ACTION_ATTACK,
                        target_0, target_1
                    ]
                elif type_name == 'resource':
                    return [ACTION_COLLECT, target_0, target_1]
                elif type_name == 'item':
                    return [ACTION_PICKUP, target_0, target_1]
        elif self.block[x, y] == BLOCK_BACKPACK:
            if self.nameint[x, y] < 0: # empty, return
                return []
            if event.button == pygame.BUTTON_RIGHT:
                return [ACTION_DISCARD, target_0, target_1]
            if self.nameint[x, y] in [int(x.split(':')[-1]) for x in self.env.backend_cfg.equip_list]:
                return [ACTION_EQUIP, target_0, target_1]
            elif self.nameint[x, y] in self.env.backend_cfg.consume_list:
                return [ACTION_CONSUME, target_0, target_1]
        elif self.block[x, y] == BLOCK_EQUIPMENT:
            if self.nameint[x, y] < 0: # empty, return
                return []
            return [ACTION_EQUIP, target_0, target_1]
        elif self.block[x, y] == BLOCK_SYNTHESIZE:
            return [ACTION_SYNTHESIZE, target_0, target_1]
        return []

    def _get_target_param(self):
        target_0 = -1
        target_1 = -1
        x = self.block_x
        y = self.block_y
        if self.block[x, y] == BLOCK_SYNTHESIZE:
            target_0 = self.nameint[x, y]
            target_1 = 1
        elif self.block[x, y] == BLOCK_BACKPACK:
            target_0 = self.nameint[x, y]
            target_1 = 1
        elif self.block[x, y] == BLOCK_EQUIPMENT:
            # equipment
            target_0 = self.nameint[x, y]
            target_1 = 1
        elif self.block[x, y] == BLOCK_MAP:
            # map
            lt_x, lt_y = self._get_display_rect()
            target_0 = x - 1 + lt_x
            target_1 = y - 1 + lt_y
        return int(target_0), int(target_1)

    def _init_display(self):
        pygame.init()
        self.screen = pygame.display.set_mode(
            (self.window_x * PIC_SIZE, self.window_y * PIC_SIZE),
            pygame.RESIZABLE
        )
        self.clock = pygame.time.Clock()
        self.font      = pygame.font.Font(FONT, int(self.block_size // 2))
        self.attr_font = pygame.font.Font(FONT, int(self.block_size // 4))
        self._init_assets()
        self._init_block()
        for name in BLOCK_ASSET_NAME.values():
            assert name in self.assets.keys(), "Could not find {name} in assets"
        for name in FOG_ASSET_NAME:
            assert name in self.assets.keys(), "Could not find {name} in assets"

    def _init_assets(self):
        for file in os.listdir(asset_dir):
            if '.png' != file[-4:]:
                continue
            surf = pygame.image.load(os.path.join(asset_dir, file)).convert_alpha()
            self.assets[file[:-4]] = surf

    def _init_block(self):
        # map
        for x in range(1, 1 + self.display_size):
            for y in range(1, 1 + self.display_size):
                self.block[x, y] = BLOCK_MAP
        # attribute
        for x in range(1, 1 + 6):
            for y in range(2 + self.display_size, self.window_y - 1):
                self.block[x, y] = BLOCK_ATTRIBUTE
        # info
        shift_x = 8
        for y in range(2 + self.display_size, self.window_y - 1):
            for x in range(8, 1 + self.display_size):
                self.block[x, y] = BLOCK_ATTRIBUTE
        # backpack
        shift_x = 2 + self.display_size
        shift_y = 1
        for i in range(self.env.backpack_size):
            y = int(i // 10)
            x = i - y * 10
            self.block[x + shift_x, y + shift_y] = BLOCK_BACKPACK
        # equipment
        shift_y += self.backpack_line_n + 1
        for i in range(self.env.equipment_size):
            y = int(i // 10)
            x = i - y * 10
            self.block[x + shift_x, y + shift_y] = BLOCK_EQUIPMENT
        # synthesize list
        shift_y += self.equipment_line_n + 1
        for i in range(len(self.env.synthesize_list)):
            y = int(i // 10)
            x = i - y * 10
            self.block[x + shift_x, y + shift_y] = BLOCK_SYNTHESIZE

    def _draw_border(self):
        for x in range(self.window_x):
            for y in range(self.window_y):
                name = BLOCK_ASSET_NAME[self.block[x, y]]
                self.screen.blit(
                    surf_scale(self._get_asset(name), [self.block_size] * 2),
                    (x * self.block_size, y * self.block_size)
                )

    def _draw_map(self):
        lt_x, lt_y = self._get_display_rect()
        # weather
        weather_id = int(self.ui_info[0])
        weather_name = self.env.backend_cfg.typeid2name[f"weather:{weather_id}"]
        # map
        self.screen.blit(
            self.font.render("(X)".center(4), True, FONT_WHITE),
            ((1 + min(self.display_size, self.env.map_size_x)) * self.block_size, int(0.25 * self.block_size))
        )
        self.screen.blit(
            self.font.render("(Y)".center(4), True, FONT_WHITE),
            (0, (1 + min(self.display_size, self.env.map_size_y)) * self.block_size)
        )
        cursor = 1
        for x in range(self.env.map_size_x):
            for y in range(self.env.map_size_y):
                block_x = x - lt_x
                block_y = y - lt_y
                if block_x >=0 and block_y >= 0 and block_x < self.display_size and block_y < self.display_size:
                    if block_x == 0:
                        self.screen.blit(
                            self.font.render(str(y).center(4), True, FONT_WHITE),
                            (0, int((1.25 + block_y) * self.block_size))
                        )
                    if block_y == 0:
                        self.screen.blit(
                            self.font.render(str(x).center(4), True, FONT_WHITE),
                            ((1 + block_x) * self.block_size, int(0.25 * self.block_size))
                        )
                    name = self.env.backend_cfg.typeid2name[f"landform:{int(self.ui_info[cursor])}"]
                    self.screen.blit(
                        surf_scale(self._get_asset(name), [self.block_size] * 2),
                        ((1 + block_x) * self.block_size, (1 + block_y) * self.block_size)
                    )
                    self.screen.blit(
                        surf_scale(self.assets[weather_name], [self.block_size] * 2),
                        ((1 + block_x) * self.block_size, (1 + block_y) * self.block_size)
                    )
                    if int(self.ui_info[cursor+1]) >= 0:
                        type_name = TYPE_NAME[int(self.ui_info[cursor+1])]
                        name = self.env.backend_cfg.typeid2name[
                            f"{type_name}:{int(self.ui_info[cursor+2])}"
                        ]
                        self.screen.blit(
                            surf_scale(self._get_asset(name), [self.block_size] * 2),
                            ((1 + block_x) * self.block_size, (1 + block_y) * self.block_size)
                        )
                        # if type_name == 'agent':
                        #     self.screen.blit(
                        #         self.attr_font.render(f"{int(self.ui_info[cursor+3])}".center(5), True, FONT_WHITE, FONT_RED),
                        #         (int((1.125 + block_x) * self.block_size), (1 + block_y) * self.block_size)
                        #     )
                        #     self.screen.blit(
                        #         self.attr_font.render(f"{int(self.ui_info[cursor+4])}".center(3), True, FONT_WHITE, FONT_GREEN),
                        #         ((1 + block_x) * self.block_size, int((1.75 + block_y) * self.block_size))
                        #     )
                        #     self.screen.blit(
                        #         self.attr_font.render(f"{int(self.ui_info[cursor+5])}".center(3), True, FONT_WHITE, FONT_BLUE),
                        #         (int((1.5 + block_x) * self.block_size), int((1.75 + block_y) * self.block_size))
                        #     )
                        # elif type_name == 'being':
                        #     self.screen.blit(
                        #         self.attr_font.render(f"{int(self.ui_info[cursor+3])}".center(5), True, FONT_WHITE, FONT_RED),
                        #         (int((1.125 + block_x) * self.block_size), (1 + block_y) * self.block_size)
                        #     )
                cursor += 6
        # is daytime
        self.is_daytime = (self.ui_info[cursor] > 1e-4)
        cursor += 1
        # position
        agent_x = int(self.ui_info[cursor])
        agent_y = int(self.ui_info[cursor+1])
        # fog
        for x in range(self.env.map_size_x):
            for y in range(self.env.map_size_y):
                block_x = x - lt_x
                block_y = y - lt_y
                if block_x < 0 or block_y < 0:
                    continue
                if block_x >= self.display_size or block_y >= self.display_size:
                    continue
                if abs(x - agent_x) + abs(y - agent_y) <= self.current_vision_range:
                    continue
                self.screen.blit(
                    surf_scale(self.assets[FOG_ASSET_NAME[int(self.is_daytime)]], [self.block_size] * 2),
                    ((1 + block_x) * self.block_size, (1 + block_y) * self.block_size)
                )
        cursor += 2
        return cursor

    def _draw_attribute(self, cursor):
        # attribute
        attribute_num = int(self.ui_info[cursor])
        cursor += 1
        shift_x = 1
        shift_y = 2 + self.display_size
        for i in range(attribute_num):
            y = int((shift_y + i / 2) * self.block_size)
            x = int(shift_x * self.block_size)
            self.screen.blit(
                self.font.render(f"{self.env.attribute_name[i]:15s}{int(self.ui_info[cursor]):5d}", True, FONT_WHITE),
                (x, y)
            )
            if self.env.attribute_name[i] == 'Vision' and self.is_daytime:
                self.current_vision_range = int(self.ui_info[cursor])
            elif self.env.attribute_name[i] == 'NightVision' and not self.is_daytime:
                self.current_vision_range = int(self.ui_info[cursor])
            cursor += 1
        self.screen.blit(
            self.font.render("Attribute", True, FONT_WHITE),
            [int((shift_x + .25) * self.block_size), int((shift_y - .75) * self.block_size)]
        )
        return cursor

    def _draw_backpack(self, cursor):
        backpack_size = int(self.ui_info[cursor])
        cursor += 1
        shift_x = 2 + self.display_size
        shift_y = 1
        for i in range(backpack_size):
            y = i // 10
            x = i - y * 10
            x += shift_x
            y += shift_y
            self.screen.blit(
                surf_scale(self.assets['slot_bp'], [self.block_size] * 2),
                (x * self.block_size, y * self.block_size)
            )
            if int(self.ui_info[cursor]) >= 0:
                name = self.env.backend_cfg.typeid2name[f"item:{int(self.ui_info[cursor])}"]
                self.screen.blit(
                    surf_scale(self._get_asset(name), [self.block_size] * 2),
                    (x * self.block_size, y * self.block_size)
                )
                self.screen.blit(
                    self.font.render(str(int(self.ui_info[cursor+1])), True, FONT_WHITE),
                    (int((x + 0.15) * self.block_size), int((y + 0.15) * self.block_size))
                )
            self.nameint[x, y] = int(self.ui_info[cursor])
            cursor += 2
        self.screen.blit(
            self.font.render("Backpack", True, FONT_WHITE),
            [int((shift_x + .25) * self.block_size), int((shift_y - .75) * self.block_size)]
        )
        return cursor

    def _draw_equipment(self, cursor):
        equipment_size = int(self.ui_info[cursor])
        cursor += 1
        shift_x = 2 + self.display_size
        shift_y = 2 + self.backpack_line_n
        for i in range(equipment_size):
            y = i // 10
            x = i - y * 10
            x += shift_x
            y += shift_y
            self.screen.blit(
                surf_scale(self.assets['slot_eq'], [self.block_size] * 2),
                (x * self.block_size, y * self.block_size)
            )
            if int(self.ui_info[cursor]) >= 0:
                name = self.env.backend_cfg.typeid2name[f"item:{int(self.ui_info[cursor])}"]
                self.screen.blit(
                    surf_scale(self._get_asset(name), [self.block_size] * 2),
                    (x * self.block_size, y * self.block_size)
                )
            self.nameint[x, y] = int(self.ui_info[cursor])
            cursor += 1
        self.screen.blit(
            self.font.render("Equipment", True, FONT_WHITE),
            [int((shift_x + .25) * self.block_size), int((shift_y - .75) * self.block_size)]
        )
        return cursor

    def _draw_synthesize_list(self):
        shift_x = 2 + self.display_size
        shift_y = 3 + self.backpack_line_n + self.equipment_line_n
        for i in range(len(self.env.synthesize_list)):
            y = i // 10
            x = i - y * 10
            x += shift_x
            y += shift_y
            name = self.env.backend_cfg.typeid2name[f"item:{self.env.synthesize_list[i]}"]
            self.screen.blit(
                surf_scale(self._get_asset(name), [self.block_size] * 2),
                (x * self.block_size, y * self.block_size)
                )
            self.nameint[x, y] = self.env.synthesize_list[i]
        self.screen.blit(
            self.font.render("Synthesize List", True, FONT_WHITE),
            [int((shift_x + .25) * self.block_size), int((shift_y - .75) * self.block_size)]
        )

    def _draw_info(self):
        x = 8
        y = 2 + self.display_size
        self.screen.blit(
            self.font.render(f"Information", True, FONT_WHITE),
            [int((x + .25) * self.block_size), int((y - .75) * self.block_size)]
        )
        shift_pixel_x = 0
        shift_pixel_y = 0
        for word in self.mouse_info.split(' '):
            word_surf = self.font.render(word + ' ', True, FONT_WHITE)
            if x * self.block_size + shift_pixel_x + word_surf.get_width() >= (1 + self.display_size) * self.block_size:
                shift_pixel_y += self.block_size // 2
                shift_pixel_x = 0
            self.screen.blit(word_surf, [x * self.block_size + shift_pixel_x, y * self.block_size + shift_pixel_y])
            shift_pixel_x += word_surf.get_width()

    def _get_display_rect(self):
        cursor = 1 + self.env.map_size_x * self.env.map_size_y * 6 + 1 # weather, map, daytime
        agent_x = self.ui_info[cursor]
        agent_y = self.ui_info[cursor+1]
        left_top_x = max(0, min(self.env.map_size_x - self.display_size, agent_x - self.display_size // 2))
        left_top_y = max(0, min(self.env.map_size_y - self.display_size, agent_y - self.display_size // 2))
        return int(left_top_x), int(left_top_y)

    def _get_asset(self, name):
        assert name in self.assets.keys(), "Could not find {name} in assets"
        return self.assets[name]

if __name__ == "__main__":
    import gym, eden
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('--load_history', '-l', action='store_true', help='whether to load actions from history.log')
    parser.add_argument('--display_size', '-d', type=int, default=20, help='the map display size, should be no less than 16')
    args = parser.parse_args()

    env = gym.make('eden-v0')
    env.reset()
    if args.load_history:
        action_history = []
        with open('history.log', 'r') as file:
            lines = file.readlines()
            for line in lines:
                if '[[' not in line:
                    continue
                multi_action = line[:-1].strip('[]').split('], [')
                action_history.append([[int(x) for x in single_action.split(', ')] for single_action in multi_action])
        for action in action_history:
            env.step(action)
    render = Render(env, display_size=args.display_size)
    render.ui_run()


import math
import os
from pathlib import Path
from typing import Any, Optional, Tuple, Union
from warnings import warn

import torch

from renate.types import NestedTensors

def mmap_tensor(
    filename: str, size: Union[int, Tuple[int, ...]], dtype: torch.dtype
) -> torch.Tensor:
    """Creates or accesses a memory-mapped tensor."""
    t = torch.from_file(
        filename,
        shared=True,
        size=math.prod(size) if isinstance(size, tuple) else size,
        dtype=dtype,
        device="cpu",
    )
    return t.view(size)

class Storage(torch.utils.data.Dataset):
    """An abstract class for permanent storage of datasets."""

    def __init__(self, directory: str) -> None:
        self._directory = directory

    def __len__(self) -> int:
        return self._length

    def __getitem__(self, idx: int) -> Any:
        raise NotImplementedError()

    def dump_dataset(self, ds: torch.utils.data.Dataset) -> None:
        raise NotImplementedError()

    def load_dataset(self, directory: Union[str, Path]):
        raise NotImplementedError()

class MemoryMappedTensorStorage(Storage):
    """A class implementing permanent storage of nested tensor datasets.

    This implements storage for `length` data points consisting of nested tensors of fixed types
    and shapes. `Storage` implements `__len__` and `__getitem__` and therefore can be used as a
    torch `Dataset`. To populate the storage, it also implements `dump_dataset`. It does _not_ keep
    track which slots have or have not been populated.

    `Storage` is given a path to a directory, where it creates (or accesses, if they already exist)
    memory-mapped tensor files.

    Args:
        directory: Path to a directory.
        data_point: Prototypical datapoint from which to infer shapes/dtypes.
        length: Number of items to be stored.
    """

    def __init__(self, directory: str) -> None:
        warn(
            f"""{self.__class__.__name__} will be deprecated very soon. Use FileTensorStorage
            instead. {self.__class__.__name__} is currently not fully functional, as some of the
            necessary parts of the interface have been modified and simplified. """,
            DeprecationWarning,
            stacklevel=2,
        )
        super().__init__(directory)
        self._storage: Optional[NestedTensors] = None

    @staticmethod
    def _create_mmap_tensors(path: str, data_point: NestedTensors, length: int) -> NestedTensors:
        if isinstance(data_point, torch.Tensor):
            os.makedirs(os.path.dirname(path), exist_ok=True)
            filename = f"{path}.pt"
            return mmap_tensor(filename, size=(length, *data_point.size()), dtype=data_point.dtype)
        elif isinstance(data_point, tuple):
            return tuple(
                MemoryMappedTensorStorage._create_mmap_tensors(
                    os.path.join(path, f"{i}.pt"), data_point[i], length
                )
                for i in range(len(data_point))
            )
        elif isinstance(data_point, dict):
            return {
                key: MemoryMappedTensorStorage._create_mmap_tensors(
                    os.path.join(path, f"{key}.pt"), data_point[key], length
                )
                for key in data_point
            }
        else:
            raise TypeError(f"Expected nested tuple/dict of tensors, found {type(data_point)}.")

    @staticmethod
    def _get(storage: NestedTensors, idx: int) -> NestedTensors:
        if isinstance(storage, torch.Tensor):
            return storage[idx]
        elif isinstance(storage, tuple):
            return tuple(MemoryMappedTensorStorage._get(t, idx) for t in storage)
        elif isinstance(storage, dict):
            return {key: MemoryMappedTensorStorage._get(t, idx) for key, t in storage.items()}
        else:
            raise TypeError(f"Expected nested tuple/dict of tensors, found {type(storage)}.")

    def __getitem__(self, idx: int) -> NestedTensors:
        """Read the item stored at index `idx`."""
        return self._get(self._storage, idx)

    @staticmethod
    def _set(storage: NestedTensors, idx: int, data_point: NestedTensors) -> None:
        if isinstance(storage, torch.Tensor):
            assert isinstance(data_point, torch.Tensor)
            assert data_point.dtype is storage.dtype
            storage[idx] = data_point
        elif isinstance(storage, tuple):
            assert isinstance(data_point, tuple)
            assert len(data_point) == len(storage)
            for i in range(len(storage)):
                MemoryMappedTensorStorage._set(storage[i], idx, data_point[i])
        elif isinstance(storage, dict):
            assert isinstance(data_point, dict)
            assert set(data_point.keys()) == set(storage.keys())
            for key in storage:
                MemoryMappedTensorStorage._set(storage[key], idx, data_point[key])
        else:
            raise TypeError(f"Expected nested tuple/dict of tensors, found {type(storage)}.")

    def dump_dataset(self, ds):
        self._length = len(ds)
        self._storage = self._create_mmap_tensors(self._directory, ds[0], self._length)
        for idx in range(len(self)):
            self._set(self._storage, idx, ds[idx])

class FileTensorStorage(Storage):
    """A class implementing permanent storage of nested tensor datasets to disk as pickle files.

    This implements storage for `length` data points consisting of nested tensors of fixed types
    and shapes. `Storage` implements `__len__` and `__getitem__` and therefore can be used as a
    torch `Dataset`. To populate the storage, it also implements `dump_dataset`. It does _not_ keep
    track which slots have or have not been populated.

    `Storage` is given a path to a directory, where it creates (or accesses, if they already exist)
    pickle files one for each point in the dataset.

    Args:
        directory: Path to a directory.
    """

    def __init__(self, directory: str) -> None:
        super().__init__(directory)

    def dump_dataset(self, ds: torch.utils.data.Dataset) -> None:
        for i in range(len(ds)):
            torch.save(ds[i], self._compose_file_path_from_index(i))

    def __getitem__(self, idx: int) -> Any:
        if not hasattr(self, "_length"):
            self.load_dataset(None)
        return torch.load(self._compose_file_path_from_index(idx))

    def load_dataset(self, directory: Union[str, Path]):
        self._length = len([x for x in os.listdir(self._directory) if x.endswith(".pt")])

    def _compose_file_path_from_index(self, idx: int) -> str:
        return os.path.join(self._directory, f"{idx}.pt")


from django.shortcuts import render, get_object_or_404
from django.shortcuts import redirect
from allauth.socialaccount.models import SocialAccount
from .models import Repository, Milestone, Task
import requests
from .scripts import sync_repos
from .forms import MilestoneForm, TaskForm

def homepage(request):
    return render(request, 'roadmap/home.html')

def create_new_roadmap_subsite(request):
    if not request.user.is_authenticated:
        return render(request, 'roadmap/create_new_roadmap.html')

    username = SocialAccount.objects.get(user=request.user)
    url = f"https://api.github.com/users/{username}/repos"
    response = requests.get(url)

    if response.status_code == 200:
        repos = response.json()
        sync_repos.sync(repos)
    else:
        repos = []

    context = {"repos": repos}

    return render(request, 'roadmap/create_new_roadmap.html', context)

def create_new_roadmap(request, repository_id):
    repository = get_object_or_404(Repository, git_id=repository_id)
    milestones = Milestone.objects.filter(repository=repository)
    tasks = Task.objects.filter(repository=repository)

    milestone_form = MilestoneForm()
    task_form = TaskForm(repository=repository)

    context = {
        'milestone_form': milestone_form,
        'milestones': milestones,
        'task_form': task_form,
        'tasks': tasks,
        'repository': repository,
    }

    if request.method == 'POST':
        milestone_form = MilestoneForm(request.POST)
        task_form = TaskForm(request.POST, repository=repository)

        if 'milestoneform' in request.POST:
            if milestone_form.is_valid():
                milestone = milestone_form.save(commit=False)
                milestone.repository = repository
                milestone.save()

        if 'taskform' in request.POST:
            if task_form.is_valid():
                task = task_form.save(commit=False)
                task.repository = repository
                task.save()

    return render(request, 'roadmap/create_roadmap.html', context)

def my_roadmaps_subsite(request):
    if not request.user.is_authenticated:
        return render(request, 'roadmap/my_roadmaps.html')

    username = SocialAccount.objects.get(user=request.user)
    url = f"https://api.github.com/users/{username}/repos"
    response = requests.get(url)

    if response.status_code == 200:
        repos = response.json()
        sync_repos.sync(repos)
    else:
        repos = []

    context = {"repos": repos}

    return render(request, 'roadmap/my_roadmaps.html', context)

def roadmap(request, repository_id):
    repository = get_object_or_404(Repository, git_id=repository_id)
    milestones = Milestone.objects.filter(repository=repository)

    context = {
        'milestones' : milestones,
        'repository' : repository,
    }

    return render(request, 'roadmap/roadmap.html', context)

def mark_task_done(request, task_id):
    task = get_object_or_404(Task, pk=task_id)
    task.isdone = True
    task.save()
    repository_git_id = task.repository.git_id
    return redirect(f'http://localhost:8000/roadmaps/{repository_git_id}/')

def mark_task_undone(request, task_id):
    task = get_object_or_404(Task, pk=task_id)
    task.isdone = False
    task.save()
    repository_git_id = task.repository.git_id
    return redirect(f'http://localhost:8000/roadmaps/{repository_git_id}/')

def delete_task(request, task_id):
    task = get_object_or_404(Task, id=task_id)
    repository_git_id = task.repository.git_id
    task.delete()
    return redirect(f'http://localhost:8000/create_new_roadmap/{repository_git_id}/')

def delete_milestone(request, milestone_id):
    milestone = get_object_or_404(Milestone, id=milestone_id)
    repository_git_id = milestone.repository.git_id
    milestone.delete()
    return redirect(f'http://localhost:8000/create_new_roadmap/{repository_git_id}/')


#!/usr/bin/env python3

import json

def sum_numbers(data, ignore_red=False):
    if isinstance(data, list):
        total = 0
        for e in data:
            total += sum_numbers(e, ignore_red)
        return total
    elif isinstance(data, str):
        return 0
    elif isinstance(data, int):
        return data
    elif isinstance(data, dict):
        total = 0
        for key in data:
            if ignore_red and data[key] == 'red':
                return 0
            total += sum_numbers(key, ignore_red)
            total += sum_numbers(data[key], ignore_red)
        return total
    else:
        print("Unknown type", type(data))
    return 0

with open('input.txt', 'r') as f:
    data = json.load(f)

print(sum_numbers(data))
print(sum_numbers(data, True))


from unidecode import unidecode
import unittest

class Event:
    def __init__(self, name, player, quantity):
        self.name = name
        self.player = player
        self.quantity = quantity

    def __str__(self):
        return ', '.join([self.name, unidecode(self.player), str(self.quantity)])

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    @staticmethod
    def GetEventUpdates(oldEvents, newEvents):

        result = []
        newSavesEvents = filter(lambda x: x.name == "Saves", newEvents)
        if len(newSavesEvents) > 0:
            oldSavesEvents = filter(lambda x: x.name == "Saves", oldEvents)
            if len(oldSavesEvents) > 0:
                for newSavesEvent in newSavesEvents:
                    oldSavesEvent = next((x for x in oldSavesEvents if x.player == newSavesEvent.player), None)
                    if not oldSavesEvent or (oldSavesEvent and oldSavesEvent.quantity/3 < newSavesEvent.quantity/3):
                        result.append(newSavesEvent)
            else:
                result.extend(newSavesEvents)
        result.extend(filter(lambda x: x not in oldEvents and x.name != "Saves", newEvents))
        return result

class TestEvent(unittest.TestCase):
    def test_onePlayerNoSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 3)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 0)

    def test_onePlayerMinorSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 5)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 0)

    def test_onePlayerSavesDecrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 2)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 0)

    def test_onePlayerValidSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 6)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e2)

    def test_onePlayerValidSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 14)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e2)

    def test_onePlayerNewSaves(self):
        e1 = Event("Foo", u"Cech", 0)
        e2 = Event("Saves", u"Cech", 14)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e2)

    def test_onePlayerOldSaves(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Foo", u"Cech", 14)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0].name, "Foo")

    def test_twoPlayersNoSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 3)
        e3 = Event("Saves", u"Guzan", 5)
        e4 = Event("Saves", u"Guzan", 5)
        events = Event.GetEventUpdates([e1, e3], [e2, e4])
        self.assertEqual(len(events), 0)

    def test_twoPlayersMinorSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 5)
        e3 = Event("Saves", u"Guzan", 6)
        e4 = Event("Saves", u"Guzan", 8)
        events = Event.GetEventUpdates([e1, e3], [e2, e4])
        self.assertEqual(len(events), 0)

    def test_twoPlayersValidSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 6)
        e3 = Event("Saves", u"Guzan", 7)
        e4 = Event("Saves", u"Guzan", 9)
        events = Event.GetEventUpdates([e1, e3], [e2, e4])
        self.assertEqual(len(events), 2)
        self.assertEqual(events[0], e2)
        self.assertEqual(events[1], e4)

    def test_twoPlayersOnePlayerValidSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 5)
        e3 = Event("Saves", u"Guzan", 7)
        e4 = Event("Saves", u"Guzan", 9)
        events = Event.GetEventUpdates([e1, e3], [e2, e4])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e4)

    def test_twoPlayersNewSaves(self):
        e1 = Event("Foo", u"Cech", 0)
        e2 = Event("Saves", u"Cech", 14)
        e3 = Event("Saves", u"Guzan", 7)
        events = Event.GetEventUpdates([e1], [e2, e3])
        self.assertEqual(len(events), 2)
        self.assertEqual(events[0], e2)
        self.assertEqual(events[1], e3)

    def test_twoPlayersOnePlayerNewSaves(self):
        e1 = Event("Saves", u"Cech", 14)
        e2 = Event("Saves", u"Cech", 14)
        e3 = Event("Saves", u"Guzan", 7)
        events = Event.GetEventUpdates([e1], [e2, e3])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e3)

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