"""An HTML outputter for Chordbook"""

from chordbook.output._base import CbkOutputter

class CbkHtmlOutputter(CbkOutputter):

    """An HTML outputter for Chordbook"""

    # FIXME - templating should be external
    # For now let's just put it here
    html_head = """
<!DOCTYPE html>

<meta charset="utf-8" />
<title>{{TITLE}}</title>

"""

    html_foot = """

"""

    def __init__(self, outputdir):
        CbkOutputter.__init__(self, outputdir)
        self.outputfilesuffix = "html"

    def replace_entities(self, chord):
        """Take a bar of chords, replace suitable HTML entities"""

        # replace '#' with &#x266f
        chord = chord.replace("#", "♯")
        # replace m7b5 with oslash
        chord = chord.replace("m7b5", "ø7")
        # replace 'b' with &#x266d
        chord = chord.replace("b", "♭")
        # replace 'maj7' with Δ
        chord = chord.replace("maj7", "Δ")
        # replace 'LR' with left repeat sign
        # Eat the trailing space so it doesn't get its own td
        # Add trailing   so it displays correctly
        chord = chord.replace("LR ", "𝄆 ")
        # replace 'RR' with right repeat sign
        chord = chord.replace("RR", "𝄇")
        # replace 'pause' with pause sign
        chord = chord.replace("pause", "𝄐")
        # replace '(+)' with coda sign
        chord = chord.replace("(+)", "&#x1d10c")

        return chord

    def make_tune(self, tune):
        """Format an individual tune"""
        html = "
\n"
        anchor = tune.name.replace(" ", "")
        html += "

"
        key = self.replace_entities(tune.key)
        if tune.transpose != "":
            key = self.replace_entities(tune.transpose) + " (orig " + key + ")"
        html += "
" + tune.name + \
                "
	" + tune.get_artist() + \
                " " + tune.time + " " + key + "	\n"
        html += "

"

        seen = {}
        for section in tune.structure:
            if section.title() in seen:
                html += "
" + section.title() + "
\n"
            else:
                html += "
" + section.title() + "
\n"
                html += "
\n"
                chunks = tune.chunk_section(tune.__getattribute__(section))
                for chunk in chunks:
                    html += "
"
                    chords = tune.process_section(chunk)
                    i = 0
                    for crds in chords:
                        # Replace plaintext with musical HTML equivalents
                        crds = self.replace_entities(crds)
                        # Each bar is a td, last bar has no | on right
                        if (i < len(chords) - 1):
                            html += ""
                        else:
                            html += ""
                        # Spread chords within bar out using another table
                        html += "

