import tensorflow as tf
from tensorflow.contrib import rnn
import numpy as np

class BIDAF(object):
    '''
    char_embed_size:embed size for single character
    char_size:num of char
    word_length:max single word length
    '''
    def __init__(self,char_embed_size,char_size,word_length,
                 word_size,batch_num,word_embed_size,T=150,J=30,K=6):
        self.char_embed_size = char_embed_size
        self.char_size = char_size
        self.word_length = word_length
        self.word_size = word_size
        self.word_embed_size = word_embed_size

        self.d = char_embed_size + word_embed_size
        self.num_units = self.d
        self.num_blocks = 1

        self.num_heads = 1

        self.loss = None
        self.p1_accuracy = None
        self.p2_accuracy = None
        self.accuracy = None

        self.batch_num = batch_num

        with tf.name_scope('char_embedding'):
            self.char_W = tf.Variable(tf.random_uniform([self.char_size,self.char_embed_size],-1.0,1.0),name='char_W')
        with tf.name_scope('word_embedding'):
            self.word_W = tf.Variable(tf.random_uniform([self.word_size,self.word_embed_size],-1.0,1.0),name='word_W')

        self.word_length = word_length

        self.T = T
        self.J = J
        self.K = K

        self.c_char = tf.placeholder(dtype=tf.int32,shape=[None,T,word_length],name='c_char')
        self.c_word = tf.placeholder(dtype=tf.int32,shape=[None,T],name='c_word')

        self.q_char = tf.placeholder(dtype=tf.int32,shape=[None,J,word_length],name='q_char')
        self.q_word = tf.placeholder(dtype=tf.int32,shape=[None,J],name='q_word')

        self.a_char = tf.placeholder(dtype=tf.int32,shape=[None,K,word_length],name='a_char')
        self.a_word = tf.placeholder(dtype=tf.int32,shape=[None,K])

        self.p1_seq = tf.placeholder(dtype=tf.int32,shape=[None,T],name='p1_seq')
        self.p2_seq = tf.placeholder(dtype=tf.int32,shape=[None,T],name='p2_seq')

        self.label = tf.placeholder(dtype=tf.float32,shape=[None,3],name='label')

        self.model_construct()
        self.opt_construct()

    def model_construct(self):
        #context embed
        self.c_char_embed_flat = self.char_embed_layer(tf.reshape(self.c_char,[-1,self.word_length]),num_filters=self.char_embed_size)
        self.c_char_embed = tf.reshape(self.c_char_embed_flat,[-1,self.T,int(self.c_char_embed_flat.get_shape()[-1])],name='c_char_embed')
        print('c_char_embed',self.c_char_embed)
        self.c_word_embed = self.word_embed_layer(self.c_word)
        print('c_word_embed',self.c_word_embed)
        self.c_embed = tf.concat([self.c_char_embed,self.c_word_embed],axis=-1,name='c_embed')
        c_embed_last_dim = int(self.c_embed.get_shape()[-1])
        print(c_embed_last_dim)

        #query embed
        self.q_char_embed_flat = self.char_embed_layer(tf.reshape(self.q_char,[-1,self.word_length]),num_filters=self.char_embed_size)
        self.q_char_embed = tf.reshape(self.q_char_embed_flat,[-1,self.J,int(self.q_char_embed_flat.get_shape()[-1])],name='q_char_embed')
        self.q_word_embed = self.word_embed_layer(self.q_word)
        self.q_embed = tf.concat([self.q_char_embed,self.q_word_embed],axis=-1,name='q_embed')
        q_embed_last_dim = int(self.q_embed.get_shape()[-1])

        #answer embed [batch*3,K,d]
        self.a_char_embed_flat = self.char_embed_layer(tf.reshape(self.a_char,[-1,self.word_length]),num_filters=self.char_embed_size)
        self.a_char_embed = tf.reshape(self.a_char_embed_flat,[-1,self.K,int(self.a_char_embed_flat.get_shape()[-1])],name='q_char_embed')
        self.a_word_embed = self.word_embed_layer(self.a_word)
        self.a_embed = tf.concat([self.a_char_embed,self.a_word_embed],axis=-1,name='a_embed')
        a_embed_last_dim = int(self.a_embed.get_shape()[-1])

        #high way scope
        with tf.variable_scope('high_way_layer') as scope:
            self.X = tf.reshape(self.high_way_layer(tf.reshape(self.c_embed,[-1,c_embed_last_dim])),[-1,self.T,c_embed_last_dim])
            scope.reuse_variables()
            self.Q = tf.reshape(self.high_way_layer(tf.reshape(self.q_embed,[-1,q_embed_last_dim])),[-1,self.J,q_embed_last_dim])
        '''
        with tf.variable_scope('test') as scope:
            test = tf.Variable(tf.truncated_normal([32,150,512]))
            test = self.attention(test,self.num_blocks,self.num_units,self.num_heads)
            print('tested')
        '''
        #first bilstm layer
        with tf.variable_scope('first_attention_layer_context') as scope:
            print(self.X)
            self.H = self.attention(self.X,self.num_blocks,self.num_units,self.num_heads)
            #scope.reuse_variables()
        with tf.variable_scope('first_attention_layer_query') as scope:
            self.U = self.attention(self.Q,self.num_blocks,self.num_units,self.num_heads)

        #similarity layer
        #[batch_num,T,J]
        self.S = self.similarity_layer(self.H,self.U)

        #context to query attention
        self.A = tf.nn.softmax(self.S,dim=-1,name='A')
        d = self.U.get_shape()[-1]
        self.U_bar_list = []
        for i in range(self.batch_num):
            A = tf.squeeze(tf.slice(self.A,[i,0,0],[1,-1,-1]))
            U = tf.squeeze(tf.slice(self.U,[i,0,0],[1,-1,-1]))
            self.U_bar_list.append(tf.expand_dims(tf.matmul(A,U),0))

        self.U_bar = tf.concat(self.U_bar_list,axis=0)

        #query to context attention
        self.b = tf.nn.softmax(tf.reduce_max(self.S,axis=-1),dim=-1,name='b')
        self.h_bar_list = []

        for i in range(self.batch_num):
            b = tf.slice(self.b,[i,0],[1,-1])
            H = tf.squeeze(tf.slice(self.H,[i,0,0],[1,-1,-1]))
            self.h_bar_list.append(tf.matmul(b,H))

        self.h_bar = tf.concat(self.h_bar_list,axis=1)
        self.H_bar = tf.reshape(tf.tile(self.h_bar,[1,self.T]),[-1,self.T,int(d)])
        print('H',self.H)
        print('H_bar',self.H_bar)
        print('U_bar',self.U_bar)
        #G layer
        self.G = self.G_layer(self.H,self.H_bar,self.U_bar)
        print('G',self.G)
        #second lstm layer
        with tf.variable_scope('second_attention_layer') as scope:
            self.M = self.attention(inputs=self.G,num_blocks=self.num_blocks,num_units=int(self.G.get_shape()[-1]),num_heads=self.num_heads)
        print('M',self.M)
        '''
        #third lstm layer
        self.M2 = self.third_bilstm_layer(self.M)
        '''
        #answer lstm layer [batch,3,d]
        with tf.variable_scope('answer_attention_layer') as scope:
            self.A_lstm = self.answer_lstm_layer(self.a_embed)

        #classification layer
        GM = tf.concat([self.G,self.M],axis=-1)
        print('GM',GM)
        '''
        answer_W = tf.get_variable('answer_W',shape=[5*d*self.T,self.d],initializer=tf.contrib.layers.xavier_initializer())
        answer_b = tf.get_variable('answer_b',shape=[self.d],initializer=tf.contrib.layers.xavier_initializer())
        '''
        #[batch,d,1]

        #pre_word_embed = tf.expand_dims(tf.matmul(tf.reshape(GM,[-1,int(5*d*self.T)]),answer_W) + answer_b,axis=-1)
        pre_word_embed = tf.expand_dims(self.GM_conv_layer(GM,self.d),-1)
        print('pre_word_embed',pre_word_embed)
        #[batch,3]
        self.answer_logit = tf.squeeze(tf.matmul(self.A_lstm,pre_word_embed))
        print('answer_logit',self.answer_logit)

    def opt_construct(self):
        self.loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=self.label,logits=self.answer_logit))
        self.opt = tf.train.AdamOptimizer(learning_rate=0.001)
        self.train_op = self.opt.minimize(self.loss)

        self.pred = tf.argmax(self.answer_logit,axis=1,name='pred')

        #Accuracy
        with tf.name_scope('accuracy'):
            self.accuracy = tf.reduce_mean(tf.cast(tf.equal(self.pred,tf.argmax(self.label,axis=1)),tf.float32))

    def char_embed_layer(self,input_char,num_filters=3,filter_size=2):
        with tf.name_scope('char_embedding'):
            embedded_chars = tf.nn.embedding_lookup(self.char_W,input_char)
            embedded_chars_expanded = tf.expand_dims(embedded_chars,-1)

            filter_shape = [filter_size, self.char_embed_size, 1, num_filters]
            W = tf.Variable(tf.truncated_normal(filter_shape,stddev=0.1),name='W')
            b = tf.Variable(tf.constant(0.1,shape=[num_filters]),name='b')
            conv = tf.nn.conv2d(embedded_chars_expanded,W,strides=[1,1,1,1],padding='VALID',name='conv')
            h = tf.nn.relu(tf.nn.bias_add(conv,b),name='relu')
            pooled = tf.nn.max_pool(h,ksize=[1,self.word_length - filter_size + 1,1,1],strides=[1,1,1,1],padding='VALID',name='pool')

            pooled_shape = pooled.get_shape()
            total_size = None
            for idx in list(range(len(pooled_shape)))[1:]:
                if total_size is None:
                    total_size = int(pooled_shape[-1 * idx])
                else:
                    total_size *= int(pooled_shape[-1 * idx])

            print('total size of char_embed_layer:{}'.format(total_size))

            return tf.reshape(pooled,[-1,int(total_size)])
    def GM_conv_layer(self,inputs,num_filters=512,filter_size=3):
        with tf.name_scope('GM_conv_layer'):

            filter_shape = [filter_size, int(inputs.get_shape()[-1]), 1, num_filters]
            inputs = tf.expand_dims(inputs,-1)

            W = tf.Variable(tf.truncated_normal(filter_shape,stddev=0.1),name='W')
            b = tf.Variable(tf.constant(0.1,shape=[num_filters]),name='b')

            conv = tf.nn.conv2d(inputs,W,strides=[1,1,1,1],padding='VALID',name='conv')
            h = tf.nn.relu(tf.nn.bias_add(conv,b),name='relu')
            d = int(h.get_shape()[1])
            pooled = tf.nn.max_pool(h,[1,d,1,1],strides=[1,1,1,1],padding='VALID')
            return tf.reshape(pooled,[-1,num_filters])

    def word_embed_layer(self,input_word):
        with tf.name_scope('word_embedding'):
            embedded_word = tf.nn.embedding_lookup(self.word_W,input_word)
        return embedded_word

    def high_way_layer(self,input):
        input_shape = input.get_shape()
        last_dim = int(input_shape[-1])

        HW = tf.get_variable('HW',shape=[last_dim,last_dim],initializer=tf.contrib.layers.xavier_initializer())
        Hb = tf.get_variable('Hb',shape=[last_dim],initializer=tf.contrib.layers.xavier_initializer())

        H = tf.nn.xw_plus_b(input,HW,Hb)

        TW = tf.get_variable('TW',shape=[last_dim,last_dim],initializer=tf.contrib.layers.xavier_initializer())
        Tb = tf.get_variable('Tb',shape=[last_dim],initializer=tf.contrib.layers.xavier_initializer())

        T = tf.nn.xw_plus_b(input,TW,Tb)

        return H * T + input * (1 - T)
    '''
    def first_bilstm_layer(self,input):
        input_shape = input.get_shape()
        d = int(input_shape[-1])

        fw_cell = rnn.BasicLSTMCell(d,forget_bias=1.,state_is_tuple=True,reuse=tf.get_variable_scope().reuse)
        bw_cell = rnn.BasicLSTMCell(d,forget_bias=1.,state_is_tuple=True,reuse=tf.get_variable_scope().reuse)

        rnn_outputs,_ = tf.nn.bidirectional_dynamic_rnn(fw_cell,bw_cell,input,scope='first-bi-lstm',dtype=tf.float32)

        return tf.concat(rnn_outputs,axis=2,name='first_bilstm_output')
    '''
    def similarity_layer(self,H,U):
        d = int(H.get_shape()[-1])
        h_dim = int(H.get_shape()[-2])
        u_dim = int(U.get_shape()[-2])
        print('Similarity layer h_dim:{},u_dim:{}'.format(h_dim,u_dim))

        Sw = tf.get_variable('Sw',shape=[3 * d,1],initializer=tf.contrib.layers.xavier_initializer())
        H = tf.reshape(tf.transpose(H,[0,2,1]),[-1,h_dim])
        U = tf.reshape(tf.transpose(U,[0,2,1]),[-1,u_dim])

        fH = tf.tile(H,[u_dim,1])
        fU = tf.tile(tf.expand_dims(tf.concat(tf.unstack(U,axis=-1),axis=0),-1),[1,h_dim])
        fHU = fH * fU

        fH = tf.reshape(fH,[-1,u_dim,int(1 * d),h_dim])
        fU = tf.reshape(fU,[-1,u_dim,int(1 * d),h_dim])
        fHU = tf.reshape(fHU,[-1,u_dim,int(1 * d),h_dim])

        f = tf.concat([fH,fU,fHU],axis=2)
        f = tf.reshape(tf.transpose(f,[0,1,3,2]),[-1,int(3 * d)])

        #[batch_num,T,J]
        return tf.transpose(tf.reshape(tf.squeeze(tf.matmul(f,Sw)),[-1,u_dim,h_dim]),[0,2,1])

    def G_layer(self,H,H_bar,U_bar):
        d = int(H.get_shape()[-1])

        def g(h,h_bar,u_bar):
            return tf.concat([h,u_bar,h * u_bar,h * h_bar],axis=-1)

        h_list = tf.unstack(H,axis=1,name='h_list')
        h_bar_list = tf.unstack(H_bar,axis=1,name='h_bar_list')
        u_bar_list = tf.unstack(U_bar,axis=1,name='u_bar_list')

        g_list = []
        for idx in range(len(h_list)):
            h = h_list[idx]
            h_bar = h_bar_list[idx]
            u_bar = u_bar_list[idx]
            g_ele = g(h,h_bar,u_bar)
            g_list.append(g_ele)

        return tf.transpose(tf.reshape(tf.concat(g_list,axis=-1),[-1,int(4 * d),self.T]),[0,2,1],name='G')
    '''
    def second_bilstm_layer(self,input):
        input_shape = input.get_shape()
        d = int(int(input_shape[-1]) / 8)

        with tf.name_scope('second_lstm_layer'):
            fw_cell = rnn.BasicLSTMCell(d,forget_bias=1.,state_is_tuple=True)
            bw_cell = rnn.BasicLSTMCell(d,forget_bias=1.,state_is_tuple=True)

            rnn_outputs,_ = tf.nn.bidirectional_dynamic_rnn(fw_cell,bw_cell,input,scope='second-bi-lstm',dtype=tf.float32)

        return tf.concat(rnn_outputs,axis=2,name='second_bilstm_output')

    def third_bilstm_layer(self,input):
        input_shape = input.get_shape()
        d = int(int(input_shape[-1]) / 2)

        with tf.name_scope('third_lstm_layer'):
            fw_cell = rnn.BasicLSTMCell(d,forget_bias=1.,state_is_tuple=True)
            bw_cell = rnn.BasicLSTMCell(d,forget_bias=1.,state_is_tuple=True)

            rnn_outputs,_ = tf.nn.bidirectional_dynamic_rnn(fw_cell,bw_cell,input,scope='third-bi-lstm',dtype=tf.float32)
        return tf.concat(rnn_outputs,axis=2,name='third_bilstm_output')
    '''
    def answer_lstm_layer(self,input):
        input_shape = input.get_shape()
        #batch = int(input_shape[0])
        #assert batch == self.batch_num * 3
        batch = 3 * self.batch_num
        with tf.name_scope('answer_lstm_layer'):
            cell = tf.nn.rnn_cell.BasicRNNCell(self.d)
            initial_state = cell.zero_state(batch, dtype=tf.float32)
            outputs,state = tf.nn.dynamic_rnn(cell,input,initial_state=initial_state,dtype=tf.float32)
            state = tf.reshape(state,[-1,3,self.d])
        return state

    def attention(self,inputs,num_blocks,num_units=512,num_heads=8,dropout_rate=0.0,is_training=True,causality=False,reuse=None):
        def normalize(inputs,
                  epsilon = 1e-8,
                  scope="ln",
                  reuse=None):
            '''
            Applies layer normalization.

            Args:
              inputs: A tensor with 2 or more dimensions, where the first dimension has
                `batch_size`.
              epsilon: A floating number. A very small number for preventing ZeroDivision Error.
              scope: Optional scope for `variable_scope`.
              reuse: Boolean, whether to reuse the weights of a previous layer
                by the same name.

            Returns:
              A tensor with the same shape and data dtype as `inputs`.
            '''
            with tf.variable_scope(scope, reuse=reuse):
                inputs_shape = inputs.get_shape()
                params_shape = inputs_shape[-1:]

                mean, variance = tf.nn.moments(inputs, [-1], keep_dims=True)
                beta= tf.Variable(tf.zeros(params_shape))
                gamma = tf.Variable(tf.ones(params_shape))
                normalized = (inputs - mean) / ( (variance + epsilon) ** (.5) )
                outputs = gamma * normalized + beta

            return outputs

        def multihead_attention(queries,
                            keys,
                            num_units=512,
                            num_heads=8,
                            dropout_rate=0.0,
                            is_training=True,
                            causality=False,
                            scope="multihead_attention",
                            reuse=None):
            '''Applies multihead attention.

            Args:
              queries: A 3d tensor with shape of [N, T_q, C_q].
              keys: A 3d tensor with shape of [N, T_k, C_k].
              num_units: A scalar. Attention size.
              dropout_rate: A floating point number.
              is_training: Boolean. Controller of mechanism for dropout.
              causality: Boolean. If true, units that reference the future are masked.
              num_heads: An int. Number of heads.
              scope: Optional scope for `variable_scope`.
              reuse: Boolean, whether to reuse the weights of a previous layer
                by the same name.

            Returns
              A 3d tensor with shape of (N, T_q, C)
            '''
            with tf.variable_scope(scope, reuse=reuse):
            # Set the fall back option for num_units
                if num_units != int(queries.get_shape()[-1]):
                    num_units = int(queries.get_shape()[-1])

            # Linear projections
                Q = tf.layers.dense(queries, num_units, activation=tf.nn.relu) # (N, T_q, C)
                K = tf.layers.dense(keys, num_units, activation=tf.nn.relu) # (N, T_k, C)
                V = tf.layers.dense(keys, num_units, activation=tf.nn.relu) # (N, T_k, C)

            # Split and concat
                Q_ = tf.concat(tf.split(Q, num_heads, axis=2), axis=0) # (h*N, T_q, C/h)
                K_ = tf.concat(tf.split(K, num_heads, axis=2), axis=0) # (h*N, T_k, C/h)
                V_ = tf.concat(tf.split(V, num_heads, axis=2), axis=0) # (h*N, T_k, C/h)

            # Multiplication
                outputs = tf.matmul(Q_, tf.transpose(K_, [0, 2, 1])) # (h*N, T_q, T_k)

            # Scale
                outputs = outputs / (K_.get_shape().as_list()[-1] ** 0.5)

            # Key Masking
                key_masks = tf.sign(tf.abs(tf.reduce_sum(keys, axis=-1))) # (N, T_k)
                key_masks = tf.tile(key_masks, [num_heads, 1]) # (h*N, T_k)
                key_masks = tf.tile(tf.expand_dims(key_masks, 1), [1, tf.shape(queries)[1], 1]) # (h*N, T_q, T_k)

                paddings = tf.ones_like(outputs)*(-2**32+1)
                outputs = tf.where(tf.equal(key_masks, 0), paddings, outputs) # (h*N, T_q, T_k)

            # Causality = Future blinding
                if causality:
                    diag_vals = tf.ones_like(outputs[0, :, :]) # (T_q, T_k)
                    tril = tf.contrib.linalg.LinearOperatorTriL(diag_vals).to_dense() # (T_q, T_k)
                    masks = tf.tile(tf.expand_dims(tril, 0), [tf.shape(outputs)[0], 1, 1]) # (h*N, T_q, T_k)

                    paddings = tf.ones_like(masks)*(-2**32+1)
                    outputs = tf.where(tf.equal(masks, 0), paddings, outputs) # (h*N, T_q, T_k)

            # Activation
                outputs = tf.nn.softmax(outputs) # (h*N, T_q, T_k)

            # Query Masking
                query_masks = tf.sign(tf.abs(tf.reduce_sum(queries, axis=-1))) # (N, T_q)
                query_masks = tf.tile(query_masks, [num_heads, 1]) # (h*N, T_q)
                query_masks = tf.tile(tf.expand_dims(query_masks, -1), [1, 1, tf.shape(keys)[1]]) # (h*N, T_q, T_k)
                outputs *= query_masks # broadcasting. (N, T_q, C)

            # Dropouts
                outputs = tf.layers.dropout(outputs, rate=dropout_rate, training=tf.convert_to_tensor(is_training))

            # Weighted sum
                outputs = tf.matmul(outputs, V_) # ( h*N, T_q, C/h)

            # Restore shape
                outputs = tf.concat(tf.split(outputs, num_heads, axis=0), axis=2 ) # (N, T_q, C)

            # Residual connection
                outputs += queries

            # Normalize
                outputs = normalize(outputs) # (N, T_q, C)

            return outputs

        def feedforward(inputs,
                    num_units=[2048, 512],
                    scope="multihead_attention",
                    reuse=None):
            '''Point-wise feed forward net.

            Args:
              inputs: A 3d tensor with shape of [N, T, C].
              num_units: A list of two integers.
              scope: Optional scope for `variable_scope`.
              reuse: Boolean, whether to reuse the weights of a previous layer
                by the same name.

            Returns:
              A 3d tensor with the same shape and dtype as inputs
            '''
            with tf.variable_scope(scope, reuse=reuse):
            # Inner layer
                params = {"inputs": inputs, "filters": num_units[0], "kernel_size": 1,
                      "activation": tf.nn.relu, "use_bias": True}
                outputs = tf.layers.conv1d(**params)

            # Readout layer
                params = {"inputs": outputs, "filters": num_units[1], "kernel_size": 1,
                      "activation": None, "use_bias": True}
                outputs = tf.layers.conv1d(**params)

            # Residual connection
                outputs += inputs

            # Normalize
                outputs = normalize(outputs)

            return outputs

        for i in range(num_blocks):
            with tf.variable_scope("num_blocks_{}".format(i)):
            ### Multihead Attention
                inputs = multihead_attention(queries=inputs,keys=inputs,num_units=num_units,num_heads=num_heads,dropout_rate=dropout_rate,is_training=is_training,causality=False,reuse=reuse)

            ### Feed Forward
                inputs = feedforward(inputs,num_units=[4*num_units, num_units],reuse=reuse)
        return inputs


