#everyone but freshman
import glob
import pandas as pd
import os
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from scipy import stats
from scipy.stats import f_oneway
from scipy.stats import tukey_hsd
import csv
from scikit_posthocs import posthoc_tukey
from statannotations.Annotator import Annotator
import math

def by_grades_2022(all_hrv):
    all_hrv_df = pd.read_excel(all_hrv)
    #all_hrv_df[['quality', 'HR', 'AVNN', 'SDNN','RMSSD','PNN50']] = all_hrv_df[['quality', 'HR', 'AVNN', 'SDNN','RMSSD','PNN50']].apply(pd.to_numeric)
    only_freshman = all_hrv_df[(all_hrv_df['date'].dt.year == 2022) & (all_hrv_df['grade'] == 2026)]
    #group the sport column by its unique values and count the occurrences
    counts = only_freshman.groupby('Sport').size()
    # identify 'Sports' values that appear less than 4 times
    mask = only_freshman['Sport'].isin(counts[counts < 3].index)
    # replace those values with 'other'
    only_freshman.loc[mask, 'Sport'] = 'Other'
    #replace "No_Sport" with "other"
    only_freshman.loc[only_freshman['Sport'] == 'No_Sport', 'Sport'] = 'Other'

    no_freshman = all_hrv_df[(all_hrv_df['date'].dt.year == 2022) & (all_hrv_df['grade'].isin([2025, 2024, 2023]))]
    #group the sport column by its unique values and count the occurrences
    counts = no_freshman.groupby('Sport').size()
    # identify 'Sports' values that appear less than 4 times
    mask = no_freshman['Sport'].isin(counts[counts < 3].index)
    # replace those values with 'other'
    no_freshman.loc[mask, 'Sport'] = 'Other'

    return only_freshman, no_freshman

def create_pie_chart(all_hrv):
    all_hrv_df = pd.read_excel(all_hrv)
    # extract year and create new column
    all_hrv_df['date_year'] = all_hrv_df['date'].dt.year
    all_hrv_df['name'] = all_hrv_df['name'].str.lower().str.replace(' ', '')
    # Group by name and year, and count the number of entries
    counts = all_hrv_df.groupby(['name', 'date_year']).size().unstack(fill_value=0)
    counts = pd.DataFrame(counts)
    counts.index.name = 'name'
    counts.columns.name = 'date_year'
    # Reset index to convert 'name' from index to a regular column
    counts = counts.reset_index()
    # Rename the columns to the desired format
    # count the number of rows that meet the specified conditions
    num_2021_gt_0_and_2022_eq_0 = len(counts[(counts[2021] > 0) & (counts[2022] == 0)])
    num_2021_eq_0_and_2022_gt_0 = len(counts[(counts[2021] == 0) & (counts[2022] > 0)])
    num_2021_and_2022_gt_0 = len(counts[(counts[2021] > 0) & (counts[2022] > 0)])
    # Print the results
    print(f"Number of rows with 2021 > 0 and 2022 = 0: {num_2021_gt_0_and_2022_eq_0}")
    print(f"Number of rows with 2021 = 0 and 2022 > 0: {num_2021_eq_0_and_2022_gt_0}")
    print(f"Number of rows with 2021 > 0 and 2022 > 0: {num_2021_and_2022_gt_0}")
    # numbers of subjects in each category
    numbers = [num_2021_gt_0_and_2022_eq_0, num_2021_eq_0_and_2022_gt_0, num_2021_and_2022_gt_0]
    # Labels for each number
    labels = ['Only 2021\n'+'('+str(num_2021_gt_0_and_2022_eq_0)+')', 'Only 2022\n'+'('+str(num_2021_eq_0_and_2022_gt_0)+')', 'Both years\n'+'('+str(num_2021_and_2022_gt_0)+')']
    # Creating the pie chart
    fig0, ax0 = plt.subplots(figsize=(10,10))
    ax0.pie(numbers, labels=labels, autopct='%1.1f%%')
    # Adding a title
    ax0.set_title('Subjects by Data Collection Year')
    fig0.savefig('years_piechart.png')
    #By gender
    fig1, ax1 = plt.subplots(figsize=(10,10))
    gender_counts = all_hrv_df['gender'].value_counts()
    fig1, ax1 = plt.subplots(figsize=(10,10))
    gender_counts = gender_counts.rename(index={'female':'Female','male':'Male','unknown': 'N.A'})
    ax1.pie(gender_counts, labels=gender_counts.index, autopct='%1.1f%%',)
    ax1.set_title('Gender Distribution')
    fig1.savefig('gender_piechart.png')
    # Sport pie chart
    sport_counts = all_hrv_df['Sport'].value_counts()
    all_hrv_df['Sport_reduced'] = all_hrv_df['Sport'].apply(lambda x: x if sport_counts[x] >= 15 else 'Other')
    counts_reduced = all_hrv_df['Sport_reduced'].value_counts()
    fig2, ax2 = plt.subplots(figsize=(10,10))
    ax2.pie(counts_reduced, labels=counts_reduced.index, autopct='%1.1f%%', labeldistance=1.1, pctdistance=0.8)
    ax2.text(-0.65, 1.37, '* Sports with less than 15 entries are in the "Other" category', fontsize=10, color='grey')
    ax2.set_title('Sports Distribution')
    plt.savefig('sports_piechart3.png')
    plt.show()

def group_data_by_variable(DataFrame, group_var, hr_var):
    grouped_data = []
    unique_groups = np.unique(DataFrame[group_var])
    if group_var == 'Sport':
        idx = np.where(unique_groups == 'Other')[0][0]
        unique_groups = np.concatenate((np.delete(unique_groups, idx), ['Other']))
        sport_order = {'Boys Basketball': 0, 'Girls Basketball': 1,'Boys Soccer': 2,
        'Girls Soccer': 3,'Cross Country': 4, 'Field Hockey': 5,'Football': 6,'Ice Hockey': 7,'Squash': 8,
        'Tennis': 9,'Volleyball': 10,'Water Polo': 11,'Basketball': 12, 'No_Sport': 13, 'Other': 14}
        unique_groups = sorted(unique_groups, key=lambda s: sport_order[s])
    for group in unique_groups:
        grouped_data.append(DataFrame[DataFrame[group_var] == group][hr_var])

    return unique_groups, grouped_data

def stats_and_plotting(unique_groups,grouped_data,DataFrame,hr_var,group_var, counter):
    if str(max(DataFrame['grade'])) == '2025':
        grades = 'no_freshman_'
        title_grades = 'No Freshman'
    else:
        grades = 'only_freshman_'
        title_grades = 'Only Freshman'
    save_path = '/Users/felixbrener/Documents/violin_swarm/'
    f_result= stats.f_oneway(*grouped_data)
    plt.figure(counter, figsize=(13, 8))
    counter = counter + 1
    #removing erronoius measurements
    #double check if there's a second zero for rmssd
    if hr_var == 'PNN50':
        DataFrame = DataFrame[DataFrame[hr_var] >= 0]
        minimumval = ' values less than\nzero '
    elif hr_var == 'RMSSD':
        DataFrame = DataFrame[DataFrame['AVNN'] > 0]
        minimumval = ' values less than\nzero '
    else:
        DataFrame = DataFrame[DataFrame[hr_var] > 0]
        minimumval = ' values of zero or\nless '
    #check again for values that should go in the other category
    #group the sport column by its unique values and count the occurrences
    counts = DataFrame.groupby('Sport').size()
    # identify 'Sports' values that appear less than 4 times
    mask = DataFrame['Sport'].isin(counts[counts < 3].index)
    # replace those values with 'other'
    DataFrame.loc[mask, 'Sport'] = 'Other'
    #if statement to check of all the unique grousp still exist in the data set
    #reseting unique groups now that more values have been removed
    unique_groups = np.unique(DataFrame[group_var])
    if group_var == 'Sport':
        sport_order = {'Boys Basketball': 0, 'Girls Basketball': 1,'Boys Soccer': 2,
        'Girls Soccer': 3,'Cross Country': 4, 'Field Hockey': 5,'Football': 6,'Ice Hockey': 7,'Squash': 8,
        'Tennis': 9,'Volleyball': 10,'Water Polo': 11,'Basketball': 12, 'No_Sport': 13, 'Other': 14}
        unique_groups = sorted(unique_groups, key=lambda s: sport_order[s])
    if  f_result.pvalue < 0.05:
        #Performing Tukey's HSD test
        tukey_df = posthoc_tukey(DataFrame, val_col=hr_var, group_col=group_var)
        #checking result of posthoc_tukey's
        #comverting the matrix to a non-redundant list of comparisons with the p-value
        remove = np.tril(np.ones(tukey_df.shape), k=0).astype("bool")
        tukey_df[remove] = np.nan
        #removing the lower half and diagonal of the matrix and turning the matrix format into a long dataframe
        molten_df = tukey_df.melt(ignore_index=False).reset_index().dropna()
        #filtering the rows where the value is less than 0.05
        filtered_rows = molten_df[molten_df['value'] < 0.05]
        #creatign swarm plots
        ax = sns.violinplot(data=DataFrame, x=group_var, y=hr_var, order=unique_groups, alpha = 0.5)
        ax = sns.swarmplot(data=DataFrame, x=group_var, y=hr_var, order=unique_groups, alpha = 0.7, color = '#FFFFFF', edgecolor='black')
        #ax = sns.swarmplot(data=DataFrame, x=group_var, y=hr_var, order=unique_groups, alpha = 0.65)
        # add pointplot with average values
        ax = sns.pointplot(data=DataFrame, x=group_var, y=hr_var, color="black", markers="d", scale=1.5, join=False, ci=None, size=10, order=unique_groups, linewidth=2, label='Group Average')

        if hr_var == 'RMSSD' or hr_var =='SDNN' or hr_var =='AVNN':
            ax.set(xlabel =group_var, ylabel = hr_var + "(ms)", title = hr_var +' by '+group_var)
        elif hr_var == 'HR':
            ax.set(xlabel =group_var, ylabel = hr_var + "(bpm)", title = hr_var +' by '+group_var)
        elif hr_var == 'PNN50':
            ax.set(xlabel =group_var, ylabel = hr_var + "(percentage)", title = hr_var +' by '+group_var)
        else:
            ax.set(xlabel =group_var, ylabel = hr_var, title = hr_var +' by '+group_var)
        if group_var == 'gender':
            ax.set(xlabel='Gender')
        ax.text(0, 1.006, "p-value annotation legend:\nNot Significant: p > 5.00e-02\n*: 1.00e-02 < p <= 5.00e-02\n**: 1.00e-03 < p <= 1.00e-02\n***: 1.00e-04 < p <= 1.00e-03\n****: p <= 1.00e-04", transform=ax.transAxes, fontsize=9)
        ax.text(0.8, 1.006, "n = " + str(len(DataFrame)) + " subjects\nAll subjects with "+str(hr_var)+ minimumval + "have been removed from the dataset", transform=ax.transAxes, fontsize=9)
        if len(filtered_rows) > 0:
            pairs = [(i[1]["index"], i[1]["variable"]) for i in filtered_rows.iterrows()]
            p_values = [i[1]["value"] for i in filtered_rows.iterrows()]

            annotator = Annotator(ax, pairs, data=DataFrame, x=group_var, y=hr_var, order=unique_groups)
            annotator.configure(text_format="star", loc="inside")
            annotator.set_pvalues_and_annotate(p_values)

        plt.title(hr_var +' by '+ group_var+'\n'+title_grades)
        if len(unique_groups) > 10:
            plt.xticks(rotation=15)
        if group_var == 'birth_year':
            labels_fixed = list(unique_groups[:-1]) + ['unknown']
            plt.xticks(range(len(unique_groups)), labels_fixed)
        # double the number of y-axis tic marks if there are less than 9
        if len(ax.get_yticks()) < 10:
            tick_interval = (ax.get_yticks()[-1] - ax.get_yticks()[0]) / (len(ax.get_yticks()) - 1)
            new_ticks = [ax.get_yticks()[0] + i*tick_interval/2 for i in range(2*len(ax.get_yticks())-1)]
            ax.set_yticks(new_ticks)
        plt.axhline(y=np.mean(DataFrame[hr_var]), color='#00E665', linestyle='--', label='Average '+ hr_var)
        # count the number of data points in each group
        counts = DataFrame[group_var].value_counts()
        # create a dictionary to map the counts to the group names
        count_dict = dict(zip(counts.index, counts.values))
        # add the counts to the x-tick labels
        if group_var == 'birth_year':
            unique_groups = ['unknown' if x == 2023 else x for x in unique_groups]
            count_dict['unknown'] = count_dict.pop(2023)
        xtick_labels = [f'{name}\n({count_dict[name]})' for name in unique_groups]
        ax.set_xticklabels(xtick_labels)
        plt.legend()
        if counter == 30:
            plt.show()
        else:
            plt.show(block = False)

    else:
        print('Unable to reject hypothesis')
        ax = sns.violinplot(data=DataFrame, x=group_var, y=hr_var, order=unique_groups, alpha = 0.5)
        ax = sns.swarmplot(data=DataFrame, x=group_var, y=hr_var, order=unique_groups, alpha = 0.7, color = '#FFFFFF', edgecolor='black')
        #ax = sns.swarmplot(data=DataFrame, x=group_var, y=hr_var, order=unique_groups, alpha = 0.65)
        # add pointplot with average values
        ax = sns.pointplot(data=DataFrame, x=group_var, y=hr_var, color="black", markers="d", scale=1.5, join=False, ci=None, size=10, order=unique_groups, linewidth=2, label='Group Average')

        if hr_var == 'RMSSD' or hr_var =='SDNN' or hr_var =='AVNN':
            ax.set(xlabel =group_var, ylabel = hr_var + "(ms)", title = hr_var +' by '+group_var)
        elif hr_var == 'HR':
            ax.set(xlabel =group_var, ylabel = hr_var + "(bpm)", title = hr_var +' by '+group_var)
        elif hr_var == 'PNN50':
            ax.set(xlabel =group_var, ylabel = hr_var + "(percentage)", title = hr_var +' by '+group_var)
        else:
            ax.set(xlabel =group_var, ylabel = hr_var, title = hr_var +' by '+group_var)
        if group_var == 'gender':
            ax.set(xlabel='Gender')
        plt.title(hr_var +' by '+ group_var+'\n'+title_grades)
        ax.text(0.89, 1.006, "n = " + str(len(DataFrame)) + " subjects", transform=ax.transAxes, fontsize=9)
        if len(unique_groups) > 10:
            plt.xticks(rotation=15)
        if group_var == 'birth_year':
            labels_fixed = list(unique_groups[:-1]) + ['unknown']
            plt.xticks(range(len(unique_groups)), labels_fixed)
        # double the number of y-axis tic marks if there are less than 9
        if len(ax.get_yticks()) < 10:
            tick_interval = (ax.get_yticks()[-1] - ax.get_yticks()[0]) / (len(ax.get_yticks()) - 1)
            new_ticks = [ax.get_yticks()[0] + i*tick_interval/2 for i in range(2*len(ax.get_yticks())-1)]
            ax.set_yticks(new_ticks)
        plt.axhline(y=np.mean(DataFrame[hr_var]), color='#00E665', linestyle='--', label='Average '+ hr_var)
        # count the number of data points in each group
        counts = DataFrame[group_var].value_counts()
        # create a dictionary to map the counts to the group names
        count_dict = dict(zip(counts.index, counts.values))
        # add the counts to the x-tick labels
        if group_var == 'birth_year':
            unique_groups = ['unknown' if x == 2023 else x for x in unique_groups]
            count_dict['unknown'] = count_dict.pop(2023)
        xtick_labels = [f'{name}\n({count_dict[name]})' for name in unique_groups]
        ax.set_xticklabels(xtick_labels)
        plt.legend()
        if counter == 30:
            plt.show(block = True)
        else:
            plt.show(block = False)
    # save the figure
    fig_name = "violin_swarm_" + grades + str(counter) + '.png'  # change the file name as per your preference
    plt.savefig(save_path + fig_name)
    return counter + 1

