import torch
import time

from collections import OrderedDict
from torch import nn, optim
from torchvision import models
from utility_functions import process_image

def create_new_model(arch, hidden_units):
    '''Function loads new pretrained CNN model (tourch.modules), freezes its parameters
    and creates new classifier. Available architectures: vgg1, vgg19, densenet121, alexnet
    '''
    # List of supported achitectures
    in_features = {
        'vgg11': 25088,
        'vgg19': 25088,
        'densenet121': 1024,
        'alexnet': 9216
    }

    # Create new model and freeze params
    model = getattr(models, arch)(pretrained=True)

    for param in model.parameters():
        param.requires_grad = False

    # Create new classirier according to model architecture
    model.classifier = create_new_classifier(in_features[arch], hidden_units)

    return model

def create_new_classifier(in_features, hidden_units, out_features=102):
    '''Function creates new classifier for CNN.
    '''
    classifier = nn.Sequential(OrderedDict([('input', nn.Linear(in_features=in_features, out_features=hidden_units, bias=True)),
                                            ('relu', nn.ReLU()),
                                            ('droput', nn.Dropout(0.2)),
                                            ('h1', nn.Linear(in_features=hidden_units, out_features=out_features, bias=True)),
                                            ('output', nn.LogSoftmax(dim=1))
                                           ]))
    return classifier

def train_model(model, lr, epochs, train_data, valid_data, use_gpu):
    '''Function trains model accroding to parameters. Function uses NLLLoss function as a criterion
    and Adam optimizer.
    '''
    # Checking if GPU available
    if torch.cuda.is_available() and use_gpu:
        device = 'cuda'
    else:
        device = 'cpu'

    model.to(device)

    criterion = nn.NLLLoss()
    optimizer = optim.Adam(model.classifier.parameters(), lr=lr)

    for e in range(epochs):

        start_time = time.time()
        train_loss = 0

        for inputs, labels in train_data:

            # set gradient to zero and enable dropout
            model.train()
            optimizer.zero_grad()

            inputs, labels = inputs.to(device), labels.to(device)

            # get log probabilities from output and calculate loss
            logps = model.forward(inputs)
            loss = criterion(logps, labels)

            # backpropagation and gradient descent
            loss.backward()
            optimizer.step()

            train_loss += loss

        # disable calculating grad to test model and disable droput
        with torch.no_grad():

            model.eval()
            valid_loss = 0
            accuracy = 0

            for inputs, labels in valid_data:
                inputs, labels = inputs.to(device), labels.to(device)
                logps = model.forward(inputs)
                loss = criterion(logps, labels)
                valid_loss += loss

                # calculate accuracy
                ps = torch.exp(logps)
                top_p, top_class = ps.topk(1, dim=1)
                equals = top_class == labels.view(*top_class.shape)
                accuracy += torch.mean(equals.type(torch.FloatTensor)).item()

        end_time = time.time() - start_time

        print(f"Epoch {e + 1:02}/{epochs} | "
              f"Train loss = {train_loss/len(train_data):.3f} | "
              f"Validation loss = {valid_loss/len(valid_data):.3f} | "
              f"Validation accuracy = {accuracy/len(valid_data):.3f} | "
              f"Time: {end_time//60:.0f}m {end_time % 60:.0f}s")

def save_model_checkpoint(model, arch, save_dir):
    '''Function saves model parameters.
    '''
    checkpoint = {'classifier': model.classifier,
                  'state_dict': model.state_dict(),
                  'arch': arch,
                  'class_to_idx': model.class_to_idx
                  }

    torch.save(checkpoint, save_dir + '/checkpoint_by_cmd.pth')

def load_model_checkpoint(path_to_checkpoint):
    '''Function returns a model with parameters from checkpoint
    '''
    checkpoint = torch.load(path_to_checkpoint, map_location=lambda storage, loc: storage)
    model = getattr(models, checkpoint['arch'])(pretrained=True)
    model.classifier = checkpoint['classifier']
    model.load_state_dict(checkpoint['state_dict'])
    model.class_to_idx = checkpoint['class_to_idx']
    model.eval()
    return model

def predict_classes(image, model, topk, use_gpu):
    ''' Predict the class (or classes) of an image using a trained deep learning model.
    '''
    if torch.cuda.is_available() and use_gpu:
        device = 'cuda'
    else:
        device = 'cpu'

    model.to(device)
    image = image.to(device)

    # get prediction and top K probs
    ps = torch.exp(model.forward(image))
    probs, classes = ps.topk(topk)

    # transform probs and classes to list
    probs = probs.view(topk).tolist()
    classes = classes.view(topk).tolist()

    keys = list(model.class_to_idx.keys())

    for i in range(topk):
        classes[i] = keys[classes[i]]

    return probs, classes


import random

# Словарь с именами известных людей и датами их рождения
dict_people = {
    'A_S_Pushkin': '06.06.1799',
    'John_Lennon': '09.10.1940',
    'M_Y_Lermontov': '15.10.1814',
    'Albert_Einstein': '14.03.1879',
    'Steve_Jobs': '24.02.1955',
    'Bill_Gates': '28.10.1955',
    'Yuri_Gagarin': '09.03.1934',
    'Peter_I': '09.06.1672',
    'D_I_Mendeleev': '08.02.1834',
    'F_M_Dostoevsky': '11.11.1821'
}

# Список дней прописью
days = {'01': 'первое', '02': 'второе', '03': 'третье', '04': 'четвертое', '05': 'пятое', '06': 'шестое',
        '07': 'седьмое',
        '08': 'восьмое', '09': 'девятое', '10': 'десятое', '11': 'одиннадцатое', '12': 'двенадцатое',
        '13': 'тринадцатое',
        '14': 'четырнадцатое', '15': 'пятнадцатое', '16': 'шестнадцатое', '17': 'семнадцатое', '18': 'восемнадцатое',
        '19': 'девятнадцатое', '20': 'двадцатое', '21': 'двадцать первое', '22': 'двадцать второе',
        '23': 'двадцать третье',
        '24': 'двадцать четвертое', '25': 'двадцать пятое', '26': 'двадцать шестое', '27': 'двадцать седьмое',
        '28': 'двадцать восьмое', '29': 'двадцать девятое', '30': 'тридцатое', '31': 'тридцать первое'}

# Список месяцев прописью
months = {'01': 'января', '02': 'февраля', '03': 'марта', '04': 'апреля', '05': 'мая', '06': 'июня',
          '07': 'июля', '08': 'августа', '09': 'сентября', '10': 'октября', '11': 'ноября', '12': 'декабря'}

def date_to_text(date):
    day, month, year = date.split('.')
    return f'{days[day]} {months[month]} {year} года.'

def run_victorina():
    play = True
    while play == True:
        # Выбор пяти случайных людей из списка
        results = random.sample(list(dict_people.keys()), 5)
        win = 0
        lose = 0
        for item in results:
            answer = input(f'Введите год рождения {item}(в формате - dd.mm.yyyy): ')
            if answer == dict_people[item]:
                print('Поздравляем, это правильный ответ!!!')
                win += 1
            else:
                print('Это неправильный ответ!!!')
                correct_answer = date_to_text(dict_people[item])
                print(f'Правильный ответ: {correct_answer}')
                lose += 1
        print(f'Правельных ответов: {win}, неправильных ответов: {lose}')

        while True:
            again = input('Хотите попробовать еще раз? y/n')
            if 'y' in again.lower() or 'д' in again.lower():
                play = True
                break
            elif 'n' in again.lower() or 'н' in again.lower():
                play = False
                break
            else:
                print('Неизвестная команда!')