__all__ = ["HDFMapMSIMagneticField"]

import h5py
import numpy as np

from warnings import warn

from bapsflib._hdf.maps.msi.templates import HDFMapMSITemplate
from bapsflib.utils.exceptions import HDFMappingError

class HDFMapMSIMagneticField(HDFMapMSITemplate):
    """
    Mapping class for the 'Magnetic field' MSI diagnostic.

    Simple group structure looks like:

    .. code-block:: none

        +-- Magnetic field
        |   +-- Magnet power supply currents
        |   +-- Magnetic field profile
        |   +-- Magnetic field summary
    """

    def __init__(self, group: h5py.Group):
        """
        :param group: the HDF5 MSI diagnostic group
        :type group: :class:`h5py.Group`
        """
        # initialize
        HDFMapMSITemplate.__init__(self, group)

        # populate self.configs
        self._build_configs()

    def _build_configs(self):
        """Builds the :attr:`configs` dictionary."""
        # look for required datasets
        for dset_name in [
            "Magnet power supply currents",
            "Magnetic field profile",
            "Magnetic field summary",
        ]:
            if dset_name not in self.group:
                why = f"dataset '{dset_name}' not found"
                raise HDFMappingError(self.info["group path"], why=why)

        # initialize general info values
        pairs = [("calib tag", "Calibration tag"), ("z", "Profile z locations")]
        for pair in pairs:
            try:
                val = self.group.attrs[pair[1]]
                if isinstance(val, (list, tuple, np.ndarray)):
                    self._configs[pair[0]] = val
                else:
                    self._configs[pair[0]] = [val]
            except KeyError:
                self._configs[pair[0]] = []
                warn(
                    f"Attribute '{pair[1]}' not found for MSI diagnostic "
                    f"'{self.device_name}', continuing with mapping"
                )

        # initialize 'shape'
        # - this is used by HDFReadMSI
        self._configs["shape"] = ()

        # initialize 'shotnum'
        self._configs["shotnum"] = {
            "dset paths": (),
            "dset field": ("Shot number",),
            "shape": (),
            "dtype": np.int32,
        }

        # initialize 'signals'
        # - there are two signal fields
        #   1. 'magnet ps current'
        #   2. 'magnetic field'
        #
        self._configs["signals"] = {
            "magnet ps current": {
                "dset paths": (),
                "dset field": (),
                "shape": (),
                "dtype": np.float32,
            },
            "magnetic field": {
                "dset paths": (),
                "dset field": (),
                "shape": (),
                "dtype": np.float32,
            },
        }

        # initialize 'meta'
        self._configs["meta"] = {
            "shape": (),
            "timestamp": {
                "dset paths": (),
                "dset field": ("Timestamp",),
                "shape": (),
                "dtype": np.float64,
            },
            "data valid": {
                "dset paths": (),
                "dset field": ("Data valid",),
                "shape": (),
                "dtype": np.int8,
            },
            "peak magnetic field": {
                "dset paths": (),
                "dset field": ("Peak magnetic field",),
                "shape": (),
                "dtype": np.float32,
            },
        }

        # ---- update configs related to 'Magnetic field summary'   ----
        # - dependent configs are:
        #   1. 'shotnum'
        #   2. all of 'meta'
        #
        dset_name = "Magnetic field summary"
        dset = self.group[dset_name]

        # define 'shape'
        expected_fields = [
            "Shot number",
            "Timestamp",
            "Data valid",
            "Peak magnetic field",
        ]
        if dset.ndim == 1 and all(field in dset.dtype.names for field in expected_fields):
            self._configs["shape"] = dset.shape
        else:
            why = "'/Magnetic field summary' does not match expected shape"
            raise HDFMappingError(self.info["group path"], why=why)

        # update 'shotnum'
        self._configs["shotnum"]["dset paths"] = (dset.name,)
        self._configs["shotnum"]["shape"] = dset.dtype["Shot number"].shape

        # update 'meta/timestamp'
        self._configs["meta"]["timestamp"]["dset paths"] = (dset.name,)
        self._configs["meta"]["timestamp"]["shape"] = dset.dtype["Timestamp"].shape

        # update 'meta/data valid'
        self._configs["meta"]["data valid"]["dset paths"] = (dset.name,)
        self._configs["meta"]["data valid"]["shape"] = dset.dtype["Data valid"].shape

        # update 'meta/peak magnetic field'
        self._configs["meta"]["peak magnetic field"]["dset paths"] = (dset.name,)
        self._configs["meta"]["peak magnetic field"]["shape"] = dset.dtype[
            "Peak magnetic field"
        ].shape

        # update configs related to 'Magnet power supply currents'  ----
        # - dependent configs are:
        #   1. 'signals/magnet ps current'
        #
        dset_name = "Magnet power supply currents"
        dset = self.group[dset_name]
        self._configs["signals"]["magnet ps current"]["dset paths"] = (dset.name,)

        # check 'shape'
        _build_success = True
        if dset.dtype.names is not None:
            # dataset has fields (it should not have fields)
            _build_success = False
        elif dset.ndim == 2:
            if dset.shape[0] == self._configs["shape"][0]:
                self._configs["signals"]["magnet ps current"]["shape"] = (dset.shape[1],)
            else:
                _build_success = False
        else:
            _build_success = False
        if not _build_success:
            why = "'/Magnet power supply currents' does not match expected shape"
            raise HDFMappingError(self.info["group path"], why=why)

        # update configs related to 'Magnetic field profile'        ----
        # - dependent configs are:
        #   1. 'signals/magnetic field'
        #
        dset_name = "Magnetic field profile"
        dset = self.group[dset_name]
        self._configs["signals"]["magnetic field"]["dset paths"] = (dset.name,)

        # check 'shape'
        _build_success = True
        if dset.dtype.names is not None:
            # dataset has fields (it should not have fields)
            _build_success = False
        elif dset.ndim == 2:
            if dset.shape[0] == self._configs["shape"][0]:
                self._configs["signals"]["magnetic field"]["shape"] = (dset.shape[1],)
            else:
                _build_success = False
        else:
            _build_success = False
        if not _build_success:
            why = "'/Magnetic field profile' does not match expected shape"
            raise HDFMappingError(self.info["group path"], why=why)