if __name__ == '__main__':

    all_hrv = '/Users/felixbrener/Documents/ARC/all_hrv.xlsx'
    hrv_list = ['HR','AVNN', 'SDNN', 'RMSSD','PNN50']
    group_list = ['Sport','birth_year','gender']
    counter = 0

#create_pie_chart(all_hrv)

for group in group_list:
    group_var = group
    for hrv in hrv_list:
        hr_var = hrv
        only_freshman, no_freshman = by_grades_2022(all_hrv)
        #finds all unique values in demographics data columns for upper grades
        #unique_groups, grouped_data = group_data_by_variable(no_freshman, group_var, hr_var)
        #performs one way ANOVa and tukey's HSD and then created box plots showing significant differences
        #counter = stats_and_plotting(unique_groups,grouped_data, no_freshman, hr_var,group_var, counter)
        #finds all unique values in demographics data columns for freshman
        unique_groups, grouped_data = group_data_by_variable(no_freshman, group_var, hr_var)
        #performs one way ANOVa and tukey's HSD and then created box plots showing significant differences
        counter = stats_and_plotting(unique_groups,grouped_data, no_freshman, hr_var,group_var, counter)
        #stats_and_plotting calls group_data_by_variable
        #group_data_by_variable calls add_demographics_data
        #group_data_by_variable()


from __future__ import division

from django.db import models

from pixelpuncher.item.models import ItemType
from pixelpuncher.player.models import GENDER, AvatarLayer, Player

TRIGGER_TYPE = (
    ("ASK", "Ask about",),
    ("TELL", "Tell about",),
    ("ACK", "Acknowledge",),
    ("GRT", "Greeting")
)

RESPONSE_HANDLER = (
    ('RND', 'Random',),
    ('ORD', 'Ordered',),
)

RELATIONSHIP_TYPE = (
    ('RIVL', 'Rival',),
    ('FRND', 'Friend',),
    ('CUST', 'Customer',),
    ('ROMC', 'Romantic',),
)

RELATIONSHIP_LEVEL = (
    ('BS', 'Best',),
    ('GD', 'Good',),
    ('NT', 'Netural',),
    ('BD', 'Bad',),
    ('HR', 'Horrible',),
)

class ResponseHandlers(object):
    Random = 'RND'
    Ordered = 'ORD'

class RelationshipLevels(object):
    BEST = 'BS'
    GOOD = 'GD'
    NETURAL = 'NT'
    BAD = 'BD'
    HORRIBLE = 'HR'

class Triggers(object):
    ASK = 'ask'
    TELL = 'tell'
    HELP = 'help'
    GREET = 'greet'
    ACKNOWLEDGE = 'ack'

class NPCAvatar(models.Model):
    name = models.CharField(max_length=25)
    body_layer = models.ForeignKey(AvatarLayer, null=True, blank=True, related_name="+")
    hair_layer = models.ForeignKey(AvatarLayer, null=True, blank=True, related_name="+")
    face_layer = models.ForeignKey(AvatarLayer, null=True, blank=True, related_name="+")
    shirt_layer = models.ForeignKey(AvatarLayer, null=True, blank=True, related_name="+")

    def __unicode__(self):
        return self.name

class NPC(models.Model):
    name = models.CharField(max_length=25)
    gender = models.CharField(max_length=1, default="M", choices=GENDER)
    level = models.IntegerField(default=1)

    # Used when creating new relationships between NPC and player
    default_relationship_type = models.CharField(max_length=4, choices=RELATIONSHIP_TYPE, default='CUST')

    total_health = models.IntegerField(default=10)
    total_energy = models.IntegerField(default=10)

    power = models.IntegerField(default=1)
    technique = models.IntegerField(default=1)
    endurance = models.IntegerField(default=1)

    avatar = models.ForeignKey(NPCAvatar, null=True, blank=True)

    def __unicode__(self):
        return self.name

class NPCRelationship(models.Model):
    npc = models.ForeignKey(NPC, related_name="+")
    player = models.ForeignKey(Player, related_name="npcs")

    # Type and level determine how npc treats player
    # Score determines how close level is to going up or down.
    score = models.IntegerField(default=0)
    relationship_type = models.CharField(max_length=4, choices=RELATIONSHIP_TYPE)
    relationship_level = models.CharField(max_length=4, choices=RELATIONSHIP_LEVEL, default='NT')

    current_health = models.IntegerField(default=10)
    current_energy = models.IntegerField(default=10)
    pixels = models.IntegerField(default=0)

    avatar = models.ForeignKey(NPCAvatar, null=True, blank=True)

    def __unicode__(self):
        return self.npc.name

class Response(models.Model):
    text = models.TextField()
    health_change = models.IntegerField(default=0)
    energy_change = models.IntegerField(default=0)
    pixels_change = models.IntegerField(default=0)
    xp_change = models.IntegerField(default=0)
    reward_items = models.ManyToManyField(ItemType, related_name="+", blank=True)
    relationship_points = models.IntegerField(default=0)

    priority = models.IntegerField(default=0)  # determines which response to give first
    frequency = models.IntegerField(default=0)  # how often response can be given in minutes
    # Frequency options: timed, no limit, max number (n times)

    level_requirement = models.IntegerField(default=0)  # zero means no requirement
    required_items = models.ManyToManyField(ItemType, related_name="+", blank=True)

    # Used for when an NPC tells player about a location
    location_unlock = models.ForeignKey("location.Location", related_name="+", null=True, blank=True)

    def __unicode__(self):
        return self.text

class ResponseTrigger(models.Model):
    npcs = models.ManyToManyField(NPC, related_name="triggers")
    responses = models.ManyToManyField(Response, related_name="triggers")
    trigger_text = models.CharField(max_length=30)
    trigger_type = models.CharField(max_length=4, choices=TRIGGER_TYPE)
    response_handler = models.CharField(max_length=3, choices=RESPONSE_HANDLER, default='RND')

    def __unicode__(self):
        return self.trigger_text

class ResponseLog(models.Model):
    # Track responses given to player by NPCs
    player = models.ForeignKey(Player, related_name="+")
    response = models.ForeignKey(Response, related_name="+")
    response_trigger = models.ForeignKey(ResponseTrigger, related_name="+")
    response_date = models.DateTimeField()


while True:
    try:
        n = int(input())
        factorial = 1
        if n == 0:
            print(factorial)
        else:
            for i in range(1, n + 1):
                factorial = factorial * i
            print(factorial)
    except:
        break

#python支持大数计算，无限位数。
#对于小整数，它会使用机器自身的整数计算功能去快速计算，当超出机器自身所能支持的范围的时候，自动转换大数计算。
#我用它算过100000的阶乘。 :)


import fastText
import numpy as np
from gensim.models import KeyedVectors
from nltk.stem import PorterStemmer, LancasterStemmer, SnowballStemmer

PORTER_STEMMER = PorterStemmer()
LANCASTER_STEMMER = LancasterStemmer()
SNOWBALL_STEMMER = SnowballStemmer("english")

WORD_TRANSFORMERS = [
    lambda x: x.lower(),
    lambda x: x.upper(),
    lambda x: x.capitalize(),
    PORTER_STEMMER.stem,
    LANCASTER_STEMMER.stem,
    SNOWBALL_STEMMER.stem,
]

def word_forms(word):
    """
        Yields different forms of word, one by one
    """
    yield word
    yield from (transformer(word) for transformer in WORD_TRANSFORMERS)

def maybe_get_embedding(word, model):
    for form in word_forms(word):
        if form in model:
            return model[form]

    word = word.strip("-'")
    for form in word_forms(word):
        if form in model:
            return model[form]

    return None

def construct_empty(word2index, dim):
    return np.zeros((max(word2index.values()) + 1, dim), dtype=np.float32)

def gensim_to_embedding_matrix(word2index, path):
    """
        path - path to model obtained with gensim.models.KeyedVectors.save
    """
    model = KeyedVectors.load(path)
    embedding_matrix = construct_empty(word2index, model.vector_size)
    unknown_words = []

    for word, i in word2index.items():
        maybe_embedding = maybe_get_embedding(word, model)
        if maybe_embedding is not None:
            embedding_matrix[i] = maybe_embedding
        else:
            unknown_words.append(word)

    return embedding_matrix, unknown_words

def fasttext_to_embedding_matrix(word2index, path):
    """
        path - path to binary model obtained from fasttext util
    """
    model = fastText.load_model(path)
    embedding_matrix = construct_empty(word2index, model.get_dimension())
    for word, index in word2index.items():
        embedding_matrix[index] = model.get_word_vector(word)
    return embedding_matrix