from __future__ import annotations

import numpy as np

from .utilities import vensim_name_to_identifier
from pysd.translators.structures.abstract_model import AbstractModel, AbstractSection
from pysd.translators.structures.abstract_expressions import IntegStructure, LookupsStructure, DataStructure
from pysd.translators.vensim.vensim_file import VensimFile
from typing import Union, Any
from dataclasses import dataclass, field
from itertools import product
from numbers import Number
import pathlib

@dataclass(frozen=True)
class VensimVariableContext:
    """
    Holds information about a given Vensim variable

    Attributes
    ----------
    name : str
        Name of the variable. Names are converted into identifiers(whitespaces are replaced with underscores)
    subscripts : tuple[str]
        subscripts defined for the variable. This is in the same format as `AbstractComponent.subscripts[0]`
    is_stock : bool
        Whether the variable is a stock variable. Default is `False`
    is_static_data : bool
        Whether the variable is static data.
    is_lookup : bool
        Whether the variable is defined as a LookupStructure.
    is_vensim_datastructure : bool
        Whether the variable is defined within Vensim as a DataStructure.
    """
    name: str
    subscripts: tuple[str] = field(default_factory=tuple)
    is_stock: bool = field(default=False)
    is_static_data: bool = field(default=False)
    is_lookup: bool = field(default=False)
    is_vensim_datastructure: bool = field(default=False)

    def __hash__(self) -> int:
        return hash(self.name)

@dataclass
class StateVectorIndexMap:
    """
    This class is used as an element for indicating the map between the indices of a 1d-array to multiple named
    nd-arrays. Its usage will be normally be through a list `list[StateVectorIndexMap]`, declared as
    `VensimModelContext.state_vector_index_map`. Then, each index of the
    `StateVectorIndexMap` in the list, will correspond to the actual variable name and its subscript index held by it.
    For example, if we had `[None, StateVectorIndexMap(name="A", indices=(0, 0)]`, this means that the 1st
    (note that we don't use the 0th element since stan starts arrays with index 1) element corresponds to the variable
    named "A". But since A is subscripted with two subscripts, the indices attribute tells us that it's the 0th value
    of the zero-th and first subscript.

    Attributes
    ----------
    name : str
        Variable name
    indices : tuple[int]
        If the variable has subscripts, this corresponds to the index of subscript values the index of the 1d-array
        is mapped to. The specific order within the tuple follows `VensimVariableContext.subscripts`
    """
    name: str
    indices: tuple[int]

class VensimModelContext:
    """
    This class holds information about the Vensim model.

    Attributes
    ----------
    _abstract_model : pysd.translators.structures.abstract_model.AbstractModel
        The `pysd` abstract model
    _first_section : pysd.translators.structures.abstract_model.AbstractSection
        The first `AbstractSection` defined within the model. This is purely for convenience and equivalent to
        `self._abstract_model.sections[0]`
    variables : dict[str, VensimVariableContext]
        The dict containing non-stock variables. The variable names are **converted to
        identifiers**
    integ_outcome_variables : dict[str, VensimVariableContext]
        Dict of stock variables. Note that if a variable is a stock variable, it's included in both
        `integ_outcome_vector_names` and `variables`
    subscripts : dict[str, tuple[Any]]
        Values of the subscripts defined within the Vensim model. Key is a string denoting the subscript name, values
        is a list of a sequence of arbitrary values for the subscript.
    state_vector_index_map : list[Union[None, StateVectorIndexMap]]
        This list holds the indices each stock variable values should go in if all stock variables were to be stored
        in a single vector. This is necessary because Stan requires that the input/output format of the ODE function
        be a single dimension vector. This means we need to take potentially multiple variables that are
        multidimensional, flatten them into one-dimensional vectors, and concatenate them. **Important**: Since stan
        indexing starts from 1, the 0'th index has `None` to indicate that it is not used.
    """
    def __init__(self, vensim_model_path: Union[str, pathlib.Path]) -> None:
        """
        Parameters
        ----------
        vensim_model_path : string or pathlib.Path
        """
        vf = VensimFile(vensim_model_path)
        vf.parse()
        self._abstract_model: AbstractModel = vf.get_abstract_model()
        self.variables: dict[str, VensimVariableContext] = {}
        self.integ_outcome_variables: dict[str, VensimVariableContext] = {}
        self._first_section: AbstractSection = self._abstract_model.sections[0]
        self.state_vector_index_map: list[StateVectorIndexMap] = [None]

        # Some basic checks to make sure the AM is compatible
        assert len(self._abstract_model.sections) == 1, "Number of sections in AbstractModel must be 1."

        for element in self._abstract_model.sections[0].elements:
            element.name = vensim_name_to_identifier(element.name)
            # Save names of variables defined in the model
            assert len(element.components) == 1, f"Number of components in AbstractElement must be 1, but {element.name} has {len(element.components)}"

            component = element.components[0]
            subscripts = tuple(component.subscripts[0])  # Get the subscripts defined for the variable.
            # See https://pysd.readthedocs.io/en/master/structure/vensim_translation.html#pysd.translators.vensim.vensim_element.Component

            # Check if the variable is just static data
            is_static_data = isinstance(component.ast, (int, float, np.ndarray))

            # Check if the variable is a lookup
            is_lookup = isinstance(component.ast, LookupsStructure)

            # Check if the variable is a Vensim datastructure
            is_datastructure = isinstance(component.ast, DataStructure)

            variable_name = vensim_name_to_identifier(element.name)
            is_stock = isinstance(component.ast, IntegStructure)
            self.variables[variable_name] = VensimVariableContext(vensim_name_to_identifier(element.name), subscripts,
                                                                  is_stock=is_stock, is_static_data=is_static_data,
                                                                  is_lookup=is_lookup,
                                                                  is_vensim_datastructure=is_datastructure)

            # Additionally record the stock variables
            if is_stock:
                self.integ_outcome_variables[variable_name] = VensimVariableContext(vensim_name_to_identifier(element.name),
                                                                                subscripts, is_stock=True)

        # record values of subscripts
        self.subscripts: dict[str, tuple[Any]] = {}  # holds the values of subscripts defined within the model.
        for subscript in self._first_section.subscripts:
            self.subscripts[subscript.name] = tuple(subscript.subscripts)

        # We create the mapping that maps subscripted, multidimensional stock variables into a single length vector.
        for var_name, var_context in self.integ_outcome_variables.items():
            subscript_dim = self.get_variable_shape(var_name)

            # Calculate all possibles indices. If a subscript dimension is (2, 2), this means (1, 1), (1, 2),
            # (2, 1), (2, 2) is possible.
            subscript_indices = product(*[range(1, x + 1) for x in subscript_dim])

            for indices in subscript_indices:
                self.state_vector_index_map.append(StateVectorIndexMap(var_name, indices))

    def set_timesteps_subscript(self, value: tuple[Number]) -> None:
        """
        This function is used to register the "timesteps" subscript. The timesteps subscript is used for stock variables
        to indicate the time index.

        Parameters
        ----------
        value : tuple[Number]
            values of the subscript
        """
        self.subscripts["timesteps"] = value

    @property
    def first_section(self) -> AbstractSection:
        return self._first_section

    @property
    def abstract_model(self) -> AbstractModel:
        return self._abstract_model

    def get_subscript_values(self, subscript_name: str) -> tuple[Any]:
        """
        Return the values of a given subscript.

        Parameters
        ----------
        subscript_name : str
            Subscript name

        Returns
        -------
        A tuple with the values of the subscripts
        """
        return tuple(self.subscripts[subscript_name])

    def get_variable_shape(self, variable_name: str) -> tuple[int]:
        """
        Return the required dimension of vensim variables.

        If a Vensim variable is equipped with a subscript 'A' that has 2 values, it would need to be allocated as a
        length-2 vector. In this case, this method will return `(2, )` indicating what its shape should be.

        Parameters
        ----------
        variable_name : str
            Variable name, must be an identifier

        Returns
        -------
        A tuple of integer(s) indicating its required shape.
        """
        variable_context = self.variables[variable_name]
        shape = []
        for subscript in variable_context.subscripts:
            shape.append(len(self.subscripts[subscript]))

        return tuple(shape)

    def print_variable_info(self) -> None:
        """
        Print some debug information about the variables present in the Vensim model.
        """
        var_names = []
        max_length = len("original name") + 1
        for element in self._abstract_model.sections[0].elements:
            is_stock = False
            for component in element.components:
                if isinstance(component.ast, IntegStructure):
                    is_stock = True
                    break

            var_names.append((element.name, vensim_name_to_identifier(element.name), is_stock,))
            max_length = max(max_length, len(element.name) + 1)

        header = ("original name".ljust(max_length) + "stan variable name".ljust(max_length) + "is stock")
        print(header)
        print("-" * len(header))
        for x in var_names:
            print(x[0].ljust(max_length) + x[1].ljust(max_length) + ("V" if x[2] else ""))