"""
For finding the face and face landmarks for further manipulication
"""

import cv2
import mediapipe as mp
import numpy as np

mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
mp_pose = mp.solutions.pose

class FaceMeshDetector:
    def __init__(self,
                 static_image_mode=False,
                 max_num_faces=1,
                 min_detection_confidence=0.5,
                 min_tracking_confidence=0.5):

        self.static_image_mode = static_image_mode
        self.max_num_faces = max_num_faces
        self.min_detection_confidence = min_detection_confidence
        self.min_tracking_confidence = min_tracking_confidence

        # Facemesh
        self.mp_face_mesh = mp.solutions.face_mesh
        # The object to do the stuffs
        self.face_mesh = self.mp_face_mesh.FaceMesh(
            self.static_image_mode,
            self.max_num_faces,
            True,
            self.min_detection_confidence,
            self.min_tracking_confidence
        )

        self.mp_drawing = mp.solutions.drawing_utils
        self.drawing_spec = self.mp_drawing.DrawingSpec(thickness=1, circle_radius=1)

    def findFaceMesh(self, img, draw=True):
        # convert the img from BRG to RGB
        img = cv2.cvtColor(cv2.flip(img, 1), cv2.COLOR_BGR2RGB)

        # To improve performance, optionally mark the image as not writeable to
        # pass by reference.
        img.flags.writeable = False
        self.results = self.face_mesh.process(img)

        # Draw the face mesh annotations on the image.
        img.flags.writeable = True
        img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

        self.imgH, self.imgW, self.imgC = img.shape

        self.faces = []

        if self.results.multi_face_landmarks:
            for face_landmarks in self.results.multi_face_landmarks:
                if draw:
                    self.mp_drawing.draw_landmarks(
                        image = img,
                        landmark_list = face_landmarks,
                        connections = self.mp_face_mesh.FACEMESH_TESSELATION,
                        landmark_drawing_spec = self.drawing_spec,
                        connection_drawing_spec = self.drawing_spec)

                face = []
                for id, lmk in enumerate(face_landmarks.landmark):
                    x, y = int(lmk.x * self.imgW), int(lmk.y * self.imgH)
                    face.append([x, y])

                    # show the id of each point on the image
                    # cv2.putText(img, str(id), (x-4, y-4), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (255, 255, 255), 1, cv2.LINE_AA)

                self.faces.append(face)

        return img, self.faces

class HandsDetector:
    def __init__(self,
                 min_detection_confidence=0.7,
                 min_tracking_confidence=0.5,
                 model_complexity=0)->None:

        self.hands_mesh = mp.solutions.hands.Hands(
                            model_complexity=model_complexity,
                    min_detection_confidence=min_detection_confidence,
                    min_tracking_confidence=min_tracking_confidence)

        self.mp_drawing = mp.solutions.drawing_utils
        self.mp_drawing_styles = mp.solutions.drawing_styles

        self.drawing_spec = self.mp_drawing.DrawingSpec(thickness=1, circle_radius=1)

        pass

    def findHands(self, img, draw=True):
        # convert the img from BRG to RGB
        img = cv2.cvtColor(cv2.flip(img, 1), cv2.COLOR_BGR2RGB)

        # To improve performance, optionally mark the image as not writeable to
        # pass by reference.
        img.flags.writeable = False
        self.results = self.hands_mesh.process(img)

        # Draw the face mesh annotations on the image.
        img.flags.writeable = True
        img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

        self.imgH, self.imgW, self.imgC = img.shape

        self.hands = []
        self.handedness = []
        worldlist = None

        if self.results.multi_hand_world_landmarks:
            worldlist = [[[hand_point.x, hand_point.y, hand_point.z] for idx, hand_point in enumerate(world_landmarks.landmark)] for world_landmarks in self.results.multi_hand_world_landmarks]

        if self.results.multi_hand_landmarks:
            i = 0
            for hand_landmarks in self.results.multi_hand_landmarks:
                hand_number = self.results.multi_hand_landmarks.index(hand_landmarks)
                if draw:
                    self.mp_drawing.draw_landmarks(
                        img,
                        hand_landmarks,
                        mp_hands.HAND_CONNECTIONS,
                        mp_drawing_styles.get_default_hand_landmarks_style(),
                        mp_drawing_styles.get_default_hand_connections_style())

                hand = [[int(lmk.x * self.imgW), int(lmk.y * self.imgH)] for id, lmk in enumerate(hand_landmarks.landmark)]
                handedness = [label.label for id, label in enumerate(self.results.multi_handedness[hand_number].classification)]
                self.hands.append(hand)
                self.handedness.append(handedness[0])

        return img, self.hands, self.handedness, np.array(worldlist)

class PoseDetector():

    def __init__(self,min_detection_confidence=0.7, min_tracking_confidence=0.5)->None:

        self.body_pose = mp_pose.Pose(
                    min_detection_confidence=min_detection_confidence,
                    min_tracking_confidence=min_tracking_confidence)

        self.mp_drawing = mp.solutions.drawing_utils
        self.mp_drawing_styles = mp.solutions.drawing_styles

        self.drawing_spec = self.mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
        pass

    def findPose(self, img, draw=True):
        # convert the img from BRG to RGB
        img = cv2.cvtColor(cv2.flip(img, 1), cv2.COLOR_BGR2RGB)

        # To improve performance, optionally mark the image as not writeable to
        # pass by reference.
        img.flags.writeable = False
        self.results = self.body_pose.process(img)

        self.imgH, self.imgW, self.imgC = img.shape

        # Draw the face mesh annotations on the image.
        img.flags.writeable = True
        img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

        worldlist = None
        landmarks = None

        if self.results.pose_world_landmarks:
            worldlist = [[body_point.x, body_point.y, body_point.z] for idx, body_point in enumerate(self.results.pose_world_landmarks.landmark)]

        if self.results.pose_landmarks:
            landmarks = [[int(body_point.x * self.imgW), int(body_point.y * self.imgW)] for idx, body_point in enumerate(self.results.pose_landmarks.landmark)]

        if draw:
            self.mp_drawing.draw_landmarks(
            img,
            self.results.pose_landmarks,
            mp_pose.POSE_CONNECTIONS,
            landmark_drawing_spec=mp_drawing_styles.get_default_pose_landmarks_style())

        return img, np.array(landmarks), np.array(worldlist)

# sample run of the module
def main():

    detector = FaceMeshDetector()
    hand_detector = HandsDetector()
    pose_detector = PoseDetector()

    cap = cv2.VideoCapture(0)

    while cap.isOpened():
        success, img = cap.read()

        if not success:
            print("Ignoring empty camera frame.")
            continue

        img_face, faces = detector.findFaceMesh(img)
        img_hands, hands, handed_ness, worldlist_hands = hand_detector.findHands(img)
        img_pose, landmarks_body, wordlist_body = pose_detector.findPose(img)

        if faces:
            print('faces detected')
        if hands:
            print('hands detected')
        if landmarks_body.any():
            print('body detected')

        # cv2.imshow('MediaPipe FaceMesh', img_hands)
        # cv2.imshow('MediaPipe FaceMesh', img_face)

        horizontal = np.concatenate((img_face, img_hands, img_pose), axis=1)

        cv2.imshow('all landmarks', horizontal)

        # press "q" to leave
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()

if __name__ == "__main__":
    # demo code
    main()


import numpy as np
import torch
import math

def rotate_Y(input, beta):
	'''
	beta: angle, range 0~360.
	'''
	output = torch.zeros_like(input)
	beta = beta * (math.pi / 180) # angle to radian
	output[..., 0] = np.cos(beta)*input[..., 0] + np.sin(beta)*input[..., 2]
	output[..., 2] = -np.sin(beta)*input[..., 0] + np.cos(beta)*input[..., 2]
	output[..., 1] = input[..., 1]

	output[..., 3] = np.cos(beta)*input[..., 3] + np.sin(beta)*input[..., 5]
	output[..., 5] = -np.sin(beta)*input[..., 3] + np.cos(beta)*input[..., 5]
	output[..., 4] = input[..., 4]
	return output