def one_hot_char_embeddings(word2index, char_vectorizer):
    """
        vectorizer - fitted vectorizer
    """

    words = [""] * (max(word2index.values()) + 1)
    for word, i in word2index.items():
        words[i] = word

    return char_vectorizer.transform(words).toarray().astype(np.float32)


#!/bin/python
import sys
import notify2
import subprocess
from time import sleep

def notification(message: str):
    """
    Display notification to the desktop
    Task:
        1. show() -> it will generate a complete new pop
        2. update() -> it will update the payload part of same notification pop-up, not issuing any new one.
    Usage : python <filename.py> typeObj:str value:int objective:str
    typeObj: RAM/SWAP/NORMAL
    value: current usage of RAM or SWAP (for NORMAL, the value = 0)
    objective: show/update
    """
    # initialize the notification
    notify2.init("notifywhenLOAD")
    notifyObj = notify2.Notification("Emergency Alert!", message)
    notifyObj.set_timeout(12000)
    return notifyObj

def main():
    a = notification(f"{sys.argv[1]} exceeds {sys.argv[2]}")
    if sys.argv[1] in ["RAM", "SWAP"] and sys.argv[3] == "update":
        a.update(f"{sys.argv[1]} Alert!! Warning for death")
        # a.update('river')
        a.set_urgency(2)
        a.show()
    elif sys.argv[1] in ["RAM", "SWAP"] and sys.argv[3] == "show":
        a.set_timeout(10000)
        a.set_urgency(1)
        a.show()
    elif sys.argv[1] == "NORMAL":
        a.update("ChiLLax!!! Nothing to worry about")
        a.set_urgency(0)
        a.show()

main()


from tqdm             import tqdm
from autograd         import grad, hessian, jacobian
from copy             import copy
import autograd.numpy as np

from libs.operators        import positive_definite
from libs.line_search      import *

class QuasiNewton:
    def __init__(self, func, initialX, interval=[-1e15, 1e15], ftol=1e-6, maxIters=1e3, maxItersLS=200):
        self.costFunc   = func
        self.gradFunc   = grad(self.evaluate)
        self.hessFunc   = hessian(self.evaluate)
        self.maxIters   = int(maxIters)
        self.maxItersLS = maxItersLS
        self.interval   = interval
        self.fevals     = 0
        self.ftol       = ftol

        self.x_is_matrix= False

        if np.ndim(initialX) > 1:
            self.x_is_matrix = True
            initialX = np.squeeze(initialX)

        self.xLen = np.shape(initialX)[0]
        self.direction  = np.zeros((maxIters, self.xLen))
        self.x          = np.zeros((maxIters, self.xLen))
        self.x[0] = initialX

        self.gradient   = np.zeros((self.maxIters, self.xLen))
        self.S          = np.zeros((self.maxIters, self.xLen, self.xLen))

        self.epsilon1 = self.ftol
        self.k = 0
        self.m = 0
        self.rho = 0.1
        self.sigma = 0.7
        self.tau = 0.1
        self.chi = 0.75
        self.m_hat = 600
        self.epsilon2 = 1e-10

        self.S[0] = np.eye(self.xLen)

    def evaluate(self, x):
        if self.x_is_matrix:
            x = np.reshape(x, (self.xLen,1))
        result = self.costFunc(x)
        self.fevals += 1
        return result

    def line_search(self, x):
        def funcLS(alpha):
            return self.evaluate(x + alpha*self.direction[self.iter])

        lineSearch = FibonacciSearch(funcLS, self.interval, ftol=self.ftol, maxIters=self.maxItersLS)
        self.alpha[self.iter] = lineSearch.optimize()
        self.xLS = self.x[self.iter] + self.alpha[self.iter]*self.direction[self.iter]
        return self.xLS

    def get_S(self):
        pass

    # def get_direction(self, x):
    #     if self.k > 0:
    #         self.gradient[self.k] = self.gradFunc(self.x[self.k])
    #         self.S[self.k]        = self.get_S()
    #
    #     direction = -(self.S[self.k] @ self.gradient[self.k])
    #     return direction

    def get_alpha0(self):
        if np.abs(self.fLGrad) > self.epsilon2:
            self.alpha0 = -2*self.delta_f0/self.fLGrad
        else:
            self.alpha0 = 1

        if (self.alpha0 <= 0) or (self.alpha0 > 1):
            self.alpha0 = 1
        return self.alpha0

    def optimize(self):
        self.fevals = 0
        ## Step 1
        self.f0 = self.evaluate(self.x[0])
        self.gradient[0] = self.gradFunc(self.x[0])
        self.m += 2
        self.f_00 = copy(self.f0)
        self.delta_f0 = copy(self.f0)

        while self.k < self.maxIters-1:
            # print("Iter: ", self.k)
            self.escape = False
            ## Step 2
            self.direction[self.k] = -(self.S[self.k] @ self.gradient[self.k])
            self.alphaL = 0
            self.alphaU = 1e99
            self.fL = copy(self.f0)
            self.fLGrad = (self.gradFunc(self.x[self.k] + self.alphaL*self.direction[self.k]).T)@self.direction[self.k]
            self.alpha0 = self.get_alpha0()

            while self.escape == False:
                ## Step 3
                self.deltaK = self.alpha0*self.direction[self.k]
                self.f0 = self.evaluate(self.x[self.k] + self.deltaK)
                self.m += 1

                ## Step 4
                cond1 = self.f0 > self.fL + self.rho*(self.alpha0 - self.alphaL)*self.fLGrad
                cond2 = np.abs(self.fL - self.f0) > self.epsilon2
                if cond1 and cond2:
                    self.alphaU = self.alpha0
                    self.alpha0_hat = self.alphaL + ((self.alpha0 - self.alphaL)**2)*self.fLGrad/(2*(self.fL - self.f0 + (self.alpha0 - self.alphaL)*self.fLGrad))

                    self.alpha0L_hat = self.alphaL + self.tau*(self.alphaU - self.alphaL)
                    if self.alpha0_hat < self.alpha0L_hat:
                        self.alpha0_hat = self.alpha0L_hat

                    self.alpha0U_hat = self.alphaU - self.tau*(self.alphaU - self.alphaL)
                    if self.alpha0_hat > self.alpha0U_hat:
                        self.alpha0_hat = self.alpha0U_hat

                    self.alpha0 = self.alpha0_hat
                    # Go to Step 3
                else:
                    ## Step 5
                    self.f0Grad = (self.gradFunc(self.x[self.k] + self.alpha0*self.direction[self.k]).T)@self.direction[self.k]
                    self.m += 1

                    ## Step 6
                    cond1 = self.f0Grad < self.sigma*self.fLGrad
                    cond2 = np.abs(self.fL - self.f0) > self.epsilon2
                    if cond1 and cond2:
                        deltaAlpha0 = (self.alpha0 - self.alphaL)*self.f0Grad/(self.fLGrad - self.f0Grad)
                        if deltaAlpha0 <= 0:
                            self.alpha0_hat = 2*self.alpha0
                        else:
                            self.alpha0_hat = self.alpha0 + deltaAlpha0

                        self.alpha0U_hat = self.alpha0 + self.chi*(self.alphaU - self.alpha0)
                        if self.alpha0_hat > self.alpha0U_hat:
                            self.alpha0_hat = self.alpha0U_hat

                        self.alphaL = self.alpha0
                        self.alpha0 = self.alpha0_hat
                        self.fL = self.f0
                        self.fLGrad = self.f0Grad
                        # Go to Step 3
                    else:
                        ## Step 7
                        self.x[self.k+1] = self.x[self.k] + self.deltaK
                        self.delta_f0 = self.f_00 - self.f0
                        # Stopping condition
                        if np.linalg.norm(self.deltaK, ord=2) < self.epsilon1 and np.linalg.norm(self.delta_f0) < self.epsilon1:
                            print("Stopping conditions reached. Algorithm terminating.")
                            self.xOpt = self.x[self.k+1]
                            return self.xOpt, self.costFunc(self.xOpt), self.fevals
                        self.f_00 = self.f0

                        ## Step 8
                        self.gradient[self.k+1] = self.gradFunc(self.x[self.k+1])
                        self.gamma = self.gradient[self.k+1] - self.gradient[self.k]

                        self.D = self.deltaK.T@self.gamma
                        if self.D <= 0:
                            self.S[self.k+1] = np.eye(self.xLen)
                        else:
                            self.S[self.k+1] = self.get_S()
                        self.k += 1
                        self.escape == True
                        # Go to Step 2
        print("\nAlgorithm did not converge.")
        self.xOpt = self.x[self.k]
        return self.xOpt, self.costFunc(self.xOpt), self.fevals

class QuasiNewtonDFP(QuasiNewton):
    def get_S(self):
        arg1 = (self.deltaK @ np.transpose(self.deltaK))/(np.transpose(self.deltaK) @ self.gamma)
        arg2 = (self.S[self.k]@self.gamma)@(self.gamma.T@self.S[self.k])/(self.gamma.T@self.S[self.k]@self.gamma)

        self.S[self.k+1] = self.S[self.k] + arg1 - arg2
        return self.S[self.k+1]

class QuasiNewtonBFGS(QuasiNewton):
    def get_S(self):
        arg1 = (1 + ((self.gamma.T@self.S[self.k])@self.gamma)/(self.gamma.T@self.deltaK))*((self.deltaK@self.deltaK.T)/self.gamma.T@self.deltaK)
        arg2 = (self.deltaK@(self.gamma.T@self.S[self.k]) + self.S[self.k]@self.gamma@self.deltaK.T)/(self.gamma.T@self.deltaK)

        self.S[self.k+1] = self.S[self.k] + arg1 - arg2
        return self.S[self.k+1]


import os
import pandas as pd
from nltk.sentiment import SentimentIntensityAnalyzer
from textblob import TextBlob

# Define the path to the input CSV file
input_file = 'Full Comments.csv'

# Create a folder for the sentiment analysis results
output_folder = 'Sentiment Analysis'
if not os.path.exists(output_folder):
    os.makedirs(output_folder)

# Read the input CSV file into a pandas DataFrame
df = pd.read_csv(input_file)

# Initialize the sentiment analysis models
textblob_model = TextBlob
vader_model = SentimentIntensityAnalyzer()

# Perform sentiment analysis and store the results in separate DataFrames
positive_comments_textblob = pd.DataFrame(columns=['Username', 'Comment'])
negative_comments_textblob = pd.DataFrame(columns=['Username', 'Comment'])
positive_comments_vader = pd.DataFrame(columns=['Username', 'Comment'])
negative_comments_vader = pd.DataFrame(columns=['Username', 'Comment'])

for index, row in df.iterrows():
    username = row['Username']
    comment = row['Comment']

    # Sentiment analysis using TextBlob
    textblob_sentiment = textblob_model(comment).sentiment.polarity

    # Sentiment analysis using VADER
    vader_sentiment = vader_model.polarity_scores(comment)['compound']

    if textblob_sentiment >= 0:
        # Positive sentiment according to TextBlob
        positive_comments_textblob = pd.concat([positive_comments_textblob,
                                                pd.DataFrame({'Username': [username], 'Comment': [comment]})],
                                               ignore_index=True)
    else:
        # Negative sentiment according to TextBlob
        negative_comments_textblob = pd.concat([negative_comments_textblob,
                                                pd.DataFrame({'Username': [username], 'Comment': [comment]})],
                                               ignore_index=True)

    if vader_sentiment >= 0:
        # Positive sentiment according to VADER
        positive_comments_vader = pd.concat([positive_comments_vader,
                                             pd.DataFrame({'Username': [username], 'Comment': [comment]})],
                                            ignore_index=True)
    else:
        # Negative sentiment according to VADER
        negative_comments_vader = pd.concat([negative_comments_vader,
                                             pd.DataFrame({'Username': [username], 'Comment': [comment]})],
                                            ignore_index=True)

# Save the positive and negative comments for each model in separate CSV files
textblob_output_folder = os.path.join(output_folder, 'TextBlob')
vader_output_folder = os.path.join(output_folder, 'VADER')

if not os.path.exists(textblob_output_folder):
    os.makedirs(textblob_output_folder)