import os
import sys
from sys import path
path.append('./modules')
path.append('./templates')
from flask import Flask, request, current_app
from flask.templating import render_template
import logging
import modules
from modules.process_text import ProcessText
from modules.anonymizeText import anonText
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask_restful import Api, Resource
from flask.json import jsonify
import json

#initialize the class to process text
pc = ProcessText()
at = anonText()

app = Flask(__name__, template_folder='templates')

#Configure flask DB attributes
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db' # new
db = SQLAlchemy(app)
ma = Marshmallow(app)
api = Api(app)
logging.basicConfig(level=logging.DEBUG)

#Database outline for each rec
class Rec(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    #1 if male, 0 if female
    gender = db.Column(db.Integer)
    content = db.Column(db.String(500))

    def __repr__(self):
        return '<Review %s>' % self.content
#Schema for the rec reviews
class RecSchema(ma.Schema):
    class Meta:
        fields = ("id","gender","content")
        model = Rec
#Create Schema for our DB model
rec_schema = RecSchema()
recs_schema = RecSchema(many=True)
#Methods to add the rec letter to the DB
class PostListResource(Resource):
    def get(self):
        posts = Rec.query.all()
        return recs_schema.dump(posts)
    def post(self):
        new_post = Rec(
            gender=request.json['gender'],
            content=request.json['content']
        )
        db.session.add(new_post)
        db.session.commit()
        return rec_schema.dump(new_post)
    def patch(self, post_id):
        post = Rec.query.get_or_404(post_id)
        if 'gender' in request.json:
            post.title = request.json['gender']
        if 'content' in request.json:
            post.content = request.json['content']
        db.session.commit()
        return rec_schema.dump(post)
    #Method to delete a review, if needed
    def delete(self, post_id):
        post = Rec.query.get_or_404(post_id)
        db.session.delete(post)
        db.session.commit()
        return '', 204

class PostResource(Resource):
    def get(self, post_id):
        post = Rec.query.get_or_404(post_id)
        return rec_schema.dump(post)

api.add_resource(PostResource, '/posts/<int:post_id>')
api.add_resource(PostListResource, '/posts')

#Home page for Flask
#Run this application using "python3 app.py" then go to localhost:5000 on Chrome

#Routes for each page
@app.route('/')
def homepage():
    return render_template('index.html')

@app.route('/index.html')
def home():
    return render_template('index.html')

@app.route('/faq.html')
def faq():
    return render_template('faq.html')

@app.route('/about_us.html')
def aboutus():
    return render_template('about_us.html')

@app.route('/references.html')
def refs():
    return render_template('references.html')

@app.route('/process_letter_text', methods=["GET","POST"])
def processLetter():
    if "anonymize" in request.form.get("action"):
            text = request.form.get("letterText")
            student_name = request.form.get("studentName")
            result = at.anonymize(text, student_name)
            current_app.logger.info(result)
            return result

    #Extract user text from the form
    text = request.form.get("letterText")

    #Extract gender from the form
    gender = request.form.get("gender_form")

    #Send the text to the processing module
    result = pc.process_text(text)

    #Post this to the DB
    to_post = Rec(gender = gender, content = text)
    db.session.add(to_post)
    db.session.commit()
    print(result[0].json)
    return render_template('text_analysis.html', results = result[0].json, unique_associations = result[1], highlighted_text = result[2], biased_words = result[3])
    #return render_template('coming_soon.html')

#We can eventually have this represent the results of machine learning for different words.
#This also could represent different ML models
#Src: https://rahmanfadhil.com/flask-rest-api/

if __name__ == '__main__':
    app.run(debug=True)


from model_encoders import *

def segmentation_model_fn(features, labels, mode, params):
    print(2)
    is_training = mode == tf.estimator.ModeKeys.TRAIN and not params['frozen']
    init_model_path = params['init_model_path']
    logger.info(f'!!! is_training: {is_training}')

    if params['structure_mode'] == 'seg' or params['structure_mode'] == 'sup':
        if params['structure_mode'] == 'sup':
            feature = tf.concat([features[0], features[1]], axis=-1)
        else:
            feature = features

        encoder = params['encoder'](feature, params['image_height'], params['image_width'], get_FCN=1,
                                    is_training=is_training)
        model = params['decoder'](encoder, params['num_classes'], is_training=is_training)
        logits = model.logits

    elif params['structure_mode'] == 'siamese':
        with tf.variable_scope('') as scope:
            encoder1 = params['encoder'](features[0], params['image_height'], params['image_width'], get_FCN=1,
                                         is_training=is_training)
            model_1 = params['decoder'](encoder1, params['num_classes'], is_training=is_training)
            scope.reuse_variables()
            encoder2 = params['encoder'](features[1], params['image_height'], params['image_width'], get_FCN=1,
                                         is_training=is_training)
            model_2 = params['decoder'](encoder2, params['num_classes'], is_training=is_training)

            logits = tf.abs(model_1.logits - model_2.logits)

    else:
        raise Exception('invalid structure_mode.')

    y_pred = tf.argmax(logits, axis=-1, output_type=tf.int32, name='y_pred')
    y_prob = tf.nn.softmax(logits)

    predictions = {
        'y_pred': y_pred,
        'y_prob': y_prob,
    }

    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode, predictions=predictions)

    valid_mask = tf.not_equal(labels, params['ignore_label'])
    valid_mask.set_shape([None, None, None])
    valid_logits = tf.boolean_mask(logits, valid_mask)
    valid_label = tf.boolean_mask(labels, valid_mask)
    valid_pred = tf.boolean_mask(y_pred, valid_mask)

    cross_entropy_loss = tf.losses.sparse_softmax_cross_entropy(valid_label, valid_logits)

    if init_model_path:
        logger.info(f'Manually restoring from pre-trained network{init_model_path}...')
        variables_in_ckpt = set(e[0] for e in tf.train.list_variables(init_model_path))
        if 'global_step' in variables_in_ckpt:
            variables_in_ckpt.remove('global_step')

        variables_to_restore = {}
        for each_variable in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES):
            if each_variable.name in variables_in_ckpt:
                variables_to_restore[each_variable.name] = each_variable

        tf.train.init_from_checkpoint(init_model_path, variables_to_restore)
        logger.info(f'{len(variables_to_restore)} variables restored successfully.')

    # tf.global_variables_initializer().run(session=tf.Session())

    if params['weight_decay'] is not None:
        trainable_vars = [v for v in tf.trainable_variables()]
        loss = cross_entropy_loss + tf.add_n([tf.nn.l2_loss(v) for v in trainable_vars]) * params['weight_decay']
    else:
        loss = cross_entropy_loss

    metrics = {
        'accuracy': tf.metrics.accuracy(valid_label, valid_pred),
        'mean_iou': tf.metrics.mean_iou(valid_label, valid_pred, params['num_classes']),
    }

    miou = compute_mean_iou(metrics['mean_iou'][1], params['num_classes'])
    f1 = compute_mean_iou(metrics['mean_iou'][1], params['num_classes'], name='f1')

    tf.identity(loss, name='loss')
    tf.identity(cross_entropy_loss, name='cross_entropy_loss')
    tf.identity(metrics['accuracy'][1], name='acc')
    tf.identity(miou, name='miou')
    tf.identity(f1, name='f1')

    # print(tf.get_collection(tf.GraphKeys.UPDATE_OPS))
    # exit(1)

    tf.summary.scalar('loss', loss)
    tf.summary.scalar('cross_entropy_loss', cross_entropy_loss)
    tf.summary.scalar('acc', metrics['accuracy'][1])
    tf.summary.scalar('miou', miou)
    tf.summary.scalar('f1', f1)

    # gt_decoded_labels = tf.py_func(decode_labels,
    #                                [labels, params['palette'], params['batch_size'], params['num_classes']], tf.uint8)

    # if mode == tf.estimator.ModeKeys.TRAIN:
    #     images = tf.cast(mean_addition(features), tf.uint8)
    #     tf.summary.image('images', tf.concat(axis=2, values=[images, gt_decoded_labels, pred_decoded_labels]),
    #                      max_outputs=12)

    if mode == tf.estimator.ModeKeys.EVAL:
        return tf.estimator.EstimatorSpec(mode, loss=loss, eval_metric_ops=metrics)

    if mode == tf.estimator.ModeKeys.TRAIN:
        global_step = tf.train.get_or_create_global_step()
        if params['lr_decay'] == 'poly':
            lr = tf.train.polynomial_decay(params['learning_rate'], global_step, params['decay_step'],
                                           end_learning_rate=params['end_learning_rate'], power=params['power'],
                                           name='learning_rate')
        elif params['lr_decay'] == 'stable':
            lr = params['learning_rate']

        else:
            raise Exception('invalid lr decay policy.')

        tf.summary.scalar('lr', lr)

        update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
        with tf.control_dependencies(update_ops):
            optimizer = tf.train.MomentumOptimizer(lr, params['momentum'])
            train_op = optimizer.minimize(loss, global_step)

        return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