def get_adj(N, J, edges):
	adj = np.eye(N*J)
	for edge in edges:
		for i in range(N):
			adj[edge[0] + i * J, edge[1] + i * J] = 1
			adj[edge[1] + i * J, edge[0] + i * J] = 1
	return torch.from_numpy(adj).float().cuda()

def get_connect(N, J):
	conn = np.zeros((N*J, N*J))
	conn[:J, :J] = 1
	conn[J:, J:] = 1
	return torch.from_numpy(conn).float().cuda()

def distance_loss(target, pred):
    mse_loss = (pred - target) ** 2
    mse_loss = mse_loss.sum(-1)
    mse_loss = mse_loss.sqrt()
    loss = mse_loss.mean()
    return loss

def relation_loss(target, pred):
    mse_loss = torch.abs(pred - target)
    loss = mse_loss.mean()
    return loss

def process_pred(pred_vel, pred_vel_aux):
	pred_vel_x = pred_vel[:, :, :16]
	pred_vel_y = pred_vel[:, :, 16:]
	pred_vel_aux_x = []
	pred_vel_aux_y = []
	for pred_ in pred_vel_aux:
		pred_vel_aux_x.append(pred_[:, :, :16])
		pred_vel_aux_y.append(pred_[:, :, 16:])
	return pred_vel_x, pred_vel_y, pred_vel_aux_x, pred_vel_aux_y


import uuid

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import Union
from calmlogging import get_logger
from db import select, upsert
from time import sleep

log = get_logger(__file__)

router = APIRouter(
    prefix="/api/v1/users",
    tags=["users"],
    # dependencies=[Depends(get_token_header)],
    responses={404: {"description": "Not found"}},
)

class User(BaseModel):
    id: Union[str, None] = None
    name: str
    email: Union[str, None] = None
    is_admin: bool = False

@router.get("/")
async def get_users():
    """Get all users."""
    sleep(1)
    users = select('SELECT * FROM users')
    return {"users": users}

@router.post("/")
async def create_users(user: User):
    """Create a user"""
    query = '''
    INSERT INTO users
        (id, name, email, is_admin)
    VALUES
        (?, ?, ?, ?)
    '''
    id = str(uuid.uuid1())
    log.info("Will try to create following user: %s" % user)
    sleep(2)

    try:
        upsert(query, (id, user.name, user.email, user.is_admin))
    except Exception as e:
        log.error("Couldn't save user! %s: %s" % (e.__class__.__name__, e))
        raise HTTPException(
            status_code=400, detail=f"Couldn't save user! {e.__class__.__name__}: {e}")

    users = select(f"SELECT * FROM users WHERE id = '{id}' LIMIT 1")
    log.info("Successfully created user with id: %s. And sleeping 2 seconds" % id)

    return users[0]

@router.get("/{id}")
async def get_user(id: str):
    """Get a single user."""
    query = "SELECT * FROM users WHERE id = ? LIMIT 1"

    try:
        user = select(query, (str(id),))

        if user:
            return user[0]
        else:
            log.error("User not found!")
            raise HTTPException(
                status_code=404, detail=f"User with id '{id}' not found")
    except Exception as e:
        log.error("Couldn't get user! %s: %s" % (e.__class__.__name__, e))
        raise HTTPException(
            status_code=404, detail=f"User with id '{id}' not found")

@router.put("/{id}")
async def update_user(id: str, user: User):
    """Update a single user."""

    log.debug("Got request: %s" % user)
    log.debug("Updating user with id: %s" % id)
    query = '''UPDATE users
              SET name = ? ,
                  email = ? ,
                  is_admin = ?
              WHERE id = ?'''
    try:
        upsert(query, (user.name, user.email, user.is_admin, id))
        log.info("Successfully updated user with id: %s" % id)
        user.id = id
        return user
    except IndexError:
        raise HTTPException(
            status_code=404, detail=f"User with id '{id}' not found")

@router.delete("/{id}")
async def delete_user(id: str):
    """Delete a single user."""
    log.debug("Deleting a user with id: %s" % id)
    user = select(f"SELECT * FROM users WHERE id = '{id}' LIMIT 1")
    log.debug("Got user before deletion: %s" % user)

    try:
        upsert(f"DELETE FROM users WHERE id = ? LIMIT 1", (id,))
        log.debug("Returning user: %s" % user[0])
        return user[0]
    except IndexError:
        raise HTTPException(
            status_code=400, detail=f"User with id '{id}' could not be deleted.")


import momoslibrary as momo # import the file that contains our functions, individual functions can also be imported

# Code for the program to take neccessary  inputs from the user

transpose_data=momo.csvListTranspose('guestlist')

age=momo.strToInt(transpose_data[1])

print(sum(age)/len(age))


# import statements
import pygame
from pygame.locals import *

# initializing the pygame
pygame.init()

# colors
white = (255, 255, 255)  # background
black = (0, 0, 0)   # barrier
red = (255, 0, 0)  # start node
green = (0, 255, 0)  # neighbours
yellow = (255, 255, 0)  # path
grey = (192, 192, 192)  # grid lines
aqua = (0, 255, 255)  # end node

# window set up
# window dimensions
width = 600
height = 600
window = pygame.display.set_mode((width, height))
pygame.display.set_caption("SEARCH ALGORITHM")

# class spots
class Spot:
    def __init__(self, color=None, position=None):
        self.number_of_spots = 50
        self.spot_dimension = width // self.number_of_spots
        self.color = color
        self.startNode_isDrawn = 0
        self.endNode_isDrawn = 0
        self.barrier_canBeDrawn = 0
        self.barrier = []
        self.new_barrier = []
        self.position = position  # for getting position

        self.open_list = []  # contains checking spots
        self.closed_list = []  # contains checked spots
        self.lst_neighbours = []  # contains the neighbours of current element
        self.start_algo = False
        self.count = -1
        self.end = 0

    def make_Closed(self):
        self.color = yellow

    def make_Open(self):
        self.color = green

    def make_barrier(self):
        self.color = black

    def make_startNode(self):
        self.color = red

    def make_endNode(self):
        self.color = aqua

    def Remove(self):
        self.color = white

    def Reset(self):
        self.color = white
        self.startNode_isDrawn = 0
        self.endNode_isDrawn = 0
        self.barrier_canBeDrawn = 0
        self.barrier = []
        self.new_barrier = []
        self.position = None

        self.open_list = []
        self.closed_list = []
        self.lst_neighbours = []
        self.start_algo = False
        self.count = -1
        self.end = 0

    def draw_spot(self, x, y):
        pygame.draw.rect(window, self.color, (x, y, self.spot_dimension, self.spot_dimension))

# variables
spot = Spot()
barrier = Spot()  # for drawing barrier rect
start = Spot()  # for drawing starting rect
end = Spot()  # for drawing end rect
pos = None  # for mouse position after click
mouse_x = 0
mouse_y = 0

def algorithm():
    # clear neighbours list at each iteration
    spot.lst_neighbours.clear()

    # current node will be elements in open list
    current_node = spot.open_list[spot.count]

    # append neighbours if it is not barrier
    if 0 < current_node[0] < width - spot.spot_dimension and barrier.barrier.count([current_node[0] + spot.spot_dimension, current_node[1]]) == 0:
        spot.lst_neighbours.append([current_node[0] + spot.spot_dimension, current_node[1]])
    if 0 < current_node[0] < height - spot.spot_dimension and barrier.barrier.count([current_node[0] - spot.spot_dimension, current_node[1]]) == 0:
        spot.lst_neighbours.append([current_node[0] - spot.spot_dimension, current_node[1]])
    if 0 < current_node[0] < height - spot.spot_dimension and barrier.barrier.count([current_node[0], current_node[1] + spot.spot_dimension]) == 0:
        spot.lst_neighbours.append([current_node[0], current_node[1] + spot.spot_dimension])
    if 0 < current_node[0] < height - spot.spot_dimension and barrier.barrier.count([current_node[0], current_node[1] - spot.spot_dimension]) == 0:
        spot.lst_neighbours.append([current_node[0], current_node[1] - spot.spot_dimension])
    if current_node[0] == 0 and barrier.barrier.count([current_node[0] + spot.spot_dimension, current_node[1]]) == 0:
        spot.lst_neighbours.append([current_node[0] + spot.spot_dimension, current_node[1]])
    if current_node[1] == 0 and barrier.barrier.count([current_node[0], current_node[1] + spot.spot_dimension]) == 0:
        spot.lst_neighbours.append([current_node[0], current_node[1] + spot.spot_dimension])
    if current_node[0] == width - spot.spot_dimension and barrier.barrier.count([current_node[0] - spot.spot_dimension, current_node[1]]) == 0:
        spot.lst_neighbours.append([current_node[0] - spot.spot_dimension, current_node[1]])
    if current_node[1] == height - spot.spot_dimension and barrier.barrier.count([current_node[0], current_node[1] - spot.spot_dimension]) == 0:
        spot.lst_neighbours.append([current_node[0], current_node[1] - spot.spot_dimension])

    # remove start node from open_list
    if len(spot.open_list) == 1:
        spot.closed_list.append(spot.open_list[0])
        spot.open_list.pop(0)

    # stop if end point is found
    if spot.open_list.count(end.position) == 1:
        spot.lst_neighbours.clear()
        spot.end = 1

    # append neighbours to open_list
    if len(spot.lst_neighbours) != 0:
        for item in spot.lst_neighbours:
            # append items of neighbours to open list
            if spot.open_list.count(item) == 0:
                spot.open_list.append(item)

    # draw spots which are not checked
    for checking_spot in spot.open_list:
        spot.make_Open()
        spot.draw_spot(checking_spot[0], checking_spot[1])

    # append checked spots to closed list
    if spot.end != 1:
        spot.closed_list.append(spot.open_list[spot.count])

    # draw checked spots
    for checked_spot in spot.closed_list:
        spot.make_Closed()
        spot.draw_spot(checked_spot[0], checked_spot[1])

    spot.count += 1

    return False

def start_algorithm():
    keys = pygame.key.get_pressed()
    # start if space key is pressed
    if keys[pygame.K_SPACE]:
        spot.start_algo = True
    if spot.start_algo:
        if start.position is not None and end.position is not None:
            spot.open_list.append(start.position)
            algorithm()

def drawGrid():
    # draw the grid lines
    for i in range(0, width):
        pygame.draw.line(window, grey, (0, i * spot.spot_dimension), (width, i * spot.spot_dimension))
    for j in range(0, height):
        pygame.draw.line(window, grey, (j * spot.spot_dimension, 0), (j * spot.spot_dimension, height))

def drawSpots():
    global mouse_x, mouse_y, pos

    # taking the mouse position (pos)
    if pygame.mouse.get_pressed(3):
        mouse_x, mouse_y = pygame.mouse.get_pos()

        # making correction in position
        if mouse_x / spot.spot_dimension >= int(mouse_x / spot.spot_dimension):
            mouse_x = int(mouse_x / spot.spot_dimension) * spot.spot_dimension
        if mouse_y / spot.spot_dimension >= int(mouse_y / spot.spot_dimension):
            mouse_y = int(mouse_y / spot.spot_dimension) * spot.spot_dimension
        pos = [mouse_x, mouse_y]

    # draw start and end spot if left mouse button is pressed
    if pygame.mouse.get_pressed(3)[0]:
        if start.startNode_isDrawn == 0 and start.position is None:
            start.position = pos.copy()
            start.startNode_isDrawn = 1
        if start.position != pos:
            if end.endNode_isDrawn == 0 and end.position is None:
                end.position = pos.copy()
                end.endNode_isDrawn = 1
        if pos != start.position and pos != end.position:
            if end.endNode_isDrawn == 1 and start.startNode_isDrawn == 1:
                barrier.new_barrier = pos.copy()
                if len(barrier.barrier) == 0:
                    barrier.barrier.append(barrier.new_barrier)
                elif len(barrier.barrier) != 0:
                    if barrier.barrier.count(barrier.new_barrier) != 1:
                        barrier.barrier.append(barrier.new_barrier)
                barrier.barrier_canBeDrawn = 1

    # remove the spots if right mouse button is pressed
    if pygame.mouse.get_pressed(3)[2]:
        barrier.Remove()
        start.Remove()
        end.Remove()
        if pos == start.position:
            start.startNode_isDrawn = 0
            start.position = None
            spot.Reset()
        if pos == end.position:
            end.endNode_isDrawn = 0
            end.position = None
            spot.Reset()
        if len(barrier.barrier) > 0:
            if barrier.barrier.count(pos) == 1:
                barrier.barrier.pop(barrier.barrier.index(pos))

    # removing all the spots at once
    if pygame.mouse.get_pressed(3)[1]:
        spot.Reset()
        start.Reset()
        end.Reset()
        barrier.Reset()

    # infinitely draw the spots on the window till removed by the user
    if start.startNode_isDrawn == 1:
        barrier.make_startNode()
        barrier.draw_spot(start.position[0], start.position[1])
    if end.endNode_isDrawn == 1:
        barrier.make_endNode()
        barrier.draw_spot(end.position[0], end.position[1])
    if barrier.barrier_canBeDrawn == 1:
        barrier.make_barrier()
        for i in range(0, len(barrier.barrier)):
            barrier.draw_spot(barrier.barrier[i][0], barrier.barrier[i][1])