"
                        for crd in crds.split(" "):
                            # Inline annotations
                            crd = crd.replace("_", " ")
                            # replace [ and ] with div
                            crd = crd.replace("[", "
")
                            crd = crd.replace("]", "
")
                            html += "
" + crd + "
	"
                        html += "

"
                        # End of bar td
                        html += "	"
                        i += 1
                    html += "
"
                seen[section.title()] = True
                html += "
\n"

        html += "
\n

\n"

        return html

    def make_contents(self, book):
        """Make the contents part of the HTML output"""
        contents = book.get_contents()

        html = "
Contents
\n
"

        for title in contents:
            name, credit = title.split("-", 1)
            anchor = name.replace(" ", "")
            html += "
" + name.strip() + \
                    " - " + credit.strip() + "
\n"

        html += "
\n"

        html += "
\n

\n"

        return html

    def make_header(self, book):
        """Make the header part of the HTML output"""
        html = "
\n"
        html += "
" + book.band + "
\n"
        html += "
Version " + book.version + "
\n"

        return html

    def make_book(self, book):
        """Output HTML version of book data"""

        self.output = self.html_head

        self.output = self.output.replace("{{TITLE}}", book.band)

        self.output += self.make_header(book)

        self.output += self.make_contents(book)

        for tune in book.tunes:
            self.output += self.make_tune(tune)

        self.output += self.html_foot

        # Do actual output
        self.output_book(book.filename)


#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

import numpy as np
import torch
from torchvision import transforms, models
from PIL import Image
import matplotlib.pyplot as plt
import ipdb

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

class NST:

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def __init__(self, content_image, style_image):

        #major attributes
        self.content_image = content_image #the content_image which has the content that we want the new image to have
        self.style_image = style_image #the content_image that has the style that we want to
        self.artwork_image_size = 300 #set the size of the artwork image

        #vgg attributes
        self.content_layers = ['conv4_2'] #list of all the layers from the cnn that we want to get the content information from
        self.style_layers = ['conv1_1', 'conv2_1', 'conv3_1', 'conv4_1', 'conv5_1'] #list of all the layers from the cnn that we want to get the style layers from
        self.cnn_map = {'0' : 'conv1_1', '5' : 'conv2_1', '10': 'conv3_1', '19': 'conv4_1', '21': 'conv4_2', '28': 'conv5_1'} #map from conv name to element in vgg structure
        self.style_weights = {"conv1_1" : 0.2, "conv2_1" : 0.2, "conv3_1" : 0.2, "conv4_1" : 0.2, "conv5_1" : 0.2} #importance weighting for each layer in cnn style loss

        #algroithm attributes
        self.alpha_beta_ratio = 10e-3 #balance of weight of content to style
        self.alpha = 1 #weight of content loss in loss function
        self.beta = self.alpha/self.alpha_beta_ratio #weight of style loss in loss function
        self.learning_rate = 0.001 #rate at which the loss is updated according to gradient
        self.convergence_threshold = 10 #converge when error is less than this
        self.max_iterations = 500 #max iterations allowed by algorithm

        #plotting & debugging attributes
        self.debugging_messages = False #whether or not to print a message at each step in the process (for debugging)
        self.print_frequency = int(self.max_iterations/10) #after how many epochs we print update
        self.incremental_plot = False #save plot after print frequency
        self.artwork_name = 'artwork' #name of artwork that will be saved
        self.save = False #whether or not to save the result to disk

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def get_hardware_specs(self):

        """
        Ascertain whether there is a pytorch-usable GPU installed.
        """

        if torch.cuda.is_available():
            self.device = 'cuda'
            print('\n' + 'A GPU was detected.' + '\n')
        else:
            self.device = 'cpu'
            print('\n' + 'Warning - a GPU was not detected.' + '\n')

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def create_artwork(self):

        """
        Execute all methods necessary to style the content_image in the style of the style_image to produce artwork.
        """

        if self.debugging_messages:
            print('Starting ...')

        self.beta = self.alpha/self.alpha_beta_ratio #set beta in case it was updated

        self.get_hardware_specs() #test for gpu
        self.retrieve_vgg_network() #get vgg
        self.image_preprocessing() #prepare the images
        self.minimise_loss() #run algorithm
        self.convert_outputs() #convert from tensor to image
        self.save_plot(self.artwork, name = self.artwork_name, id = 'artwork', show = True) #save the result and save and show

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def convert_outputs(self):

        """
        Convert the outputs from tensor to image.
        """

        self.artwork = self.tensor_to_image(self.artwork, 'artwork')
        self.content = self.tensor_to_image(self.content_image, 'content_image')
        self.style_image = self.tensor_to_image(self.style_image, 'style_image')

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def retrieve_vgg_network(self):

        """
        Get the vgg trained model from pytorch.
        Set the requires_grad attribute to False to stop updates.
        """

        if self.debugging_messages:
            print('Now getting VGG network...')

        self.vgg = models.vgg19(pretrained = True).features
        for parameter in self.vgg.parameters():
            parameter.requires_grad = False
        self.vgg.to(self.device)

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def image_preprocessing(self):

        """
        Do some image pre-processing so that the methods can be run optimally.
        """

        if self.debugging_messages:
            print('Now transforming images...')

        process = transforms.Compose([transforms.Resize(self.artwork_image_size), transforms.ToTensor(), transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
        self.content_image = process(self.content_image).type(torch.FloatTensor).to(self.device)
        self.style_image = process(self.style_image).type(torch.FloatTensor).to(self.device)

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def tensor_to_image(self, tensor, id):

        """
        Take an image tensor and return a numpy array [0, 1] that can be plotted in matplotlib.
        Used only for debugging/validation purposes.
        Inverse normalize is used becuase otherwise the images come out too dark. Following mehtod
        from https://discuss.pytorch.org/t/simple-way-to-inverse-transform-normalization/4821
        """

        if self.debugging_messages:
            print('Converting tensor to image...')

        image = tensor.cpu().clone().detach().numpy().squeeze() #make numpy
        image = image.transpose(1,2,0) #rearrange
        image = image*np.array((0.5,0.5,0.5)) + np.array((0.5,0.5,0.5)) #scale values
        image = np.where(image > 1, 1, image)
        image = np.where(image < 0, 0, image)
        image = ((image - image.min())/(image.max() - image.min()) * 255).astype(np.uint8) #scale to 0-255
        return image

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def get_activation(self, tensor):

        """
        Using the cnn get the activation for a particular layer, for a particular input image, using a forward pass of the cnn.
        Used to calculate the content and style loss.

        params
        tensor: either the content or style image
        layers: which set of layers to look up (either content or style layers)

        returns
        feature_map: dict with activation of each layer that we are interested in.
        """

        if self.debugging_messages:
            print('Getting activation...')

        content_feature_maps = {}
        style_feature_maps = {}
        input_layer_values = tensor
        input_layer_values = input_layer_values.unsqueeze(0)
        for indx, cnn_layer in self.vgg._modules.items():
            input_layer_values = cnn_layer(input_layer_values)
            if indx in self.cnn_map:
                if self.cnn_map[indx] in self.content_layers:
                    content_feature_maps[self.cnn_map[indx]] = input_layer_values
                elif self.cnn_map[indx] in self.style_layers:
                    style_feature_maps[self.cnn_map[indx]] = input_layer_values

        return content_feature_maps, style_feature_maps

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def get_gram_matrix(self, feature_map):

        """
        Calculate the gram matrix for an input feature_map.
        """

        if self.debugging_messages:
            print('Getting gram matrix...')

        _, d, h, w = feature_map.size()
        feature_map = feature_map.view(d, h * w)
        style_gram = torch.mm(feature_map, feature_map.t())

        return style_gram

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def get_style_loss(self, artwork_style_feature_maps):

        """
        Calculate the style loss for a given gram matrix.
        Used in every epoch of the algorithm's update.
        """

        if self.debugging_messages:
            print('Getting style loss...')

        style_loss = 0

        for layer in self.style_layers:
            artwork_gram = self.get_gram_matrix(artwork_style_feature_maps[layer]) #get the gram matrix from the artwork activation layer
            style_loss += self.style_weights[layer] * torch.mean((self.style_target_grams[layer] - artwork_gram)**2) * (1/(4*(((self.artwork.shape[0] * self.artwork.shape[1])**2) * (9**2))))

        return style_loss

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def minimise_loss(self):

        """
        Run the algorithm that minimises the loss function.
        Call various methods in order to compute the different components of the loss function.
        """

        def sm(tensor):
            return np.abs(tensor.detach().cpu().numpy()).sum()

        if self.debugging_messages:
            print('Running main algorithm...')

        self.artwork = self.content_image.clone().requires_grad_(True).to(self.device) #create the data structure for the artwork
        self.get_targets() #initialise the content and style targets
        self.optimizer = torch.optim.Adam([self.artwork], lr = self.learning_rate) #set the optimisation module

        epoch = 1
        while True:

            #retrieve the feature maps from the cnn for the artwork
            artwork_content_feature_maps, artwork_style_feature_maps = self.get_activation(self.artwork) #get the feature_map representations

            #calculate the losses
            content_loss = torch.mean((self.content_feature_maps[self.content_layers[0]] - artwork_content_feature_maps[self.content_layers[0]])**2) #the content loss
            style_loss = self.get_style_loss(artwork_style_feature_maps) #the style loss
            total_loss = (self.alpha*content_loss) + (self.beta*style_loss) #the total loss

            #printing & saving incremental changes
            if epoch%self.print_frequency == 0:
                print("Epoch: " + str(epoch) + "| Loss: " + str(int(total_loss.item())) + " |" + str(int(epoch/self.max_iterations*100)) + "% complete.")
                if self.incremental_plot:
                    self.save_plot(self.artwork, self.artwork_name, id = 'artwork', show = False, epoch = epoch)

            #convergence test
            if (total_loss < self.convergence_threshold) or (epoch == self.max_iterations):
                break
            epoch += 1

            #update the artwork by gradient descent
            self.optimizer.zero_grad() #reset the gradients to avoid accumulation
            total_loss.backward() #gradient descent
            self.optimizer.step() #update params

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def get_targets(self):

        """
        Perform a forward pass with the content and feature images to get the feature maps in the cnns.
        Also compute the gram matricies of the style image, which is used as out target in the style loss
        calculations.
        These feature maps are used as the 'target' in our loss calculations.
        This is only called onces since the target isnt changing.
        """

        if self.debugging_messages:
            print('Setting the update targets...')

        self.content_feature_maps, _ = self.get_activation(self.content_image)
        _, self.style_feature_maps = self.get_activation(self.style_image)
        self.style_target_grams = {layer:self.get_gram_matrix(self.style_feature_maps[layer]) for layer in self.style_feature_maps}

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def show_comparison(self):

        """
        Show the result of the artwork with the original.
        """

        fig, (ax1, ax2, ax3) = plt.subplots(1, 3)
        ax1.imshow(self.style_image)
        ax1.title.set_text('Style Image')
        ax1.axis('off')
        ax2.imshow(self.content_image)
        ax2.title.set_text('Content Image')
        ax2.axis('off')
        ax3.imshow(self.artwork)
        ax3.title.set_text('Artwork')
        ax3.axis('off')
        plt.show()

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def save_plot(self, img, name, id, show = False, epoch = -1):

        """
        Take an image and save it to disk.
        """

        if not isinstance(img, np.ndarray):
            img = self.tensor_to_image(img, id)

        fig, ax1 = plt.subplots(1, 1)
        ax1.title.set_text(name)
        ax1.axis('off')
        ax1.imshow(img, label = name)
        if epoch != -1: #for the incremental plot save the plot to disk
            plt.imsave('../incremental plots/' + name + ' ' + str(epoch) + '.png', img, format='png')
            plt.close()
        elif self.save: #for the final result save to disk
            plt.imsave('../results/' + name + '.png', img, format='png')
            plt.show()
        else:
            plt.show()

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


from pyspark import SparkContext, SparkConf
from pyspark.sql import SQLContext
import pandas as pd

import parameters.Globals as G
import functions.Utilities as U
import matplotlib.pyplot as plt
from functions.FooPlot import create_dict_colors
from functions.FooPySpark import *

import datetime

class Category:
    """
        Prints out a pie graph with the catogories that are the must
        popular by region
    """
    sc: object
    sql: object
    color ={''}

    #def __init__(self, host_):
    #    # check all options at :
    #    'https://spark.apache.org/docs/latest/configuration.html'
    #    self.host = host_
    #    conf = SparkConf().setAll([('spark.master', self.host),
    #                               ('spark.executor.memory', '4g'),
    #                               ('spark.app.name', 'foursquare mining App'),
    #                               ('spark.executor.cores', '4'),
    #                               ('spark.cores.max', '4'),
    #                               ('spark.driver.memory', '4g')])
    #    self.engine(conf)
    #
    # TODO : Overload constructor with more options for database setup
    def __init__(self, user_, u_pass, ip_port):
        url = 'mongodb://'+user_+':'+u_pass+'@'\
              + str(ip_port)+'/?authSource=admin'
        #
        conf = SparkConf().setAll([('spark.master', 'local[*]'),
                                   ('spark.app.name', 'foursquare Mongo connection App'),
                                   ('spark.mongodb.input.uri', url),
                                   ('spark.mongodb.output.uri', url),
                                   ('spark.jars.packages', 'org.mongodb.spark:mongo-spark-connector_2.11:2.3.1')])

        self.sc = SparkContext(conf=conf)
        self.sql = SQLContext(self.sc)

    # def engine(self, conf_: object):
    #    self.sc = SparkContext(conf=conf_)
    #    self.sql = SQLContext(self.sc)

    # Reads json data
    # file_name : string
    def load_json_file(self, file_name) -> object:
        dataVenues = self.sql.read.json(G.SAVE_PATH_4SQR+file_name)
        dataVenues = dataVenues.select(
            f.col('categories.primary'),
            f.col('id'),
            f.col('name'),
            f.col('categories.name').alias('cat_name'),
            f.col('categories.id').alias('cat_id'),
            #f.col('categories.shortName').alias('cat_shortName')
            f.col('location.country'),
            f.col('location.state'),
            f.col('location.formattedAddress'),
            f.col('location.postalCode'),
            f.col('location.lng'),
            f.col('location.lat')
        )
        #dataFsqr.printSchema()

        return dataVenues

    # TODO : When calling .load() connection fails spark-mongo-connector
    # driver fails, possible error : version, invalid jar package
    def load_mongoDB(self, database_, collection_) -> object:
        df = self.sql.read.format("com.mongodb.spark.sql.DefaultSource")\
                          .option("database", database_)\
                          .option("collection", collection_).load()

        df = df.select(
            f.col('categories.primary'),
            f.col('id'),
            f.col('name'),
            f.col('categories.name').alias('cat_name'),
            f.col('categories.id').alias('cat_id'),
            f.col('location.country'),
            f.col('location.state'),
            f.col('location.formattedAddress'),
            f.col('location.postalCode'),
            f.col('location.lng'),
            f.col('location.lat')
        )
        return df

    # Loads mongo with cleaned format for pie plot group
    # returns : DataFrame
    def load_full_collection_mongoDB(self,database_, collection_) -> object:
        df = self.sql.read.format("com.mongodb.spark.sql.DefaultSource") \
            .option("database", database_) \
            .option("collection", collection_).load()

        return df

    # Create new collection in mongoDB
    def write_mongoDB(self, df_A, database_, collection_):
        try:
            df_A.write.format("com.mongodb.spark.sql.DefaultSource")\
                .mode("overwrite")\
                .option("database", database_)\
                .option("collection", collection_).save()
            print('Data frame saved in MongoDB as : %s:%s '
                  % (database_, collection_))
        except Exception as e:
            print('Error loading DataFrame :\n', e)

    @staticmethod
    def load_list_toPandas(collection: list) -> object:
        df = pd.DataFrame(collection)
        #df_a = df[['categories.name',
        #           'id']].rename(columns={'categories.name': 'cat_name', 'id': 'id_i'})
        #df = self.sql.createDataFrame(df)
        #df = self.sql.createDataFrame(list(map(lambda x: Row(words=x), collection)))
        return df

    # Drops duplicates, drop empty category fields
    def clean_categories(self, df_A):
        # Drops repeated ids
        df_A = df_A.drop_duplicates(subset=['id'])
        print(' after drop duplicate : ', df_A.count())
        # Filters
        filter_A = f.size(f.col('cat_name')) != 0
        filter_B = f.col('primary')[0] == True

        df_A = df_A.filter(filter_A & filter_B) \
            .select('*', df_A['cat_name'][0].alias('category'))

        print(' after filter empty category : ', df_A.count())
        return df_A

    # Filter by Categories : drops repeated ids, and empty
    # category fields
    def filter_categories_colored(self, df_A, ValidCategories, ApplyCatFilter):
        # If no filter applied, too may categories blocks view colors
        colors_dict = create_dict_colors(ValidCategories)
        if ApplyCatFilter:
            # Keeps selected Categories
            df_A = df_A.filter(f.col('category').isin(ValidCategories))
            # Create column of colors for categories

        df_A = df_A.withColumn('color_cat',
                               color_category_udf(colors_dict)(f.col('category')))

        return df_A, colors_dict

    # Adds column<municipio> crosssed with PostalCode
    def validate_postalCode_municipio(self, df_A):
        # Load Postal Codes of CDMX
        df_PC = self.sql.read.format("com.databricks.spark.csv") \
            .options(delimiter=',')\
            .options(header='true', inferSchema='true') \
            .load('./data_sample/PostalCodeCDMX.csv')

        # Drop duplicates
        df_PC = df_PC.drop_duplicates(subset=['d_codigo'])
        # Cross PostalCode vs Municipio
        a = df_A.alias('a')
        b = df_PC.alias('b')
        df_A = a.join(b, f.col('a.postalCode') == f.col('b.d_codigo'), 'left')\
            .select([f.col('a.'+xx) for xx in a.columns] +
                    [f.col('b.D_mnpio').alias('municipio'),f.col('b.d_tipo_asenta')])

        # Filter not assigned municipio to PostalCode
        df_A = df_A.filter(f.col('municipio').isNotNull())
        print('after drop <municipio> null values : ', df_A.count())
        return df_A

    # Filer and keyword in address street
    def filter_by_keyword_address(self, df_A, keywords: list) -> object:
        AddressData = ['formattedAddress', 'postalCode']
        df_A = df_A.filter(contains_keyword_udf(keywords)(f.struct(AddressData)))\
            .select('*')
        return df_A

    # Groups by category, all categories or filtered categories
    # returns -> dict : categori vs count
    def group_by_categories_dict(self, df_A,
                            categories_: list, ApplyFilter) -> dict:
        df_A = df_A.groupby('category').count()\
            .sort(f.col('count').desc())
        if ApplyFilter:
            df_A = df_A.filter(f.col('category').isin(categories_))

        CatCountDict = {}
        for item in df_A.collect():
            CatCountDict[item['category']] = item['count']

        # CatCountDict.update([('Other', CountOther)])
        return CatCountDict

    # Counts remaining categories out of MaxCategoryDisplay
    def count_others(self, KeyCat, CountDict):
        CountOther = 0
        for Key in CountDict.keys():
            if Key not in KeyCat:
                CountOther += CountDict[Key]

        return CountOther

    # Plots iterated pie plots by <municipio>
    def plot_pie(self, df):
        df_mnpio = df.groupby('municipio').count()\
            .sort(f.col('count').desc()).toPandas()
        mnpio = df_mnpio['municipio'].values.tolist()
        #mnpio = mnpio[:3]
        N = len(mnpio)
        print(mnpio)
        for i in range(0, N):
            plt.figure(figsize=(15, 12))
            df_plot = df.filter(f.col('municipio') == mnpio[i]).select('*')
            df_plot = df_plot.groupby('category').count().sort(f.col('count').desc())
            #df_plot = df_plot.filter(f.col('count') > 40).select('*')
            df_plot = with_column_index(df_plot)
            df_plot = df_plot.withColumn('explode', f.col('explode')*0.008)
            df_plot = df_plot.toPandas()
            plt.pie(df_plot['count'],
                    explode=df_plot['explode'],
                    labels=df_plot['category'],
                    autopct='%1.1f%%',
                    startangle=0)
            plt.title(str(mnpio[i]))
            plt.show()

    # Maps 4sqr format to OCB DataModel
    # returns : List of dictionary
    @staticmethod
    def maps_to_OCB_dataModel(df: object) -> list:
        print('Mapeando datos a formato OCB')
        D = datetime.datetime.today()
        try:
            ocb_model = df.rdd.map(
                lambda x: {"id": "4sqr-"+str(x['id']),
                           "type": "PointOfInterest",
                           "address": {
                              "type": "StructuredValue",
                              "value": {
                                  "addressCountry": U.cleanChars(x["country"]),
                                  "addressLocality": U.cleanChars(x["formattedAddress"])
                              }
                           },
                           "category": {
                               "type": "Text",
                               "value": [
                                  "1",
                                  U.cleanChars(x["category"]),
                                  x["color_cat"]
                               ]
                           },
                           "dateCreated": {
                              "type": "DateTime",
                              "value": str(D.date())+'T'+str(D.time())+'Z'
                           },
                           "description": {
                              "type": "Text",
                              "value": U.cleanChars(x["category"])
                           },
                           "location": {
                              "type": "geo:json",
                              "value": {
                                  "type": "Point",
                                  "coordinates": [
                                      x["lng"],
                                      x["lat"]
                                  ]
                              }
                           },
                           "name": {
                              "type": "Text",
                              "value": U.cleanChars(x["name"])
                           },
                           "url": {
                              "type": "Text",
                              "value": "no url"
                           }
                           })

            print('maped data ....')
            out = ocb_model.collect()
            print(type(out))

        except Exception as e:
            out = []
            print('Error mapping venues to OCB format :\n', str(e))

        return out


# -*- coding: utf-8 -*-
"""
Created on Mon Mar 6 2020

"""

# function to read text file
def read_text_file(path):
    """
    :param path: text file path
    :return: read text file
    """
    f = open(path, "r")
    return f.read()

# Word counter
def word_count(string):
    """
    :param string: text file or input text's
    :return: word counts [dict]
    """

    counts = dict()
    words = string.lower().split()

    for word in words:
        if word in counts:
            counts[word] += 1
        else:
            counts[word] = 1
    print('The Total words in the given statements are: ', len(words))

    return counts

def input_texts_count():
    while True:
        try:
            string = input("\nWords: ")
            counts = word_count(string)
            print("counts: ", counts)
        except KeyboardInterrupt:
            break  # breaking the loop


#使输出的html应用看起来更复杂一些
#能接受内部参数
from flask import Flask,render_template
import datetime

app=Flask(__name__)

@app.route('/1/')
def index_v1():
    """
    params：
        user:输入参数——用户名
        html_text:响应值
    """
    user={'username':"ChenQQ"}
    html_text="""

            <title>inner flask page</title>

hello,"""+user['username']+"""

    """
    return html_text

@app.route('/2/')
def index_v2():
    """
    实现python代码和html页面的参数传递
    实现前、后端分离
    """
    user={'username':"ChenQQ"}
    return render_template('index_v2.html',title='ChenQQ',user=user)

@app.route('/3/')
def index_v3():
    """
    产生更多参数，html页面更复杂，实现if else loop循环等基本业务
    """
    user={'username':"ChenQQ"}
    borrower={'postcard':"111","borrowdate":"2021-09-22"}
    booklist=[
        {"author":"name1","bookname":"book1"},
        {"author":"name2","bookname":"book2"},
        {"author":"name3","bookname":"book3"},
        {"author":"name4","bookname":"book4"}
    ]
    return render_template("index_v3.html",title="title",borrower=borrower,booklist=booklist)

@app.route('/4/')
def index_v4():
    """继承"""
    today=datetime.date.today()
    user={'username':"ChenQQ"}
    borrower={'postcard':'222','borrowdate':today}
    tabletitle={'author','bookname'}
    booklist=[
        {"author":"name1","bookname":"book1"},
        {"author":"name2","bookname":"book2"},
        {"author":"name3","bookname":"book3"},
        {"author":"name4","bookname":"book4"}
    ]
    return render_template('index_v4.html',user=user,borrower=borrower,tabletitle=tabletitle,booklist=booklist)

@app.route('/test1/')
def test1():
    title="test1"
    username={"name1":"ChenQQ"}
    return render_template('test1.html',title=title,username=username)

@app.route('/test2/')
def test2():
    today=datetime.date.today()
    title="test2"
    user={'username':'ChenQQ'}
    borrower={'postcard':'11',"borrowdate":today}
    booklist=[
        {'author':'name1','bookname':'book1'},
        {'author':'name2','bookname':'book2'}
    ]
    return render_template('test2.html',title=title,borrower=borrower,booklist=booklist)

if __name__=="__main__":
    app.run()


import torch.nn as nn
from torch.distributions.normal import Normal
import numpy as np
import torch as th
import torch.nn.functional as F
from torch.distributions.normal import Normal

class SquashedGaussianPolicy(nn.Module):
    def __init__(self, args):
        super(SquashedGaussianPolicy, self).__init__()
        self.args = args

        self.state_encoder = nn.Sequential(nn.Linear(args.state_dim, args.hidden_dim),
                                           nn.ReLU(),
                                           nn.Linear(args.hidden_dim, args.hidden_dim))

        self.mu = nn.Linear(args.hidden_dim, args.action_dim)
        self.log_std = nn.Linear(args.hidden_dim, args.action_dim)

    def forward(self, state):
        x = F.relu(self.state_encoder(state))
        mu = self.mu(x)
        log_std = self.log_std(x)
        log_std = th.clamp(log_std, self.args.LOG_STD_MIN, self.args.LOG_STD_MAX)
        std = th.exp(self.log_std(x))  # log_std = th.clamp(log_std, LOG_STD_MIN, LOG_STD_MAX)
        pi = Normal(mu, std)
        return pi


import math

def solve(n, k, roads):
    myGraph = {}
    nodeEdge1 = None
    nodeEdge2 = None
    edgeNeeded = None
    edge_counter = 1
    for i in roads:
        a = i[0]
        b = i[1]
        edge = i[2]
        if (not myGraph.get(a)):
            myGraph[a] = {}
        myGraph[a][b] = edge
        if (not myGraph.get(b)):
            myGraph[b] = {}
        myGraph[b][a] = edge
        if (edge_counter == k):
            nodeEdge1 = a
            nodeEdge2 = b
            edgeNeeded = edge
        edge_counter+=1

    def dijkstra(begin, end):
        shortest = {}
        last = {}
        notVisitedNodes = []
        notVisitedNodes = myGraph.copy()
        path = []
        for everyNode in notVisitedNodes:
            shortest[everyNode] = math.inf
        shortest[begin] = 0
        while (notVisitedNodes):
            closestNode = None
            for node in notVisitedNodes:
                if (closestNode==None) or (shortest[node]<shortest[closestNode]):
                    closestNode = node
            currentPath = myGraph[closestNode].items()
            for data in currentPath:
                if (data[1]+shortest[closestNode]<shortest[data[0]]):
                    shortest[data[0]] = data[1] + shortest[closestNode]
                    last[data[0]] = closestNode
            notVisitedNodes.pop(closestNode)
        currentNode = end
        while currentNode != begin:
            path.insert(0,currentNode)
            currentNode = last[currentNode]
        path.insert(0,begin)
        #print("distancia:", shortest[end])
        #print(path)
        return shortest[end]#,path]
    values = []
    for i in myGraph:
        if (i!=nodeEdge1 and i!=nodeEdge2):
            values.append((dijkstra(nodeEdge1, i), dijkstra(nodeEdge2, i)))
        elif (i==nodeEdge1):
            values.append((0, dijkstra(nodeEdge2,i)))
        else:
            values.append((dijkstra(nodeEdge1,i),0))

    def biseccionChafa(INFER, SUPER):
        if (n==2):
            v =edgeNeeded/2
            return [float('%0.05f' % v), float('%0.05f' % v)]
        inf, sup = INFER, SUPER

        while (sup-inf >0.00001 or sup==inf or sup==0):
            currentInf = inf + (sup-inf)/4
            currentSup = inf +3*(sup-inf)/4
            resInf, resSup = [], []
            for i in values:
                currentMin = min(i[0], i[1])
                u = edgeNeeded-currentInf + i[1]#resInf.append(edgeNeeded-currentInf + i[1])
                v = edgeNeeded-currentSup + i[1]#resSup.append(edgeNeeded-currentSup + i[1])
                u1 = i[0]+currentInf#resInf.append(i[0]+currentInf)
                v1 = i[0]+currentSup#resSup.append(i[0]+currentSup)
                resInf.append(min(u,u1))
                resSup.append(min(v,v1))
            deviationInf = max(resInf)
            deviationSup = max(resSup)
            nextV = (inf+sup)/2
            if (deviationInf<=deviationSup):
                sup = nextV
            else:
                inf = nextV
        return [float('%0.05f' % round(min(inf,sup))),float('%0.05f' % round(max(resInf)) if min(inf,sup)==inf else round(max(resSup)))]
    dis = biseccionChafa(0, edgeNeeded)
    return("%0.05f" %(dis[0]),"%0.05f" % (dis[1]))

#2
#2 1 1
#1 2 10
#4 4 1
#1 2 10
#2 3 10
#3 4 1
#4 1 5
#dasRoads = [
#    [1, 2, 10],
#    [2, 3, 10],
#    [3, 4, 1],
#    [4, 1, 5]
#]
#dasRoads = [[1,2,10]]
#solve(2,1,dasRoads)
#dasRoads = [
#    [1, 2, 10],
#    [2, 3, 10],
#    [3, 4, 1],
#    [4, 1, 5]
#]
#solve(4,1,dasRoads)
#dasRoads = [
#    [3, 7, 43],
#[7, 10, 91],
#[10, 1, 17],
#[1, 9, 86],
#[9, 5, 98],
#[5, 4, 85],
#[4, 8, 48],
#[8, 6, 94],
#[6, 2, 57],
#[5, 2, 80]
#]
#solve(10,4,dasRoads)
#dasRoads = [
#    [6, 9, 93],
#[9, 4, 18],
#[4 ,3 ,80],
#[3, 7, 94],
#[7, 1, 68],
#[1, 5, 58],
#[5 ,10, 72],
#[10, 8, 45],
#[8, 2 ,93],
#[7, 10, 72],
#]
#solve(10,8,dasRoads)
#dasRoads = [
#    [1, 7, 77],
#[7, 8, 1],
#[8 ,10, 85],
#[10, 2, 21],
#[2, 4, 51],
#[4, 5, 66],
#[5, 9, 86],
#[9, 6, 89],
#[6, 3, 26],
#[9, 3, 70]
#]
#solve(10,5,dasRoads)
f = open("txt\\test_2_1.txt", "r")
v = []
environVars = []
count = 0
for x in f:
    if (count!=0):
        a = x
        temp1 = []
        for word in a.split():
            if word.isdigit():
                temp1.append(int(word))
        v.append(temp1)
    else:
        a = x
        for word in a.split():
            if word.isdigit():
                environVars.append(int(word))
    count +=1
print(solve(environVars[0],environVars[2],v))


import random
import threading

from Ant import Ant
from AntSimGui import AntSimGui
from ColonyNode import ColonyNode
from ColonyNodeView2 import ColonyNodeView2
from ColonyView2 import ColonyView2
from ForagerAnt import ForagerAnt
from QueenAnt import QueenAnt
from ScoutAnt import ScoutAnt
from SoldierAnt import SoldierAnt

def setInterval(interval):
    def decorator(function):
        def wrapper(*args, **kwargs):
            stopped = threading.Event()

            def loop(): # executed in another thread
                while not stopped.wait(interval): # until stopped
                    function(*args, **kwargs)

            t = threading.Thread(target=loop)
            t.daemon = True # stop if the program exits
            t.start()
            return stopped
        return wrapper
    return decorator

class Colony:
    def __init__(self, colony_view: ColonyView2, ant_sim_gui: AntSimGui, x_length, y_length):
        self.ant_sim_gui = ant_sim_gui
        self.colony_view = colony_view
        self.colony_nodes = []
        self.colony_node_view = None
        self.x_length = x_length
        self.y_length = y_length
        self.ants: list[Ant] = []
        self.initialize_colony_grid()
        self.queen = None
        self.central_node = None
        self.turn_count = 0
        self.hatched_ant = None

    def common_setup(func):
        def wrapper(self):
            self.central_node = self.colony_nodes[13][13]
            self.central_node.show_node()
            self.central_node.set_food_count(1000)
            self.queen = QueenAnt(self.central_node)
            self.ants.append(self.queen)
            self.central_node.add_ant(self.queen)

            func(self)

            self.ant_sim_gui.set_colony_view(self.colony_view)
        return wrapper

    def base_node_layout(func):
        def wrapper(self):
            func(self)
            central_node_perimeter_nodes = list(self.central_node.adjacent_colony_nodes.values())
            for node in central_node_perimeter_nodes:
                node.show_node()
        return wrapper

    @common_setup
    @base_node_layout
    def normal_setup(self):
        # central_node.set_soldier_count(10)
        for x in range(50):
            forager_ant = ForagerAnt(self.central_node)
            self.ants.append(forager_ant)
            self.central_node.add_ant(forager_ant)

        for x in range(4):
            scout_ant = ScoutAnt(self.central_node)
            self.ants.append(scout_ant)
            self.central_node.add_ant(scout_ant)

        for x in range(10):
            soldier_ant = SoldierAnt(self.central_node)
            self.ants.append(soldier_ant)
            self.central_node.add_ant(soldier_ant)

        self.central_node.set_food_count(1000)

    @common_setup
    def queen_test_setup(self):
        pass

    @common_setup
    def forager_test_setup(self):
        for x in range(1):
            forager_ant = ForagerAnt(self.central_node)
            self.ants.append(forager_ant)
            self.central_node.add_ant(forager_ant)

        central_node_perimeter_nodes = list(self.central_node.adjacent_colony_nodes.values())
        for node in central_node_perimeter_nodes:
            node.show_node()
            for outer_node in list(node.adjacent_colony_nodes.values()):
                outer_node.show_node()

        self.colony_nodes[11][11].set_food_count(500)
        self.colony_nodes[15][15].set_food_count(500)

    @common_setup
    def soldier_test_setup(self):
        self.show_all_nodes()
        for x in range(4):
            soldier_ant = SoldierAnt(self.central_node)
            self.ants.append(soldier_ant)
            self.central_node.add_ant(soldier_ant)

    def show_all_nodes(self):
        for x in range(self.x_length):
            for y in range(self.y_length):
                self.colony_nodes[x][y].show_node()

    @common_setup
    @base_node_layout
    def scout_test_setup(self):
        for x in range(4):
            scout_ant = ScoutAnt(self.central_node)
            self.ants.append(scout_ant)
            self.central_node.add_ant(scout_ant)

    def initialize_colony_grid(self):
        for x in range(self.x_length):
            row = []
            self.colony_nodes.append(row)
            for y in range(self.y_length):
                colony_node_view = ColonyNodeView2(self.colony_view.scrollAreaWidgetContents)
                self.colony_view.add_colony_node_view(colony_node_view, x, y)
                colony_node = ColonyNode(colony_node_view, x, y, self)
                row.append(colony_node)

                # Build node perimeter references
                # Set north and south nodes
                if y > 0:
                    south_node = self.colony_nodes[x][y-1]
                    assert south_node, "North node is None"
                    colony_node.adjacent_colony_nodes['south'] = south_node
                    if x > 0:
                        southwest_node = south_node.adjacent_colony_nodes['west']
                        colony_node.adjacent_colony_nodes['southwest'] = southwest_node
                        if x < self.x_length - 1 and y < self.y_length - 1:
                            southwest_node.adjacent_colony_nodes['northeast'] = colony_node
                    south_node.adjacent_colony_nodes['north'] = colony_node

                # Set east and west nodes
                if x > 0:
                    west_node = self.colony_nodes[x-1][y]
                    assert west_node, "West node is None"
                    colony_node.adjacent_colony_nodes['west'] = west_node
                    if y < self.y_length - 1:
                        northwest_node = west_node.adjacent_colony_nodes['north']
                        colony_node.adjacent_colony_nodes['northwest'] = northwest_node
                        if y > 0:
                            northwest_node.adjacent_colony_nodes['southeast'] = colony_node
                    west_node.adjacent_colony_nodes['east'] = colony_node
        print('Colony Grid Initialized')

    def add_bala_to_colony(self):
        from BalaAnt import BalaAnt

        x, y = None, None
        choice = random.randint(0, 3)
        if choice == 0:
            x = 0
        elif choice == 1:
            x = self.x_length - 1
        elif choice == 2:
            y = 0
        else:
            y = self.y_length - 1

        if x is not None:
            y = random.choice(range(self.y_length))
        elif y is not None:
            x = random.choice(range(self.x_length))
        else:
            raise Exception('Both x and y are none')

        print(f'Spawning new bala ant in node {x},{y}')
        bala_node = self.colony_nodes[x][y]
        bala_ant = BalaAnt(bala_node)
        self.ants.append(bala_ant)
        bala_node.add_ant(bala_ant)

    @setInterval(.5)
    def take_all_turns(self):
        self.take_turn()

    def take_turn(self):
        if not self.queen.is_dead():
            # All ants take their turn
            for ant in self.ants:
                if not ant.is_dead():
                    ant.take_turn()
            self.ants = [ant for ant in self.ants if not ant.is_dead()]

            # Increment turn count
            self.turn_count += 1

            # Bala chance
            bala_chance = random.randint(1, 100)
            # if bala_chance < 4:
            if bala_chance < 51:
                self.add_bala_to_colony()

            # Degrade pheramone
            self.ant_sim_gui.fire_degradation_event(self.turn_count)

            # Add hatched ant to the rotation
            if self.hatched_ant:
                self.ants.append(self.hatched_ant)
        else:
            print("The queen is dead. Simulation terminated.")
            raise Exception()


import os
import requests
import json

# Author: Alexis Finch
#
# Date: July 5, 2023
#
# The purpose of this program is to present a list of cost indexes for Manufacturing and Reactions for an alliance
# (or alliances) in EVE Online
# The data can then be sent to Discord or Slack
#
# Set it up on a CRON job or task scheduler to cycle regularly, and it'll keep you up to date on the cost indexes
# in your systems!

# Formats indexes for sake of readability. Converts decimals into percentages.
def indexFormatter(index):
    return f"{index:.2%}"

def parseIndicesBySystemList(index_response, alliance_systems):
    indices_list = [[], []]
    # Reads through all indexes returned by ESI

    for cost_index in index_response:
        # Then checks the list of system IDs in the alliance systems list, to see if it's on the list
        for system in alliance_systems:
            # If the systems match (cost index pertains to a system on the alliance_systems list
            if cost_index['solar_system_id'] == system['id']:
                if cost_index['cost_indices'][0]['cost_index'] > configuration['display_threshold']:
                    indices_list[0].append([system['name'], cost_index['cost_indices'][0]['cost_index']])
                if cost_index['cost_indices'][5]['cost_index'] > configuration['display_threshold']:
                    indices_list[1].append([system['name'], cost_index['cost_indices'][5]['cost_index']])

    # sorts the data
    indices_list[0].sort(key=lambda x: x[1])
    indices_list[0].reverse()

    indices_list[1].sort(key=lambda x: x[1])
    indices_list[1].reverse()

    return indices_list

def buildOutputString(indices_list):
    outputString = "\nManufacturing Cost Index Report:\n\n```\n"

    if not indices_list[0]:
        outputString += "Nothing to report.\n"

    for system in indices_list[0]:
        system[1] = indexFormatter(system[1])
        outputString += ('{0:7} {1:>8}'.format(*system)) + "\n"

    outputString += "```\n\nReaction Cost Index Report:\n\n```\n"

    if not indices_list[1]:
        outputString += "Nothing to report.\n"

    for system in indices_list[1]:
        system[1] = indexFormatter(system[1])
        outputString += ('{0:7} {1:>8}'.format(*system)) + "\n"

    outputString += "```"

    return outputString

def filterByRegions(alliance_systems):
    inRegionFilteredList = []
    resolve_region_id_url = 'https://esi.evetech.net/latest/universe/regions/'
    resolve_constellation_id_url = 'https://esi.evetech.net/latest/universe/constellations/'

    for region in configuration['regions']:
        regionJSON = requests.get(resolve_region_id_url+str(region)).json()
        for constellation in regionJSON['constellations']:
            constellationJSON = requests.get(resolve_constellation_id_url+str(constellation)).json()
            for system in constellationJSON['systems']:
                for trackedSystem in alliance_systems:
                    if system == trackedSystem['id']:
                        inRegionFilteredList.append(trackedSystem)

    return inRegionFilteredList

def postSlackWebhook(content):
    # Pulls the slack URL from the ENV Variable
    slack_url = os.environ["INDY_BOT_SLACK_WEBHOOK_URL"]

    # Sends it in the proper format, to the slack webhook
    requests.post(slack_url, data=json.dumps({'text': content}), headers={'Content-Type': 'application/json'})

def postDiscordWebhook(content):
    # Pulls the discord webhook URL from the ENV variable
    discord_url = os.environ['INDY_BOT_DISCORD_WEBHOOK_URL']

    # Sends it in the proper format, to the discord webhook
    requests.post(discord_url, data=json.dumps({'content': content}), headers={'Content-Type': 'application/json'})

def GetIndices(alliance_IDs):
    sov_url = 'https://esi.evetech.net/latest/sovereignty/structures/'
    indices_url = 'https://esi.evetech.net/latest/industry/systems/'

    sov_response = requests.get(sov_url).json()

    alliance_systems = []

    for system in sov_response:
        if system['alliance_id'] in alliance_IDs and (system['structure_type_id'] == 32458 or
                                                      system['structure_type_id'] == 32226):
            if system['solar_system_id'] not in alliance_systems:
                alliance_systems.append(system['solar_system_id'])

    resolve_system_name_url = 'https://esi.evetech.net/latest/universe/names/'
    alliance_systems = requests.post(resolve_system_name_url,
                                     headers={'Accept': 'application/json', 'Content-Type': 'application/json',
                                              'Cache-Control': 'no-cache'},
                                     json=alliance_systems).json()

    alliance_systems = filterByRegions(alliance_systems)

    index_response = requests.get(indices_url).json()

    system_indices_list = parseIndicesBySystemList(index_response, alliance_systems)

    output_string = buildOutputString(system_indices_list)

    # if the config file is true for slack
    if configuration['webhooks']['slack']:
        postSlackWebhook(output_string)

    # if the config file is true for discord
    if configuration['webhooks']['discord']:
        postDiscordWebhook(output_string)

# opens config file
configFile = open("./config.json")

# returns JSON object as a dictionary
configuration = json.load(configFile)

# Calls the function to fetch, and send, the indexes
GetIndices(configuration["alliance_IDs"])


from typing import Any, Union

from django.views import generic
from django.contrib.auth.mixins import PermissionRequiredMixin
from students.forms import StudentForm, SearchStudentForm, ModifyStudentInfoForm
from django.urls import reverse_lazy, reverse
from django.shortcuts import render, redirect
from students.tables import StudentTable
from django_tables2 import SingleTableMixin
from django_filters.views import FilterView
from .models import Student
from django.core.exceptions import ImproperlyConfigured

class index(generic.TemplateView):
    template_name = 'students/index.html'

class StudentListView(PermissionRequiredMixin, SingleTableMixin, FilterView):
    model = Student
    context_object_name = 'student_list'
    template_name = 'students/student_list.html'
    permission_required = 'students.viewStudents'
    table_class = StudentTable

    def get_table_kwargs(self):
        user = self.request.user
        if user.has_perms('student.modifyStudent') or user.has_perms('student.delete_student'):
            return {'empty_text': 'No Student in the database.'}
        return {'exclude': ('select', 'actions'), 'empty_text': 'No Student in the database.'}

class AddStudentView(PermissionRequiredMixin, generic.CreateView):
    model = Student
    context_object_name = 'add_student'
    template_name = 'students/add_new_student.html'
    permission_required = 'students.addStudents'
    form_class = StudentForm
    success_url = reverse_lazy('students:student_list')

class StudentHomeView(PermissionRequiredMixin, generic.ListView):
    model = Student
    context_object_name = 'student_home'
    template_name = 'students/StudentHomeView.html'
    permission_required = 'students.home'

class FormTableView(SingleTableMixin, generic.FormView):
    result_template_name = None
    table_data = {}

    def filter_table_data(self, form):
        return None

    def form_valid(self, form):
        self.table_data = self.filter_table_data(form)
        return render(self.request, self.result_template_name, context=self.get_context_data(form=form))

class SearchStudentView(PermissionRequiredMixin, FormTableView):
    permission_required = 'students.searchStudents'
    template_name = 'students/search_student.html'
    result_template_name = 'students/search_student_result.html'
    form_class = SearchStudentForm
    table_class = StudentTable

    def get_table_kwargs(self):
        return {
            'empty_text': 'No results matching query.'
        }

    def filter_table_data(self, form):
        print(Student.objects.none())
        student_list = Student.objects
        first_name = form.cleaned_data['first_name']
        last_name = form.cleaned_data['last_name']
        cellPhone = form.cleaned_data['cellPhone']
        email = form.cleaned_data['email']
        ssn = form.cleaned_data['ssn']
        zipcode = form.cleaned_data['zipcode']

        if not any((first_name, last_name, cellPhone, ssn, zipcode)):
            return Student.objects.none()

        if first_name:
            student_list = student_list.filter(first_name__iexact=first_name)
        if last_name:
            student_list = student_list.filter(last_name__iexact=last_name)
        if cellPhone:
            student_list = student_list.filter(cellPhone__exact=cellPhone)
        if email:
            student_list = student_list.filter(email__iexact=email)
        if ssn:
            student_list = student_list.filter(email__exact=ssn)
        if zipcode:
            student_list = student_list.filter(email__exact=zipcode)
        return student_list

class DeleteStudentView(PermissionRequiredMixin, generic.DeleteView):
    permission_required = 'students.deleteStudent'
    model = Student
    context_object_name = 'delete_student'
    template_name = 'students/student_confirm_delete.html'
    success_url = reverse_lazy('students:student_list')

    def get_object(self, queryset=None):
        return Student.objects.get(pk=self.request.GET.get('student_id'))

class ModifyStudentView(PermissionRequiredMixin, generic.UpdateView):
    model = Student
    permission_required = 'students.modifyStudent'
    context_object_name = 'modify_student'
    template_name = 'students/modify_student_form.html'
    form_class = ModifyStudentInfoForm
    success_url = reverse_lazy("students:student_list")

    def get_object(self):
        return Student.objects.get(pk=self.request.GET.get('student_id'))


import os
import locale

import pytest

from tempfile import NamedTemporaryFile
from tempfile import mkdtemp
from shutil import rmtree

locale.setlocale(locale.LC_ALL, "C")

def pytest_runtest_setup(item):
    if any(mark.name == "pytorch" for mark in item.iter_markers()):
        pytest.importorskip("torch")

@pytest.fixture
def temp_file_1_name():
    temp = NamedTemporaryFile(delete=False, suffix="_1")
    temp.close()
    yield temp.name
    os.remove(temp.name)

@pytest.fixture
def temp_file_2_name():
    temp = NamedTemporaryFile(delete=False, suffix="_2")
    temp.close()
    yield temp.name
    os.remove(temp.name)

@pytest.fixture
def temp_file_3_name():
    temp = NamedTemporaryFile(suffix="_2", delete=False)
    temp.close()
    yield temp.name
    os.remove(temp.name)

@pytest.fixture
def temp_dir():
    dir_name = mkdtemp()
    yield dir_name
    rmtree(dir_name)

@pytest.fixture(autouse=True)
def logging_cleanup():
    yield
    from pydrobert.kaldi.logging import deregister_all_loggers_for_kaldi

    deregister_all_loggers_for_kaldi()


from functools import reduce

def load_data():
    with open('./input.txt', 'r') as file:
        return file.readlines()

def calorie_by_elf(data):
    results = []
    curr_elf = 1  # id for the current elf. May need this down the line
    curr_cals = 0  # accumulator for calories on curr_elf
    for snack in data:
        if snack == "\n":
            # moving to a new elf, push crur to the results list
            results.append((curr_elf, curr_cals))
            curr_elf += 1  # move id to the next elf
            curr_cals = 0  # reset calorie accumulator
        else:
            curr_cals += int(snack)  # accumulate curr_elf calories
    return results

if __name__ == "__main__":
    data = load_data()

    # part one: find the elf carrying the most calories. How many are they carrying?
    elf_calories = calorie_by_elf(data)
    elf_calories.sort(key=lambda e: e[1], reverse=True)
    print(f"The elf with the most calories is #{elf_calories[0][0]} with {elf_calories[0][1]} calories")

    # part two: find the 3 elves with the most calories. How many are there in total?
    top_3_elves = elf_calories[0:3]
    total_calories = reduce(lambda a, c: a + c[1], top_3_elves, 0)
    print(f"The total calories carried by the top 3 elves is: {total_calories}")


from dataclasses import dataclass
import hci_packets as hci
import link_layer_packets as ll
import unittest
from hci_packets import ErrorCode
from py.bluetooth import Address
from py.controller import ControllerTest
from typing import List

@dataclass
class TestRound:
    req_tx_phys: int
    req_rx_phys: int
    phy_ltpref_c_to_p: List[int]
    phy_ltpref_p_to_c: List[int]

class Test(ControllerTest):

    # LL/CON/PER/BV-40-C [Initiating PHY Update Procedure]
    async def test(self):
        # Test parameters.
        controller = self.controller
        acl_connection_handle = 0xefe
        peer_address = Address('11:22:33:44:55:66')

        # Prelude: Establish an ACL connection as central with the IUT.
        controller.send_cmd(
            hci.LeSetAdvertisingParameters(advertising_interval_min=0x200,
                                           advertising_interval_max=0x200,
                                           advertising_type=hci.AdvertisingType.ADV_IND,
                                           own_address_type=hci.OwnAddressType.PUBLIC_DEVICE_ADDRESS,
                                           advertising_channel_map=0x7,
                                           advertising_filter_policy=hci.AdvertisingFilterPolicy.ALL_DEVICES))

        await self.expect_evt(
            hci.LeSetAdvertisingParametersComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

        controller.send_cmd(hci.LeSetAdvertisingEnable(advertising_enable=True))

        await self.expect_evt(hci.LeSetAdvertisingEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

        controller.send_ll(ll.LeConnect(source_address=peer_address,
                                        destination_address=controller.address,
                                        initiating_address_type=ll.AddressType.PUBLIC,
                                        advertising_address_type=ll.AddressType.PUBLIC,
                                        conn_interval=0x200,
                                        conn_peripheral_latency=0x200,
                                        conn_supervision_timeout=0x200),
                           rssi=-16)

        await self.expect_ll(
            ll.LeConnectComplete(source_address=controller.address,
                                 destination_address=peer_address,
                                 conn_interval=0x200,
                                 conn_peripheral_latency=0x200,
                                 conn_supervision_timeout=0x200))

        await self.expect_evt(
            hci.LeEnhancedConnectionComplete(status=ErrorCode.SUCCESS,
                                             connection_handle=acl_connection_handle,
                                             role=hci.Role.PERIPHERAL,
                                             peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS,
                                             peer_address=peer_address,
                                             connection_interval=0x200,
                                             peripheral_latency=0x200,
                                             supervision_timeout=0x200,
                                             central_clock_accuracy=hci.ClockAccuracy.PPM_500))

        # 1. Upper Tester sends an HCI_LE_Set_PHY command to the IUT with the ALL_PHYS fields set to a
        # value of 0x03. Upper Tester receives an HCI_Command_Status event indicating success in
        # response.
        controller.send_cmd(
            hci.LeSetPhy(connection_handle=acl_connection_handle,
                         all_phys_no_transmit_preference=True,
                         all_phys_no_receive_preference=True,
                         tx_phys=0,
                         rx_phys=0))

        await self.expect_evt(hci.LeSetPhyStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

        await self.expect_ll(
            ll.LlPhyReq(source_address=controller.address, destination_address=peer_address, tx_phys=0x7, rx_phys=0x7))

        controller.send_ll(
            ll.LlPhyUpdateInd(source_address=peer_address,
                              destination_address=controller.address,
                              phy_c_to_p=0x2,
                              phy_p_to_c=0x2))

        # 2. The Upper Tester receives an HCI_LE_PHY_Update_Complete event from the IUT.
        await self.expect_evt(
            hci.LePhyUpdateComplete(status=ErrorCode.SUCCESS,
                                    connection_handle=acl_connection_handle,
                                    tx_phy=hci.PhyType.LE_2M,
                                    rx_phy=hci.PhyType.LE_2M))

        test_rounds = [
            TestRound(0x03, 0x01, [0x02], [0x01]),
            TestRound(0x05, 0x02, [0x01], [0x02]),
            TestRound(0x02, 0x04, [0x02], [0x04]),
            TestRound(0x01, 0x02, [0x01], [0x02]),
            TestRound(0x04, 0x01, [0x04], [0x01]),
            TestRound(0x03, 0x06, [0x02], [0x02]),
            TestRound(0x01, 0x01, [0x01], [0x01]),
            TestRound(0x04, 0x03, [0x04], [0x01]),
            TestRound(0x05, 0x01, [0x01], [0x01]),
            TestRound(0x04, 0x04, [0x04], [0x04]),
            TestRound(0x05, 0x07, [0x04], [0x02, 0x04]),
            TestRound(0x05, 0x05, [0x04], [0x01]),
            TestRound(0x04, 0x02, [0x04], [0x02]),
            TestRound(0x03, 0x07, [0x01], [0x04, 0x01]),
            TestRound(0x06, 0x06, [0x02], [0x04]),
            TestRound(0x03, 0x02, [0x02], [0x02]),
            TestRound(0x01, 0x06, [0x01], [0x04]),
            TestRound(0x05, 0x06, [0x01], [0x04]),
            TestRound(0x04, 0x05, [0x04], [0x01]),
            TestRound(0x01, 0x05, [0x01], [0x04]),
            TestRound(0x05, 0x03, [0x01], [0x02]),
            TestRound(0x01, 0x04, [0x01], [0x04]),
            TestRound(0x01, 0x03, [0x01], [0x02]),
            TestRound(0x03, 0x05, [0x02], [0x01]),
            TestRound(0x06, 0x04, [0x02], [0x04]),
            TestRound(0x02, 0x07, [0x02], [0x01, 0x02]),
            TestRound(0x06, 0x01, [0x02], [0x01]),
            TestRound(0x02, 0x02, [0x02], [0x02]),
            TestRound(0x03, 0x04, [0x01], [0x04]),
            TestRound(0x07, 0x03, [0x04, 0x01], [0x01]),
            TestRound(0x02, 0x01, [0x02], [0x01]),
            TestRound(0x03, 0x03, [0x01], [0x01]),
            TestRound(0x02, 0x03, [0x02], [0x01]),
            TestRound(0x04, 0x07, [0x04], [0x02, 0x04]),
            TestRound(0x07, 0x04, [0x01, 0x04], [0x04]),
            TestRound(0x07, 0x01, [0x04, 0x02], [0x01]),
            TestRound(0x06, 0x05, [0x04], [0x01]),
            TestRound(0x02, 0x06, [0x02], [0x04]),
            TestRound(0x07, 0x07, [0x01, 0x02], [0x01, 0x04]),
            TestRound(0x04, 0x06, [0x04], [0x02]),
            TestRound(0x02, 0x05, [0x02], [0x01]),
            TestRound(0x06, 0x02, [0x04], [0x02]),
            TestRound(0x07, 0x02, [0x01, 0x02], [0x02]),
            TestRound(0x07, 0x06, [0x04, 0x01], [0x04]),
            TestRound(0x06, 0x07, [0x02], [0x02, 0x01]),
            TestRound(0x06, 0x03, [0x02], [0x02]),
            TestRound(0x05, 0x04, [0x04], [0x04]),
            TestRound(0x07, 0x05, [0x04, 0x02], [0x01]),
            TestRound(0x01, 0x07, [0x01], [0x04, 0x02]),
        ]

        # 3. Perform steps 4 through 11 2N times as follows, where N is the number of cases in Table 4.67,
        # Table 4.68, or Table 4.69 (selected based on the supported PHY(s)):
        # ▪ firstly using cases 1 to N from the relevant table in order;
        # ▪ then using the cases from the relevant table in a random order.
        phy_c_to_p = 0x2
        phy_p_to_c = 0x2
        for test_round in test_rounds:
            (phy_c_to_p, phy_p_to_c) = await self.steps_4_11(peer_address, acl_connection_handle, phy_c_to_p,
                                                             phy_p_to_c, **vars(test_round))

    async def steps_4_11(self, peer_address: Address, connection_handle: int, phy_c_to_p: int, phy_p_to_c: int,
                         req_tx_phys: int, req_rx_phys: int, phy_ltpref_c_to_p: List[int],
                         phy_ltpref_p_to_c: List[int]):
        controller = self.controller

        def phy_from_mask(mask: int):
            if mask & 0x4:
                return hci.PhyType.LE_CODED
            elif mask & 0x2:
                return hci.PhyType.LE_2M
            else:
                return hci.PhyType.LE_1M

        # 4. Lower Tester sends an LL_PHY_REQ PDU to the IUT to initiate a PHY change with the payload
        # defined in the LL_PHY_REQ section of the relevant table.
        controller.send_ll(
            ll.LlPhyReq(source_address=peer_address,
                        destination_address=controller.address,
                        tx_phys=req_tx_phys,
                        rx_phys=req_rx_phys))

        # 5. Lower Tester receives an LL_PHY_RSP control PDU from the IUT with at least one bit set in
        # each field (TX_PHYS, RX_PHYS).
        phy_rsp = await self.expect_ll(
            ll.LlPhyRsp(source_address=controller.address,
                        destination_address=peer_address,
                        tx_phys=self.Any,
                        rx_phys=self.Any))

        self.assertTrue(phy_rsp.tx_phys != 0)
        self.assertTrue(phy_rsp.rx_phys != 0)

        # 6. Lower Tester responds with an LL_PHY_UPDATE_IND PDU.
        next_phy_c_to_p = req_tx_phys & phy_rsp.rx_phys
        next_phy_p_to_c = req_rx_phys & phy_rsp.tx_phys

        if next_phy_c_to_p.bit_count() > 1:
            for phy in phy_ltpref_c_to_p:
                if (next_phy_c_to_p & phy) != 0:
                    next_phy_c_to_p = phy
                    break

        if next_phy_p_to_c.bit_count() > 1:
            for phy in phy_ltpref_p_to_c:
                if (next_phy_p_to_c & phy) != 0:
                    next_phy_p_to_c = phy
                    break

        next_phy_c_to_p = next_phy_c_to_p or phy_c_to_p
        next_phy_p_to_c = next_phy_p_to_c or phy_p_to_c

        controller.send_ll(
            ll.LlPhyUpdateInd(source_address=peer_address,
                              destination_address=controller.address,
                              phy_c_to_p=(0 if next_phy_c_to_p == phy_c_to_p else next_phy_c_to_p),
                              phy_p_to_c=(0 if next_phy_p_to_c == phy_p_to_c else next_phy_p_to_c)))

        # 7. Lower Tester receives a packet from the IUT acknowledging the LL_PHY_UPDATE_IND.
        # If both the PHY_C_TO_P and PHY_P_TO_C fields of the LL_PHY_UPDATE_IND are zero, skip
        # to step 11.

        # 8. Lower Tester sends empty DATA packets to the IUT, receiving acknowledgements until the event
        # count matches the indicated Instant of the PHY change.

        # 9. At the Instant of the PHY change the IUT starts maintaining the connection with the new PHY(s)
        # selected by the Lower Tester.

        # 10. Lower Tester sends empty DATA packets to the IUT, receiving acknowledgements. If the PHY(s)
        # have changed, the Lower Tester shall use the new PHY(s).

        # 11. If the PHY(s) were changed, Upper Tester receives a LE_PHY_Update_Complete event from the
        # IUT containing the PHYs selected. If both PHYs were NOT changed, Upper Tester does NOT
        # receive a LE_PHY_Update_Complete event
        if next_phy_c_to_p != phy_c_to_p or next_phy_p_to_c != phy_p_to_c:
            await self.expect_evt(
                hci.LePhyUpdateComplete(connection_handle=connection_handle,
                                        status=ErrorCode.SUCCESS,
                                        tx_phy=phy_from_mask(next_phy_p_to_c),
                                        rx_phy=phy_from_mask(next_phy_c_to_p)))

        return (next_phy_c_to_p, next_phy_p_to_c)


# EASY

'''
"rotate" every alphanumeric character by a certain amount. Rotating a
character means replacing it with another character that is a certain
number of steps away in normal alphabetic or numerical order.
For example, if the string "Zebra-493?" is rotated 3 places, the
resulting string is "Cheud-726?". Every alphabetic character is
replaced with the character 3 letters higher (wrapping around from
Z to A), and every numeric character replaced with the character
3 digits higher (wrapping around from 9 to 0).
Note that the non-alphanumeric characters remain unchanged.
Solution:

if code is not isnumeric()
ASCII code 48 - 57 -> Numbers

isupper() and and isalpha()
ASCII code 65 - 90 -> UpperCASE

islower() and isalpha()
Ascii code 97 - 122 -> lowercase

# function to get ascii for number
    x = ord(letter) + k

    # if we go past z=122

'''

#!/bin/python3

def rotationalCipher(input, rotation_factor):

    for l in input:
        print(l)

        if l.isupper():
            print ("Char is upper ", l)
        elif l.islower():
            print("Char is lowercase", l)
        elif l.isnumeric():
            print("Char is numeric")
        else:
            print("Char is special char")

 # driver code
if __name__ == '__main__':
    input = ""

    #l1 = ListNode

    result = rotationalCipher('Zebra----0000', 6)

Hackerrank/Strings/check type of character in a string.py


from codecs import backslashreplace_errors
import math
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.interpolate import interp1d
from bisect import bisect_left
import scipy.integrate as sc # simpson numerical integration routine

#These are real data as of 14th july 2023
totalTime = 337.0 * 60 * 60 # 337 h of "tracking time"
areaBore = math.pi * (2.15 * 2.15) # cm² because bore diameter is 4.3 cm
chipArea = 0.16*np.pi # in cm. I assume all flux is focused into a circular area of radius 4 mm. Thus pi*r^2= pit* 0.4^2 mm² on the detector. Relevant area for background!

BinWidth = 1.0 # in keV, the bin width of the energy bins
Energies = np.array([0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) # Energy of the center of each bin in keV
#Background = np.array([3.19e-8, 8.92e-7, 2.74e-6, 2.58e-6, 1.70e-6, 1.74e-6, 1.72e-6, 3.06e-6, 6.07e-6, 3.42e-6]) # for R = 10 mm converted to a rate in keV⁻¹cm⁻²s⁻¹
Background = np.array([0, 1.75e-6, 1.97e-6, 1.75e-6, 1.53e-6, 1.53e-6, 1.31e-6, 2.62e-6, 6.55e-6, 2.62e-6]) # for R = 4 mm
Candidates = np.array([0,      2,      0,     0,      0,      0,       0,      2,    8,      0]) #number of candidates in each energy bin or channel
EnergiesSoftware = np.array([1.75, 2.5,   3.75,    5.25,   7,   12]) #right edge of each energy bin
SoftwareEfficiencyAr1 = np.array([0.65, 0.68,   0.77,     0.71,   0.79,   0.74])
SoftwareEfficiencyAr2 = np.array([0.62, 0.79,   0.75,     0.68,   0.79,   0.71])
SoftwareEfficiencyXe = np.array([0.80, 0.94,   0.84,     0.81,   0.88,   0.87])

def solarAxionFlux(ω: float) -> float: # ω is axion energy in keV, in units 10^-12
    # From CAST constraints on the axion-electron coupling (2013)
    # axion flux produced by the Primakoff effect in solar core in units of keV⁻¹m⁻²yr⁻¹
    flux = (2.0 * (10 ** 18) * (1 / (10 ** -12)) **2 * ω**2.450 * np.exp(-0.829 * ω ))
    # convert flux to correct units --> keV⁻¹m⁻²yr⁻¹ = 3.17098e-12 keV⁻¹cm⁻²s⁻¹ !!!!
    return flux * 3.17098e-12 #in the correct units keV⁻¹cm⁻²s⁻¹

def solarAxionFlux2019(E: float) -> float:
    phi10 = 6.02 * 10 ** 10 # keV⁻¹cm⁻²s⁻¹
    flux2019 = phi10 * (1 / (10 ** -10)) ** 2 * E ** 2.481 / np.exp(E/1.205)
    return flux2019

def conversionProbability():
    # the conversion probability in the CAST magnet ( does not depend on g_aγ esxplicitly because we have taken it out to be able to raise it
    # later to the power of 4 without turning it >0)
    # simplified vacuum conversion prob. for small masses
    B = 9.0 * 195.353 #to convert into natural units. I need the factor 195.353 and the resulting units for B turn into eV^2. See tesla_conversion.nim
    L = 9.26 * 5.06773e+06 # resulting units in eV^-1
    return (1 / 10**9 * B * L / 2.0) ** 2 # divided by 10**9 to convert from GeV^-1 to eV^-1

# Here, dfTel and lerpTel are global variables that are defined independently of the function telescopeEff.
# So they are only done once, and then used inside the function if this is called.
# This csv file assumes parallel light. But in our case whe get light from the solar core, which is about 3 arcmin,
# so the efficiency is lower, like in the paper of 2013.
dfTel = pd.read_csv("data/llnl_xray_telescope_cast_effective_area_parallel_light_DTU_thesis.csv")
dfTel["Efficiency"] = dfTel["EffectiveArea[cm²]"] / areaBore * (8.174 / 10.15) # The numbers scale the parallel light effective area to the CAST JCAP 2015 effective area
#print(dfTel)
lerpTel = interp1d(dfTel["Energy[keV]"], dfTel["Efficiency"], bounds_error = False, fill_value = 0.0)
def telescopeEff(E):
    return lerpTel(E)

# Including the software efficiency by interpolation
#lerpSoftEffAr1 = interp1d(EnergiesSoftware, SoftwareEfficiencyAr1, bounds_error = False, fill_value = 0.0)
#def softwareEff(E):
#    return lerpSoftEffAr1(E)

def softwareEff(E):
    idx = 0
    for e in EnergiesSoftware:
        if E < e:
            break
        idx = idx + 1
    return SoftwareEfficiencyAr1[idx]

#Including the detector (gas+mylar) efficiecny
dfDetAr = pd.read_csv("data/ArgonAndWindowEfficiency.csv")
lerpDetAr = interp1d(dfDetAr["Photon energy [keV]"], dfDetAr["Efficiency"], bounds_error = False, fill_value = 0.0)
def detectorArEff(E):
    return lerpDetAr(E)

def totalSignal(g_aγ4):
    ## Flux integrated to total time, energy and area in counts of X-rays.
    # 1. integrate the solar flux
    ## NOTE: in practice this integration must not be done in this proc! Only perform once!
    xs = np.linspace(0.0, 10.0, 100)
    fl = np.array([solarAxionFlux(x) * telescopeEff(x) * detectorArEff(x) * softwareEff(x) for x in xs])
    #fl = np.array([solarAxionFlux(x, g_aγ) for x in xs])
    integral = sc.simpson(fl, # convert units to float for compatibility
                          xs) # convert back to units (integrated out `keV⁻¹`!)
    # 2. compute final flux by "integrating" out the time and area
    #print("Integral of axion flux * efficiency = ", integral, " time ", totalTime, " bore ", areaBore, " prob ", conversionProbability(g_aγ))
    #print("Total signal [counts] = ", integral * totalTime * areaBore * conversionProbability(g_aγ))
    return integral * totalTime * areaBore * conversionProbability() * g_aγ4

## NOTE: only important that signal and background have the same units!
# It gives the amount of signal in counts keV⁻¹ expected for each channel.
# In this case channels are energy bins, so correspond to energy E.
def signal(E, g_aγ4): # in counts keV⁻¹
    ## Returns the axion flux based on `g` and energy `E`
    return solarAxionFlux(E) * totalTime * areaBore * conversionProbability() * telescopeEff(E) * detectorArEff(E) * softwareEff(E) * g_aγ4 #be careful because this area is that of the bore, not the spot on the readout

def background(idx):
    ## Compute an interpolation of energies and background? Not necesarily in the binned approach.
    ## NOTE: For simplicity we only evaluate at the channel energies anyway. In practice
    ## one likely wants interpolation to handle all energies in the allowed range correctly!
    ## idx = Energies.lowerBound(E) # get idx of this energy
    ## Note: area of interest is the region on the chip, in which the signal is focused!
    ## This also allows us to see that the "closer" we cut to the expected axion signal on the
    ## detector, the less background we have compared to the *fixed* signal flux!
    #print("Background = ", (Background[idx] * totalTime * chipArea))
    return (Background[idx] * totalTime * chipArea) # in counts keV⁻¹  #be careful because this area is that of the spot on the readout, not the bore

def totalBackground(energies):
    #This computes the total number of background counts based on my background model.
    integralBackground = 0.0
    for index in range(energies.size):
        b = background(index)
        integralBackground += b * BinWidth
    return integralBackground
print(f"Total number of background counts =  {totalBackground(Energies)}" )

def likelihood(g_aγ4: float, energies: np.ndarray, cs: np.ndarray) -> float:
    """
    `energies` = energies corresponding to each channel
    `cs` = each element is number of counts in that energy channel
    """
    result = np.exp(-totalSignal(g_aγ4)) # `e^{-s_tot}`

    for i in range(cs.size):
        c = cs[i]       # number of candidates in this channel
        E = energies[i] # energy of this channel
        s = signal(E, g_aγ4)
        b = background(i)
        result *= pow(1 + s / b, float(c))

    return result

def logLikelihood(g_aγ4: float, energies: np.ndarray, cs: np.ndarray):
    return -np.log(likelihood(g_aγ4, energies, cs))

def likelihood2(g_aγ4: float, energies: np.ndarray, cs: np.ndarray) -> float:
    result = np.exp(-(totalSignal(g_aγ4)+totalBackground(energies))) #e^(-(s_tot + b_tot))

    for i in range(cs.size):
        c = cs[i]
        E = energies[i]
        s = signal(E, g_aγ4)
        b = background(i)
        result *= pow(s+b, c) / math.factorial(c)

    return result

def logLikelihood2(g_aγ4: float, energies: np.ndarray, cs: np.ndarray):
    return -np.log(likelihood2(g_aγ4, energies, cs))

# Now we are going to compute an expected limit.
# First we need to write a function to compute a limit.
def limit(energies: np.ndarray, cs: np.ndarray, likelihoodFunction=likelihood):
    # Compute limit, CDF@95%
    # limit needs non logspace x & y data! (at least if computed in this simple way)
    g4Lin = np.linspace(0.0, 1e-40, 1000)
    likelihoodLin = [likelihoodFunction(g4, energies, cs) for g4 in g4Lin]
    LCumSum = np.cumsum(likelihoodLin)          # cumulative sum
    LMax = LCumSum.max()               # maximum of the cumulative sum
    LCdf = LCumSum / LMax              # normalize to get (empirical) CDF
    limitIdx = bisect_left(LCdf, 0.95) # limit at 95% of the CDF

    return g4Lin[limitIdx]

def limitViaIntegral(energies: np.ndarray, cs: np.ndarray):
    # Compute limit, CDF@95%
    # limit needs non logspace x & y data! (at least if computed in this simple way)
    num = 1000
    g4Lin = np.linspace(0.0, 1e-40, num)
    likelihoodLin = [likelihood(g4, energies, cs) for g4 in g4Lin]
    fullIntegral = sc.simpson(likelihoodLin, g4Lin)
    # this does not work. It was an attempt to recover the old limit by a change of variables from dg^4 to dg.
        #gLin = np.linspace(0.0, 1e-10, num)
        #likelihoodLin = np.array([likelihood(g, energies, cs) * 4*g**3 for g in gLin])
        #fullIntegral = sc.simpson(likelihoodLin, gLin)
    # Here it would be using g, so I would recover the old limit, the one that integrates over dg instead of dg^4.
    #gLin = np.linspace(0.0, 1e-10, num)
    #likelihoodLin = np.array([likelihood(g**4, energies, cs) for g in gLin])
    #fullIntegral = sc.simpson(likelihoodLin, gLin)
    #int95 = fullIntegral * 0.95
    integrals = np.array([sc.simpson(likelihoodLin[0:i], g4Lin[0:i]) for i in range(1, num)])
    integrals = integrals / fullIntegral
    limitIdx = bisect_left(integrals, 0.95)

    #plt.plot(gLin, likelihoodLin) # to make a line plot
    plt.scatter(g4Lin, likelihoodLin) # to make dots
    plt.xlabel("Coupling constant (GeV⁻4)")
    plt.ylabel("Likelihood")
    #plt.xscale('log')
    #plt.show()
    plt.axvline(x=g4Lin[limitIdx], color='r')
    plt.savefig("energy_bins_likelihood_g4_via_integral.pdf")
    plt.close()

    return g4Lin[limitIdx]

# def limit4(energies: np.ndarray, cs : np.ndarray, toPlot: bool):

def drawCandidates(energies: np.ndarray):
    cs = np.zeros(energies.size) # it produces an array filled with zeroes, i.e. `np.zeros(2) == [0, 0]` (as numpy)
    for i in range(energies.size):
        b = background(i)
        c = np.random.poisson(b) #number of candidates in bin i, based on a Poisson distribution with mean b
        cs[i] = c
    return cs
# Compute the expected limit, i.e., the median of the possible limits we can get

def MonteCarloLim(energies: np.ndarray, nmc): # nmc = number Monte Carlo
    limits = np.zeros(nmc)
    for i in range(nmc):
        cs = drawCandidates(energies)
        lim = limit(energies, cs)
        print("Toy (expected) limit i = ", i, " is = ", pow(lim, 0.25))
        limits[i] = lim
    return limits

def AsimovDataset():
    ad = np.zeros(Background.size)
    for i in range(Background.size):
        ad[i] = background(i) * 1 # where 1 is the bin width in keV
    return ad

# Compute the real limit
lim = limit(Energies, Candidates)
print(f"\033[1;35;40m Limit at : {pow(lim, 0.25)}\033[0m")
lim2 = limit(Energies, Candidates, likelihood2)
print(f"\033[1;35;40m Limit via Nature paper approach at : {pow(lim2, 0.25)}\033[0m")
limInt = limitViaIntegral(Energies, Candidates)
#print(f"Limit via integral at : {pow(limInt, 0.25)}")
print(f"\033[1;35;40m Limit via integral at : {pow(limInt, 0.25)}\033[0m")

# print(f"Limit via integral at : {limInt}") # if I use g instead of g^4
# Compute the expected limit

limAsimov = limit(Energies, AsimovDataset())
print(f"\033[1;35;40m Expected limit via Asimov dataset at : {pow(limAsimov,0.25)}\033[0m")

MCLim = MonteCarloLim(Energies, 1) #1000 takes about 2.5 hours
np.savetxt("expected_limits_g4.csv", MCLim, delimiter = ",")
print(f"\033[1;35;40m Expected limit via median at : {pow(np.median(MCLim),0.25)}\033[0m")

# Make some plots

# Histogram of the expected limit array
plt.hist(MCLim)
plt.xlabel("Monte Carlo limits at coupling constant (GeV$^{-4}$)")
plt.ylabel("Counts")
plt.axvline(x=np.median(MCLim), color='r')
plt.savefig("MCLimits_g4.pdf")
plt.close()

# conversion probability plot
g_aγ = np.linspace(1e-13, 1e-10, 1000)
plt.plot(g_aγ, conversionProbability()*(g_aγ**2)) # I multiply by g^2 because in the function I had excluded it by dividing it out.
plt.xlabel("$g_{aγ}$ (GeV⁻¹)")
plt.ylabel("Conversion probability")
#plt.title("Conversion Probability vs g_aγ")
plt.savefig("ConversionProbability.pdf")
plt.close()

#Primakoff solar axion flux
E = np.linspace(0, 10, 200)
g_aγ = 1e-10
solarAxionFlux_values = np.array([solarAxionFlux(e) for e in E])
plt.plot(E, solarAxionFlux_values*(g_aγ**2))
plt.xlabel('Energy (keV)')
plt.ylabel('Solar axion flux for $g_{a\gamma}·10^{-10}$ (keV⁻¹ cm⁻² s⁻¹)')
plt.savefig("SolarAxionPrimakoffFlux.pdf")
plt.close()

solarAxionFlux2019_values = np.array([solarAxionFlux2019(e) for e in E])
plt.plot(E, solarAxionFlux2019_values*(g_aγ**2))
plt.xlabel('Energy (keV)')
plt.ylabel('Solar axion flux 2019 for $g_{a\gamma}·10^{-10}$ (keV⁻¹ cm⁻² s⁻¹)')
plt.savefig("SolarAxionPrimakoffFlux2019.pdf")
plt.close()

# My signal, which is the expected solar axion flux corrected by my efficiencies
g_aγ4 = 1e-40
signal_values = [signal(e, g_aγ4) for e in E]
plt.plot(E, signal_values)
plt.xlabel('Energy (keV)')
plt.ylabel('Received solar axion flux (keV⁻¹cm⁻²s⁻¹)')
plt.savefig("SolarAxionTheoreticalSignalFlux.pdf")
plt.close()

# Total signal
g_aγ4 = np.linspace(1e-52, 1e-40, 1000)
totalSignal_values = [totalSignal(g4) for g4 in g_aγ4]
plt.plot(g_aγ4, totalSignal_values)
plt.xlabel('$g_{aγ}^4$ (GeV$^{-4}$)')
plt.ylabel('Total signal (counts)')
plt.savefig("TotalSignal.pdf")
plt.close()

# Telescope efficiency
plt.plot(dfTel["Energy[keV]"], dfTel["Efficiency"])
plt.xlabel("Energy (keV)")
plt.ylabel("Efficiency")
plt.savefig("telescopeEfficiency.pdf")
plt.close()

#loglikelihood plot, i.e. -chi^2/2 vs gag^4 ??
# This does not work properly because when I raise g to the power of 4 I make it always >0
# I need to re-write the full script but making the functions `solarFlux` and `conversionProbability`
# independent of g, and then introduce g later.
# see the new script binned_lokelihood_CAST_g4.py
g_aγs = np.linspace(-1e-40, 1e-40, 1000)
logL = [logLikelihood(g_aγ, Energies, Candidates) for g_aγ in g_aγs]
plt.plot(g_aγs, logL)
plt.xlabel(' $g_{aγ}^4$ (GeV$^{-4}$)')
plt.ylabel('-log L or Chi$^2/2$')
plt.savefig("ChiSquareg4.pdf")
plt.close()

g_aγs = np.linspace(-1e-10, 1e-40, 1000)
L = [likelihood(g_aγ, Energies, Candidates) for g_aγ in g_aγs]
plt.plot(g_aγs, L)
plt.xlabel(' $g_{aγ}^4$ (GeV$^{-4}$)')
plt.ylabel('L')
plt.savefig("likelihood_negative_g4.pdf")
plt.close()

g4Lin = np.linspace(0.0, 1e-40, 1000)
likelihoodLin = [likelihood(g4, Energies, Candidates) for g4 in g4Lin]
plt.plot(g4Lin, likelihoodLin)
plt.xlabel("Coupling constant (GeV$^-4$)")
plt.ylabel("Likelihood")
#plt.xscale('log')
#plt.show()
plt.axvline(x=lim, color='r')
plt.savefig("energy_bins_likelihood_g4_bottom.pdf")
plt.close()

likelihoodLin2 = [likelihood2(g4, Energies, Candidates) for g4 in g4Lin]
plt.plot(g4Lin, likelihoodLin2)
plt.xlabel("Coupling constant (GeV$^-4$)")
plt.ylabel("Likelihood2")
#plt.xscale('log')
#plt.show()
plt.axvline(x=lim, color='r')
plt.savefig("energy_bins_likelihood_g4_Nature_approach.pdf")
plt.close()

g_aγs = np.linspace(-1e-40, 1e-40, 1000)
logL2 = [logLikelihood2(g_aγ, Energies, Candidates) for g_aγ in g_aγs]
plt.plot(g_aγs, logL2)
plt.xlabel(' $g_{aγ}^4$ (GeV$^{-4}$)')
plt.ylabel('-log L or Chi$^2/2$')
plt.savefig("ChiSquareg4_Nature_approach.pdf")
plt.close()


import inspect

import dlt
import dlt.destinations
from dlt import pipeline, attach, run, source, resource

DLT = dlt.__name__
DESTINATIONS = dlt.destinations.__name__
PIPELINE = pipeline.__name__
ATTACH = attach.__name__
RUN = run.__name__
SOURCE = source.__name__
RESOURCE = resource.__name__

DETECTED_FUNCTIONS = [PIPELINE, SOURCE, RESOURCE, RUN]
SIGNATURES = {
    PIPELINE: inspect.signature(pipeline),
    ATTACH: inspect.signature(attach),
    RUN: inspect.signature(run),
    SOURCE: inspect.signature(source),
    RESOURCE: inspect.signature(resource)
}


from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os

# Init app
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))

# Database configuration
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Database initialization
db = SQLAlchemy(app)

# Marshmallow initialization
ma = Marshmallow(app)

# Hospital Class/Model
class Hospital(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True, nullable=False)
    foundation_year = db.Column(db.Integer, nullable=False)
    adress = db.Column(db.String(100), unique=True, nullable=False)
    capacity = db.Column(db.Integer, nullable=False)
    departments = db.relationship('Department', cascade='all,delete', backref='Hospital')

    def __init__(self, name, foundation_year, adress, capacity):
        self.name = name
        self.foundation_year = foundation_year
        self.adress = adress
        self.capacity = capacity

# Hospital Schema
class HospitalSchema(ma.Schema):
    class Meta:
        fields = ('id', 'name', 'foundation_year', 'adress', 'capacity')

# Hospital schema initialization
hospital_schema = HospitalSchema()
hospitals_schema = HospitalSchema(many=True)

# Create a Hospital
@app.route('/hospital', methods=['POST'])
def app_hospital():
    name = request.json['name']
    foundation_year = request.json['foundation_year']
    adress = request.json['adress']
    capacity = request.json['capacity']

    error_message1 = 'The foundation year must be between 1500 and 2020'
    if ((foundation_year > 2020) or (foundation_year < 1500)):
        return error_message1
    error_message2 = 'The capacity must be between 1 and 5000'
    if ((capacity > 5000) or (capacity < 1)):
        return error_message2
    error_message3 = 'Hospital with this adress already exists'
    hospitals = Hospital.query.all()
    for h in hospitals:
        if (h.adress == adress):
            return error_message3

    new_hospital = Hospital(name, foundation_year, adress, capacity)

    db.session.add(new_hospital)
    db.session.commit()

    return hospital_schema.jsonify(new_hospital)

# Get All Hospitals
@app.route('/hospital', methods=['GET'])
def get_hospitals():
    all_hospitals = Hospital.query.all()
    result = hospitals_schema.dump(all_hospitals)
    return jsonify(result.data)

# Get Single Hospital
@app.route('/hospital/<id>', methods=['GET'])
def get_hospital(id):
    hospital = Hospital.query.get(id)
    return hospital_schema.jsonify(hospital)

# Update a Hospital
@app.route('/hospital/<id>', methods=['PUT'])
def update_hospital(id):
    hospital = Hospital.query.get(id)

    name = request.json['name']
    foundation_year = request.json['foundation_year']
    adress = request.json['adress']
    capacity = request.json['capacity']

    error_message1 = 'The foundation year must be between 1500 and 2020'
    if ((foundation_year > 2020) or (foundation_year < 1500)):
        return error_message1
    error_message2 = 'The capacity must be between 1 and 5000'
    if ((capacity > 5000) or (capacity < 1)):
        return error_message2
    error_message3 = 'Hospital with this adress already exists'
    hospitals = Hospital.query.all()
    for h in hospitals:
        if (h.adress == adress):
            return error_message3

    hospital.name = name
    hospital.foundation_year = foundation_year
    hospital.adress = adress
    hospital.capacity = capacity

    db.session.commit()

    return hospital_schema.jsonify(hospital)

# Delete Hospital
@app.route('/hospital/<id>', methods=['DELETE'])
def delete_hospital(id):
    hospital = Hospital.query.get(id)
    db.session.delete(hospital)
    db.session.commit()
    return hospital_schema.jsonify(hospital)

# Department Class/Model
class Department(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    hospital_id = db.Column(db.Integer, db.ForeignKey('hospital.id'))
    doctors = db.relationship('Doctor', cascade='all,delete', backref='Department')

    def __init__(self, name, hospital_id):
        self.name = name
        self.hospital_id = hospital_id

# Department Schema
class DepartmentSchema(ma.Schema):
    class Meta:
        fields = ('id', 'name', 'hospital_id')

# Department schema initialization
department_schema = DepartmentSchema()
departments_schema = DepartmentSchema(many=True)

# Create a Department
@app.route('/department', methods=['POST'])
def app_department():
    name = request.json['name']
    hospital_id = request.json['hospital_id']

    new_department = Department(name, hospital_id)

    db.session.add(new_department)
    db.session.commit()

    return department_schema.jsonify(new_department)

# Get All Departments
@app.route('/department', methods=['GET'])
def get_departments():
    all_departments = Department.query.all()
    result = departments_schema.dump(all_departments)
    return jsonify(result.data)

# Get Single Department
@app.route('/department/<id>', methods=['GET'])
def get_department(id):
    department = Department.query.get(id)
    return department_schema.jsonify(department)

# Update a Department
@app.route('/department/<id>', methods=['PUT'])
def update_department(id):
    department = Department.query.get(id)

    name = request.json['name']
    hospital_id = request.json['hospital_id']

    department.name = name
    department.hospital_id = hospital_id

    db.session.commit()

    return department_schema.jsonify(department)

# Delete Department
@app.route('/department/<id>', methods=['DELETE'])
def delete_department(id):
    department = Department.query.get(id)
    db.session.delete(department)
    db.session.commit()
    return department_schema.jsonify(department)

# Treatment Table
Treatment = db.Table('Treatment',
    db.Column('doctor_id', db.Integer, db.ForeignKey('doctor.id')),
    db.Column('patient_id', db.Integer, db.ForeignKey('patient.id'))
)

# Doctor Class/Model
class Doctor(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    birth_year = db.Column(db.Integer, nullable=False)
    start_year = db.Column(db.Integer, nullable=False)
    gender = db.Column(db.String(100), nullable=False)
    department_id = db.Column(db.Integer, db.ForeignKey('department.id'))
    patients = db.relationship('Patient', cascade='all,delete', secondary=Treatment)

    def __init__(self, name, birth_year, start_year, gender, department_id):
        self.name = name
        self.birth_year = birth_year
        self.start_year = start_year
        self.gender = gender
        self.department_id = department_id

# Doctor Schema
class DoctorSchema(ma.Schema):
    class Meta:
        fields = ('id', 'name', 'birth_year', 'start_year', 'gender', 'department_id')

# Doctor schema initialization
doctor_schema = DoctorSchema()
doctors_schema = DoctorSchema(many=True)

# Create a Doctor
@app.route('/doctor', methods=['POST'])
def app_doctor():
    name = request.json['name']
    birth_year = request.json['birth_year']
    start_year = request.json['start_year']
    gender = request.json['gender']
    department_id = request.json['department_id']

    new_doctor = Doctor(name, birth_year, start_year, gender, department_id)

    db.session.add(new_doctor)
    db.session.commit()

    return doctor_schema.jsonify(new_doctor)

# Get All Doctors
@app.route('/doctor', methods=['GET'])
def get_doctors():
    all_doctors = Doctor.query.all()
    result = doctors_schema.dump(all_doctors)
    return jsonify(result.data)

# Get Single Doctor
@app.route('/doctor/<id>', methods=['GET'])
def get_doctor(id):
    doctor = Doctor.query.get(id)
    return doctor_schema.jsonify(doctor)

# Update a Doctor
@app.route('/doctor/<id>', methods=['PUT'])
def update_doctor(id):
    doctor = Doctor.query.get(id)

    name = request.json['name']
    birth_year = request.json['birth_year']
    start_year = request.json['start_year']
    gender = request.json['gender']
    department_id = request.json['department_id']

    doctor.name = name
    doctor.birth_year = birth_year
    doctor.start_year = start_year
    doctor.gender = gender
    doctor.department_id = department_id

    db.session.commit()

    return doctor_schema.jsonify(doctor)

# Delete Doctor
@app.route('/doctor/<id>', methods=['DELETE'])
def delete_doctor(id):
    doctor = Doctor.query.get(id)
    db.session.delete(doctor)
    db.session.commit()
    return doctor_schema.jsonify(doctor)

# Patient Class/Model
class Patient(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    birth_year = db.Column(db.Integer, nullable=False)
    weight = db.Column(db.Integer, nullable=False)
    height = db.Column(db.Integer, nullable=False)
    gender = db.Column(db.String(100), nullable=False)

    def __init__(self, name, birth_year, weight, height, gender):
        self.name = name
        self.birth_year = birth_year
        self.weight = weight
        self.height = height
        self.gender = gender

# Patient Schema
class PatientSchema(ma.Schema):
    class Meta:
        fields = ('id', 'name', 'birth_year', 'weight', 'height', 'gender')

# Patient schema initialization
patient_schema = PatientSchema()
patients_schema = PatientSchema(many=True)

# Create a Patient
@app.route('/patient', methods=['POST'])
def app_patient():
    name = request.json['name']
    birth_year = request.json['birth_year']
    weight = request.json['weight']
    height = request.json['height']
    gender = request.json['gender']

    new_patient = Patient(name, birth_year, weight, height, gender)

    db.session.add(new_patient)
    db.session.commit()

    return patient_schema.jsonify(new_patient)

# Get All Patients
@app.route('/patient', methods=['GET'])
def get_patients():
    all_patients = Patient.query.all()
    result = patients_schema.dump(all_patients)
    return jsonify(result.data)

# Get Single Patient
@app.route('/patient/<id>', methods=['GET'])
def get_patient(id):
    patient = Patient.query.get(id)
    return patient_schema.jsonify(patient)

# Update a Patient
@app.route('/patient/<id>', methods=['PUT'])
def update_patient(id):
    patient = Patient.query.get(id)

    name = request.json['name']
    birth_year = request.json['birth_year']
    weight = request.json['weight']
    height = request.json['height']
    gender = request.json['gender']

    patient.name = name
    patient.birth_year = birth_year
    patient.weight = weight
    patient.height = height
    patient.gender = gender

    db.session.commit()

    return patient_schema.jsonify(patient)

# Delete Patient
@app.route('/patient/<id>', methods=['DELETE'])
def delete_patient(id):
    patient = Patient.query.get(id)
    db.session.delete(patient)
    db.session.commit()
    return patient_schema.jsonify(patient)

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


#사용자에게 연속해서5개의 정수를 입력받아 다음과 같이 출려되도록 하시오
# 입력이 몇번째인지 출력
#입력된 값의 합

idx = 1
value = []  #입력된 값을 리스트에 저장하기위한변수
count = 0   #누적합이 보관될 변수
while idx < 6:
    #num = int(input('%d번째' %idx))
    num = int(input('{}번째 입력 : '.format(idx)))
    count = count + num
    value.append(num)
    idx = idx + 1

print('누적합 : ' , count)
print('입력된값 : ', value)