def compute_mean_iou(total_cm, num_classes, name='mean_iou'):
    """Compute the mean intersection-over-union via the confusion matrix."""
    sum_over_row = tf.to_float(tf.reduce_sum(total_cm, 0))
    sum_over_col = tf.to_float(tf.reduce_sum(total_cm, 1))
    cm_diag = tf.to_float(tf.diag_part(total_cm))
    denominator = sum_over_row + sum_over_col - cm_diag
    if name == 'f1':
        denominator += cm_diag

    # The mean is only computed over classes that appear in the
    # label or prediction tensor. If the denominator is 0, we need to
    # ignore the class.
    num_valid_entries = tf.reduce_sum(tf.cast(tf.not_equal(denominator, 0), dtype=tf.float32))

    # If the value of the denominator is 0, set it to 1 to avoid
    # zero division.
    denominator = tf.where(
        tf.greater(denominator, 0),
        denominator,
        tf.ones_like(denominator))
    iou = tf.div(cm_diag, denominator)

    for i in range(num_classes):
        tf.identity(iou[i], name=f'train_{name}_class{i}')
        tf.summary.scalar(f'train_{name}_class{i}', iou[i])

    # If the number of valid entries is 0 (no classes) we return 0.
    result = tf.where(tf.greater(num_valid_entries, 0), tf.reduce_sum(iou, name=name) / num_valid_entries, 0)
    if name == 'f1':
        result *= 2
    return result


from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

import csv, os
import pandas as pd
from datetime import datetime as dt
import re

from statistics import mean, median, variance, stdev
import matplotlib.animation as animation

import myErrors
from myUtils import CSVListIn

def bars3d_demo(arg):
    fig = plt.figure()
    ax  = fig.add_subplot(111, projection='3d')
    for c,z in zip(['r', 'g', 'b', 'y'], [60, 20, 10, 0]):
        xs = np.arange(20)
        ys = np.random.rand(20)

        cs = [c] * len(xs)
        cs[0] = 'c'
        ax.bar(xs, ys, zs=z, zdir='y', color=cs, alpha=0.8)

    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')

    plt.show()

def outputSeriesOf(snapshots, timestamps):

    fig = plt.figure(figsize=(15,15))
    ax = fig.add_subplot(111, projection='3d')
    for ss, ts in zip(snapshots, timestamps):
        xs = ss[:,0]
        ys = ss[:,1]
        zs = ts

        ax.bar(xs, ys, zs, zdir='y',color='b', alpha=0.8, width=1)

        # ax.set_zlim([0,1])
        # ax.set_xlim([734100,734300])

        ax.set_xlabel('price')
        ax.set_ylabel('time')
        ax.set_zlabel('size')

    plt.show()

def getSnapshotsSize():
    csvList = CSVListIn('./log/snapshot')
    return len(csvList)

def getSnapshotsBetween(first, final):
    csvList = CSVListIn('./log/snapshot')

    filenames = csvList[first : final]
    snapshots = np.ndarray([len(filenames),600,2])
    for i, fn in enumerate(filenames):
        path = './log/snapshot/' + fn
        snapshots[i] = pd.read_csv(path, header=None).values
        # print(snapshots[i,:])

    return snapshots

def getRecentSnapshots(quantity):
    csvList = CSVListIn('./log/snapshot')
    nFiles = len(csvList)
    filenames = quantity if nFiles >= quantity else len(csvList)
    if nFiles >= quantity:
        filenames = csvList[nFiles - quantity :nFiles]
    else:
        filenames = csvList
    # print(filenames)

    snapshots = np.ndarray([len(filenames),600,2])
    for i, fn in enumerate(filenames):
        path = './log/snapshot/' + fn
        snapshots[i] = pd.read_csv(path, header=None).values
        # print(snapshots[i])
    # print(snapshots)

    return snapshots