def reDrawWindow():
    # filling background with white color
    window.fill(white)
    # functions
    start_algorithm()
    # draw the spots on screen
    drawSpots()
    # draw the grid
    drawGrid()
    # updating the display everytime
    pygame.display.update()

# main function
def mainloop():
    run = True
    # running the programme till quit
    while run:
        # handling events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            # exit using escape button
            if event.type == pygame.KEYDOWN:
                if event.key == K_ESCAPE:
                    run = False
        reDrawWindow()
    pygame.quit()

if __name__ == "__main__":
    mainloop()


from typing import Any, Dict, Tuple

import torch
from lightning import LightningModule
from torchmetrics import MinMetric, MeanMetric
from src.data.components.ocr_vocab import Vocab
from src.models.components.labelsmoothingloss import LabelSmoothingLoss
from src.models.vietocr_utils.download_ckpt import download_weights
# from src.models.components.cer import CER

class OCRLitModule(LightningModule):
    def __init__(
        self,
        net: torch.nn.Module,
        pretrain: str,
        optimizer: torch.optim.Optimizer,
        scheduler: torch.optim.lr_scheduler,
        compile: bool,
        vocab: Vocab
    ) -> None:
        super().__init__()

        # this line allows to access init params with 'self.hparams' attribute
        # also ensures init params will be stored in ckpt
        self.save_hyperparameters(logger=False)

        self.vocab = vocab
        self.net = net(vocab_size=len(vocab))
        if pretrain:
            print("USING PRETRAINED MODEL")
            weight_file = download_weights(pretrain)
            state_dict = torch.load(weight_file, map_location=torch.device(self.device))
            for name, param in self.net.named_parameters():
                if name not in state_dict:
                    print('{} not found'.format(name))
                elif state_dict[name].shape != param.shape:
                    print('{} missmatching shape, required {} but found {}'.format(name, param.shape, state_dict[name].shape))
                    del state_dict[name]
            try:
                self.net.load_state_dict(state_dict, strict=False)
            except:
                print("Do not use pretrained model")

        # loss function
        self.criterion = LabelSmoothingLoss(
            classes=len(vocab),
            padding_idx=vocab.pad,
            smoothing=0.1
        )

        # for averaging loss across batches
        self.train_loss = MeanMetric()
        self.val_loss = MeanMetric()
        self.test_loss = MeanMetric()

        # # for averaging CER across batches
        # self.cer = CER()
        # self.train_cer = MeanMetric()
        # self.val_cer = MeanMetric()
        # self.test_cer = MeanMetric()

        # for tracking best so far validation accuracy
        self.val_loss_best = MinMetric()
        # self.val_cer_best = MinMetric()

    def forward(self, x: torch.Tensor, tgt_input, tgt_padding_mask) -> torch.Tensor:
        """Perform a forward pass through the model `self.net`.

        :param x: A tensor of images.
        :return: A tensor of logits.
        """
        return self.net(x, tgt_input, tgt_padding_mask)

    def on_train_start(self) -> None:
        """Lightning hook that is called when training begins."""
        # by default lightning executes validation step sanity checks before training starts,
        # so it's worth to make sure validation metrics don't store results from these checks
        self.val_loss.reset()
        # self.val_cer.reset()

    def model_step(
        self, batch: Tuple[torch.Tensor, torch.Tensor]
    ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
        """Perform a single model step on a batch of data.

        :param batch: A batch of data (a tuple) containing the input tensor of images and target labels.

        :return: A tuple containing (in order):
            - A tensor of losses.
            - A tensor of predictions.
            - A tensor of target labels.
        """
        img, tgt_input, tgt_output, tgt_padding_mask = batch['img'], batch['tgt_input'], batch['tgt_output'], batch['tgt_padding_mask']
        output = self.forward(img, tgt_input= tgt_input, tgt_padding_mask=tgt_padding_mask)
        output = output.flatten(0,1)
        tgt_output = tgt_output.flatten(0,1)

        loss = self.criterion(output, tgt_output)

        return loss, output,tgt_output

    def training_step(
        self, batch: Tuple[torch.Tensor, torch.Tensor], batch_idx: int
    ) -> torch.Tensor:
        """Perform a single training step on a batch of data from the training set.

        :param batch: A batch of data (a tuple) containing the input tensor of images and target
            labels.
        :param batch_idx: The index of the current batch.
        :return: A tensor of losses between model predictions and targets.
        """
        loss, preds, targets = self.model_step(batch)

        # update and log metrics
        self.train_loss(loss)
        self.log("train/loss", self.train_loss, on_step=False, on_epoch=True, prog_bar=True)

        # # cer_score = self.cer(preds, targets)
        # # self.train_cer(cer_score)
        # # self.log("train/cer", self.train_cer, on_step=False, on_epoch=True, prog_bar=True)

        # return loss or backpropagation will fail
        return loss

    def on_train_epoch_end(self) -> None:
        "Lightning hook that is called when a training epoch ends."
        pass

    def validation_step(self, batch: Tuple[torch.Tensor, torch.Tensor], batch_idx: int) -> None:
        """Perform a single validation step on a batch of data from the validation set.

        :param batch: A batch of data (a tuple) containing the input tensor of images and target
            labels.
        :param batch_idx: The index of the current batch.
        """
        loss, preds, targets = self.model_step(batch)

        # update and log metrics
        self.val_loss(loss)
        self.log("val/loss", self.val_loss, on_step=False, on_epoch=True, prog_bar=True)

        # # cer_score = self.cer(preds, targets)
        # # self.val_cer(cer_score)
        # # self.log("val/cer", self.val_cer, on_step=False, on_epoch=True, prog_bar=True)

    def on_validation_epoch_end(self) -> None:
        "Lightning hook that is called when a validation epoch ends."
        loss = self.val_loss.compute()  # get current val acc
        self.val_loss_best(loss)  # update best so far val acc
        # log `val_acc_best` as a value through `.compute()` method, instead of as a metric object
        # otherwise metric would be reset by lightning after each epoch
        self.log("val/loss_best", self.val_loss_best.compute(), sync_dist=True, prog_bar=True)

        # # cer_score = self.val_cer.compute()
        # # self.val_cer_best(cer_score)
        # # self.log("val/cer_best", self.val_cer_best.compute(), sync_dist=True, prog_bar=True)

    def test_step(self, batch: Tuple[torch.Tensor, torch.Tensor], batch_idx: int) -> None:
        """Perform a single test step on a batch of data from the test set.

        :param batch: A batch of data (a tuple) containing the input tensor of images and target
            labels.
        :param batch_idx: The index of the current batch.
        """
        loss, preds, targets = self.model_step(batch)

        # update and log metrics
        self.test_loss(loss)
        self.log("test/loss", self.test_loss, on_step=False, on_epoch=True, prog_bar=True)

    def on_test_epoch_end(self) -> None:
        """Lightning hook that is called when a test epoch ends."""
        pass

    def setup(self, stage: str) -> None:
        """Lightning hook that is called at the beginning of fit (train + validate), validate,
        test, or predict.

        This is a good hook when you need to build models dynamically or adjust something about
        them. This hook is called on every process when using DDP.

        :param stage: Either `"fit"`, `"validate"`, `"test"`, or `"predict"`.
        """
        if self.hparams.compile and stage == "fit":
            self.net = torch.compile(self.net)

    def configure_optimizers(self) -> Dict[str, Any]:
        """Choose what optimizers and learning-rate schedulers to use in your optimization.
        Normally you'd need one. But in the case of GANs or similar you might have multiple.

        Examples:
            https://lightning.ai/docs/pytorch/latest/common/lightning_module.html#configure-optimizers

        :return: A dict containing the configured optimizers and learning-rate schedulers to be used for training.
        """
        optimizer = self.hparams.optimizer(params=self.parameters())
        if self.hparams.scheduler is not None:
            scheduler = self.hparams.scheduler(optimizer=optimizer)
            return {
                "optimizer": optimizer,
                "lr_scheduler": {
                    "scheduler": scheduler,
                    "monitor": "val/loss",
                    "interval": "epoch",
                    "frequency": 1,
                },
            }
        return {"optimizer": optimizer}

if __name__ == "__main__":
    print("Here")


from rest_framework import serializers

from item.serializers import ItemSerializer
from . import models

class CategorySerializer(serializers.ModelSerializer):
    items = ItemSerializer(many=True, read_only=True)

    class Meta:
        # fields는 데이터베이스 속성을 제어합니다.
        fields =(
            'no',
            'mall_no',
            'name',
            'desc',
            'register_datetime',
            'update_information_datetime',
            'items',
        )
        model = models.Category


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

import os
from setuptools import setup, find_packages

here = os.path.abspath(os.path.dirname(__file__))
README = open(os.path.join(here, 'README.md')).read()

requires = [
    'pytz',
]

# Use part of the sphinx docs index for the long description

setup(
    name="python-utils",
    version='0.0.1',
    packages=find_packages(),
    install_requires=requires,
    description='python utils',
    long_description=README,
    author="liulnn",
    author_email="liulnn@126.com",
    license="BSD",
    url="https://github.com/liulnn/python-utils.git",
    include_package_data=True,
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Environment :: Web Environment",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: BSD License",
        "Operating System :: OS Independent",
        "Programming Language :: Python",
        "Framework :: Django",
    ]
)


################################################################################
# fetches data from cepea database
#
# Obs:
# for clarification in regards to the olefile module check
# this stackoverflow thread: https://stackoverflow.com/questions/
# 58336366/compdocerror-when-importing-xls-file-format-to-python-using-pandas-read-excel
################################################################################

# import form the system
from concurrent.futures import ThreadPoolExecutor as executor
from typing import List
import logging, logging.config

# import from packages
import requests
import olefile
import pandas as pd

#app imports
from DB.transactions import add_series

# logging
logging.config.fileConfig('./logging/logging.conf')
logger = logging.getLogger('dbLoaders')

# series to be included
info = [("milho", 77),
        ("acucar", 53),
        ("etanol-diario-paulinia", 111),
        ("boi-gordo", 2)]

tickers = [f"cepea.{n}" for _, n in info]

def build_url(name:str, number:int) -> str:
    """
    builds the relevant url for the ticker in case
    """
    return f'https://www.cepea.esalq.usp.br/br/indicador/series/{name}.aspx?id={number}'

def process(resp:requests.models.Response) -> pd.DataFrame:
    """
    fetchs the series related to the url used as input. Return a
    dataframe
    """
    if resp.ok:
        ole = olefile.OleFileIO(resp.content)
        return  pd.read_excel(ole.openstream("Workbook"))
    logger.error(f"Unable to fetch data from {resp.url}")

def ingest_series(info: List[tuple]) -> None:
    """
    adds series information into the database
    """
    with requests.session() as session:
        with executor() as e:
            urls = []
            for p in info:
                urls.append(build_url(*p))
            dfs = list(e.map(lambda u: process(session.get(u)), urls, timeout=60))

    for n,tck in enumerate(tickers):
        add_series(tck, dfs[n].columns[0], "CEPEA", "AGRI", "SERIES-TEMPORAIS")

if __name__ == '__main__':
    ingest_series(info)


#https://dmoj.ca/problem/ccc11j1
#CCC '11 J1 - Which Alien?

a = int(input())
b = int(input())

if a >= 3 and b <= 4:
    print("TroyMartian")
if a <= 6 and b >= 2:
    print("VladSaturnian")
if a <= 2 and b <= 3:
    print("GraemeMercurian")


"""Trench Map"""

def neighbours(z):
    for dz in [-1 + 1j, 1j, 1 + 1j, -1, 0, 1, -1 - 1j, -1j, 1 - 1j]:
        yield z + dz