if not os.path.exists(vader_output_folder):
    os.makedirs(vader_output_folder)

positive_comments_textblob.to_csv(os.path.join(
    textblob_output_folder, 'positive.csv'), index=False)
negative_comments_textblob.to_csv(os.path.join(
    textblob_output_folder, 'negative.csv'), index=False)
positive_comments_vader.to_csv(os.path.join(
    vader_output_folder, 'positive.csv'), index=False)
negative_comments_vader.to_csv(os.path.join(
    vader_output_folder, 'negative.csv'), index=False)

print("Sentiment analysis completed. Results are stored in separate folders for each model.")


# -*- coding: utf-8 -*-
"""
Created on Tue Dec 20 11:07:37 2022

@author: JGarciaP
"""
import streamlit as st
import pandas as pd
import numpy as np
import joblib

model_filename = 'rf_model.pkl'
loaded_model = joblib.load(model_filename)
print("Modelo Cargado")

st.title('Status Diabetes')
st.header("Consulte su glucosa")
st.subheader("Ingrese los datos para su verificación")

with st.form(key='diabetes-pred-form'):

    col1, col2, col3, col4= st.columns(4)
    embarazos = col1.slider(label='Cuantos embarazos ha tenido:', min_value=0, max_value=20)
    glucosa = col2.slider(label='Ingrese valor de glucosa:', min_value=50, max_value=400)
    diastolica = col3.text_input(label='Ingrese su presión:')
    grosor_piel = col4.text_input(label='Ingrese su grosor de piel:')

    col5, col6, col7, col8= st.columns(4)
    insulina= col5.slider(label='Valor de Insulina:', min_value=20, max_value=400)
    BMI = col6.slider(label='Ingrese valor IMC:', min_value=50, max_value=400)
    diabetes_hereditaria= col7.text_input(label='Ingrese su ascendencia:')
    age= col8.text_input(label='Ingrese su edad:')

    submit = st.form_submit_button(label='Analizar')

    calculo = pd.DataFrame({'Pregnancies':embarazos, 'PlasmaGlucose':glucosa, 'DiastolicBloodPressure':diastolica,
                            'TricepsThickness':grosor_piel, 'SerumInsulin':insulina, 'BMI':BMI,
                            'DiabetesPedigree':diabetes_hereditaria,
                            'Age':age},index=[0])
    predicted_diabetes = loaded_model.predict(calculo)[0]
    print(predicted_diabetes)


import sys

from django.apps import apps as django_apps
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db.utils import OperationalError, ProgrammingError

from .get_sites_module import get_sites_module
from .single_site import SiteDomainRequiredError

class InvalidSiteError(Exception):
    pass

def add_or_update_django_sites(apps=None, sites=None, verbose=None):
    """Removes default site and adds/updates given `sites`, etc.

    Title is stored in SiteProfile.

    kwargs:
        * sites: format
            sites = (
                (<site_id>, <site_name>, <title>),
                ...)
    """
    all_sites = {}
    if verbose:
        sys.stdout.write("  * updating sites.\n")
    apps = apps or django_apps
    site_model_cls = apps.get_model("sites", "Site")
    site_model_cls.objects.filter(name="example.com").delete()
    if not sites:
        all_sites = get_sites_module().all_sites
    elif isinstance(sites, (list, tuple)):
        all_sites = {"default": sites}

    for sites in all_sites.values():
        for single_site in sites:
            if get_sites_module() and single_site.name == "edcs_sites.sites":
                continue
            if verbose:
                sys.stdout.write(f"  * {single_site.name}.\n")
            site_obj = get_or_create_site_obj(single_site, apps)
            get_or_create_site_profile_obj(single_site, site_obj, apps)
    return all_sites

def get_or_create_site_obj(single_site, apps):
    if "multisite" in settings.INSTALLED_APPS and not single_site.domain:
        raise SiteDomainRequiredError(
            f"Domain required when using `multisite`. Got None for `{single_site.name}`"
        )
    site_model_cls = apps.get_model("sites", "Site")
    try:
        site_obj = site_model_cls.objects.get(pk=single_site.site_id)
    except ObjectDoesNotExist:
        site_obj = site_model_cls.objects.create(
            pk=single_site.site_id, name=single_site.name, domain=single_site.domain
        )
    else:
        site_obj.name = single_site.name
        site_obj.domain = single_site.domain
        site_obj.save()
    return site_obj

def get_or_create_site_profile_obj(single_site, site_obj, apps):
    site_profile_model_cls = apps.get_model("edcs_sites", "SiteProfile")
    opts = dict(
        title=single_site.title,
        country=single_site.country,
        country_code=single_site.country_code,
        description=single_site.description or single_site.title,
    )
    try:
        site_profile = site_profile_model_cls.objects.get(site=site_obj)
    except ObjectDoesNotExist:
        site_profile_model_cls.objects.create(site=site_obj, **opts)
    except (OperationalError, ProgrammingError):
        pass
    else:
        for k, v in opts.items():
            setattr(site_profile, k, v)
        site_profile.save()


#'''Rock Paper Scissors
#Rock > Scissor
#Paper > Rock
#Scissor > Paper
#'''
import random

W = 0
L = 0
D = 0

def game():
    user = input("Enter R for Rock\nEnter P for Paper\nEnter S for Scissor\n")

    a = random.randint(1,3)
    if(a == 1):
        comp = "R"
    elif(a == 2):
        comp = "P"
    elif(a == 3):
        comp = "S"

    print(f"You choose {user}")
    print(f"Computer choose {comp}")

    if (comp == user):
        return None
    if(comp == "R"):
        if(user == "P"):
            return True
        elif(user == "S"):
            return False
    if(comp == "P"):
        if(user == "S"):
            return True
        elif(user == "R"):
            return False
    if(comp == "S"):
        if(user == "R"):
            return True
        elif(user == "P"):
            return False
    pass

while True:
    result = game()
    if(result == None):
        D = D + 1
        print("DRAW")
    elif(result == True):
        W = W + 1
        print("You WON")
    else:
        L = L + 1
        print("You LOSE")
    print(f"WIN : {W} DRAW : {D} LOSE : {L}")
    i = input(print("press C to continue and E to Exit"))
    if(i == "C"):
        pass
    elif(i == "E"):
        break


# Python OOP
from calendar import weekday
from hashlib import new
import datetime
import time

from numpy import ix_
import terminal_formatting as tf
class Employee:         # Class
    numb = 0            # Class variable
    raise_amount = 1.04 # Class variable

    def __init__(self,first,last,pay):                 # self represents the class instance
        self.first = first                             # Assigns function variable to a local variable
        self.last = last                               # Last name variable
        self.email = first + '.' + last + '@email.com' # Creates an email based on the first and last name given
        self.pay = pay                                 # Pay variable

        Employee.numb += 1 # Increases the number variable for each instance of the class

    def fullname(self):                             # Method that returns the first and last name of the Employee instance
        return '{} {}'.format(self.first,self.last) # Returns the full name of the Employee instance

    def apply_raise(self):                           # Method that applies the raise amount to the class instance
        self.pay = int(self.pay * self.raise_amount) # Calculates the pay after the raise is applies for the instance

    @classmethod                   # Alternative constructor
    def set_raise_amt(cls,amount): # cls == class variable name == class
        cls.raise_amount = amount  # Sets the raise amount to the instance amount

    @classmethod                              # Alternative contructor that takes a given string and converts it into a class instance
    def from_string(cls,emp_str):             # inputs instance variable and the given employee string
        first, last, pay = emp_str.split('-') # Parses the string separated by hyphens
        return cls(first,last,pay)            # Returns the parsed variables

    @staticmethod                                    # Does not operate on the instance or the class
    def is_workday(day):                             # Defines is_workday function
        if day.weekday() == 5 or day.weekday() == 6: # 5 == Saturday, 6 == Sunday
            return False                             # False if it is a weekend
        return True                                  # True if it is a weekday

# Inheritance -- Inherits the functionality from the Employee class
class Developer(Employee):                       # Developer class that inherits Employee attributes
    raise_amount = 1.10                          # Developer raise_amount
    def __init__(self,first,last,pay,prog_lang): # Add programming language
        super().__init__(first,last,pay)         # Calls the parent (Employee) __init__ method
        self.prog_lang = prog_lang               # Sets the instance programming language

# Inheritance -- Inherits the functionality from the Employee class
class Manager(Employee):                              # Subclass of Employee
    def __init__(self,first,last,pay,employees=None): # Adds number of employees to a manager
        super().__init__(first,last,pay)              # Calls the parent (Employee) __init__ method
        if employees is None:                         # Redefines employees=None to avoid having an object in the parameters
            self.employees = []                       # Sets employees to an empty list
        else:
            self.employees = employees # Sets employees to the class instance employees

    def add_emp(self,emp):             # Defines the add employee method to the Manager class
        if emp not in self.employees:  # Adds an employee to the class imstance
            self.employees.append(emp) # Appends the emp to the employees list

    def remove_emp(self,emp):          # Defines the remove employee method to the manager class
        if emp in self.employees:      # Revoves the employee from the Manager class instance
            self.employees.remove(emp) # Removes the emp from the employee list

    def print_emps(self):                               # Method to print the employees tied to the manager
        print('\nManager --> ',self.fullname())         # Print manager name
        for emp in self.employees:                      # For each emp in the employees list
            print('\n    Employee --> ',emp.fullname()) # Print the emp's full name from the Employee class

# print(help(Employee))  # Prints information regarding the Employee class
# print(help(Developer)) # Prints information regarding the Developer class
# print(help(Manager))   # Prints information regarding the Manager class

emp_1 = Employee('Dalton','Kipp',50000)             # Employee class instance
emp_2 = Employee('Test','Employee',100000)          # Employee class instance 2
dev_1 = Developer('Bob', 'Jackson', 60000,'Python') # Developer class instance
dev_2 = Developer('Test','Developer',120000,'C++')  # Developer class instance 2
mgr_1 = Manager('Sue','Smith',90000,[dev_1])        # Manager class instance
mgr_2 = Manager('Test','Manager',700000,[emp_2])    # Manager class instance

date = datetime.date(2022,3,10) # Defines date

tf.dl('[ TEST ]','=',':')

print('\nEmployee.is_workday(date) --> ',Employee.is_workday(date)) # Calls static method from the employee class with specified date

Employee.set_raise_amt(1.05) # == Employee.raise_amount = 1.05

emp_str_1 = 'John-Doe-70000'    # Employee String to be put into from_string()
emp_str_2 = 'Steve-Smith-30000' # Employee String to be put into from_string()
emp_str_3 = 'Jane-Doe-90000'    # Employee String to be put into from_string()

new_emp_1 = Employee.from_string(emp_str_1)                 # Creates a class instance from a string
new_emp_2 = Employee.from_string(emp_str_2)                 # Creates a class instance from a string
new_emp_3 = Employee.from_string(emp_str_3)                 # Creates a class instance from a string
print('\nnew_emp_1.email --> ',new_emp_1.email)             # Prints the employee email from emp_str_1
print('\nEmployee.raise_amount --> ',Employee.raise_amount) # Prints the class variable raise_amount
emp_1.raise_amount = 1.25                                   # Defines class instance raise_amount
print('\nemp_1.raise_amount --> ',emp_1.raise_amount)       # Prints the Employee class instance (emp_1) raise_amount
emp_1.apply_raise()                                         # Applies the Employee apply_raise() to emp_1
print('\ndev_1.raise_amount -->',dev_1.raise_amount)        # Prints the Developer class instance (dev_1) raise_amount
dev_1.apply_raise()                                         # Applies the Developer class raise_amount to the Employee class apply_raise
print('\ndev_1.pay --> ',dev_1.pay)                         # Prints the pay of dev_1 with the applied raise from Employee
print('\ndev_1.prog_lang --> ',dev_1.prog_lang)             # Prints dev_1 programming language
print('\nmgr_1.email -->',mgr_1.email)                      # Prints mgr_1 email