def getRecentTimestamps(quantity):
    csvList = CSVListIn('./log/snapshot')
    nFiles = len(csvList)
    filenames = quantity if nFiles >= quantity else len(csvList)
    if nFiles >= quantity:
        filenames = csvList[nFiles - quantity -1:nFiles-1]
    else:
        filenames = csvList

    regex = r'\d{20}'
    pattern = re.compile(regex)

    timestamps = np.ndarray(len(filenames),dtype=dt)
    for i, fn in enumerate(filenames):
        matchObj = pattern.match(fn)
        strTimestamp = matchObj.group()
        timestamp = dt.strptime(strTimestamp, '%Y%m%d%H%M%S%f')

        timestamps[i] = timestamp

    return timestamps

def getTimestampDiff(timestamps):
    deltas = [(timestamp - timestamps[0]).total_seconds() for timestamp in timestamps ]
    # print(deltas)
    return deltas

def reshape(x,min,max):
    y = 0
    if (x <= max) & (x >= min):
        y = x
    elif x < min:
        y = min
    elif x > max:
        y = max
    else:
        y = x
    return y

def change0within(x,min,max):
    y = 0
    if (x <= max) & (x >= min):
        y = 0
    elif x < min:
        y = x
    elif x > max:
        y = x
    else:
        y = x
    return y

def sortSnapshots(snapshots):
    """ 気配値表をaskbidの降順に並べ替える"""
    s = snapshots.shape
    # TODO: 全ての値から現在のmidpriceで減じる
    # print(s)

    snapshots_sorted = np.zeros(s)
    snapshots_des    = np.zeros(s)
    for i in range(0,s[0]):
        arg = np.argsort(snapshots[i,:,0])
        snapshots_des[i,:,:] = snapshots[i,arg[-1::-1],:]

    # snapshots_bak = snapshots
    # snapshots_sorted[:, 0      :s[1]//2, :] = snapshots_des[:, 0:s[1]//2, :]
    # snapshots_sorted[:, s[1]//2:s[1]   , :] = snapshots_bak[:, 0:s[1]//2, :]
    snapshots_sorted = snapshots_des
    myErrors.checkSnapshotOrder(snapshots_sorted)
    return snapshots_sorted, s