def solve(text):
    lines = [line.strip() for line in text.splitlines()]
    enhancer = [1 if c == "#" else 0 for c in lines[0]]

    def will_be_on(z, image, is_inverted):
        index = sum(2 ** (8 - i) for i, zn in enumerate(neighbours(z)) if (zn in image) != is_inverted)
        return bool(enhancer[index]) == is_inverted

    def enhance_infinite_flipper(image, N):
        image_is_inverted = False
        for _ in range(N):
            candidates = {z for c in image for z in neighbours(c)}
            image = {z for z in candidates if will_be_on(z, image, image_is_inverted)}
            image_is_inverted = not image_is_inverted
        return image

    image = {
        i + j * 1j
        for j, row in enumerate(lines[2:][::-1])
        for i, c in enumerate(row) if c == "#"
    }
    yield len(enhance_infinite_flipper(image, 2))
    yield len(enhance_infinite_flipper(image, 50))

"""
quit()

# Below is a solution for the test input, which did not require a flipping
# inversion of the pixel value from iteration to iteration

enhancer_string = (
    "..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#."
    ".#..##..###..######.###...####..#..#####..##..#.#####...##.#.#.."
    "#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####....."
    "#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####"
    ".#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##."
    "#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#.."
    "#.##.#....##..#.####....##...##..#...#......#.#.......#.......##"
    "..####..#...#.#.#...##..#.#..###..#####........#..####......#..#"
)
image_chars = (
    "#..#.\n"
    "#....\n"
    "##..#\n"
    "..#..\n"
    "..###"
)

enhancer = [1 if c == "#" else 0 for c in enhancer_string]
lines = image_chars.splitlines()
image = {i + j * 1j for j, row in enumerate(lines[::-1]) for i, c in enumerate(row) if c == "#"}

def show_image(image):
    i_min = int(min(z.imag for z in image))
    i_max = int(max(z.imag for z in image))
    r_min = int(min(z.real for z in image))
    r_max = int(max(z.real for z in image))
    for i in reversed(list(range(i_min, i_max + 1))):
        for r in range(r_min, r_max + 1):
            print("#" if r + i * 1j in image else ".", end="")
        print()

def will_be_on(z, image):
    index = sum(2 ** (8 - i) for i, zn in enumerate(neighbours(z)) if zn in image)
    return bool(enhancer[index])

show_image(image)
candidates = {z for c in image for z in neighbours(c)}
image = {z for z in candidates if will_be_on(z, image)}
show_image(image)
candidates = {z for c in image for z in neighbours(c)}
image = {z for z in candidates if will_be_on(z, image)}
show_image(image)
"""


import requests
import json
import os
from bs4 import BeautifulSoup
import pprint

def get_image_url(soup):
  return soup.select_one('.recipe-image > img')['src']

def get_ingredients(soup):
  ingredients = []
  lis = soup.find("div", { "class": "ingredients" }).find_all("li")
  for li in lis:
    ingredients.append(li.get_text().split('-')[0])

  return ingredients

def get_steps(soup):
  steps = []
  steps_elements = soup.find("div", { "class": "steps" }).find_all("li")
  step_index = 1

  for step in steps_elements:
    steps.append({
      "title": "Krok " + str(step_index),
      "text": step.get_text(),
    })
    step_index+=1

  return steps

def add_domain_name(slug):
  return os.environ["SCRAPPING_DOMAIN_URL"] + slug

def fetch_recipes():
  PAGES_TO_FETCH = 1
  recipes = []
  error_count = 0

  has_recipes = os.path.isfile('recipes.dat')

  if not has_recipes:
    print('Scrapping started')
    for page in range(1, PAGES_TO_FETCH + 1):
      response = requests.get(add_domain_name(os.environ["DINNER_URL"]) + str(page))
      page_soup = BeautifulSoup(response.text, 'html.parser')
      recipes_elements = page_soup.select_one('app-header-recipe-list + div').find_all("a", { "class": "recipe-box__title" })

      for recipe in recipes_elements:
        recipe_url = add_domain_name(recipe["href"])
        response = requests.get(recipe_url)
        recipe_soup = BeautifulSoup(response.text, 'html.parser')
        print_page_url = add_domain_name(recipe_soup.select_one('app-recipe-page-tools a')["href"])

        static_page = requests.get(print_page_url)
        static_page_soup = BeautifulSoup(static_page.text, 'html.parser')

        try:
          recipe_obj = {
            "url": recipe_url,
            "name": recipe.get_text(),
            "image_url": get_image_url(static_page_soup),
            "ingredients": get_ingredients(static_page_soup),
            "description": get_steps(static_page_soup)
          }
          print(recipe.get_text())
          recipes.append(recipe_obj)
        except:
          error_count += 1
          print("[ERROR] " + recipe_url)
    with open('recipes.dat', 'w') as json_file:
      json.dump(recipes, json_file)
    print("\nSuccesfuly added: " + str(len(recipes)) + ", " + str(error_count) + " skipped\n")
  else:
    recipes = json.loads(open('recipes.dat', 'r').read())
  return recipes


import re
import discord_logging
import dateparser
from dateutil.relativedelta import relativedelta
from dateparser.search import search_dates
import parsedatetime
import pytz
from datetime import datetime
from datetime import timedelta
import urllib.parse
import urllib3
import prawcore
import requests

import counters
import static

log = discord_logging.get_logger()
debug_time = None
cal = parsedatetime.Calendar()

def process_error(message, exception, traceback):
	is_transient = \
		isinstance(exception, prawcore.exceptions.ServerError) or \
		isinstance(exception, prawcore.exceptions.ResponseException) or \
		isinstance(exception, prawcore.exceptions.RequestException) or \
		isinstance(exception, requests.exceptions.Timeout) or \
		isinstance(exception, requests.exceptions.ReadTimeout) or \
		isinstance(exception, requests.exceptions.RequestException) or \
		isinstance(exception, urllib3.exceptions.ReadTimeoutError)
	log.warning(f"{message}: {type(exception).__name__} : {exception}")
	if is_transient:
		log.info(traceback)
		counters.errors.labels(type='api').inc()
	else:
		log.warning(traceback)
		counters.errors.labels(type='other').inc()

	return is_transient

def find_reminder_message(body, trigger):
	line_match = re.search(
		r'(?:{trigger}.+)(?:(?:\[)([^\]]+?)(?:\])|(?:\")([^\"]+?)(?:\")|(?:“)([^”]*?)(?:”))(?:[^(]|\n|$)'.format(
			trigger=trigger),
		body,
		flags=re.IGNORECASE)
	if line_match:
		return line_match.group(1) or line_match.group(2) or line_match.group(3)

	match = re.search(
		r'(?:(?:\[)([^\]]+?)(?:\])|(?:\")([^\"]+?)(?:\")|(?:“)([^”]*?)(?:”))(?:[^(]|\n|$)',
		body,
		flags=re.IGNORECASE)
	if match:
		return match.group(1) or match.group(2) or match.group(3)
	else:
		return None

def find_reminder_time(body, trigger):
	regex_string = r'(?:{trigger}.? +)(.*?)(?:\[|\n|\"|“|$|http)'.format(trigger=trigger)
	times = re.findall(regex_string, body, flags=re.IGNORECASE)
	if len(times) > 0 and times[0] != "":
		return times[0][:80]

	regex_string = r'(?:{trigger}.? *)(.*?)(?:\[|\n|\"|“|$|http)'.format(trigger=trigger)
	times = re.findall(regex_string, body, flags=re.IGNORECASE)
	if len(times) > 0 and times[0] != "":
		return times[0][:80]
	else:
		return None

def parse_time(time_string, base_time, timezone_string):
	base_time = datetime_as_timezone(base_time, timezone_string)

	try:
		date_time = dateparser.parse(
			time_string,
			languages=['en'],
			settings={"PREFER_DATES_FROM": 'future', "RELATIVE_BASE": base_time.replace(tzinfo=None)})
	except Exception:
		date_time = None

	if date_time is None:
		try:
			results = search_dates(
				time_string,
				languages=['en'],
				settings={"PREFER_DATES_FROM": 'future', "RELATIVE_BASE": base_time.replace(tzinfo=None)})
			if results is not None:
				temp_time = results[0][1]
				if temp_time.tzinfo is None:
					temp_time = datetime_force_utc(temp_time)

				if temp_time > base_time:
					date_time = results[0][1]
			else:
				date_time = None
		except Exception:
			date_time = None

	if date_time is None:
		try:
			date_time, result_code = cal.parseDT(time_string, base_time)
			if result_code == 0:
				date_time = None
		except Exception:
			date_time = None

	if date_time is None:
		return None

	if date_time.tzinfo is None:
		if timezone_string is not None:
			date_time = pytz.timezone(timezone_string).localize(date_time)
		else:
			date_time = datetime_force_utc(date_time)

	date_time = datetime_as_utc(date_time)

	return date_time

def render_time(date_time, user=None, format_string=None):
	timezone = user.timezone if user is not None else None
	time_format = user.time_format if user is not None else None
	if format_string is None:
		if time_format == "12":
			format_string = "%Y-%m-%d %I:%M:%S %p %Z"
		else:
			format_string = "%Y-%m-%d %H:%M:%S %Z"

	bldr = str_bldr()
	bldr.append("[**")
	bldr.append(datetime_as_timezone(date_time, timezone).strftime(format_string))
	bldr.append("**](http://www.wolframalpha.com/input/?i=")
	bldr.append(date_time.strftime('%Y-%m-%d %H:%M:%S %Z').replace(" ", "%20"))
	bldr.append(" To Local Time".replace(" ", "%20"))
	bldr.append(")")
	return ''.join(bldr)

def render_time_diff(start_date, end_date):
	seconds = int((end_date - start_date).total_seconds())
	if seconds > 59:
		try:
			adjusted_end_date = start_date + relativedelta(seconds=int(min(seconds * 1.02, seconds + 60 * 60 * 24)))
		except OverflowError:
			adjusted_end_date = datetime_force_utc(datetime(year=9999, month=12, day=31))

		delta = relativedelta(adjusted_end_date, start_date)
	else:
		delta = relativedelta(end_date, start_date)
	if delta.years > 0:
		return f"{delta.years} year{('s' if delta.years > 1 else '')}"
	elif delta.months > 0:
		return f"{delta.months} month{('s' if delta.months > 1 else '')}"
	elif delta.days > 0:
		return f"{delta.days} day{('s' if delta.days > 1 else '')}"
	elif delta.hours > 0:
		return f"{delta.hours} hour{('s' if delta.hours > 1 else '')}"
	elif delta.minutes > 0:
		return f"{delta.minutes} minute{('s' if delta.minutes > 1 else '')}"
	elif delta.seconds > 0:
		return f"{delta.seconds} second{('s' if delta.seconds > 1 else '')}"
	else:
		return ""

def message_link(message_id):
	return f"https://www.reddit.com/message/messages/{message_id}"

def reddit_link(slug):
	return f"https://www.reddit.com{slug}"

def id_from_fullname(fullname):
	return re.sub(r't\d_', "", fullname)

def datetime_as_timezone(date_time, timezone_string):
	if timezone_string is None:
		return date_time
	else:
		return date_time.astimezone(pytz.timezone(timezone_string))

def datetime_as_utc(date_time):
	return date_time.astimezone(pytz.utc)

def datetime_force_utc(date_time):
	return pytz.utc.localize(date_time)

def time_offset(date_time, hours=0, minutes=0, seconds=0):
	if date_time is None:
		return True
	return date_time < datetime_now() - timedelta(hours=hours, minutes=minutes, seconds=seconds)

def add_years(date_time, years):
	try:
		return date_time.replace(year=date_time.year + years)
	except ValueError:
		return date_time + (datetime(date_time.year + years, 3, 1) - datetime(date_time.year, 3, 1))

def get_next_anniversary(account_created_utc):
	if account_created_utc is None:
		log.info("Account creation date is none")
		return datetime_now()
	account_created = datetime_from_timestamp(account_created_utc)
	next_anniversary = add_years(account_created, datetime_now().year - account_created.year)
	if next_anniversary < datetime_now():
		next_anniversary = add_years(next_anniversary, 1)

	log.debug(
		f"Account created {get_datetime_string(account_created)}, anniversary {get_datetime_string(next_anniversary)}")
	return next_anniversary

def datetime_now():
	if debug_time is None:
		return datetime_force_utc(datetime.utcnow().replace(microsecond=0))
	else:
		return debug_time