print(tf.g('\nisinstance(mgr_1,Employee) --> '),isinstance(mgr_1,Employee))         # Tests if mgr_1 is an instance of the Employee Class
print(tf.y('\nisinstance(mgr_1,Developer) --> '),isinstance(mgr_1,Developer))       # Tests if the mgr_1 is an instance of the Developer class
print('\nissubclass(Developer,Employee) --> ',issubclass(Developer,Employee)) # Tests if the Developer class is a subclass of Employee
print('\nissubclass(Manager,Developer) --> ',issubclass(Manager,Developer))   # Tests if the Manager class is a subclass of Developer
mgr_1.add_emp(dev_2)    # Adds dev_2 to mgr_1 employees
mgr_1.add_emp(emp_1)    # Adds emp_2 to mgr_1 employees
mgr_1.remove_emp(dev_1) # Removes dev_1 from mgr_1 employees
mgr_1.print_emps()      # Prints manager 1 and their employees
mgr_2.print_emps()      # Prints manager 2 and their employees
tf.dl('[ TEST ]','=',':')
tf.nl()


# -*- coding: utf-8 -*-
"""
Created on Tue Apr 20 12:20:28 2021

@author: mrgna
"""

import numpy as np
from scipy import stats
from statsmodels.distributions.empirical_distribution import ECDF
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow_probability as tfp
tf.config.set_visible_devices([], 'GPU')

####### Comparisson of paths
class PathComparator():
    def __init__(self,paths1,paths2, T, names = ["paths1","paths2"]):
        self.n = paths1.shape[1] - 1
        self.T = T

        self.paths = [paths1,paths2]
        self.returns = [p[:,1:] / p[:,:-1] - 1 for p in self.paths]
        self.times = np.linspace(0,self.T,self.n+1)
        self.names = names

    def run_comparrison(self, plot = True):
        #Compare mean and std of paths

        self.means = [np.mean(p, 0) for p in self.paths]
        self.stds = [np.std(p, 0) for p in self.paths]

        if plot is True:
            [plt.plot(self.times,m) for m in self.means]
            plt.title(("Plot of means"))
            plt.show()

            [plt.plot(self.times,s) for s in self.stds]
            plt.show()

        ### QQ plot and ECDF
        self.idxs = [1,-1]
        self.ecdf_saved = []
        self.ecdf_ranges = []

        for idx in self.idxs:
            # QQ Plot

            percentiles = np.linspace(0.01,0.99,99)
            self.quantiles = [np.quantile(p[:,idx], percentiles) for p in self.paths]

            #qq plot with theoretical quantiles of simulated bs paths
            if plot is True:
                plt.scatter(self.quantiles[0], self.quantiles[1], s = 5)
                plt.plot(self.quantiles[0][[0,-1]],self.quantiles[0][[0,-1]],c='k')
                plt.show()

            # ECDF
            ecdfs = [ECDF(p[:,idx]) for p in self.paths]

            range1 = np.linspace(np.min(self.paths[0][:,idx]),np.max(self.paths[0][:,idx]),1000)

            tmp_ecdf_dist = np.abs(ecdfs[0](range1) - ecdfs[1](range1))
            max_dif_x = np.argmax(tmp_ecdf_dist)
            max_dif = np.max(np.abs(tmp_ecdf_dist))

            if plot is True:
                plt.plot(range1, ecdfs[0](range1))
                plt.plot(range1, ecdfs[1](range1))
                #plt.plot([range1[max_dif_x]]*2,[0,1])
                plt.show()

            self.ecdf_saved.append([ecdf(range1) for ecdf in ecdfs])
            self.ecdf_ranges.append(range1)

        #### Kolmogorov-Smirnov across time

        self.pvalues = [stats.ks_2samp(self.paths[0][:,i], self.paths[1][:,i], mode = 'exact')[1] for i in range(1,self.n+1)]

        if plot is True:
            plt.plot(self.times[1:], self.pvalues)
            plt.show()

        #### corr comparrison

        def calculate_cor_lag(x,lag):
            lead_x = x[:,lag:]
            lag_x = x[:,:-lag]
            cov_x = tfp.stats.correlation(lead_x,lag_x, 0, event_axis = None)
            return cov_x.numpy()

        self.lags = range(1,self.n)
        self.abs_corrs = [[np.mean(calculate_cor_lag(np.abs(lr), l)) for l in self.lags] for lr in self.returns]

        if plot is True:
            plt.plot(self.lags,self.abs_corrs[0])
            plt.plot(self.lags,self.abs_corrs[1])
            plt.show()

        self.corrs = [[np.mean(calculate_cor_lag(lr, l)) for l in self.lags] for lr in self.returns]

        if plot is True:
            plt.plot(self.lags,self.corrs[0])
            plt.plot(self.lags,self.corrs[1])
            plt.show()

if __name__ == '__main__':
    import BlackScholesModel
    import HestonModel
    import MarketGenerator

    BS = False

    real_n = 20
    n = 20
    real_T = 1/12
    dt = real_T / real_n
    cond_n = 0

    if BS:
        ########## Black shocles
        n = n
        T = dt * n

        s0 = 1
        mu = 0.05
        sigma1 = 0.3
        sigma2 = 0.3
        rate = 0.01

        corr = np.array([1])

        model1 = BlackScholesModel.BlackScholesModel(s0, mu, sigma1, np.ones((1,1)), rate, dt)
        model2 = BlackScholesModel.BlackScholesModel(s0, mu, sigma2, np.ones((1,1)), rate, dt)

        n_paths1 = 1000
        n_paths2 = 1000

        model1.reset_model(n_paths1)
        model2.reset_model(n_paths2)

        for _ in range(n):
            model1.evolve_s_b()
            model2.evolve_s_b()

        paths1 = model1.spot_hist[:,0,:]
        paths2 = model2.spot_hist[:,0,:]

        PathComparator(paths1,paths2,T).run_comparrison()

    ###### Heston
    else:
        n = n
        T = dt * n

        s0 = 1
        mu = 0.05
        v0 = 0.1
        kappa = 10
        theta = 0.1
        sigma = 1
        rho = -0.9
        rate = 0.01
        dt = T/n
        ddt = 0.01

        model1 = HestonModel.HestonModel(s0,mu,v0,kappa,theta,sigma,rho,rate,dt,ddt)
        model2 = HestonModel.HestonModel(s0,mu,v0,kappa,theta,sigma,rho,rate,dt,ddt)

        model1.use_v = True
        model2.use_v = True

        n_paths1 = 1000
        n_paths2 = 1000

        model1.reset_model(n_paths1)
        model2.reset_model(n_paths2)

        for _ in range(n):
            model1.evolve_s_b()
            model2.evolve_s_b()

        paths1 = model1.spot_hist[:,0,:]
        paths2 = model2.spot_hist[:,0,:]

        PathComparator(paths1,paths2,T).run_comparrison()

     ####### MG
    n_samples = 1000
    real_decoder = True

    MG = MarketGenerator.MarketGenerator(model1, n, cond_n)
    MG.create_vae(latent_dim = n, layers_units=[40], alpha = 0.95, beta = 100, real_decoder= real_decoder)
    MG.create_training_path(n_samples, overlap = True, seed = None, cheat = True)
    MG.train_vae(epochs = 500, batch_size = 128, lrs = [0.01,0.0001,0.00001])

    if BS is False:
        plt.plot(model1.spot_hist[:,1,:].T)
        plt.show()

    training_paths = MG.training_paths

    #get cond
    cond = MG.cond

    k = 20000 // n_samples
    tmp_cond = np.repeat(cond,k,axis = 0) if cond is not None else None
    mg_paths = MG.generate_paths(n_samples*k, cond = tmp_cond, save = False,
                                 std = 1, mean = 0, real_decoder = real_decoder)

    MG.plot_generated_paths(100, cond[:100,:] if cond_n > 0 else None)
    plt.plot(training_paths[:100,:].T)
    plt.show()

    pc = PathComparator(training_paths,mg_paths,T)
    pc.run_comparrison()

    ###### Test on longer
    if real_n > n:
        n_long_samples = 20000
        if cond_n == 0:
            cond = None
        else:
            if BS:
                    model1.reset_model(1)
                    for i in range(cond_n):
                        model1.evolve_s_b()
                    spots = model1.spot_hist[:,0,:]
                    cond = spots[:,1:] / spots[:,:-1] - 1
                    cond = np.repeat(cond,n_long_samples,axis = 0)

            else:
                if cond_n > 0:
                    new_v0 = v0
                    model1.reset_model(1000)
                    for i in range(100):
                        model1.evolve_s_b()
                    idx = np.argmin(np.abs(model1.v - new_v0)) #v0
                    spots = model1.spot_hist[:,0,:]
                    cond = spots[idx:idx+1,1:] / spots[idx:idx+1,:-1] - 1
                    cond = cond[:,-cond_n:]
                    cond = np.repeat(cond,n_long_samples,axis = 0)

                    model1.v0 = new_v0
                else:
                    cond = None

        long_mg_paths = MG.generate_longer_paths(n_long_samples, length = real_n, cond = cond, save = False,
                                                 std = 1, mean = 0, real_decoder = real_decoder)

        MG.plot_generated_paths(100, cond[:100,:] if cond_n > 0 else None, real_n)

        model1.reset_model(20000)
        for i in range(real_n):
            model1.evolve_s_b()
        long_model_paths = model1.spot_hist[:,0,:]

        pc_long = PathComparator(long_model_paths,long_mg_paths,T)
        pc_long.run_comparrison()

        if BS is False:
            model1.v0 = v0


import sys

text = list(sys.stdin.readline().rstrip())

cnt = 0

for i,t in enumerate(text):
    if i == 0:
        if t != " ":
            cnt += 1
    else:
        if t != " " and text[i-1] == " ":
            cnt += 1
print(cnt)


import collections
import functools
import itertools
import multiprocessing
import random

import numpy as np
import tensorflow as tf
from absl import flags

from libml import utils, ctaugment
from libml.utils import EasyDict
from third_party.auto_augment import augmentations, policies

FLAGS = flags.FLAGS
POOL = None
POLICIES = EasyDict(cifar10=policies.cifar10_policies(),
                    cifar100=policies.cifar10_policies(),
                    svhn=policies.svhn_policies(),
                    svhn_noextra=policies.svhn_policies())

RANDOM_POLICY_OPS = (
    'Identity', 'AutoContrast', 'Equalize', 'Rotate',
    'Solarize', 'Color', 'Contrast', 'Brightness',
    'Sharpness', 'ShearX', 'TranslateX', 'TranslateY',
    'Posterize', 'ShearY'
)
AUGMENT_ENUM = 'd x m aa aac ra rac'.split() + ['r%d_%d_%d' % (nops, mag, cutout) for nops, mag, cutout in
                                                itertools.product(range(1, 5), range(1, 16), range(0, 100, 25))] + [
                   'rac%d' % (mag) for mag in range(1, 10)]

flags.DEFINE_integer('K', 1, 'Number of strong augmentation for unlabeled data.')
flags.DEFINE_enum('augment', 'd.d',
                  [x + '.' + y for x, y in itertools.product(AUGMENT_ENUM, AUGMENT_ENUM)] +
                  [x + '.' + y + '.' + z for x, y, z in itertools.product(AUGMENT_ENUM, AUGMENT_ENUM, AUGMENT_ENUM)] + [
                      'd.d.d.d', 'd.aac.d.aac', 'd.rac.d.rac'],
                  'Dataset augmentation method (x=identity, m=mirror, d=default, aa=auto-augment, aac=auto-augment+cutout, '
                  'ra=rand-augment, rac=rand-augment+cutout; for rand-augment, magnitude is also randomized'
                  'rxyy=random augment with x ops and magnitude yy),'
                  'first is for labeled data, others are for unlabeled.')

def init_pool():
    global POOL
    if POOL is None:
        para = max(1, len(utils.get_available_gpus())) * FLAGS.para_augment
        POOL = multiprocessing.Pool(para)

def augment_mirror(x):
    return tf.image.random_flip_left_right(x)

def augment_shift(x, w):
    y = tf.pad(x, [[w] * 2, [w] * 2, [0] * 2], mode='REFLECT')
    return tf.random_crop(y, tf.shape(x))

def augment_noise(x, std):
    return x + std * tf.random_normal(tf.shape(x), dtype=x.dtype)

def numpy_apply_policy(x, policy):
    return augmentations.apply_policy(policy, x).astype('f')