# 気配値の曲面をグレースケールの画像に変換する
## 現在の気配値の最大を基準価格として，基準価格以上の価格を切り捨て
def snapshots2Gray(snapshots):
    s = snapshots.shape
    # TODO: 全ての値から現在のmidpriceで減じる
    # print(s)
    currentBestBid = snapshots[s[0]-1,s[1]//2-1,0]
    currentBestAsk = snapshots[s[0]-1,s[1]//2,0]
    currentMidPrice = (currentBestBid + currentBestAsk )/2
    snapshots[:,:,0] -= currentMidPrice
    # print(snapshots)

    # TODO: 現在の気配値の値の絶対値の最大値を基準価格とする
    currentWorstBid = snapshots[s[0]-1,0,0]
    currentWorstAsk = snapshots[s[0]-1,s[1]-1,0]
    if (abs(currentWorstBid) > abs(currentWorstAsk)):
        refPrice = currentWorstBid
    else:
        refPrice = currentWorstAsk

    # refPrice = currentMidPrice

    # TODO: 全ての値を基準価格*2で割る．
    snapshots[:,:,0] /= (refPrice * 2)
    # print(snapshots)

    # TODO: [-0.5,0.5]外の価格は+-0.5とする
    reshaped = snapshots
    reshaped[:,:,0] = np.frompyfunc(reshape, 3, 1)(snapshots[:,:,0],-0.5,0.5)
    # print(reshaped)

    # TODO: 全ての値を0.5加算する
    reshaped[:,:,0] += 0.5

    # TODO: [0,1]をn分割して，時間ごとのヒストグラムを生成する
    n = s[0]
    nSeq = s[1]
    nTime= s[0]
    arr = np.arange(0,1+1/n,1/n)
    histSequence = np.zeros((nTime,n))
    for i in range(nTime): # ある時刻で
        snapshot = reshaped[i,:,:]
        # print(snapshot)
        for j in range(nSeq):
            for k in range(n):
                # print(snapshot[j,0])
                # print(arr[k+1])
                if (snapshot[j,0] <= arr[k+1]) &( snapshot[j,0] >= arr[k]):
                    histSequence[i,k] += snapshot[j,1]
                    break
                else:
                    pass
    # plt.imshow(histSequence, 'gray')
    # plt.show()

    # histSequence[:,:] = np.frompyfunc(reshape, 3, 1)(histSequence[:,:],0.0,1.0)

    for i in range(nTime):
        m = mean(histSequence[i,:])
        med = median(histSequence[i,:])
        sd = stdev(histSequence[i,:])
        histSequence[i,:] = np.frompyfunc(reshape, 3, 1)(histSequence[i,:],med-sd,med+sd)
        s = histSequence[i,:].sum()
        histSequence[i,:] /= s
        # print(med-sd,med+sd)

    # histSequence[:,0] = np.frompyfunc(reshape, 3, 1)(histSequence[:,0],0.0,1.0)
    # histSequence[:,n-1] = np.frompyfunc(reshape, 3, 1)(histSequence[:,n-1],0.0,1.0)
    # print(histSequence.T)
    return histSequence.T

# 気配値の曲面をグレースケールの画像に変換する
## 最新の気配値の標準偏差を基準価格として，1σ以上の値を切り捨て
def snapshots2Gray2(snapshots):
    s = snapshots.shape
    # TODO: 全ての値から現在のmidpriceで減じる
    # print(s)
    currentBestBid = snapshots[s[0]-1,s[1]//2-1,0]
    currentBestAsk = snapshots[s[0]-1,s[1]//2,0]
    currentMidPrice = (currentBestBid + currentBestAsk )/2
    snapshots[:,:,0] -= currentMidPrice
    # print(snapshots)

    # TODO: 最新の気配値の標準偏差を基準価格とする
    sd = stdev(snapshots[s[0]-1,:,0])
    refPrice = sd

    # TODO: 全ての値を基準価格で割る．
    snapshots[:,:,0] /= (refPrice)
    # print(snapshots)

    # TODO: [-0.5,0.5]外の価格は+-0.5とする
    reshaped = snapshots
    reshaped[:,:,0] = np.frompyfunc(reshape, 3, 1)(snapshots[:,:,0],-0.5,0.5)
    # print(reshaped)

    # TODO: 全ての値を0.5加算する
    reshaped[:,:,0] += 0.5

    # TODO: [0,1]をn分割して，時間ごとのヒストグラムを生成する
    n = s[0]
    nSeq = s[1]
    nTime= s[0]
    arr = np.arange(0,1+1/n,1/n)
    histSequence = np.zeros((nTime,n))
    for i in range(nTime): # ある時刻で
        snapshot = reshaped[i,:,:]
        # print(snapshot)
        for j in range(nSeq):
            for k in range(n):
                # print(snapshot[j,0])
                # print(arr[k+1])
                if (snapshot[j,0] <= arr[k+1]) &( snapshot[j,0] >= arr[k]):
                    histSequence[i,k] += snapshot[j,1]
                    break
                else:
                    pass
    # plt.imshow(histSequence, 'gray')
    # plt.show()

    # histSequence[:,:] = np.frompyfunc(reshape, 3, 1)(histSequence[:,:],0.0,1.0)

    for i in range(nTime):
        m = mean(histSequence[i,:])
        med = median(histSequence[i,:])
        sd = stdev(histSequence[i,:])
        histSequence[i,:] = np.frompyfunc(reshape, 3, 1)(histSequence[i,:],med-sd,med+sd)
        s = histSequence[i,:].sum()
        histSequence[i,:] /= s
        # print(med-sd,med+sd)

    # histSequence[:,0] = np.frompyfunc(reshape, 3, 1)(histSequence[:,0],0.0,1.0)
    # histSequence[:,n-1] = np.frompyfunc(reshape, 3, 1)(histSequence[:,n-1],0.0,1.0)
    # print(histSequence.T)
    return histSequence.T

# 気配値の曲面をグレースケールの画像に変換する
## 最新の気配値の標準偏差を基準価格と
def snapshots2Gray3(snapshots):
    s = snapshots.shape
    # TODO: 全ての値から現在のmidpriceで減じる
    # print(s)
    currentBestBid = snapshots[s[0]-1,s[1]//2-1,0]
    currentBestAsk = snapshots[s[0]-1,s[1]//2,0]
    currentMidPrice = (currentBestBid + currentBestAsk )/2
    snapshots[:,:,0] -= currentMidPrice
    # print(snapshots)

    # # TODO: 現在の気配値の値の絶対値の最大値を基準価格とする
    # currentWorstBid = snapshots[s[0]-1,0,0]
    # currentWorstAsk = snapshots[s[0]-1,s[1]-1,0]
    # if (abs(currentWorstBid) > abs(currentWorstAsk)):
    #     refPrice = currentWorstBid
    # else:
    #     refPrice = currentWorstAsk

    # TODO: 現在の気配値の標準偏差を基準価格とする
    print(snapshots[s[0]-1,:,0])
    refPrice = stdev(snapshots[s[0]-1,:,0])

    # TODO: 全ての値を基準価格*2で割る．
    snapshots[:,:,0] /= (refPrice * 2)
    # print(snapshots)

    reshaped = snapshots
    # reshaped[:,:,0] = np.frompyfunc(reshape, 3, 1)(snapshots[:,:,0],-0.5,0.5)
    # print(reshaped)

    # TODO: 全ての値を0.5加算する
    reshaped[:,:,0] += 0.5

    # TODO: [0,1]をn分割して，時間ごとのヒストグラムを生成する
    n = s[0]
    nSeq = s[1]
    nTime= s[0]
    arr = np.arange(0,1+1/n,1/n)
    histSequence = np.zeros((nTime,n))
    for i in range(nTime): # ある時刻で
        snapshot = reshaped[i,:,:]
        # print(snapshot)
        for j in range(nSeq):
            for k in range(n):
                # print(snapshot[j,0])
                # print(arr[k+1])
                if (snapshot[j,0] <= arr[k+1]) &( snapshot[j,0] >= arr[k]):
                    histSequence[i,k] += snapshot[j,1]
                    break
                else:
                    pass
    # plt.imshow(histSequence, 'gray')
    # plt.show()

    # histSequence[:,:] = np.frompyfunc(reshape, 3, 1)(histSequence[:,:],0.0,1.0)

    # for i in range(nTime):
    #     m = mean(histSequence[i,:])
    #     med = median(histSequence[i,:])
    #     sd = stdev(histSequence[i,:])
    #     histSequence[i,:] = np.frompyfunc(reshape, 3, 1)(histSequence[i,:],med-sd,med+sd)
    #     s = histSequence[i,:].sum()
    #     histSequence[i,:] /= s
    #     # print(med-sd,med+sd)

    for i in range(nTime):
        m = mean(histSequence[i,:])
        med = median(histSequence[i,:])
        sd = stdev(histSequence[i,:])
        histSequence[i,:] = np.frompyfunc(change0within, 3, 1)(histSequence[i,:],med-sd*2,med+sd*2)
        s = histSequence[i,:].sum()
        if s != 0:
            histSequence[i,:] /= s
        # print(med-sd,med+sd)

    # histSequence[:,0] = np.frompyfunc(reshape, 3, 1)(histSequence[:,0],0.0,1.0)
    # histSequence[:,n-1] = np.frompyfunc(reshape, 3, 1)(histSequence[:,n-1],0.0,1.0)
    # print(histSequence.T)
    return histSequence.T

# 気配値の曲面をグレースケールの画像に変換する
## 現在の気配値の標準偏差を基準価格として，2σ以上の価格を切り捨て
def snapshots2Gray4(snapshots):
    snapshots, s = sortSnapshots(snapshots)

    currentBestBid = snapshots[s[0]-1,s[1]//2,0]
    currentBestAsk = snapshots[s[0]-1,s[1]//2+1,0]
    currentMidPrice = (currentBestBid + currentBestAsk )/2
    snapshots[:,:,0] -= currentMidPrice
    # print(snapshots)

    # TODO: 現在の気配値の標準偏差を基準価格とする
    refPrice = stdev(snapshots[s[0]-1,:,0])

    # TODO: 全ての値を基準価格*2で割る．
    snapshots[:,:,0] /= (refPrice * 2)
    # print(snapshots)

    reshaped = snapshots
    # reshaped[:,:,0] = np.frompyfunc(reshape, 3, 1)(snapshots[:,:,0],-0.5,0.5)

    # TODO: 全ての値を0.5加算する
    reshaped[:,:,0] += 0.5

    # TODO: [0,1]をn分割して，時間ごとのヒストグラムを生成する
    n = s[0]
    nSeq = s[1]
    nTime= s[0]
    arr = np.arange(0,1+1/n,1/n)
    histSequence = np.zeros((nTime,n))
    for i in range(nTime): # ある時刻で
        snapshot = reshaped[i,:,:]
        # print(snapshot)
        for j in range(nSeq):
            for k in range(n):
                # print(snapshot[j,0])
                # print(arr[k+1])
                if ( arr[k] < snapshot[j,0]) & (snapshot[j,0] <= arr[k+1]):
                    histSequence[i,k] += snapshot[j,1]
                    break
                else:
                    pass
    # plt.imshow(histSequence, 'gray')
    # plt.show()

    # histSequence[:,:] = np.frompyfunc(reshape, 3, 1)(histSequence[:,:],0.0,1.0)

    for i in range(nTime):
        m = mean(histSequence[i,:])
        med = median(histSequence[i,:])
        sd = stdev(histSequence[i,:])
        histSequence[i,:] = np.frompyfunc(change0within, 3, 1)(histSequence[i,:],med-1*sd,med+1*sd)
        s = histSequence[i,:].sum()
        histSequence[i,:] /= s
        # print(med-sd,med+sd)

    # histSequence[:,0] = np.frompyfunc(reshape, 3, 1)(histSequence[:,0],0.0,1.0)
    # histSequence[:,n-1] = np.frompyfunc(reshape, 3, 1)(histSequence[:,n-1],0.0,1.0)
    # print(histSequence.T)
    return histSequence.T

if __name__ == '__main__':
    # テスト用気配値
    # snapshots = np.array([
    #     [
    #         [736236.0,0.1],
    #         [736234.0,0.06],
    #         [736874.0,0.02930897],
    #         [736875.0,0.04]
    #     ],
    #     [
    #         [736253.0,0.16],
    #         [736252.0,0.5],
    #         [736865.0,0.01],
    #         [736871.0,0.0284677]
    #     ],
    #     [
    #         [736250.0,2.42],
    #         [736249.0,0.01],
    #         [736877.0,0.08744157],
    #         [736878.0,0.592]
    #     ],
    #     [
    #         [736236.0,0.1],
    #         [736234.0,0.06],
    #         [736862.0,0.05],
    #         [736869.0,0.06]
    #     ]
    # ])

    # snapshots = getRecentSnapshots(100)
    # timestamps = getRecentTimestamps(100)
    # outputSeriesOf(snapshots, getTimestampDiff(timestamps))

    # # 特定期間の気配値の取得
    # l = getSnapshotsSize()
    # # print(getSnapshotsSize())
    # first = l - 300
    # final = l - 200
    # snapshots = getSnapshotsBetween(first,final)
    #
    # # 気配値をグレースケールに変換
    # ssGray = snapshots2Gray2(snapshots)
    # print(ssGray)
    # plt.imshow(ssGray, 'gray')
    # plt.show()

    # n個の気配値からグラフを動画にして出力
    n = 500
    fig = plt.figure()
    ims = []
    l = getSnapshotsSize()
    for i in np.arange(l-n-100,l-100):
        print(f'{(i-(l-n-100))/n*100}% finished')
        snapshots = getSnapshotsBetween(i-100,i)
        ssGray = snapshots2Gray4(snapshots)
        im = plt.imshow(ssGray, 'gray')
        ims.append([im])

    ani = animation.ArtistAnimation(fig, ims, interval=100)
    ani.save('anim.mp4', writer="ffmpeg")

    # snapshots = getSnapshotsBetween(1500,1600)
    # ssGray1 = snapshots2Gray(snapshots)
    # im = plt.imshow(ssGray1, 'gray')
    # plt.show()

    # n = 100
    # fig = plt.figure()
    # ims = []
    # l = getSnapshotsSize()
    # print(l,n)
    # snapshots = getSnapshotsBetween(l-n-100-300,l-n-300)
    # ssGray3 = snapshots2Gray4(snapshots)
    # im2 = plt.imshow(ssGray3, 'gray')
    # plt.show()


#Definido funções:
def leiaInt(msg):
    ok = False
    valor = 0
    while True:
        num = str(input(msg))
        if num.isnumeric():
            valor = int(num)
            ok = True
        else:
            print('\n\033[1;31mVocê não digitou um número inteiro!\033[m\n')
        if ok:
            break
    return valor

#Programa principal:
print('-*-'*15)
num = leiaInt('Digite um número inteiro: ')
print(f'\nVocê digitou o número \033[1;32m{num}\033[m')


#! /usr/bin/env python
import os
import sys
import argparse
import serial
import ctypes
import random
import multiprocessing
import rospy
import numpy as np
import time
import csv
from math import pi
from math import sin, cos
import datetime as dt

from kortex_driver.srv import *
from kortex_driver.msg import *
from sensor_msgs.msg import JointState
from std_msgs.msg import Int32, Float32MultiArray

ACTIONS =  {'r': [ 0, -1,  0,  0,  0,  0],
            'l': [ 0,  1,  0,  0,  0,  0],
            'f': [ 1,  0,  0,  0,  0,  0],
            'b': [-1,  0,  0,  0,  0,  0],
            'u': [ 0,  0,  1,  0,  0,  0],
            'd': [ 0,  0, -1,  0,  0,  0],
            'none': [ 0,  0,  0,  0,  0,  0]}
ACTION_KEYS = {'motion': ['r', 'l', 'f', 'b', 'u', 'd'], 'reset': 'n'}
ACTION_START_TIME = 0
NUM_EPOCH = 0
NUM_EPISODE = 0
LAST_ACTION = None

def weighted_sample_action():
    global ACTION_KEYS
    prob = np.array([2., 1., 1., 1., 2., 1.])
    index = np.random.choice(np.arange(6), p=prob/np.sum(prob))
    return ord(ACTION_KEYS['motion'][index])

def feedback_pose_abs(robot_name):
    feedback = rospy.wait_for_message("/" + robot_name + "/base_feedback", BaseCyclic_Feedback)
    base = feedback.base
    pose = [base.tool_pose_x, base.tool_pose_y, base.tool_pose_z]
    pose = pose + [base.tool_pose_theta_x, base.tool_pose_theta_y, base.tool_pose_theta_z]
    return pose

def force_cb(force, cb_args):
    global ACTIONS
    global ACTION_KEYS
    global LAST_ACTION
    args = cb_args[0]
    robot_name = cb_args[1]
    keyboard_pub = cb_args[2]
    keyboard_msg = cb_args[3]

    resistance = rospy.wait_for_message("/resistance", Int32)
    if resistance.data > 1:
        action = ord('n')
        keyboard_msg.data = action
        keyboard_pub.publish(keyboard_msg)
    else:
        action = weighted_sample_action()
        while not action_safety(args, action, robot_name):
            action = weighted_sample_action()
        keyboard_msg.data = action
        keyboard_pub.publish(keyboard_msg)

    LAST_ACTION = chr(action)

    print(type(force.data), type(force.data[0]))

    print('Resistance: ', resistance, 'Last action', chr(action))

def epoch_cb(data, cb_args):
    global ACTIONS
    global ACTION_KEYS
    global LAST_ACTION
    args = cb_args[0]
    robot_name = cb_args[1]
    keyboard_pub = cb_args[2]
    keyboard_msg = cb_args[3]
    # action = ord(random.sample(ACTION_KEYS['motion'], 1)[0])
    action = weighted_sample_action()
    while not action_safety(args, action, robot_name):
        action = weighted_sample_action()
    keyboard_msg.data = action
    keyboard_pub.publish(keyboard_msg)

def action_safety(args, action, robot_name):
    '''
    verify the safety of the action by computing the z positon
    '''
    global ACTIONS
    global ACTION_KEYS
    time_lim = args.time_lim
    zlb = args.zlb
    velocity = args.velocity
    dz = ACTIONS[chr(action)][2] * velocity * time_lim
    tool_z = feedback_pose_abs(robot_name)[2]
    if tool_z + dz < zlb:
        rospy.loginfo('Unsafe action, resampling...')
        return False
    else:
        return True

def main(args):
    global ACTIONS
    global ACTION_KEYS
    global ACTION_START_TIME
    global NUM_EPOCH
    NUM_EPOCH = args.start_epoch
    global NUM_EPISODE
    global LAST_ACTION

    tool_start = [0.483,  0.066, 0.073]
    t_epoch = args.start_epoch
    t_episode = 0

    rospy.init_node('action_publisher')
    rate=rospy.Rate(20)

    keyboard_pub = rospy.Publisher('keyboard_pub', Int32, queue_size=1)
    keyboard_msg = Int32()

    robot_name = rospy.get_param('~robot_name',"my_gen3")
    rospy.Subscriber("load_cell_force", Float32MultiArray, force_cb,
                        (args, robot_name, keyboard_pub, keyboard_msg))
    rospy.Subscriber("new_epoch_command", Int32, epoch_cb,
                        (args, robot_name, keyboard_pub, keyboard_msg))

    while not rospy.is_shutdown():

        rate.sleep()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Run robot closeloop simulation for 2000 times')
    parser.add_argument('--output_dir', default='/home/jc/logs/realrobot', help='file to store openloop test results')
    parser.add_argument('--velocity', default=0.01, type=float, help='cartesian velocity of end effector')
    parser.add_argument('--time_lim', default=4, type=float, help='robot action magnitude')
    parser.add_argument('--zlb', default=0.05, type=float, help='lower bound of z for safe zone')
    parser.add_argument('--force_lim', default=200, type=float, help='tactile force limit')
    parser.add_argument('--start_epoch', default=0, type=int, help='number of epoch to start recording')
    args = parser.parse_args()

    main(args)


#!/usr/bin/python
"""This module provides the :class:`Card` object.
This module also has 3 constant attributes that help validate or string format
the :class:`Card` object: :attr:`POSSIBLE_SUIT`, :attr:`POSSIBLE_NUMBER`, and
:attr:`VALUE_TRANSLATION`
"""

#: an array with all the possible suit strings
POSSIBLE_SUIT = ['hearts', 'diamonds', 'spades', 'clubs']

#: an array with the range [1, 13]
POSSIBLE_NUMBER = range(1, 14, 1)

#: a dictionary which translates the special face cards to strings
VALUE_TRANSLATION = {
    1  : 'Ace',
    11 : 'Jack',
    12 : 'Queen',
    13 : 'King',
}

class Card(object):
    """A Card object
    """

    def __init__(self, number, suit):
        """
        :param int number: a number between 1 and 13, inclusive
        :param str suit: a case-independent string in :attr:`POSSIBLE_SUIT`
        :raises: ValueError
        """

        #: Holds an integer in the range [1, 13] which represents the card number
        self._number = None

        #: Holds the suit as a lowercase string
        self._suit = None

        # throw ValueError if input argument is bad
        base_error_str = 'A new Card cannot be created.'

        # check if number is within [1, 13]
        if number in POSSIBLE_NUMBER:
            self._number = number
        else:
            raise ValueError(base_error_str + " Number (%s) is not within"
                             " range." % number)

        # check if suit is allowed
        # ignore case if suit.lower() in POSSIBLE_SUIT:
        # throw ValueError if input argument is bad
        if suit.lower() in POSSIBLE_SUIT:
            self._suit = suit
        else:
            raise ValueError(base_error_str + " Suit ('%s') is not in"
                             " %s." % (suit, POSSIBLE_SUIT))

    def _translate_number(self):
        """This is a hidden method that changes the card number to a
        human-readable string

        'Ace' for 1

        :returns: human-readable string for face cards or card number
        :rtype: str
        """
        if self._number in VALUE_TRANSLATION:
            return VALUE_TRANSLATION[self._number]
        else:
            return self._number

    def __repr__(self):
        """This method returns a nice string representation of the card object

        useful in printing card object as "%s"

        :returns: human readable string represenation of card object
        :rtype: str
        """
        return "%s of %s" % (self._translate_number(), self._suit.title())

    def __str__(self):
        """
        :returns: :func:`__repr__`
        :rtype: str
        """
        return self.__repr__()

    def get_value(self):
        """ This method returns the blackjack value of card in an array
        format

        if Ace, return [1, 11]

        if face card, return [10]

        otherwise return [:attr:`_number`]

        :returns: blackjack value of card in an array
        :rtype: array
        """
        if 1 == self._number:
            return [1, 11]
        elif self._number > 10:
            return [10]
        else:
            return [self._number]

    def get_number(self):
        """This method returns the raw number

        :returns: :attr:`_number`
        :rtype: int
        """
        return self._number

    def get_suit(self):
        """This method returns the suit

        :returns: :attr:`_suit`
        :rtype: str
        """
        return self._suit

    def is_ace(self):
        """This method checks if card is an Ace

        :returns: True if card is an Ace
        :rtype: bool
        """
        return 1 == self._number


from dataclasses import dataclass
from typing import Dict, Any, List

import pytest
import typing

import pyfury
from pyfury import Fury, Language

def ser_de(fury, obj):
    binary = fury.serialize(obj)
    return fury.deserialize(binary)

@dataclass
class SimpleObject:
    f1: Dict[pyfury.Int32Type, pyfury.Float64Type] = None

@dataclass
class ComplexObject:
    f1: Any = None
    f2: Any = None
    f3: pyfury.Int8Type = 0
    f4: pyfury.Int16Type = 0
    f5: pyfury.Int32Type = 0
    f6: pyfury.Int64Type = 0
    f7: pyfury.Float32Type = 0
    f8: pyfury.Float64Type = 0
    f9: List[pyfury.Int16Type] = None
    f10: Dict[pyfury.Int32Type, pyfury.Float64Type] = None

def test_struct():
    fury = Fury(language=Language.XLANG, ref_tracking=True)
    fury.register_class(SimpleObject, type_tag="example.SimpleObject")
    fury.register_class(ComplexObject, type_tag="example.ComplexObject")
    o = SimpleObject(f1={1: 1.0 / 3})
    # assert ser_de(fury, o) == o

    o = ComplexObject(
        f1="str",
        f2={"k1": -1, "k2": [1, 2]},
        f3=2**7 - 1,
        f4=2**15 - 1,
        f5=2**31 - 1,
        f6=2**63 - 1,
        f7=1.0 / 2,
        f8=2.0 / 3,
        f9=[1, 2],
        f10={1: 1.0 / 3, 100: 2 / 7.0},
    )
    assert ser_de(fury, o) == o
    with pytest.raises(AssertionError):
        assert ser_de(fury, ComplexObject(f7=1.0 / 3)) == ComplexObject(f7=1.0 / 3)
    with pytest.raises(OverflowError):
        assert ser_de(fury, ComplexObject(f3=2**8)) == ComplexObject(f3=2**8)
    with pytest.raises(OverflowError):
        assert ser_de(fury, ComplexObject(f4=2**16)) == ComplexObject(f4=2**16)
    with pytest.raises(OverflowError):
        assert ser_de(fury, ComplexObject(f5=2**32)) == ComplexObject(f5=2**32)
    with pytest.raises(OverflowError):
        assert ser_de(fury, ComplexObject(f6=2**64)) == ComplexObject(f6=2**64)

@dataclass
class SuperClass1:
    f1: Any = None
    f2: pyfury.Int8Type = 0

@dataclass
class ChildClass1(SuperClass1):
    f3: Dict[str, pyfury.Float64Type] = None

def test_inheritance():
    type_hints = typing.get_type_hints(ChildClass1)
    print(type_hints)
    assert type_hints.keys() == {"f1", "f2", "f3"}
    fury = Fury(language=Language.PYTHON, ref_tracking=True)
    obj = ChildClass1(f1="a", f2=-10, f3={"a": -10.0, "b": 1 / 3})
    assert ser_de(fury, obj) == obj
    assert (
        type(fury.class_resolver.get_serializer(ChildClass1))
        == pyfury.DataClassSerializer
    )


#Import-Anweisungen
import snscrape.modules.twitter as twitterscraper
import pandas as pd

#Twitter-Account und Start-Datum für Scraping festlegen
twitter_account = 'HSGStGallen'
start_date = '2015-01-01'

#Leere Liste für die Tweets erstellen
tweets_list = []

#Loop durch die Tweets mit snscrape und zur erstellten Liste hinzufügen
for tweet in twitterscraper.TwitterSearchScraper(f'from:{twitter_account} since:{start_date}').get_items():
    tweet_dict = {
        'id': tweet.id,
        'date': str(tweet.date),
        'content': tweet.content
    }
    tweets_list.append(tweet_dict)

#Pandas Dataframe von der Liste mit den Tweets erstellen
tweets_df = pd.DataFrame(tweets_list)

#Erstelltes Dataframe als JSON-Datei speichern
tweets_df.to_json('SimonettaFrancesco.json', orient='records', lines=True)