def datetime_from_timestamp(timestamp):
	return datetime_force_utc(datetime.utcfromtimestamp(timestamp))

def get_datetime_string(date_time, convert_utc=True, format_string="%Y-%m-%d %H:%M:%S"):
	if date_time is None:
		return ""
	if convert_utc:
		date_time = datetime_as_utc(date_time)
	return date_time.strftime(format_string)

def parse_datetime_string(date_time_string, force_utc=True, format_string="%Y-%m-%d %H:%M:%S"):
	if date_time_string is None or date_time_string == "None" or date_time_string == "":
		return None
	date_time = datetime.strptime(date_time_string, format_string)
	if force_utc:
		date_time = datetime_force_utc(date_time)
	return date_time

def html_encode(message):
	return urllib.parse.quote(message, safe='')

def build_message_link(recipient, subject, content=None):
	base = "https://www.reddit.com/message/compose/?"
	bldr = str_bldr()
	bldr.append(f"to={recipient}")
	bldr.append(f"subject={html_encode(subject)}")
	if content is not None:
		bldr.append(f"message={html_encode(content)}")

	return base + '&'.join(bldr)

def get_footer(bldr=None):
	if bldr is None:
		bldr = str_bldr()
	bldr.append("\n\n")
	bldr.append("*****")
	bldr.append("\n\n")

	bldr.append("|[^(Info)](")
	bldr.append(static.INFO_POST)
	bldr.append(")|[^(Custom)](")
	bldr.append(build_message_link(
		static.ACCOUNT_NAME,
		"Reminder",
		f"[Link or message inside square brackets]\n\n{static.TRIGGER}! Time period here"
	))
	bldr.append(")")
	bldr.append("|[^(Your Reminders)](")
	bldr.append(build_message_link(
		static.ACCOUNT_NAME,
		"List Of Reminders",
		"MyReminders!"
	))
	bldr.append(")")
	bldr.append("|[^(Feedback)](")
	bldr.append(build_message_link(
		static.OWNER,
		"RemindMeBot Feedback"
	))
	bldr.append(")")
	bldr.append("|\n|-|-|-|-|")

	return bldr

def str_bldr():
	return []

def bldr_length(bldr):
	length = 0
	for item in bldr:
		length += len(item)
	return length

def requests_available(requests_pending):
	if requests_pending == 0:
		return 0
	elif requests_pending < 200:
		return 30
	else:
		return min(1000, int(requests_pending / 5))

def check_append_context_to_link(link):
	if re.search(r"reddit\.com/r/\w+/comments/(\w+/){3}", link):
		return link + "?context=3"
	else:
		return link


import unittest
import pandas as pd
import numpy as np
from numpy.random import normal, seed

from datetime import date
from dateutil.relativedelta import relativedelta

from finmarkets import DiscountCurve, ForwardRateCurve, InterestRateSwap, InterestRateSwaption

class Test_Irs(unittest.TestCase):
    def test_irs(self):
        obs_date = date.today()
        discount_data = pd.read_excel('https://github.com/matteosan1/finance_course/raw/develop/input_files/discount_factors_2022-10-05.xlsx')
        euribor_data = pd.read_excel('https://github.com/matteosan1/finance_course/raw/develop/input_files/euribor_curve.xlsx', sheet_name='EURIBOR3M')

        dates = [obs_date + relativedelta(months=i) for i in discount_data['months']]
        dc = DiscountCurve(obs_date, dates, discount_data.loc[:, 'dfs'])

        dates = [obs_date + relativedelta(months=i) for i in euribor_data['months']]
        fr = ForwardRateCurve(obs_date, dates, euribor_data.loc[:, 'rates']*0.01)

        start_date = obs_date + relativedelta(months=1)
        nominal = 1e6
        fixed_rate = 0.023
        tenor = "3m"
        maturity = "4y"

        irs = InterestRateSwap(nominal, start_date, maturity, fixed_rate, tenor)
        self.assertAlmostEqual(irs.npv(dc, fr), 32809.34, places=2)
        #print ("NPV: {:.2f} EUR".format(irs.npv(dc, fr)))

    def test_swaption(self):
        obs_date = date.today()
        discount_data = pd.read_excel('https://github.com/matteosan1/finance_course/raw/develop/input_files/discount_factors_2022-10-05.xlsx')
        euribor_data = pd.read_excel('https://github.com/matteosan1/finance_course/raw/develop/input_files/euribor_curve.xlsx', sheet_name='EURIBOR3M')

        dates = [obs_date + relativedelta(months=i) for i in discount_data['months']]
        dc = DiscountCurve(obs_date, dates, discount_data.loc[:, 'dfs'])

        dates = [obs_date + relativedelta(months=i) for i in euribor_data['months']]
        fr = ForwardRateCurve(obs_date, dates, euribor_data.loc[:, 'rates']*0.01)

        start_date = obs_date + relativedelta(years=1)
        exercise_date = start_date
        volatility = 0.15
        nominal = 1e6
        fixed_rate = 0.023
        tenor = "3m"
        maturity = "4y"
        swaption = InterestRateSwaption(nominal, start_date, exercise_date, maturity,
                                        volatility, fixed_rate, tenor)

        price_mc, interval = swaption.payoffMC(obs_date, dc, fr)
        self.assertAlmostEqual(price_mc, 33410.71, delta=1000)
        self.assertAlmostEqual(interval, 176.39, delta=10)
        #print ("MC: {:.2f} +- {:.2f}".format(price_mc, interval))

        price_bs = swaption.payoffBS(obs_date, dc, fr)
        self.assertAlmostEqual(price_bs, 33598.66, places=2)
        #print ("BS: {:.2f}".format(price_bs))

print ("\nTest IRS")
if __name__ == '__main__':
    unittest.main()


import streamlit as st
import altair as alt
import pandas as pd
import numpy as np
from datetime import datetime, time

st.title('Practice Streamlit 30 Days')

# Day 2
st.write('## Day 2')
st.write('Hello Streamlit!')

# Day 3
st.write('## Day 3')
st.header('st.button')
if st.button('Say hello'):
    st.write('Why hello there')
else:
    st.write('Goodbye')

# Day 4
st.write('## Day 4')
st.write('https://youtu.be/Yk-unX4KnV4')

# Day 5
st.write('## Day 5')
st.header('st.write')
st.write('Hello, *World!* :sunglasses:')
st.write(1234)
df = pd.DataFrame({
     'first column': [1, 2, 3, 4],
     'second column': [10, 20, 30, 40]
     })
st.write(df)
st.write('Below is a DataFrame:', df, 'Above is a dataframe.')
df2 = pd.DataFrame(
     np.random.randn(200, 3),
     columns=['a', 'b', 'c'])
c = alt.Chart(df2).mark_circle().encode(
     x='a', y='b', size='c', color='c', tooltip=['a', 'b', 'c'])
st.write(c)

# Day 6
st.write('## Day 6')
st.write('Uploading your Streamlit app to GitHub')

# Day 7
st.write('## Day 7')
st.write('Deploying your Streamlit app with Streamlit Community Cloud')

# Day 8
st.write('## Day 8')
st.subheader('slider')
age = st.slider('How old are you?', 0, 130, 25)
st.write("I'm ", age, 'years old')

st.subheader('Range slider')
values = st.slider(
     'Select a range of values',
     0.0, 100.0, (25.0, 75.0))
st.write('Values:', values)

st.subheader('Range time slider')
appointment = st.slider(
     "Schedule your appointment:",
     value=(time(11, 30), time(12, 45)))
st.write("You're scheduled for:", appointment)

st.subheader('Datetime slider')
start_time = st.slider(
     "When do you start?",
     value=datetime(2020, 1, 1, 9, 30),
     format="MM/DD/YY - hh:mm")
st.write("Start time:", start_time)

# Day 9
st.write('## Day 9')
st.subheader('st.line_chart')
chart_data = pd.DataFrame(
    np.random.randn(20, 3),
    columns=['a', 'b', 'c']
)
st.dataframe(chart_data)
st.line_chart(chart_data)

# Day 10
st.write('## Day 10')
st.subheader('st.selectbox')
option = st.selectbox(
     'What is your favorite color?',
     ['Blue', 'Red', 'Green'])

st.write('Your favorite color is ', option)


# find the longest of the character c in the string s
# s = "abbcbbttt" c = "b" longest run: 2
# s = "abbcbbttt" c = "t" longest run: 3

def longest_run(s, c):
    for i in range(len(s), -1, -1):
        if c*i in s:
            return i

# s = "abbbbbbsssssbb", c = "b"

def longest__run2(s, c):
    # state variables
    run = 0 # The length of the current run so far
    max_run = 0 # The longest run we've seen so far

    for ch in s:
        if ch!= c:
            max_run = max(max_run, run)
            run = 0
        else:
            run += 1

    return max(max_run, run)


from scipy import spatial
import numpy as np
from glob import glob
from joblib import Parallel, delayed
import multiprocessing
import pandas as pd
import utils.metrics as metrics
from collections import defaultdict
import time
from tqdm import tqdm
import os.path
from utils.hpatch import *
from utils.misc import *

TORCH_GPU_IS_AVAILABLE = False
try:
    import torch
    TORCH_GPU_IS_AVAILABLE = torch.cuda.is_available()
except:
    pass

id2t = {0:{'e':'ref','h':'ref','t':'ref'}, \
        1:{'e':'e1','h':'h1','t':'t1'}, \
        2:{'e':'e2','h':'h2','t':'t2'}, \
        3:{'e':'e3','h':'h3','t':'t3'}, \
        4:{'e':'e4','h':'h4','t':'t4'}, \
        5:{'e':'e5','h':'h5','t':'t5'} }

tp = ['e','h','t']

moddir = os.path.dirname(os.path.abspath(__file__))
tskdir = os.path.normpath(os.path.join(moddir, "..", "..", "tasks"))

def seqs_lengths(seqs):
    ''' Helper method to return length for all seqs'''
    N = {}
    for seq in seqs:
        N[seq] = seqs[seq].N
    return N

def dist_matrix(D1,D2,distance):
    ''' Distance matrix between two sets of descriptors'''
    if distance=='L2':
        if TORCH_GPU_IS_AVAILABLE:
            with torch.no_grad():
                D = torch.cdist(torch.from_numpy(D1).cuda(),
                                torch.from_numpy(D2).cuda(),
                                p = 2).detach().cpu().numpy()
        else:
            D = spatial.distance.cdist(D1, D2,'euclidean')
    elif distance=='L1':
        if TORCH_GPU_IS_AVAILABLE:
            with torch.no_grad():
                D = torch.cdist(torch.from_numpy(D1).cuda(),
                                torch.from_numpy(D2).cuda(),
                                p = 1).detach().cpu().numpy()
        else:
            D = spatial.distance.cdist(D1, D2,'cityblock')
    elif distance=='masked_L1':
        [desc1,masks1] = np.split(D1, 2,axis=1)
        [desc2,masks2] = np.split(D2, 2,axis=1)
        D = spatial.distance.cdist(desc1*masks1, desc2*masks2,'cityblock')
    else:
        raise ValueError('Unknown distance - valid options are |L2|L1|masked_L1|')
    return D

#####################
# Verification task #
#####################
def get_verif_dists(descr,pairs,op):
    d = {}
    for t in ['e','h','t']:
        d[t] = np.empty((pairs.shape[0],1))
    idx = 0
    pbar = tqdm(pairs)
    pbar.set_description("Processing verification task %i/3 " % op)
    for p in pbar:
        [t1,t2] = [id2t[p[1]],id2t[p[4]]]
        for t in tp:
            d1 = getattr(descr[p[0]], t1[t])[p[2]]
            d2 = getattr(descr[p[3]], t2[t])[p[5]]
            distance = descr['distance']
            if distance=='L2':
                dist = spatial.distance.euclidean(d1, d2)
            elif distance=='L1':
                dist = spatial.distance.cityblock(d1, d2)
            elif distance=='masked_L1':
                [d1,m1] = np.array_split(d1, 2)
                [d2,m2] = np.array_split(d2, 2)
                dist = spatial.distance.cityblock(m1*d1, m2*d2)
            d[t][idx] = dist
        idx+=1
    return d