def stack_augment(augment: list):
    def func(x):
        xl = [augment[i](x) if augment[i] is not None else x for i in range(len(augment))]
        return {k: tf.stack([x[k] for x in xl]) for k in xl[0].keys()}

    return func

class Primitives:
    @staticmethod
    def m():
        return lambda x: augment_mirror(x['image'])

    @staticmethod
    def ms(shift):
        return lambda x: augment_shift(augment_mirror(x['image']), shift)

    @staticmethod
    def s(shift):
        return lambda x: augment_shift(x['image'], shift)

AugmentPair = collections.namedtuple('AugmentPair', 'tf numpy')
PoolEntry = collections.namedtuple('PoolEntry', 'payload batch')

class AugmentPool:
    def __init__(self, get_samples):
        self.get_samples = get_samples

    def __call__(self, *args, **kwargs):
        return self.get_samples()

NOAUGMENT = AugmentPair(tf=lambda x: dict(image=x['image'], label=x['label'], index=x.get('index', -1)),
                        numpy=AugmentPool)

class AugmentPoolAA(AugmentPool):

    def __init__(self, get_samples, policy_group):
        init_pool()
        self.get_samples = get_samples
        self.policy_group = policy_group
        self.queue = []
        self.fill_queue()

    @staticmethod
    def numpy_apply_policies(arglist):
        x, policies = arglist
        return np.stack([augmentations.apply_policy(policy, y) for y, policy in zip(x, policies)]).astype('f')

    def queue_images(self, batch):
        args = []
        image = batch['image']
        if image.ndim == 4:
            for x in range(image.shape[0]):
                args.append((image[x:x + 1], [random.choice(POLICIES[self.policy_group])]))
        else:
            for x in image[:, 1:]:
                args.append((x, [random.choice(POLICIES[self.policy_group]) for _ in range(x.shape[0])]))
        self.queue.append(PoolEntry(payload=POOL.imap(self.numpy_apply_policies, args), batch=batch))

    def fill_queue(self):
        for _ in range(4):
            self.queue_images(self.get_samples())

    def __call__(self, *args, **kwargs):
        del args, kwargs
        batch = self.get_samples()
        entry = self.queue.pop(0)
        samples = np.stack(list(entry.payload))
        if entry.batch['image'].ndim == 4:
            samples = samples.reshape(entry.batch['image'].shape)
            entry.batch['image'] = samples
        else:
            samples = samples.reshape(entry.batch['image'][:, 1:].shape)
            entry.batch['image'][:, 1:] = samples
        self.queue_images(batch)
        return entry.batch

class AugmentPoolAAC(AugmentPoolAA):

    def __init__(self, get_samples, policy_group):
        init_pool()
        self.get_samples = get_samples
        self.policy_group = policy_group
        self.queue = []
        self.fill_queue()

    @staticmethod
    def numpy_apply_policies(arglist):
        x, policies = arglist
        return np.stack([augmentations.cutout_numpy(augmentations.apply_policy(policy, y)) for y, policy in
                         zip(x, policies)]).astype('f')

class AugmentPoolRAM(AugmentPoolAA):
    # Randomized magnitude
    def __init__(self, get_samples, nops=2, magnitude=10):
        init_pool()
        self.get_samples = get_samples
        self.nops = nops
        self.magnitude = magnitude
        self.queue = []
        self.fill_queue()

    @staticmethod
    def numpy_apply_policies(arglist):
        x, policies = arglist
        return np.stack([augmentations.apply_policy(policy, y) for y, policy in zip(x, policies)]).astype('f')

    def queue_images(self, batch):
        args = []
        image = batch['image']
        policy = lambda: [(op, 0.5, np.random.randint(1, self.magnitude))
                          for op in np.random.choice(RANDOM_POLICY_OPS, self.nops)]
        if image.ndim == 4:
            for x in range(image.shape[0]):
                args.append((image[x:x + 1], [policy()]))
        else:
            for x in image[:, 1:]:
                args.append((x, [policy() for _ in range(x.shape[0])]))
        self.queue.append(PoolEntry(payload=POOL.imap(self.numpy_apply_policies, args), batch=batch))

class AugmentPoolRAMC(AugmentPoolRAM):
    # Randomized magnitude (inherited from queue images)
    def __init__(self, get_samples, nops=2, magnitude=10):
        init_pool()
        self.get_samples = get_samples
        self.nops = nops
        self.magnitude = magnitude
        self.queue = []
        self.fill_queue()

    @staticmethod
    def numpy_apply_policies(arglist):
        x, policies = arglist
        return np.stack([augmentations.cutout_numpy(augmentations.apply_policy(policy, y)) for y, policy in
                         zip(x, policies)]).astype('f')

class AugmentPoolRAMC2(AugmentPoolRAM):
    # Randomized magnitude (inherited from queue images)
    def __init__(self, get_samples, nops=2, magnitude=10):
        init_pool()
        self.get_samples = get_samples
        self.nops = nops
        self.magnitude = magnitude
        self.queue = []
        self.fill_queue()

    @staticmethod
    def numpy_apply_policies(arglist):
        x, policies = arglist
        return np.stack([augmentations.cutout_numpy(augmentations.apply_policy(policy, y)) for y, policy in
                         zip(x, policies)]).astype('f')

    def queue_images(self, batch):
        args = []
        image = batch['image']
        policy = lambda: [(op, 0.5, np.random.randint(1, self.magnitude))
                          for op in np.random.choice(RANDOM_POLICY_OPS, self.nops)]
        if image.ndim == 4:
            for x in range(image.shape[0]):
                args.append((image[x:x + 1], [policy()]))
        else:
            for x in image[:, :]:
                args.append((x, [policy() for _ in range(x.shape[0])]))
        self.queue.append(PoolEntry(payload=POOL.imap(self.numpy_apply_policies, args), batch=batch))

    def __call__(self, *args, **kwargs):
        del args, kwargs
        batch = self.get_samples()
        entry = self.queue.pop(0)
        samples = np.stack(list(entry.payload))
        if entry.batch['image'].ndim == 4:
            samples = samples.reshape(entry.batch['image'].shape)
            entry.batch['image'] = samples
        else:
            samples = samples.reshape(entry.batch['image'][:, :].shape)
            entry.batch['image'][:, :] = samples
        self.queue_images(batch)
        return entry.batch

class AugmentPoolRA(AugmentPoolAA):
    def __init__(self, get_samples, nops, magnitude, cutout):
        init_pool()
        self.get_samples = get_samples
        self.nops = nops
        self.magnitude = magnitude
        self.size = cutout
        self.queue = []
        self.fill_queue()

    @staticmethod
    def numpy_apply_policies(arglist):
        x, policies, cutout = arglist
        return np.stack([augmentations.cutout_numpy(augmentations.apply_policy(policy, y),
                                                    size=int(0.01 * cutout * min(y.shape[:2])))
                         for y, policy in zip(x, policies)]).astype('f')

    def queue_images(self, batch):
        args = []
        image = batch['image']
        # Fixed magnitude
        policy = lambda: [(op, 1.0, self.magnitude) for op in np.random.choice(RANDOM_POLICY_OPS, self.nops)]
        if image.ndim == 4:
            for x in range(image.shape[0]):
                args.append((image[x:x + 1], [policy()], self.size))
        else:
            for x in image[:, 1:]:
                args.append((x, [policy() for _ in range(x.shape[0])], self.size))
        self.queue.append(PoolEntry(payload=POOL.imap(self.numpy_apply_policies, args), batch=batch))

class AugmentPoolCTA(AugmentPool):

    def __init__(self, get_samples):
        init_pool()
        self.get_samples = get_samples
        self.queue = []
        self.fill_queue()

    @staticmethod
    def numpy_apply_policies(arglist):
        x, cta, probe = arglist
        if x.ndim == 3:
            assert probe
            policy = cta.policy(probe=True)
            return dict(policy=policy,
                        probe=ctaugment.apply(x, policy),
                        image=ctaugment.apply(x, cta.policy(probe=False)))
        assert not probe
        return dict(image=np.stack([x[0]] + [ctaugment.apply(y, cta.policy(probe=False)) for y in x[1:]]).astype('f'))

    def queue_images(self):
        batch = self.get_samples()
        args = [(x, batch['cta'], batch['probe']) for x in batch['image']]
        self.queue.append(PoolEntry(payload=POOL.imap(self.numpy_apply_policies, args), batch=batch))

    def fill_queue(self):
        for _ in range(4):
            self.queue_images()

    def __call__(self, *args, **kwargs):
        del args, kwargs
        entry = self.queue.pop(0)
        samples = list(entry.payload)
        entry.batch['image'] = np.stack(x['image'] for x in samples)
        if 'probe' in samples[0]:
            entry.batch['probe'] = np.stack(x['probe'] for x in samples)
            entry.batch['policy'] = [x['policy'] for x in samples]
        self.queue_images()
        return entry.batch

DEFAULT_AUGMENT = EasyDict(
    cifar10=AugmentPair(tf=lambda x: dict(image=Primitives.ms(4)(x), label=x['label'], index=x.get('index', -1)),
                        numpy=AugmentPool),
    cifar100=AugmentPair(tf=lambda x: dict(image=Primitives.ms(4)(x), label=x['label'], index=x.get('index', -1)),
                         numpy=AugmentPool),
    fashion_mnist=AugmentPair(tf=lambda x: dict(image=Primitives.ms(4)(x), label=x['label'], index=x.get('index', -1)),
                              numpy=AugmentPool),
    stl10=AugmentPair(tf=lambda x: dict(image=Primitives.ms(12)(x), label=x['label'], index=x.get('index', -1)),
                      numpy=AugmentPool),
    svhn=AugmentPair(tf=lambda x: dict(image=Primitives.s(4)(x), label=x['label'], index=x.get('index', -1)),
                     numpy=AugmentPool),
    svhn_noextra=AugmentPair(tf=lambda x: dict(image=Primitives.s(4)(x), label=x['label'], index=x.get('index', -1)),
                             numpy=AugmentPool),
)
AUTO_AUGMENT = EasyDict({
    k: AugmentPair(tf=v.tf, numpy=functools.partial(AugmentPoolAA, policy_group=k))
    for k, v in DEFAULT_AUGMENT.items()
})
AUTO_AUGMENT_CUTOUT = EasyDict({
    k: AugmentPair(tf=v.tf, numpy=functools.partial(AugmentPoolAAC, policy_group=k))
    for k, v in DEFAULT_AUGMENT.items()
})
RAND_AUGMENT = EasyDict({
    k: AugmentPair(tf=v.tf, numpy=functools.partial(AugmentPoolRAM, nops=2, magnitude=10))
    for k, v in DEFAULT_AUGMENT.items()
})
RAND_AUGMENT_CUTOUT = EasyDict({
    k: AugmentPair(tf=v.tf, numpy=functools.partial(AugmentPoolRAMC, nops=2, magnitude=10))
    for k, v in DEFAULT_AUGMENT.items()
})

def get_augmentation(dataset: str, augmentation: str):
    if augmentation == 'x':
        return NOAUGMENT
    elif augmentation == 'm':
        return AugmentPair(tf=lambda x: dict(image=Primitives.m()(x), label=x['label'], index=x.get('index', -1)),
                           numpy=AugmentPool)
    elif augmentation == 'd':
        return DEFAULT_AUGMENT[dataset]
    elif augmentation == 'aa':
        return AUTO_AUGMENT[dataset]
    elif augmentation == 'aac':
        return AUTO_AUGMENT_CUTOUT[dataset]
    elif augmentation == 'ra':
        return RAND_AUGMENT[dataset]
    elif augmentation.startswith('rac'):
        mag = 10 if augmentation == 'rac' else int(augmentation[-1])
        return AugmentPair(tf=DEFAULT_AUGMENT[dataset].tf,
                           numpy=functools.partial(AugmentPoolRAMC, nops=2, magnitude=mag))
    elif augmentation[0] == 'r':
        nops, mag, cutout = (int(x) for x in augmentation[1:].split('_'))
        return AugmentPair(tf=DEFAULT_AUGMENT[dataset].tf,
                           numpy=functools.partial(AugmentPoolRA, nops=nops, magnitude=mag, cutout=cutout))
    else:
        raise NotImplementedError(augmentation)

def augment_function(dataset: str):
    augmentations = FLAGS.augment.split('.')
    assert len(augmentations) == 2
    return [get_augmentation(dataset, x) for x in augmentations]

def pair_augment_function(dataset: str):
    augmentations = FLAGS.augment.split('.')
    assert len(augmentations) == 3
    unlabeled = [get_augmentation(dataset, x) for x in augmentations[1:]]
    return [get_augmentation(dataset, augmentations[0]),
            AugmentPair(tf=stack_augment([x.tf for x in unlabeled]), numpy=unlabeled[-1].numpy)]

def quad_augment_function(dataset: str):
    augmentations = FLAGS.augment.split('.')
    assert len(augmentations) == 4
    labeled = [get_augmentation(dataset, x) for x in augmentations[:2]]
    unlabeled = [get_augmentation(dataset, x) for x in augmentations[2:]]
    return [AugmentPair(tf=stack_augment([x.tf for x in labeled]), numpy=labeled[-1].numpy),
            AugmentPair(tf=stack_augment([x.tf for x in unlabeled]), numpy=unlabeled[-1].numpy)]

def many_augment_function(dataset: str):
    augmentations = FLAGS.augment.split('.')
    assert len(augmentations) == 3
    unlabeled = [get_augmentation(dataset, x) for x in (augmentations[1:2] + augmentations[2:] * FLAGS.K)]
    return [get_augmentation(dataset, augmentations[0]),
            AugmentPair(tf=stack_augment([x.tf for x in unlabeled]), numpy=unlabeled[-1].numpy)]


#For fast I/O
import sys
input = lambda: sys.stdin.readline().strip()

'''Idea
An operation is basically taking 2 adjacent distinct digits
and deleting the left of them.

Therefore, a binary string is paranoid iff it's last 2 digits
are distinct. (?)

Yeh reduce to either 010101... then finish it off
'''

for Homu in range(int(input())):
    n = int(input())
    s = input()

    ans = n   #Count strings of length 1
    for i in range(1,n):   #Substring ends at index i
        if s[i] != s[i-1]:
            ans += i

    print(ans)


import os
import sys

from flask import Flask, jsonify, request, abort, send_file
from dotenv import load_dotenv
from linebot import LineBotApi, WebhookParser
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage, TemplateSendMessage, ButtonsTemplate, MessageAction

from fsm import TocMachine
from utils import send_text_message

# Let Flask set the environment variable depending on .env file.
load_dotenv()

machine_list = []
count_machine = 0
user_list = []

def create_new_machine():

    # Create a machine instance with the states configured.
    machine = TocMachine(
        states=["start_state", "state_for_menu", "state_for_homework_management", "state_for_exam_management", "state_for_reminder_management",
            "state_for_add_homework", "state_for_delete_homework", "state_for_examine_homework", "state_for_add_exam", "state_for_delete_exam", "state_for_examine_exam",
            "state_for_add_reminder", "state_for_delete_reminder", "state_for_examine_reminder"],
        transitions=[
            {
                # "Initial state" to "selection state".
                "trigger": "go_to_menu",
                "source": "start_state",
                "dest": "state_for_menu",
            },
            {
                # "selection state" to "homework management state".
                "trigger": "go_to_homework_management",
                "source": "state_for_menu",
                "dest": "state_for_homework_management",
            },
            {
                # "selection state" to "exam management state".
                "trigger": "go_to_exam_management",
                "source": "state_for_menu",
                "dest": "state_for_exam_management",
            },
            {
                # "selection state" to "reminder management state".
                "trigger": "go_to_reminder_management",
                "source": "state_for_menu",
                "dest": "state_for_reminder_management",
            },
            {
                # "homework management state" to "add homework state".
                "trigger": "go_to_add_homework",
                "source": "state_for_homework_management",
                "dest": "state_for_add_homework",
            },
            {
                # "homework management state" to "examine homework state".
                "trigger": "go_to_examine_homework",
                "source": "state_for_homework_management",
                "dest": "state_for_examine_homework",
            },
            {
                # "homework management state" to "delete homework state".
                "trigger": "go_to_delete_homework",
                "source": "state_for_homework_management",
                "dest": "state_for_delete_homework",
            },
            {
                # "exam management state" to "add exam state".
                "trigger": "go_to_add_exam",
                "source": "state_for_exam_management",
                "dest": "state_for_add_exam",
            },
            {
                # "exam management state" to "examine exam state".
                "trigger": "go_to_examine_exam",
                "source": "state_for_exam_management",
                "dest": "state_for_examine_exam",
            },
            {
                # "exam management state" to "delete exam state".
                "trigger": "go_to_delete_exam",
                "source": "state_for_exam_management",
                "dest": "state_for_delete_exam",
            },
            {
                # "reminder management state" to "add reminder state".
                "trigger": "go_to_add_reminder",
                "source": "state_for_reminder_management",
                "dest": "state_for_add_reminder",
            },
            {
                # "reminder management state" to "examine reminder state".
                "trigger": "go_to_examine_reminder",
                "source": "state_for_reminder_management",
                "dest": "state_for_examine_reminder",
            },
            {
                # "reminder management state" to "delete reminder state".
                "trigger": "go_to_delete_reminder",
                "source": "state_for_reminder_management",
                "dest": "state_for_delete_reminder",
            },
            {
                # Back to "homework management state".
                "trigger": "go_back_to_homework_management",
                "source": ["state_for_add_homework", "state_for_examine_homework", "state_for_delete_homework"],
                "dest": "state_for_homework_management",
            },
            {
                # Back to "exam management state".
                "trigger": "go_back_to_exam_management",
                "source": ["state_for_add_exam", "state_for_examine_exam", "state_for_delete_exam"],
                "dest": "state_for_exam_management",
            },
            {
                # Back to "reminder management state".
                "trigger": "go_back_to_reminder_management",
                "source": ["state_for_add_reminder", "state_for_examine_reminder", "state_for_delete_reminder"],
                "dest": "state_for_reminder_management",
            },
            {
                # Back to "state_for_menu".
                "trigger": "go_back_to_menu",
                "source": ["state_for_homework_management", "state_for_exam_management", "state_for_reminder_management", "state_for_add_homework",
                        "state_for_examine_homework", "state_for_delete_homework", "state_for_add_exam", "state_for_examine_exam", "state_for_delete_exam",
                        "state_for_add_reminder", "state_for_examine_reminder", "state_for_delete_reminder"],
                "dest": "state_for_menu"
            },
            {
                # Back to "initial state".
                "trigger": "go_back",
                "source": ["state_for_menu", "state_for_homework_management", "state_for_exam_management", "state_for_reminder_management", "state_for_add_homework",
                        "state_for_examine_homework", "state_for_delete_homework", "state_for_add_exam", "state_for_examine_exam", "state_for_delete_exam",
                        "state_for_add_reminder", "state_for_examine_reminder", "state_for_delete_reminder"],
                "dest": "start_state"
            },
        ],
        initial="start_state",
        auto_transitions=False,
        show_conditions=True,
    )

    # Add new machine to machine list.
    global machine_list
    machine_list.append(machine)
    global count_machine
    count_machine = count_machine + 1

# Use Flask to create a web application.
app = Flask(__name__, static_url_path="")

# get channel_secret and channel_access_token from your environment variable
channel_secret = os.getenv("LINE_CHANNEL_SECRET", None)
channel_access_token = os.getenv("LINE_CHANNEL_ACCESS_TOKEN", None)
if channel_secret is None:
    print("Specify LINE_CHANNEL_SECRET as environment variable.")
    sys.exit(1)
if channel_access_token is None:
    print("Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.")
    sys.exit(1)

# Create a LineBotApi instance.
line_bot_api = LineBotApi(channel_access_token)
parser = WebhookParser(channel_secret)

#***************************************************************************************

# Bind url "webhook" to this function.
@app.route("/webhook", methods=["POST"])
def webhook_handler():
    # Get the signature.
    signature = request.headers["X-Line-Signature"]

    # Get request body as text.
    body = request.get_data(as_text=True)
    app.logger.info(f"Request body: {body}")

    # Parse webhook body.
    try:
        events = parser.parse(body, signature)
    except InvalidSignatureError:
        abort(400)

    # If event is MessageEvent and message is TextMessage, then echo text.
    for event in events:
        if not isinstance(event, MessageEvent):
            continue
        if not isinstance(event.message, TextMessage):
            continue
        if not isinstance(event.message.text, str):
            continue

        #print(f"\nFSM STATE: {machine.state}")
        print(f"REQUEST BODY: \n{body}")

        # Check whether the user is registered.
        global user_list
        is_user_found = False
        user_index = (-1)
        for index in range(len(user_list)):
            if user_list[index] == event.source.user_id:
                is_user_found = True
                user_index = index

        # Add a new machine or not.
        if is_user_found == False:
            user_list.append(event.source.user_id)
            create_new_machine();

        # Set index for this user.
        global count_machine
        if is_user_found == False:
            user_index = count_machine - 1;

        # Check whether the event results in state transition.
        if event.message.text.lower() == "reset":
            machine_list[user_index].reset_states(event)
        elif machine_list[user_index].state == "start_state":
            machine_list[user_index].check_user_start(event)
        elif machine_list[user_index].state == "state_for_menu":
            machine_list[user_index].check_state_for_operation_menu(event)
        elif machine_list[user_index].state == "state_for_homework_management":
            machine_list[user_index].check_state_for_homework_operation(event)
        elif machine_list[user_index].state == "state_for_exam_management":
            machine_list[user_index].check_state_for_exam_operation(event)
        elif machine_list[user_index].state == "state_for_reminder_management":
            machine_list[user_index].check_state_for_reminder_operation(event)
        elif machine_list[user_index].state == "state_for_add_homework":
            machine_list[user_index].add_homework(event)
        elif machine_list[user_index].state == "state_for_add_exam":
            machine_list[user_index].add_exam(event)
        elif machine_list[user_index].state == "state_for_add_reminder":
            machine_list[user_index].add_reminder(event)
        elif machine_list[user_index].state == "state_for_examine_homework":
            machine_list[user_index].examine_homework(event)
        elif machine_list[user_index].state == "state_for_examine_exam":
            machine_list[user_index].examine_exam(event)
        elif machine_list[user_index].state == "state_for_examine_reminder":
            machine_list[user_index].examine_reminder(event)
        elif machine_list[user_index].state == "state_for_delete_homework":
            machine_list[user_index].delete_homework(event)
        elif machine_list[user_index].state == "state_for_delete_exam":
            machine_list[user_index].delete_exam(event)
        elif machine_list[user_index].state == "state_for_delete_reminder":
            machine_list[user_index].delete_reminder(event)

    return "OK"

#***************************************************************************************

# Bind url "show-fsm" to this function.
@app.route("/show-fsm", methods=["GET"])
def show_fsm():
    machine.get_graph().draw("fsm.png", prog="dot", format="png")
    return send_file("fsm.png", mimetype="image/png")

# If the script is executed positively instead of called by other script, run following code.
if __name__ == "__main__":
    port = os.environ.get("PORT", 8000)
    app.run(host="0.0.0.0", port=port, debug=True)


#!/usr/bin/env python
# -*- coding: UTF-8 -*-
__author__ = "NeMuX"
__copyright__ = "Copyright 2014"
__credits__ = ["NeMuX"]
__license__ = "GPL"
__version__ = "0.1"
__maintainer__ = "NeMuX"
__email__ = "jaraujo@globalcybersec.com"
__status__ = "Development"

import sys
import csv
import sqlite3