def eval_verification(descr,split):
    print('>> Evaluating %s task' % green('verification'))

    start = time.time()
    pos = pd.read_csv(os.path.join(tskdir, 'verif_pos_split-'+split['name']+'.csv')).as_matrix()
    neg_intra = pd.read_csv(os.path.join(tskdir, 'verif_neg_intra_split-'+split['name']+'.csv')).as_matrix()
    neg_inter = pd.read_csv(os.path.join(tskdir, 'verif_neg_inter_split-'+split['name']+'.csv')).as_matrix()

    d_pos = get_verif_dists(descr,pos,1)
    d_neg_intra = get_verif_dists(descr,neg_intra,2)
    d_neg_inter = get_verif_dists(descr,neg_inter,3)

    results = defaultdict(lambda: defaultdict(lambda:defaultdict(dict)))

    for t in tp:
        l = np.vstack((np.zeros_like(d_pos[t]),np.ones_like(d_pos[t])))
        d_intra = np.vstack((d_neg_intra[t],d_pos[t]))
        d_inter = np.vstack((d_neg_inter[t],d_pos[t]))

        # get results for the balanced protocol: 1M Positives - 1M Negatives
        fpr,tpr,auc = metrics.roc(-d_intra,l)
        results[t]['intra']['balanced']['fpr'] = fpr
        results[t]['intra']['balanced']['tpr'] = tpr
        results[t]['intra']['balanced']['auc'] = auc

        fpr,tpr,auc = metrics.roc(-d_inter,l)
        results[t]['inter']['balanced']['fpr'] = fpr
        results[t]['inter']['balanced']['tpr'] = tpr
        results[t]['inter']['balanced']['auc'] = auc

        # get results for the imbalanced protocol: 0.2M Positives - 1M Negatives
        N_imb = d_pos[t].shape[0] + int(d_pos[t].shape[0]*0.2) # 1M + 0.2*1M
        pr,rc,ap = metrics.pr(-d_intra[0:N_imb],l[0:N_imb])
        results[t]['intra']['imbalanced']['pr'] = pr
        results[t]['intra']['imbalanced']['rc'] = rc
        results[t]['intra']['imbalanced']['ap'] = ap

        pr,rc,ap = metrics.pr(-d_inter[0:N_imb],l[0:N_imb])
        results[t]['inter']['imbalanced']['pr'] = pr
        results[t]['inter']['imbalanced']['rc'] = rc
        results[t]['inter']['imbalanced']['ap'] = ap
    end = time.time()
    print(">> %s task finished in %.0f secs  " % (green('Verification'),end-start))
    return results

def gen_verif(seqs,split,N_pos=1e6,N_neg=1e6):
    np.random.seed(42)

    # positives
    s = np.random.choice(split['test'], int(N_pos))
    seq2len = seqs_lengths(seqs)
    s_N = [seq2len[k] for k in s]
    s_idx = np.array([np.random.choice(np.arange(k),2,replace=False) for k in s_N])
    s_type = np.array([np.random.choice(np.arange(5),2,replace=False) for k in s_idx])
    df = pd.DataFrame({'s1': pd.Series(s, dtype=object),\
                       's2': pd.Series(s, dtype=object),\
                       'idx1': pd.Series(s_idx[:,0], dtype=int) ,\
                       'idx2': pd.Series(s_idx[:,0], dtype=int) ,\
                       't1': pd.Series(s_type[:,0], dtype=int) ,\
                       't2': pd.Series(s_type[:,1], dtype=int)})
    df = df[['s1','t1','idx1','s2','t2','idx2']] # updated order for matlab comp.
    df.to_csv(os.path.join(tskdir, 'verif_pos_split-'+split['name']+'.csv'),index=False)

    # intra-sequence negatives
    df = pd.DataFrame({'s1': pd.Series(s, dtype=object),\
                       's2': pd.Series(s, dtype=object),\
                       'idx1': pd.Series(s_idx[:,0], dtype=int) ,\
                       'idx2': pd.Series(s_idx[:,1], dtype=int) ,\
                       't1': pd.Series(s_type[:,0], dtype=int) ,\
                       't2': pd.Series(s_type[:,1], dtype=int)})
    df = df[['s1','t1','idx1','s2','t2','idx2']] # updated order for matlab comp.
    df.to_csv(os.path.join(tskdir, 'verif_neg_intra_split-'+split['name']+'.csv'),index=False)

    # inter-sequence negatives
    s_inter = np.random.choice(split['test'], int(N_neg))
    s_N_inter = [seq2len[k] for k in s_inter]
    s_idx_inter = np.array([np.random.randint(k) for k in s_N_inter])
    df = pd.DataFrame({'s1': pd.Series(s, dtype=object),\
                       's2': pd.Series(s_inter, dtype=object),\
                       'idx1': pd.Series(s_idx[:,0], dtype=int) ,\
                       'idx2': pd.Series(s_idx_inter, dtype=int) ,\
                       't1': pd.Series(s_type[:,0], dtype=int) ,\
                       't2': pd.Series(s_type[:,1], dtype=int)})
    df = df[['s1','t1','idx1','s2','t2','idx2']] # updated order for matlab comp.
    df.to_csv(os.path.join(tskdir, 'verif_neg_inter_split-'+split['name']+'.csv'),index=False)

#################
# Matching task #
#################
def eval_matching(descr,split):
    print('>> Evaluating %s task' % green('matching'))
    start = time.time()

    results = defaultdict(lambda: defaultdict(lambda:defaultdict(dict)))
    pbar = tqdm(split['test'])
    for seq in pbar:
        d_ref = getattr(descr[seq], 'ref')
        gt_l = np.arange(d_ref.shape[0])
        for t in tp:
            for i in range(1,6):
                d = getattr(descr[seq], t+str(i))
                D = dist_matrix(d_ref,d,descr['distance'])
                idx = np.argmin(D,axis=1)
                m_l = np.equal(idx,gt_l)
                results[seq][t][i]['sr'] = np.count_nonzero(m_l) / float(m_l.shape[0])
                m_d = D[gt_l,idx]
                pr,rc,ap = metrics.pr(-m_d,m_l,numpos=m_l.shape[0])
                results[seq][t][i]['ap'] = ap
                results[seq][t][i]['pr'] = pr
                results[seq][t][i]['rc'] = rc
                # print(t,i,ap,results[seq][t][i]['sr'])
    end = time.time()
    print(">> %s task finished in %.0f secs  " % (green('Matching'),end-start))
    return results

##################
# Retrieval task #
##################
def descr_from_idx(descr,idxs):
    d = np.empty((idxs.shape[0],descr['dim']))
    for i in range(idxs.shape[0]):
        d[i] = getattr(descr[idxs[i][0]], 'ref')[idxs[i][1]]
    return d

def get_query_intra_dists(descr,d,query,t):
    idx  = query[1]
    seq = query[0]
    D = np.empty((5))
    d = np.expand_dims(d, axis=0)

    for i in range(1,6):
        d_ = getattr(descr[seq], t+str(i))[idx]
        d_ = np.expand_dims(d_, axis=0)
        D[i-1] = dist_matrix(d,d_,descr['distance'])[0]
    return D

def eval_retrieval(descr,split): #WIP
    print('>> Evaluating %s task' % green('retrieval'))
    start = time.time()

    q = pd.read_csv(os.path.join(tskdir, 'retr_queries_split-'+split['name']+'.csv')).as_matrix()
    d = pd.read_csv(os.path.join(tskdir, 'retr_distractors_split-'+split['name']+'.csv')).as_matrix()

    # q_std = np.std(q, axis=0)
    # d_std = np.std(d, axis=0)
    # print(q.shape)
    # print(q_std.shape)

    desc_q = descr_from_idx(descr,q).astype(np.float32)
    desc_d = descr_from_idx(descr,d).astype(np.float32)

    # distactor masking per sequence
    m = dict((seq, d[:,0]!=seq) for seq in split['test'])

    print(">> Please wait, computing distance matrix...")
    D = dist_matrix(desc_q,desc_d,descr['distance'])
    print(">> Distance matrix done.")

    results = defaultdict(lambda: defaultdict(lambda:defaultdict(dict)))
    N_distractors = desc_d.shape[0]
    # at_ranks = [int(x*N_distractors) for x in [0.25,0.5,0.75,1]]
    at_ranks = [100,500,1000,5000,10000,15000,20000]

    pbar = tqdm(range(desc_q.shape[0]))
    pbar.set_description("Processing retrieval task")
    for i in pbar:
        query_descr = desc_q[i]
        for t in tp:
            D_intra = get_query_intra_dists(descr,desc_q[i],q[i],t)
            D_ = D[i,:]
            D_ = D_[m[q[i][0]]]
            gt = np.zeros_like(D_);

            D_ = np.hstack((D_intra,D_))

            # D_[0:5] = D_intra
            gt = np.hstack((np.array([1,1,1,1,1]),gt))
            # gt[0:5] = 1
            for k in at_ranks:
                pr,rc,ap = metrics.pr(-D_[0:k],gt[0:k])
                # print (pr.shape,rc.shape)
                # print ap
                results[i][t][k]['ap'] = ap
                # perm = np.argsort(D_[0:k], kind='mergesort',axis=0)
                # gt_perm = gt[perm]
                # mi_rank = np.mean(np.where(gt_perm))
                # results[i][t][k]['mi_rank'] = mi_rank
    end = time.time()
    print(">> %s task finished in %.0f secs  " % (green('Retrieval'),end-start))
    return results

def gen_retrieval(seqs,split,N_queries=0.5*1e4,N_distractors=2*1e4):
    np.random.seed(42)
    seq2len = seqs_lengths(seqs)

    s_q = np.random.choice(split['test'], int(N_queries*4))
    s_q_N = [seq2len[k] for k in s_q]
    s_q_idx = [np.random.randint(k) for k in s_q_N]
    s_q_idx = np.array(s_q_idx)

    s_d = np.random.choice(split['test'], int(N_distractors*10))
    s_d_N = [seq2len[k] for k in s_d]
    s_d_idx = [np.random.randint(k) for k in s_d_N]
    s_d_idx = np.array(s_d_idx)

    msk = np.zeros((s_q.shape[0],))
    for i in range(s_q.shape[0]):
        p = get_patch(seqs[s_q[i]],'ref',s_q_idx[i])
        if np.std(p)> 10 :
            msk[i] = 1

    msk = np.where(msk==1)
    s_q = s_q[msk]
    s_q_idx = s_q_idx[msk]

    msk = np.zeros((s_d.shape[0],))
    for i in range(s_d.shape[0]):
        p = get_patch(seqs[s_d[i]],'ref',s_d_idx[i])
        if np.std(p)> 10 :
            msk[i] = 1

    msk = np.where(msk==1)
    s_d = s_d[msk]
    s_d_idx = s_d_idx[msk]
    q_  = np.stack((s_q, s_q_idx), axis=-1)
    d_  = np.stack((s_d, s_d_idx), axis=-1)

    df_q = pd.DataFrame({'s': pd.Series(q_[:,0], dtype=object),\
                       'idx': pd.Series(q_[:,1], dtype=int)})
    df_q = df_q[['s','idx']] # updated order for matlab comp.

    df_d = pd.DataFrame({'s': pd.Series(d_[:,0], dtype=object),\
                       'idx': pd.Series(d_[:,1], dtype=int)})
    df_d = df_d[['s','idx']] # updated order for matlab comp.

    print(df_q.shape,df_d.shape)
    df_q = df_q.drop_duplicates()
    df_d = df_d.drop_duplicates()
    df_q = df_q.head(N_queries)
    df_q_ = df_q.copy()

    common = df_q_.merge(df_d,on=['s','idx'])
    # print(common.shape)
    df_q_.set_index(['s', 'idx'], inplace=True)
    df_d.set_index(['s', 'idx'], inplace=True)
    df_d = df_d[~df_d.index.isin(df_q_.index)].reset_index()
    # print(df_q.shape,df_d.shape)
    df_d = df_d.head(N_distractors)

    df_q.to_csv(os.path.join(tskdir, 'retr_queries_split-'+split['name']+'.csv'),index=False)
    df_d.to_csv(os.path.join(tskdir, 'retr_distractors_split-'+split['name']+'.csv'),index=False)

methods = {'verification': eval_verification,\
           'matching': eval_matching,\
           'retrieval': eval_retrieval}


n = int(input())
f1 = 'korova'
fy = 'korov'
fs = 'korovy'
yy = (n % 10)
if 10 <= n < 20 or yy == 0 or yy >= 5:
    print(n, fy)
elif n == 1 or yy == 1:
    print(n, f1)
else:
    print(n, fs)


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

# In[ ]:

base = "www.homeflix.com"
coupon = "signup/coupon"
discount = 50
amount = 4

for num in range(amount):
  print(f"{base}/{coupon}/{discount}/{num}")

print(f"{amount} coupons created")