def cargar_vulnerabilidades(file,db='info/vulnerabilidades.db'):

    conn = sqlite3.connect(db)
    c = conn.cursor()

    conn.text_factory = "str"

    # Creamos la tabla

    c.execute('''CREATE TABLE IF NOT EXISTS vulnerabilidades
             (id INTEGER PRIMARY KEY AUTOINCREMENT, nessus_id INTEGER, qualys_id TEXT, acunetix_id TEXT,
              nombre_vulnerabilidad TEXT,descripcion TEXT, solucion TEXT, workaround TEXT,
              categoria TEXT, efecto TEXT, prioridad TEXT, cvss TEXT, plataforma TEXT,
              subplataforma TEXT, cve TEXT, referencias TEXT, exploit TEXT, estado TEXT,
              patrones TEXT, revisada NUMERIC, severidad NUMERIC)''')

    cvs_file = open(file)
    reader = csv.reader(cvs_file)

    rownum = 0
    colnum = 0

    for r in reader:
        #ignoramos el encabezado
        if rownum == 0:
            colnum = len(r)
            rownum = rownum + 1

        else:
            #Formamos la cadena del INSERT

            #query = "INSERT INTO vulnerabilidades (nessus_id, qualys_id, acunetix_id, nombre_vulnerabilidad, descripcion, solucion, workaround, " \
            #        "categoria, efecto, prioridad, cvss, plataforma, subplataforma, cve, referencias, exploit, estado, patrones, revisada) " \
            #        "VALUES (" + r[1] + ",\"" + r[3] + "\", \"" + r[4] + "\", \"" + r[6] + "\", \"" + r[7] + "\", \"" + r[8] + "\", \"" + r[9] \
            #        + "\", \"" + r[10] + "\", \"" + r[11] + "\", \"" + r[12] + "\", \"" + r[13] + "\", \"" + r[14] + "\", \"" + r[15] + "\", \"" + \
            #        r[16] + "\", \"" + r[17] + "\", \"" + r[18] + "\", \"" + r[19] + "\", \"" + r[20] + "\", \"" + r[21] + "\")"
            #print(query)
            #c.execute(query)

            #data = (r[1],r[3],r[4],r[6],r[7],r[8],r[9],r[10],r[11],r[12],r[13],r[14],r[15],r[16],r[17],r[18],r[19],r[20],r[21],r[22])
            data = (r[0],r[1],r[2],r[3],r[4],r[5],r[6],r[7],r[8],r[9],r[10],r[11],r[12],r[13],r[14],r[15],r[16],r[17],r[18],r[19])
            #print(str(data) + "\n")
            c.execute('''INSERT INTO vulnerabilidades (nessus_id, qualys_id, acunetix_id, nombre_vulnerabilidad, descripcion, solucion, workaround,
            categoria, efecto, prioridad, cvss, plataforma, subplataforma, cve, referencias, exploit, estado, patrones, revisada, severidad)
            VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''',data)
            rownum = rownum + 1
    conn.commit()
    c.close()
    conn.close()
    print(str(rownum-1) + " Registros insertados...")

if __name__ == "__main__":
    if len(sys.argv)  > 1 :
        print("Procesando " + str(len(sys.argv) -1) + " archivos")
        for file in sys.argv[1:]:
            print("Cargando archivo -> " + file)
            cargar_vulnerabilidades(file)
        print("Hecho.")
    else:
        print(sys.argv[0] + ": falta un archivo como argumento" )


"""Racemate URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, re_path, include
from rest_framework import routers
from rest_framework.schemas import get_schema_view

from api.views import MyUserViewSet, RunningGroupViewSet, PastTrainingViewSet
from calc.views import CalculatorView
from group.views import RunningGroupView, MemberView, CreateGroupView, ShowGroupsView, JoinGroupView, JoinConfirmView, \
    AdminConfirmView, AdminView, ShowAdminView
from messanger.views import ForumView, ForumChoiceView, SendMessageView, SendMessageGroupView, MessangerView, \
    MessangerAllView
from racemate.views import (LogoutView, LoginView, LandingView, LandingGeneratorView,
                            RegisterView, customhandler404, customhandler500, EditUserView, ContactView, AboutView)
from training.views import AddTrainingView, AddTreningView, TreningPlanWhiteView, TreningPlan18weeksView, \
    LoadTreningView, PlanChoiceView, DeleteTrainingView, PastTrainingDelete

from django.conf import settings
from django.conf.urls.static import static

router = routers.DefaultRouter()

router.register(r'users', MyUserViewSet)
router.register(r'groups', RunningGroupViewSet)
router.register(r'pasttrainings', PastTrainingViewSet)

schema_view = get_schema_view(title='Racemate API')

handler404 = customhandler404
handler500 = customhandler500

urlpatterns = [

    # racemate
    path('admin/', admin.site.urls),
    path('accounts/login/', LoginView.as_view(), name="login"),
    path('logout/', LogoutView.as_view(), name='logout'),
    path('register/', RegisterView.as_view(), name='register'),
    path('', LandingView.as_view(), name='landing-page'),
    re_path(r'start/(?P<id>(\d)+)/$', LandingGeneratorView.as_view(), name='generate_vdot'),
    path('edituser/', EditUserView.as_view(), name='edituser'),
    path('contact/', ContactView.as_view(), name='contact'),
    path('about/', AboutView.as_view(), name='about'),

    # group
    re_path(r'running_group/(?P<id>(\d)+)/$', RunningGroupView.as_view(), name='running-group'),
    re_path(r'member/(?P<id>(\d)+)/$', MemberView.as_view(), name='member'),
    path('creategroup/', CreateGroupView.as_view(), name='create-group'),
    path('showgroups/', ShowGroupsView.as_view(), name='show-groups'),
    path('joingroup/', JoinGroupView.as_view(), name='join-group'),
    re_path(r'joingroupconfirm/(?P<id>(\d)+)/$', JoinConfirmView.as_view(), name='join-group-confirm'),
    re_path(r'adminconfirm/(?P<id>(\d)+)/(?P<sender>(\d)+)$', AdminConfirmView.as_view(), name='adminconfirm'),
    re_path(r'adminview/(?P<id>(\d)+)$', AdminView.as_view(), name='adminview'),
    path('showadmin/', ShowAdminView.as_view(), name='showadmin'),

    # messanger
    re_path(r'forum/(?P<id>(\d)+)/$', ForumView.as_view(), name='forum'),
    path('forumchoice', ForumChoiceView.as_view(), name='forum-choice'),
    path('send_message/', SendMessageView.as_view(), name='sendmessage'),
    path('send_message_group', SendMessageGroupView.as_view(), name='sendmessagegroup'),
    re_path(r'^messanger/(?P<id>(\d)+)/$', MessangerView.as_view(), name='messanger'),
    # path('messangerall/', MessangerAllView.as_view(), name='messanger_all'),

    # training
    path('add_training/', AddTrainingView.as_view(), name='addtraining'),
    path('add_plan/', AddTreningView.as_view(), name='addplan'),  # nie zrobione
    path('treningplan_white/', TreningPlanWhiteView.as_view(), name='whiteplan'),
    path('treningplan_18weeks/', TreningPlan18weeksView.as_view(), name='18weeksplan'),
    path('loadtrening/', LoadTreningView.as_view(), name='loadtrening'),
    path('planchoice/', PlanChoiceView.as_view(), name='planchoice'),
    re_path(r'^deletetraining/(?P<id>(\d)+)/$', DeleteTrainingView.as_view(), name='deletetraining'),
    re_path(r'^(?P<pk>\d+)/delete/$', PastTrainingDelete.as_view(), name='delete'),

    # calc
    path('calculator/', CalculatorView.as_view(), name='calculator'),

    # api

    re_path(r'^api/v1/', include(router.urls), name='API'),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('schema/', schema_view),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# urlpatterns = format_suffix_patterns(urlpatterns)


from django.contrib import messages
from django.contrib.auth import logout
from django.http import HttpResponseRedirect

from apps.core.defs import is_valid_user
from bluedata.helpers import reverse_url

# Seta o contexto do List
#
def set_context_list(context, self):
    # Variables
    url = self.base_url
    title = self.template_title

    # Set menu on session
    self.request.session['menu'] = self.access['menu']
    self.request.session['item'] = self.access['item']

    # Templates
    context['template'] = 'keen.html'
    context['template_title'] = title
    context['template_subtitle'] = 'listar'
    context['template_url_clear'] = reverse_url('{}_list'.format(url))
    context['template_url_update'] = '{}_update'.format(url)
    context['template_table_head'] = 'bluedata_interface/template_table_head.html'
    context['template_table_row'] = 'bluedata_interface/template_table_row.html'

    btn_add = set_button('Adicionar', reverse_url('{}_create'.format(url)), 'btn-primary', 'la la-plus')
    context['template_buttons'] = [btn_add]

# Seta o contexto do Create
#
def set_context_create(context, self):
    # Variables
    url = self.base_url
    title = self.template_title

    # Set session and menu
    self.request.session['menu'] = self.access['menu']
    self.request.session['item'] = self.access['item']

    # Templates
    context['template'] = 'keen.html'
    context['template_title'] = title
    context['template_subtitle'] = 'adicionar'
    context['template_form_fields'] = 'bluedata_interface/template_form_render.html'
    context['template_btn_save'] = True
    context['template_scripts'] = None

    btn_back = set_button('Voltar', reverse_url('{}_list'.format(url)), 'btn-outline-secondary', 'la la-angle-left')
    context['template_buttons'] = [btn_back]

# Seta o contexto do Update
#
def set_context_update(context, self):
    # Variables
    url = self.base_url
    title = self.template_title

    # Set session and menu
    self.request.session['menu'] = self.access['menu']
    self.request.session['item'] = self.access['item']
    self.request.session['uuid'] = str(self.object.id)

    # Templates
    context['template'] = 'keen.html'
    context['template_title'] = title
    context['template_subtitle'] = 'alterar'
    context['template_url_delete'] = reverse_url('{}_delete'.format(url), [str(self.object.id)])
    context['template_url_active'] = reverse_url('{}_active'.format(url), [str(self.object.id)])
    context['template_form_fields'] = 'bluedata_interface/template_form_render.html'
    context['template_btn_save'] = True
    context['template_scripts'] = None

    btn_back = set_button('Voltar', reverse_url('{}_list'.format(url)), 'btn-outline-secondary', 'la la-angle-left')
    context['template_buttons'] = [btn_back]

# Seta o contexto do Delete
#
def set_context_delete(context, self):
    # Variables
    url = self.base_url
    title = self.template_title

    # Set session and menu
    self.request.session['menu'] = self.access['menu']
    self.request.session['item'] = self.access['item']

    # Templates
    context['template'] = 'keen.html'
    context['template_title'] = title
    context['template_subtitle'] = 'excluir'

    btn_back = set_button('Voltar', reverse_url('{}_update'.format(url), [str(self.object.id)]), 'btn-outline-secondary', 'la la-angle-left')
    context['template_buttons'] = [btn_back]

# Metodo get da BaseActiveView
#
def get_base_active_view(self, kwargs):
    # Set session and menu
    self.request.session['menu'] = self.access['menu']
    self.request.session['item'] = self.access['item']

    # Check permission
    if not is_valid_user(self.request.user, self.access):
        logout(self.request)
        return HttpResponseRedirect(reverse_url('account_login'))

    msg = toggle_active(self.model.objects.get(id=kwargs['pk']))
    set_message(self, msg)
    return HttpResponseRedirect(reverse_url('{}_list'.format(self.base_url)))

# Dado um modelo modifica o status is_active
#
def toggle_active(modelo):
    if modelo.is_active:
        modelo.is_active = False
        msg = 'Registro alterado para inativo'
    else:
        modelo.is_active = True
        msg = 'Registro alterado para ativo'
    modelo.save()
    return msg

# Seta a mensagem para o template
#
def set_message(self, msg):
    messages.add_message(self.request, messages.SUCCESS, msg)

# Seta um botão para o template
#
def set_button(title, url, color, icon):
    return {'title': title, 'url': url, 'color': color, 'icon': icon}


def count_specific_word(filename, word):
    """Counts the number of times a specific word appears in a file."""
    try:
        with open(filename, encoding='utf-8') as f:
            contents = f.read()
    except FileNotFoundError:
        print(f"The file {filename} either does not exist, or cannot be found.")
    else:
        # This converts all words to lowercase:
        contents_lowered = contents.lower()

        # This filters all the punctuation and non-letter characters out (except ' so conjugated words are countable):
        character_delete = '''!@#$%^&*()-_+`~<>?/=.,:;"|{}[]'''
        for character in character_delete:
            contents_lowered = contents_lowered.replace(character, '')

        # This adds each individual word to a list, then counts up how many times each word appears:
        # all_words = contents_lowered.split()
        # word_count = all_words.count(word)
        all_words = contents_lowered
        word_count = all_words.count(word)
        # This is necessary as ' is omitted from the character filter, so "'words'" and "words" are counted as the same:
        word_count += all_words.count("'" + word + "'")

        print(f"The file {filename} has {word_count} instances of the word '{word}'.")