import numpy as np
import datetime
import pandas as pd
import matplotlib.pyplot as plt

class DELTR_Trainer():
    '''
    Disparate Exposure in Learning To Rank
    --------------------------------------

    A supervised learning to rank algorithm that incorporates a measure of performance and a measure
    of disparate exposure into its loss function. Trains a linear model based on performance and
    fairness for a protected group.
    By reducing disparate exposure for the protected group, increases the overall group visibility in
    the resulting rankings and thus prevents systematic biases against a protected group in the model,
    even though such bias might be present in the training data.

    At this point, only works for one protected group.

    :field __pathToTrainingData: file path to training data. Requires first column to contain the
                                 query ids and last column to contain the training judgments
                                 (in descending order, i.e. higher scores are better)
    :field __pathToModelFile: file path in which resulting model (i.e. list of feature weights) are stored
    :field __resultDir: directory where to save plots

    :field __numberIterations: iterations in gradient descent
    :field __learningRate: learning rate in gradient descent
    :field __initVar: range of values for initialization of weights
    :field __lambda: regularization constant

    :field __gamma: float parameter tuning the disparate exposure metric
    :field __protectedColumn: index of column in data that contains protected attribute
    :field __protectedAttribute: int that describes the protected feature in the training data
    '''

    def __init__(self, pathToTrainingData, pathToModelFile, resultDir, gamma, numIter, learningRate,
                 protCol, protAttr, initVar, lambdaa, quiet=False):
        # paths
        self.__pathToTrainingData = pathToTrainingData
        self.__pathToModelFile = pathToModelFile
        self.__resultDir = resultDir

        # constants for gradient descent
        self.__numberIterations = numIter
        self.__learningRate = learningRate
        self.__initVar = initVar
        self.__lambda = lambdaa

        # constants for DELTR
        self.__gamma = gamma
        self.__protectedColumn = protCol
        self.__protectedAttribute = protAttr

        # switch off exposure calculation if gamma is zero, because it's faster
        self.__noExposure = False
        if gamma == 0:
            self.__noExposure = True

        # print intermediate steps to stdout
        self.__quiet = quiet

    def train(self, colorblind=False):
        '''
        prepares data and launches training routine.
        also measures time for the calculation and saves resulting model to disk
        '''
        # read testfile and load training dataset
        data = pd.read_csv(self.__pathToTrainingData, decimal=',', header=None)
        if colorblind:
            # if training should be done without protected attribute, set whole protected column to zero
            data[self.__protectedColumn].values[:] = 0
            # also switch off exposure calculation, as not needed, which speeds up training
            self.__noExposure = True
        # TODO: Steffi --> warum wandelst du den dataframe in ein np-array um? schreib mal einen Kommentar dazu
        # cast dataframe entries to numeric values
        data = data.apply(pd.to_numeric, errors='ignore')
        print(data)

        # prepare data
        query_ids = np.asarray(data.iloc[:, 0])
        featureMatrix = np.asarray(data.iloc[:, 1:(data.shape[1] - 1)])
        trainingScores = np.reshape(np.asarray(data.iloc[:, data.shape[1] - 1]), (featureMatrix.shape[0], 1))

        # launch the training routine
        start = datetime.datetime.now()
        omega = self._trainNN(query_ids,
                              featureMatrix,
                              trainingScores)
        end = datetime.datetime.now()
        print("time: ", end - start)
        print("omega: ", omega)

        # safe results
        np.save(self.__pathToModelFile, omega)

    def _trainNN(self, query_ids, featureMatrix, trainingScores):
        """
        trains the Neural Network to find the optimal feature weights in listwise learning to rank

        :param query_ids: list of query IDs
        :param featureMatrix: training features
        :param trainingScores: training judgments
        """
        m = featureMatrix.shape[0]
        n_features = featureMatrix.shape[1]

        prot_idx = np.reshape(featureMatrix[:, self.__protectedColumn] == np.repeat(self.__protectedAttribute, m), (m, 1))
        # linear neural network parameter initialization
        omega = (np.random.rand(n_features, 1) * self.__initVar).reshape(-1)
        #omega = (0.01, 0.01)

        cost_converge_J = np.zeros((self.__numberIterations, 1))
#         cost_converge_L = np.zeros((self.__numberIterations, 1))
#         cost_converge_U = np.zeros((self.__numberIterations, 1))
        omega_converge = np.empty((self.__numberIterations, n_features))

        # training routine
        for t in range(0, self.__numberIterations):
            if self.__quiet == False:
                print('iteration ', t)

            # forward propagation
            predictedScores = np.dot(featureMatrix, omega)
            predictedScores = np.reshape(predictedScores,(featureMatrix.shape[0], 1))
            #predictedScores = np.reshape(np.asarray(predictedScores).astype('float'), (len(predictedScores), 1))

            # cost
            if self.__quiet == False:
                print('computing cost')

            # with regularization
            cost = self._calculateCost(trainingScores, predictedScores, query_ids, prot_idx)
            J = cost + np.transpose(np.multiply(predictedScores, predictedScores)) * self.__lambda
            cost_converge_J[t] = np.sum(J)

            if self.__quiet == False:
                print("computing gradient")

            grad = self._calculateGradient(featureMatrix, trainingScores, predictedScores, query_ids, prot_idx)
            omega = omega - self.__learningRate * np.sum(np.asarray(grad), axis=0).reshape(-1)
            omega_converge[t, :] = np.transpose(omega[:])

            if self.__quiet == False:
                print('\n')

        # plots
        plt.subplot(211)
        plt.plot(cost_converge_J)
        plt.subplot(212)
        plt.plot(omega_converge)
        plt.savefig(self.__resultDir + 'cost_and_gradient.png')

        return omega

    def _calculateCost(self, training_judgments, predictions, query_ids, prot_idx):
        """
        computes the loss in list-wise learning to rank
        it incorporates L which is the error between the training judgments and those
        predicted by a model and U which is the disparate exposure metric
        implementation of equation 6 in DELTR paper

        :param training_judgments: containing the training judgments/ scores
        :param predictions: containing the predicted scores
        :param query_ids: list of query IDs
        :param prot_idx: list stating which item is protected or non-protected
        :return: a float value --> loss
        """
        data_per_query = lambda which_query, data: \
                                       self._find_items_per_group_per_query(data,
                                                                             query_ids,
                                                                             which_query,
                                                                             prot_idx)

        # eq 2 from DELTR paper
        loss = lambda which_query: \
                            -np.dot(np.transpose(self._topp(data_per_query(which_query,
                                                                           training_judgments)[0])),
                                    np.log(self._topp(data_per_query(which_query,
                                                                     predictions)[0])))/np.log(predictions.size)

        if self.__noExposure:
            cost = lambda which_query: loss(which_query)
        else:
            # eq 6 from DELTR paper
            cost = lambda which_query:  self.__gamma \
                                        * self._exposure_diff(predictions,
                                                              query_ids,
                                                              which_query,
                                                              prot_idx) \
                                        ** 2 \
                                        +loss(which_query)
        print("U: {}".format(self._exposure_diff(predictions,query_ids,1,prot_idx)))
        print("L: {}".format(loss(1)))

        results = [cost(query) for query in query_ids]

        return np.asarray(results)

    def _calculateGradient(self, training_features, training_judgments, predictions, query_ids, prot_idx):
        """
        calculates local gradients of current feature weights
        implementation of equation 8 and appendix A in paper DELTR

        :param training_features: containing all the features
        :param training_judgments: vector containing the training judgments/ scores
        :param predictions: vector containing the prediction scores
        :param query_ids: list of query IDs
        :param prot_idx: list stating which item is protected or non-protected
        :return: float value --> optimal listwise cost
        """
        # find all training judgments and all predicted scores that belong to one query
        data_per_query = lambda which_query, data: \
                                       self._find_items_per_group_per_query(data,
                                                                            query_ids,
                                                                            which_query,
                                                                            prot_idx)
        # Exposure in rankings for protected and non-protected group, right summand in eq 8
        U_deriv = lambda which_query:   2 \
                                        * self._exposure_diff(predictions,
                                                              query_ids,
                                                              which_query,
                                                              prot_idx) \
                                        * self._normalized_topp_prot_deriv_per_group_diff(training_features,
                                                                                predictions,
                                                                                query_ids,
                                                                                which_query,
                                                                                prot_idx)
        # Training error
        l1 = lambda which_query: np.dot(np.transpose(data_per_query(which_query,
                                                                    training_features)[0]),
                                        self._topp(data_per_query(which_query,
                                                                  training_judgments)[0]))
        l2 = lambda which_query: 1 \
                                 / np.sum(np.exp(data_per_query(which_query,
                                                                predictions)[0]))
        l3 = lambda which_query: np.dot(np.transpose(data_per_query(which_query,
                                                                    training_features)[0]),
                                        np.exp(data_per_query(which_query,
                                                              predictions)[0]))

        L_deriv = lambda which_query:(-l1(which_query) + l2(which_query) * l3(which_query))/np.log(predictions.size)

        if self.__noExposure:
            # standard L2R that only considers loss
            grad = lambda which_query: L_deriv(which_query)
        else:
            # eq 8 in DELTR paper
            grad = lambda which_query: self.__gamma * U_deriv(which_query) + L_deriv(which_query).reshape(-1)

#         if Globals.ONLY_U:
#             grad = lambda which_query: gamma * U_deriv(which_query)
        results = [grad(query) for query in query_ids]
        return np.asarray(results)

    def _find_items_per_group_per_query(self, data, query_ids, which_query, prot_idx):
        """
        finds all the items with a given query ID and separates the items into protected
        and non-protected groups

        :param data: all predictions or training judgments
        :param query_ids: list of query IDs
        :param which_query: given query ID
        :param prot_idx: list stating which item is protected or non-protected
        :return: three matrices
        """
        judgments_per_query = self.__find_items_per_query(data,
                                                          query_ids,
                                                          which_query)
        prot_idx_per_query = self.__find_items_per_query(prot_idx,
                                                         query_ids,
                                                         which_query)
        protected_items_per_query = judgments_per_query[np.where(prot_idx_per_query == True)[0], :]
        nonprotected_items_per_query = judgments_per_query[np.where(prot_idx_per_query == False)[0], :]

        return judgments_per_query, protected_items_per_query, nonprotected_items_per_query

    def __find_items_per_query(self, data, query_ids, which_query):
        """
        finds items which contains the given query_id

        :param data: all predictions or training judgments
        :param query_ids: list of query IDs
        :param which_query: given query ID
        :return: matrix filtered by which_query
        """
        return data[np.where(query_ids == which_query)[0], :]

    def _exposure_diff(self, data, query_ids, which_query, prot_idx):
        """
        computes the exposure difference between protected and non-protected groups
        implementation of equation 5 in DELTR paper but without the square

        :param data: all predictions
        :param query_ids: list of query IDs
        :param which_query: given query ID
        :param prot_idx: list states which item is protected or non-protected

        :return: float value
        """
        judgments_per_query, \
        protected_items_per_query, \
        nonprotected_items_per_query = self._find_items_per_group_per_query(data,
                                                                             query_ids,
                                                                             which_query,
                                                                             prot_idx)
        exposure_prot = self.__normalized_exposure(protected_items_per_query,
                                                   judgments_per_query)
        exposure_nprot = self.__normalized_exposure(nonprotected_items_per_query,
                                                    judgments_per_query)
        exposure_diff = np.maximum(0, (exposure_nprot - exposure_prot))

        return exposure_diff

    def __normalized_exposure(self, group_data, all_data):
        '''
        calculates the exposure of a group in the entire ranking
        implementation of equation 4 in DELTR paper

        :param group_data: predictions of relevance scores for one group
        :param all_data: all predictions

        :return: float value that is normalized exposure in a ranking for one group
                 nan if group size is 0
        '''
        return (np.sum(self.__topp_prot(group_data, all_data) / np.log(2))) / group_data.size

    def __topp_prot(self, group_items, all_items):
        '''
        given a dataset of features what is the probability of being at the top position
        for one group (group_items) out of all items
        example: what is the probability of each female (or male respectively) item (group_items) to be in position 1
        implementation of equation 7 in paper DELTR

        :param group_items: vector of predicted scores of one group (protected or non-protected)
        :param all_items: vector of predicted scores of all items

        :return: numpy array of float values
        '''
        return np.exp(group_items) / np.sum(np.exp(all_items))

    def _normalized_topp_prot_deriv_per_group_diff(self, training_features, predictions, query_ids, which_query, prot_idx):
        """
        calculates the difference of the normalized topp_prot derivative of the protected and non-protected groups
        implementation of the second factor equation 12 in paper DELTR

        :param training_features: vector of all features
        :param predictions: predictions of all data points
        :param query_ids: list of query IDs
        :param which_query: given query
        :param prot_idx: list stating which item is protected or non-protected

        :return: numpy array of float values
        """
        train_judgments_per_query, \
        train_protected_items_per_query, \
        train_nonprotected_items_per_query = self._find_items_per_group_per_query(training_features,
                                                                                query_ids,
                                                                                which_query,
                                                                                prot_idx)

        predictions_per_query, \
        pred_protected_items_per_query, \
        pred_nonprotected_items_per_query = self._find_items_per_group_per_query(predictions,
                                                                                query_ids,
                                                                                which_query,
                                                                                prot_idx)

        u2 = self.__normalized_topp_prot_deriv_per_group(\
            train_nonprotected_items_per_query, \
            train_judgments_per_query, \
            pred_nonprotected_items_per_query, \
            predictions_per_query)  # derivative for non-protected group
        u3 = self.__normalized_topp_prot_deriv_per_group(\
            train_protected_items_per_query, \
            train_judgments_per_query, \
            pred_protected_items_per_query, \
            predictions_per_query)  # derivative for protected group

        return u2 - u3

    def __normalized_topp_prot_deriv_per_group(self, group_features, all_features, group_predictions, all_predictions):
        """
        normalizes the results of the derivative of topp_prot

        :param group_features: feature vector of (non-) protected group
        :param all_features: feature vectors of all data points
        :param group_predictions: predictions of all data points
        :param all_predictions: predictions of all data points

        :return: numpy array of float values
        """
        derivative = self.__topp_prot_first_derivative(group_features,
                                                       all_features,
                                                       group_predictions,
                                                       all_predictions)
        result = (np.sum(derivative / np.log(2), axis=0)) / group_predictions.size
        return result

    def __topp_prot_first_derivative(self, group_features, all_features, group_predictions, all_predictions):
        '''
        Derivative for topp_prot in pieces:
        implementation of equation 11 in paper DELTR

        :param group_features: feature vector of (non-) protected group
        :param group_predictions: predicted scores for (non-) protected group
        :param all_predictions: predictions of all data points
        :param all_features: feature vectors of all data points

        :return: numpy array with weight adjustments
        '''
        # numerator1 = np.dot(group_features, np.repeat(np.exp(group_predictions), group_features.shape[0]))
        numerator1 = np.dot(np.transpose(np.exp(group_predictions)),
                            group_features)
        numerator2 = np.sum(np.exp(all_predictions))
        numerator3 = np.sum(np.dot(np.transpose(np.exp(all_predictions)),
                                   all_features))
        denominator = np.sum(np.exp(all_predictions)) ** 2

        result = (numerator1 * numerator2 - np.exp(group_predictions) * numerator3) / denominator

        # return result as flat numpy array instead of matrix
        return np.asarray(result)

    def _topp(self, v):
        """
        computes the probability of a document being
        in the first position of the ranking
        implementation of equation 7 in paper DELTR

        :param v: all training judgments or all predictions
        :return: float value which is a probability
        """
        return np.exp(v) / np.sum(np.exp(v))


#Todays DPP: Take a list as input and find if the second highest value is a prime number or not

#Take List input
lus = []
len = int(input("Enter number of elements in list : ")) # number of elements as input
for i in range(0, len): # iterating till the range
    lus.append(int(input(" enter individual elements ")))  # adding the element
print("Unsorted list",lus)

#To Find 2nd highest
ls=sorted(lus)
print("sorted list",ls)
sechigh=ls[len-2]
print("second highest num is ",sechigh)

#Program to check prime number
indicator = True
x= sechigh
for i in range (2,x-1) :
    if (x%i == 0 ) :
        indicator = False
    elif(x==1) :
        indicator = True
if (indicator == True ) :
    print(" Sec High is prime ")
else :
    print (" Sec High is not prime")

"""Alternate way"""
a=[]
len=int(input("enter the length of list:"))
for i  in range(0,len):
    y=int(input("enter the elements of the list:"))
    a.append(y)
print(a)
b=max(a)
print(b)
a.remove(b)
print(a)
c=max(a)

indicator = True
x= c
for i in range (2,x-1) :
    if (x%i == 0 ) :
        indicator = False
    elif(x==1) :
        indicator = True
if (indicator == True ) :
    print(" NUm is prime ")
else :
    print (" Num is not prime")


import datetime

import pytz
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
# Create your models here.

class Plant(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(
        max_length=512,
        verbose_name="Name",
        help_text="Plant name",
        unique=True
    )

    def __str__(self):
        return self.name

    def get_serialized_model(self, show_datapoints=True):
        if show_datapoints:
            datapoints = [datapoint.get_serialized_model() for datapoint in Datapoint.objects.filter(plant_id=self.id)]
            return {
                'id': self.id,
                'name': self.name,
                'datapoints': datapoints
            }
        return {
                'id': self.id,
                'name': self.name
            }

    class Meta:
        verbose_name = "Plant"
        verbose_name_plural = "Plants"

class DatapointManager(models.Manager):
    def check_or_create_datapoint(self, **kwargs):
        try:
            datapoint_datetime = datetime.datetime.strptime(
                kwargs.get('datetime'),
                "%Y-%m-%dT%H:%M:%S%z"
            ).astimezone(pytz.timezone(settings.TIME_ZONE))
        except ValueError:
            datapoint_datetime = datetime.datetime.strptime(
                kwargs.get('datetime'),
                "%Y-%m-%dT%H:%M:%S"
            ).astimezone(pytz.timezone(settings.TIME_ZONE))
        try:
            model = self.get_queryset().get(
                plant_id=kwargs.get('plant_id'),
                datetime= datapoint_datetime
            )
        except ObjectDoesNotExist:
            model = self.model(
                plant_id=kwargs.get('plant_id'),
                datetime=datapoint_datetime,
                energy_expected=kwargs.get('expected').get('energy'),
                energy_observed=kwargs.get('observed').get('energy'),
                irradiation_expected=kwargs.get('expected').get('irradiation'),
                irradiation_observed=kwargs.get('observed').get('irradiation'),
            )
            model.save()
        return model

class Datapoint(models.Model):
    id = models.AutoField(primary_key=True)
    plant = models.ForeignKey(
        Plant,
        verbose_name="Plant",
        related_name="plant_datapoints",
        on_delete=models.CASCADE
    )
    energy_expected = models.DecimalField(decimal_places=14, max_digits=17)
    energy_observed = models.DecimalField(decimal_places=14, max_digits=17)
    irradiation_expected = models.DecimalField(decimal_places=14, max_digits=17)
    irradiation_observed = models.DecimalField(decimal_places=14, max_digits=17)
    datetime = models.DateTimeField(
        verbose_name="Datetime",
        help_text="Datapoint extraction datetime",
        null=True,
        blank=True
    )

    objects = DatapointManager()

    def get_serialized_model(self):
        return {
            'id': self.id,
            'plant_id': self.plant_id,
            'expected': {
                'energy': float(self.energy_expected),
                'irradiation': float(self.irradiation_expected)
            },
            'observed': {
                'energy': float(self.energy_observed),
                'irradiation': float(self.irradiation_observed)
            },
            'datetime': self.datetime.isoformat() if self.datetime else None
        }

    class Meta:
        verbose_name = "Datapoint"
        verbose_name_plural = "Datapoints"
        unique_together = ('plant', 'datetime')


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

from tempest.lib.cli import base as cli_base
from tempest.lib import exceptions
from tempest.tests.lib import base

class TestExecute(base.TestCase):
    def test_execute_success(self):
        result = cli_base.execute("/bin/ls", action="tempest",
                                  flags="-l -a")
        self.assertIsInstance(result, str)
        self.assertIn("__init__.py", result)

    def test_execute_failure(self):
        result = cli_base.execute("/bin/ls", action="tempest.lib",
                                  flags="--foobar", merge_stderr=True,
                                  fail_ok=True)
        self.assertIsInstance(result, str)
        self.assertIn("--foobar", result)

    def test_execute_failure_raise_exception(self):
        self.assertRaises(exceptions.CommandFailed, cli_base.execute,
                          "/bin/ls", action="tempest", flags="--foobar",
                          merge_stderr=True)


import requests
import json
import copy
import datetime

def search(inputs):
  loop_counter = 0
  returnlist = []
  len_returnlist = 0
  offset = 0

  json_url = "http://jservice.io/api/clues?"

  if inputs["difficulty"] != "":
    json_url = json_url+ "value="+inputs['difficulty']+"&"

  if inputs['category_ID']:
    json_url = json_url+ "category=" + inputs["category_ID"] + "&"

  if inputs["date"] and inputs["date2"]:
    json_url = json_url + "min_date=" + str(inputs["date"])+ "&max_date=" + str(inputs["date2"])+"&"

  json_url_og = json_url
  json_data = requests.get(json_url_og).json()

  while json_data != [] and len_returnlist <= int(inputs["show_count"]):
    if offset > 2000:
      return returnlist   #cut off search if time takes too long

    for dictionary in json_data:
      if inputs['searchword'] in dictionary["answer"].split() or inputs['searchword'] in dictionary["question"].split() or inputs['searchword'] in dictionary["category"]["title"].split():
        returnlist.append(dictionary)
        len_returnlist += 1

    offset += 100
    json_url = json_url_og + "offset=" + str(offset)
    json_data = requests.get(json_url).json()

  return returnlist


import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from pathlib import Path
import h5py  # Importing the h5py library for HDF5 file handling

def from_hdf5(file_hdf5):
    """
    Read data from an HDF5 file and construct a Trace object containing various astronomical data.
    This function opens the specified HDF5 file and reads various data related to astronomical observations,
    such as resolution, Full Width Half Maximum (FWHM), offsets, frames, reference frame indice, stars, and traces of space objects.

    Usage:
        >>> from sotfinder import from_hdf5
        >>> trace = from_hdf5('path_to_hdf5_file.hdf5')
    Inputs:
        file_hdf5 -> [str] Path to the HDF5 file.
    Outputs:
        Trace -> A Trace object containing structured data extracted from the HDF5 file.

    The function reads the following key data from the HDF5 file:
        - 'res': Resolution of the observation image.
        - 'fwhm': Full Width Half Maximum (FWHM) values of the image.
        - 'offset': The coordinates of the image center relative to the original coordinate origin (the center of the lower-left pixel).
        - 'ref_ind': Index of the reference frame.
        - 'transf': Affine transformation matrix to the reference frame.
        - 'frames': image frames.
        - 'stars/xy_local': Local pixel coordinates of stars in each frame.
        - 'stars/flux': Flux of stars.
        - 'stars/snr': Signal-to-noise ratio of stars.
        - 'lines': Data representing the motion trails of space objects in the observation.

    For each line (space object's motion trail):
        - 'xy_affine': Affined pixel coordinates in the reference frame.
        - 'xy_local': Local pixel coordinates in each frame.
        - 'flux': Flux values of the space object on trail.
        - 'snr': Signal-to-noise ratio.
        - 'flags': Indicators for the presence of the space object in the image frame.

    The function closes the HDF5 file after reading all necessary data.
    """

    # Open the HDF5 file for reading
    with h5py.File(file_hdf5, 'r') as fin:

        # Extracting basic information
        res = tuple(fin['res'][:])
        fwhm = fin['fwhm'][()]
        offset = fin['offset'][:]
        ref_ind = fin['ref_ind'][()]

        # Extracting frame names, transformation matrix, and images
        frames = list(fin['frames'][:])
        transf = fin['transf'][:]
        images = fin['images'][:]

        # Preparing trace information
        trace_info = {
            'res': res,
            'fwhm': fwhm,
            'offset': offset,
            '_ref_ind': ref_ind,
            'frames': frames,
            'transf': transf,
            '_images': images
        }

        # Extracting star information
        xy_local_star = [ele.reshape(len(ele)//2, 2) for ele in fin['stars/xy_local'][:]]
        # 'xy_local_star' contains the reshaped local coordinates of stars in each frame

        flux_star = fin['stars/flux'][:].tolist()
        # 'flux_star' holds the flux values of stars, converted to a list for easier manipulation

        snr_star = fin['stars/snr'][:].tolist()
        # 'snr_star' contains the signal-to-noise ratio of stars, also converted to a list

        # Organizing star information into a dictionary for the Trace object
        stars_info = {
            'xy_local': xy_local_star,
            'flux': flux_star,
            'snr': snr_star,
            '_n_mid': len(snr_star[ref_ind]) # The number of stars in the reference frame
        }
        # Adding the structured star information to 'trace_info' for further processing
        trace_info['stars'] = Stars(stars_info)

        # Processing lines representing space objects' motion trails
        lines = fin['lines']
        for key in lines.keys():
            # Extracting affine and local coordinates, flux, SNR, and flags for each trace
            xy_affine = lines[f'{key}/xy_affine'][:]
            xy_local = lines[f'{key}/xy_local'][:]
            flux = lines[f'{key}/flux'][:]
            snr = lines[f'{key}/snr'][:]
            _flags = lines[f'{key}/_flags'][:]

            # Structuring line information into a dictionary
            line_info = {
                'xy_affine': xy_affine, # Affined pixel coordinates in the reference frame
                'xy_local': xy_local,   # Local pixel coordinates in each frame
                'flux': flux,           # Flux values for the trace
                'snr': snr,             # Signal-to-noise ratio for trace
                '_flags': _flags         # Flags indicating presence of trace in the image frame
            }
            # Adding the structured line information to the trace info
            trace_info[key] = Line(line_info)

        # Update trace information with the number of frames and traces
        trace_info.update({
            '_num_frames': len(frames), # Total number of frames processed
            '_num_traces': len(lines.keys()) # Total number of identified traces
        })

    # Return the structured Trace object with all gathered information
    return Trace(trace_info)

class Trace(object):
    """
    Class representing a collection of astronomical observation data. It includes information about
    resolution, stars, trajectories of space objects, and other relevant astronomical data.

    Attributes:
        res (tuple): Resolution of the image frame.
        Typically stored as a tuple (width, height), such as (1024,1024), representing the number of pixels in each dimension of the image.
        fwhm (float): Full Width at Half Maximum of the Gaussian kernel for the image.
        offset (tuple): Pixel coordinates of the image center relative to the lower-left pixel center, such as (511.5,511.5).
        frames (list): The collection of image frames in the observation. Each frame captures a view of the sky at a specific time.
        transf (2D numpy array): Transformation matrices.
        Used for image alignment or to map coordinates from one frame to another. Essential for comparing and combining data across multiple frames.
        stars (Stars): Information about the stars in the observation.
        In form of a complex object about identified stars, such as their positions, brightness, and signal-to-noise ratios.
        line0,line1,.. (Line): The motion trails of space objects.  It contains affined/local coordinates, brightness, signal-to-noise ratios, and other relevant data.
        _ref_ind (int): Index of the reference frame in the series of observations.
        _num_frames (int): Total number of frames in the observation.
        _num_traces (int): Number of identified traces or trajectories.
        _images (3D numpy array): The background-subtracted grayscale image.
        _xy_candis (2D numpy array): Candidate coordinates for moving objects.
        It is crucial for further analysis, particularly when fine-tuning the RANSAC algorithm for trajectory detection.

    Methods:
        savefile: Saves the data into an HDF5 file, preserving its structure.
        show: Displays images based on the astronomical data.
    """
    def __init__(self, info):
        """
        Initializes a Trace instance with information from an astronomical observation.
        """
        for key in info.keys():
            setattr(self, key, info[key]) # Efficiently setting attributes from the info dictionary

    def __repr__(self):
        """
        Returns a detailed string representation of the Trace object.
        """
        return '<Trace object: RES = {} FWHM ≈ {:.2f} REF_INDEX = {:d} NUM_FRAMES = {:d} NUM_TRACES = {:d}>'.format(
            self.res, self.fwhm, self._ref_ind, self._num_frames, self._num_traces)

    def savehdf5(self, file_out):
        """
        Saves the Trace data to an HDF5 file. This method ensures that the complex
        structure of the Trace data is preserved and stored in an organized manner.

        Inputs:
            file_out -> [str] Path of the output HDF5 file. Must end with '.hdf5'.

        Raises:
            ValueError -> If the file extension is not '.hdf5'.
        """
        # Ensuring the file format is HDF5
        if not file_out.endswith('.hdf5'):
            raise ValueError("Output file format must be '.hdf5'.")

        # Create directories if they don't exist
        Path(file_out).parent.mkdir(parents=True, exist_ok=True)

        # Define a variable-length data type for storing arrays of float64
        vlen_dtype = h5py.special_dtype(vlen=np.dtype('float64'))

        # Opening the HDF5 file for writing
        with h5py.File(file_out, 'w') as fout:
            # Writing basic information like resolution, FWHM, and offset
            fout.create_dataset("res", data=self.res)
            fout.create_dataset("fwhm", data=self.fwhm)
            fout.create_dataset("offset", data=self.offset)

            # Saving star information using variable-length data type
            stars_grp = fout.create_group("stars")
            stars = self.stars

            num_frames = self._num_frames
            xy_local_star = stars_grp.create_dataset('xy_local', (num_frames,), dtype=vlen_dtype)
            flux_star = stars_grp.create_dataset('flux', (num_frames,), dtype=vlen_dtype)
            snr_star = stars_grp.create_dataset('snr', (num_frames,), dtype=vlen_dtype)

            for i in range(num_frames):
                xy_local_star[i] = stars.xy_local[i].flatten()
                flux_star[i] = stars.flux[i]
                snr_star[i] = stars.snr[i]

            # Saving trace information for each identified line (motion trail)
            lines_grp = fout.create_group("lines")
            for key, value in self.__dict__.items():
                if 'line' in key:
                    subgrp = lines_grp.create_group(key)
                    for sub_key, sub_val in value.__dict__.items():
                        subgrp.create_dataset(sub_key, data=sub_val)

            # Create datasets for other Trace attributes
            fout.create_dataset("frames", data=self.frames)
            fout.create_dataset("transf", data=self.transf)
            fout.create_dataset("ref_ind", data=self._ref_ind)
            fout.create_dataset("images", data=self._images)

    def show(self, mode='trace', fig_out=None):
        """
        Visualizes the astronomical data based on the specified mode.

        Inputs:
            mode -> [str,optional,default='trace'] Determines the visualization mode. Available Options includ 'trace' and 'image', where
                        'trace' mode plots the trajectories of moving objects.
                        'image' mode displays the positions of moving objects and stars in a specific frame.
            fig_out -> [str, optional, default=None): Path to save the output figure. If None, the figure is displayed inline.
        Outputs:
            If fig_out is specified, saves the figure to the given path. Otherwise, displays the figure on screen.
        Raises:
            ValueError: If an unknown mode is specified.
        """

        if mode == 'trace':
            self._plot_trajectories(fig_out)
        elif mode == 'image':
            self._plot_image(fig_out)
        else:
            raise ValueError(f"Unknown mode: {mode}")

    def _plot_image(self, fig_out=None):
        """
        Plots both moving space objects and stars in a specific frame.

        Inputs:
            fig_out -> [str, optional, default=None): Path to save the output figure. If None, the figure is displayed inline.
        Outputs:
            If fig_out is specified, saves the figure to the given path. Otherwise, displays the figure on screen.
        """
        '''
        images = self._images
        xy = self.xy_local + offset
        xy_star = self.xy_local + offset
        if fig_out is None:
            plot_kwargs = {'mark':(xy,'s','red')}
        else:
            plot_kwargs = {'mark':(xy,'s','red'),'figname':fig_out}
        show_image(image,origin='lower',**plot_kwargs)
        '''
        pass

    def _plot_trajectories(self, fig_out=None):
        """
        This method is called by the 'show' method to create a scatter plot of the space objects' trajectories.
        Each point in the trajectories is plotted as a small dot, and the trajectories are overlaid on a grid for reference.

        The plotting area is adjusted to be 1.5 times larger than the resolution of the images
        to ensure that trajectories extending beyond the reference frame image are fully visible.

        Inputs:
            fig_out -> [str, optional, default=None] Path to save the output figure. If None, the figure is displayed
            on screen.
        Outputs:
            If fig_out is specified, saves the figure to the given path. Otherwise, displays the figure on screen.
        """
        fig, ax = plt.subplots(dpi=300)

        with plt.style.context(('seaborn-darkgrid')):
            # Iterate over each trajectory and plot it
            for key, line in self.__dict__.items():
                if key.startswith('line'):
                    x, y = line.xy_affine.T
                    plt.scatter(x, y, marker='o',s=5,label=f'Trajectory {key}')

        ax.set_aspect('equal', 'box')
        plt.xlabel("x")
        plt.ylabel("y")

        # Extend the plot's display range to accommodate trajectories that extend beyond the reference frame's bounds
        height,width = res = self.res
        h_half,w_half = res[0]/2, res[1]/2
        xb, yb = w_half * 1.5, h_half * 1.5
        plt.xlim([-xb, xb])
        plt.ylim([-yb, yb])

        # Add boundary of the frame
        ax.add_patch(Rectangle([-w_half,-h_half], width, height,fill=False,lw=1,color='k',ls='dashdot'))

        if fig_out is None:
            plt.show()
        else:
            Path(fig_out).parent.mkdir(parents=True, exist_ok=True)
            plt.savefig(fig_out, bbox_inches='tight')

class Line(object):
    """
    Represents the trajectory of a moving space object as observed in the astronomical data.

    Attributes:
        xy_affine -> [array-like] Coordinates of the trajectory in the reference frame.
        xy_local -> [array-like] Coordinates of the trajectory in local frame.
        flux -> [array-like] Flux values associated with points on the trajectory.
        snr -> [array-like] Signal-to-noise ratio for each point in the trajectory.
        _flags -> [array-like,bool] Flags indicating the presence of the moving object in each image frame.
    """
    def __init__(self,info):
        """
        Initializes a Line instance with trajectory information.

        Inputs:
            info -> [dict] A dictionary containing trajectory data including coordinates, flux, SNR, and presence flags.
        """

        for key, value in info.items():
            setattr(self, key, np.array(value))  # Convert lists to NumPy arrays for efficient handling

    def __repr__(self):
        """
        String representation of the Line object, showing key information.
        """
        return f'<Line object: NUM_POINTS = {len(self.xy_affine)}>'

class Stars(object):
    """
    Represents the stars observed in the astronomical images.

    Attributes:
        xy_local [list of 2d array] Coordinates of stars in each local frame.
        The list length corresponds to the number of frames, and each 2D array has
        shape (k, 2), where 'k' is the number of stars in that frame.
        flux [list of 1d array] Flux values of stars across all frames.
        snr [list of 1d array] Signal-to-noise ratio for stars across all frames.
        _n_mid (int): Number of stars in the reference frame.
    """
    def __init__(self,info):
        """
        Initializes a Stars instance with information about the stars.

        Inputs:
            info -> [dict] A dictionary containing data about the stars, including their coordinates, flux, and SNR.
        """
        for key, value in info.items():
            setattr(self, key, value)  # Assigning attributes from the info dictionary

    def __repr__(self):
        """
        String representation of the Stars object, summarizing key data.
        """
        return f'<Stars object: NUM_STARS = {self._n_mid}>'


import torch
from torch.utils import data
import numpy as np
import matplotlib.pyplot as plt
import scipy
import scipy.ndimage
import scipy.io
import skimage
import math
import random
import glob

class Flowers17Dataset(data.Dataset):

    def __init__(self, folder_path, dataset_type='train',device='cpu', image_size=100):

        super(Flowers17Dataset, self).__init__()

        self.folder_path = folder_path
        self.images = []
        self.labels = []
        self.images_per_class = 80
        self.image_channels = 3
        self.image_side_size = image_size
        self.dataset_type = dataset_type

        files = glob.glob(folder_path+'*.jpg')
        files.sort(key=lambda x: x.lower())

        for i, image_path in enumerate(files):

            image_type = 'train'
            if (i % 10 == 8):
                image_type = 'val'
            if (i % 10 == 9):
                image_type = 'test'

            if dataset_type == image_type:
                self.images.append(image_path)
                self.labels.append(int(i/self.images_per_class))

        self.rotation = False
        self.crop = False
        self.flip = False
        self.blur = False
        self.noise = False

        self.mean = 0.5
        self.std_dev = 0.1
        self.normalization = False

    def __len__(self):

        return len(self.images)

    def length(self):

        return len(self.images)

    def __getitem__(self, index):

        img = scipy.misc.imread(self.images[index])

        if img.shape[0] > img.shape[1]:
            img = np.rot90(img)

        img = scipy.misc.imresize(img, (self.image_side_size,self.image_side_size))

        if(self.normalization):
            img = self.normalize(img)

        img = self.augment(img)

        img = np.transpose(img, (2, 1, 0))
        return img.astype(np.float32)/255, self.labels[index]

    def getNameForLabel(self, label):

        return self.label_names[label]

    def augment(self, image):

        if( random.random() > 0.5 and self.rotation):
            angle = random.random()*360
            image = scipy.ndimage.interpolation.rotate(image, angle,reshape=False, order=0,mode='reflect')

        if( random.random() > 0.5 and self.crop):

            cropFactor = int(random.random()*5+1)
            image = image[cropFactor:-cropFactor,cropFactor:-cropFactor]
            image = scipy.misc.imresize(image, (self.image_side_size, self.image_side_size))

        if( random.random() > 0.5 and self.flip):
            if( random.random() > 0.5 ):
                image = np.flip(image,0).copy()
            else:
                image = np.flip(image,1).copy()

        if( random.random() > 0.5 and self.blur):
            image = scipy.ndimage.gaussian_filter(image, sigma=0.25)

        if( random.random() > 0.5 and self.noise):

            r = np.random.normal(0,5,image.shape).astype(image.dtype)
            image += r
            image = np.clip(image, 0, 255)

        return image

    def normalize(self, image):

        image = image.astype(np.float32)/255

        for i in range(self.image_channels):
            image[:,:,i] *= self.std_dev/np.std(image[:,:,i])
            image[:,:,i] -= np.ones((self.image_side_size, self.image_side_size)) * np.mean(image[:,:,i])-self.mean

        return (image*255).astype(np.uint8)

    def setRotation(self, enable):
        self.rotation = enable

    def setCrop(self, enable):
        self.crop = enable

    def setFlip(self, enable):
        self.flip = enable

    def setBlur(self, enable):
        self.blur = enable

    def setNoise(self, enable):
        self.noise = enable

    def setNormalization(self, enable, mean, std_dev):
        self.normalization = enable
        self.mean = 0.5
        self.std_dev = 0.1

    def plotImage(self, image, label):

        plt.imshow( np.transpose(image[:,:,:].numpy(), (1, 2, 0)))
        plt.show()
        print('label: ',label)


import os
import cv2
import numpy as np

__all__ = ['preprocess', 'postprocess']

def normPRED(d):
    ma = np.max(d)
    mi = np.min(d)

    dn = (d-mi)/(ma-mi)

    return dn

def preprocess(img_path):
    img = cv2.imread(img_path)

    # 缩放
    img = cv2.resize(img, (512, 512))

    # 归一化
    means = [0.225, 0.224, 0.229]
    vars = [0.406, 0.456, 0.485]
    img = img/np.max(img)
    img -= vars
    img /= means

    # convert BGR to RGB
    img = img.transpose((2, 0, 1))
    img = img[np.newaxis, :, :, :].astype('float32')

    return img

def postprocess(outputs, output_dir, model_name):
    pred = 1.0 - outputs[:, 0, :, :]
    pred = normPRED(pred)
    pred = pred.squeeze()
    pred = (pred*255).astype(np.uint8)
    if not os.path.exists(output_dir):
        os.mkdir(output_dir)
    cv2.imwrite(os.path.join(output_dir, '%s.jpg' % model_name), pred)


import gmplot
from firebase_admin import db
import firebase_admin
from firebase_admin import credentials

import numpy as np
import pandas as pd

#from mpl_toolkits.mplot3d.axes3d import *
import matplotlib.pyplot as plt
from matplotlib import cm

from scipy.interpolate import griddata

from mpl_toolkits import mplot3d

#########################################################################
# Firebase Realtime Database

cred = credentials.Certificate("C:/fyp/mqtt-trial-firebase-adminsdk-yrqgx-77140342e7.json")
firebase_admin.initialize_app(cred, {
    'databaseURL': 'https://mqtt-trial-default-rtdb.firebaseio.com/'
})

#########################################################################

ref = db.reference("/server/saving-data/Pallas/2021-03-13/aoifeDrives/")
aoifeDrivesGps = ref.get()

#print(all_data)
timeStamps = []
longitudes = []
latitudes = []
altitudes = []
speeds = []

for keyID in aoifeDrivesGps:
    timeStamps.append( aoifeDrivesGps[keyID]['dateAndTime'] )
    longitudes.append( aoifeDrivesGps[keyID]['longitude'] )
    latitudes.append( aoifeDrivesGps[keyID]['latitude'] )
    altitudes.append( aoifeDrivesGps[keyID]['mslAltitude'] )
    speeds.append( aoifeDrivesGps[keyID]['speedOverGround'])

fig = plt.figure()
ax = plt.axes(projection='3d')

# Data for a three-dimensional line
ax.plot3D(longitudes, latitudes, altitudes, 'gray')

# Data for three-dimensional scattered points
ax.scatter3D(longitudes, latitudes, altitudes, c=altitudes, cmap='rainbow')
ax.set_xlabel('Longitude')
ax.set_ylabel('Latitude')
ax.set_zlabel('Altitude')

plt.savefig('./pictures/3d_plot_line.png')
plt.show()


from datetime import datetime
from django.core.cache import cache
from django.conf import settings

TIME_IDLE = getattr(settings, 'USERS_ONLINE__TIME_IDLE', 60 * 2)
TIME_OFFLINE = getattr(settings, 'USERS_ONLINE__TIME_OFFLINE', 60 * 10)

CACHE_PREFIX_USER = getattr(settings, 'USERS_ONLINE__CACHE_PREFIX_USER', 'online_user') + '_%d'
CACHE_USERS = getattr(settings, 'USERS_ONLINE__CACHE_USERS', 'online_users')

class OnlineStatus(object):
    """Online status data which will be later cached"""

    def __init__(self, request):
        self.user = request.user
        # 0 - idle, 1 - active
        self.status = 1
        self.seen = datetime.today()
        self.ip = request.META['REMOTE_ADDR']
        self.session = request.session.session_key

    def set_idle(self):
        self.status = 0

    def set_active(self):
        self.status = 1
        self.seen = datetime.today()

def refresh_user(request):
    """Sets or updates user's online status"""
    key = CACHE_PREFIX_USER % request.user.pk
    onlinestatus = cache.get(key)
    if not onlinestatus:
        onlinestatus = OnlineStatus(request)
    else:
        onlinestatus.set_active()
    cache.set(key, onlinestatus, TIME_OFFLINE)
    return onlinestatus
    #self.refresh_users_list(user=self.user)

def refresh_users_list(**kwargs):
    """Updates online users list and their statuses"""
    updated = kwargs.pop('updated', None)
    online_users = cache.get(CACHE_USERS)
    if not online_users:
        online_users = []
    updated_found = False
    for obj in online_users:
        seconds = (datetime.today() - obj.seen).seconds
        if seconds > TIME_OFFLINE:
            online_users.remove(obj)
            cache.delete(CACHE_PREFIX_USER % obj.user.pk)
        elif seconds > TIME_IDLE:
            obj.set_idle()
            user = cache.get(CACHE_PREFIX_USER % obj.user.pk)
            if not user:
                continue
            user.set_idle()
            cache.set(CACHE_PREFIX_USER % obj.user.pk, user, TIME_OFFLINE)
        if obj.user == updated.user:
            obj.set_active()
            obj.seen = datetime.today()
            updated_found = True
    if not updated_found:
        online_users.append(updated)
    cache.set(CACHE_USERS, online_users, TIME_OFFLINE)

def status_for_user(user):
    """Return status for user, duh?"""
    if user.is_authenticated():
        key = CACHE_PREFIX_USER % user.pk
        return cache.get(key)
    return None


from fastapi import APIRouter, UploadFile, File, HTTPException, Depends
from pathlib import Path
from services import summary, sentiment_calculator, transcribe_audio
from models.audio_analysis import AudioAnalysis
from sqlalchemy.orm import Session
from db.services import get_db
import os

router = APIRouter()

AUDIO_PATH = "/app/uploaded_audio/"

@router.post("/upload/")
async def upload_audio(
    file: UploadFile = File(...),
    db: Session = Depends(get_db)
):
    try:
        data = await file.read()

        Path(AUDIO_PATH).mkdir(parents=True, exist_ok=True)
        path_to_audio = os.path.join(AUDIO_PATH, file.filename)

        with open(path_to_audio, 'wb') as f:
            f.write(data)

        transcription = transcribe_audio.transcribe_audio_content(path_to_audio, 'latest_short')
        summary_text = summary.generate_summary(transcription)
        sentiment_scores = sentiment_calculator.sentiment_score(transcription)

        audio_analysis = AudioAnalysis(
            filename=file.filename,
            summary=summary_text,
            transcription=transcription,
            negative_score=sentiment_scores['negative_score'],
            neutral_score=sentiment_scores['neutral_score'],
            positive_score=sentiment_scores['positive_score']
        )

        db.add(audio_analysis)
        db.commit()

        return {"audio_id": audio_analysis.id, "message": "File uploaded successfully!"}
    except Exception as e:
        print(e)
        raise HTTPException(status_code=500, detail="File upload failed.")

@router.get("/audio/{audio_id}")
def get_audio_by_id(
    audio_id: int,
    db: Session = Depends(get_db)
):
    audio_analysis = db.query(AudioAnalysis).filter(AudioAnalysis.id == audio_id).first()
    if audio_analysis:
        return audio_analysis
    else:
        raise HTTPException(status_code=404, detail="Audio not found.")


from rdflib.extras.external_graph_libs import rdflib_to_networkx_graph
import networkx as nx
import pandas as pd
from os import listdir
from os.path import isfile, join
from rdflib import Graph, Literal, BNode, Namespace, RDF, URIRef
import itertools
import csv

DB = Namespace('http://dbpedia.org/ontology/')

mypath = 'data/PlaylistGraphsWithPatterns/'
playlists = [f for f in listdir(mypath) if isfile(join(mypath, f))]

for playlist in playlists:
	playlistId = playlist.replace(".ttl","")
	playlistGraph = Graph()
	playlistGraph.parse('data/PlaylistGraphsWithPatterns/%s' %(playlist),format='turtle')

	pairs_done = []
	G = rdflib_to_networkx_graph(playlistGraph)
	f = open('data/ShortestPaths/%s.csv' %(playlistId), 'w')
	for s1, p, o in playlistGraph.triples( (None, RDF.type, DB.Song) ):
		for s2, p, o in playlistGraph.triples( (None, RDF.type, DB.Song) ):
			if s1 != s2 and (s1,s2) not in pairs_done:
				pairs_done.append((s1,s2))
				pairs_done.append((s2,s1))
				shortestPath = nx.shortest_path(G, s1, s2)
				row = s1 + ", " + s2 + ", " + "\t".join(shortestPath) + ", " + str(len(shortestPath))
				f.write(row)
				f.write('\n')


import torch.nn as nn
import torch

class BasicConv3d(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0):
        super(BasicConv3d, self).__init__()
        self.conv = nn.Conv3d(in_planes, out_planes,
                              kernel_size=kernel_size, stride=stride,
                              padding=padding, bias=False)

        self.bn = nn.BatchNorm3d(out_planes, eps=1e-3, momentum=0.001, affine=True)
        self.relu = nn.ReLU(inplace=True)

        # init
        self.conv.weight.data.normal_(mean=0, std=0.01) # original s3d is truncated normal within 2 std
        self.bn.weight.data.fill_(1)
        self.bn.bias.data.zero_()

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

class STConv3d(nn.Module):
    def __init__(self,in_planes,out_planes,kernel_size,stride,padding=0):
        super(STConv3d, self).__init__()
        self.conv1 = nn.Conv3d(in_planes, out_planes, kernel_size=(1,kernel_size,kernel_size),
                              stride=(1,stride,stride),padding=(0,padding,padding), bias=False)
        self.conv2 = nn.Conv3d(out_planes,out_planes,kernel_size=(kernel_size,1,1),
                               stride=(stride,1,1),padding=(padding,0,0), bias=False)

        self.bn1=nn.BatchNorm3d(out_planes, eps=1e-3, momentum=0.001, affine=True)
        self.bn2=nn.BatchNorm3d(out_planes, eps=1e-3, momentum=0.001, affine=True)
        self.relu = nn.ReLU(inplace=True)

        # init
        self.conv1.weight.data.normal_(mean=0, std=0.01) # original s3d is truncated normal within 2 std
        self.conv2.weight.data.normal_(mean=0, std=0.01) # original s3d is truncated normal within 2 std
        self.bn1.weight.data.fill_(1)
        self.bn1.bias.data.zero_()
        self.bn2.weight.data.fill_(1)
        self.bn2.bias.data.zero_()

    def forward(self,x):
        x=self.conv1(x)
        x=self.bn1(x)
        x=self.relu(x)
        x=self.conv2(x)
        x=self.bn2(x)
        x=self.relu(x)
        return x

class SepInception(nn.Module):
    def __init__(self, in_planes, out_planes):
        super(SepInception, self).__init__()

        assert len(out_planes) == 6
        assert isinstance(out_planes, list)

        [num_out_0_0a,
        num_out_1_0a, num_out_1_0b,
        num_out_2_0a, num_out_2_0b,
        num_out_3_0b] = out_planes

        self.branch0 = nn.Sequential(
            BasicConv3d(in_planes, num_out_0_0a, kernel_size=1, stride=1),
        )
        self.branch1 = nn.Sequential(
            BasicConv3d(in_planes, num_out_1_0a, kernel_size=1, stride=1),
            STConv3d(num_out_1_0a, num_out_1_0b, kernel_size=3, stride=1, padding=1),
        )
        self.branch2 = nn.Sequential(
            BasicConv3d(in_planes, num_out_2_0a, kernel_size=1, stride=1),
            STConv3d(num_out_2_0a, num_out_2_0b, kernel_size=3, stride=1, padding=1),
        )
        self.branch3 = nn.Sequential(
            nn.MaxPool3d(kernel_size=(3, 3, 3), stride=1, padding=1),
            BasicConv3d(in_planes, num_out_3_0b, kernel_size=1, stride=1),
        )

        self.out_channels = sum([num_out_0_0a, num_out_1_0b, num_out_2_0b, num_out_3_0b])

    def forward(self, x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        x2 = self.branch2(x)
        x3 = self.branch3(x)
        out = torch.cat((x0, x1, x2, x3), 1)

        return out

class S3D(nn.Module):

    def __init__(self, input_channel=3):
        super(S3D, self).__init__()
	# assume input C,T,H,W == (3, 64, 224, 224)

        self.Conv_1a = STConv3d(input_channel, 64, kernel_size=7, stride=2, padding=3)

        self.block1 = nn.Sequential(self.Conv_1a) # (64, 32, 112, 112)

        ###################################

        self.MaxPool_2a = nn.MaxPool3d(kernel_size=(1,3,3), stride=(1,2,2), padding=(0,1,1))
        self.Conv_2b = BasicConv3d(64, 64, kernel_size=1, stride=1)
        self.Conv_2c = STConv3d(64, 192, kernel_size=3, stride=1, padding=1)

        self.block2 = nn.Sequential(
            self.MaxPool_2a, # (64, 32, 56, 56)
            self.Conv_2b,    # (64, 32, 56, 56)
            self.Conv_2c)    # (192, 32, 56, 56)

        ###################################

        self.MaxPool_3a = nn.MaxPool3d(kernel_size=(1,3,3), stride=(1,2,2), padding=(0,1,1))
        self.Mixed_3b = SepInception(in_planes=192, out_planes=[64, 96, 128, 16, 32, 32])
        self.Mixed_3c = SepInception(in_planes=256, out_planes=[128, 128, 192, 32, 96, 64])

        self.block3 = nn.Sequential(
            self.MaxPool_3a,    # (192, 32, 28, 28)
            self.Mixed_3b,      # (256, 32, 28, 28)
            self.Mixed_3c)      # (480, 32, 28, 28)

        ###################################

        self.MaxPool_4a = nn.MaxPool3d(kernel_size=(3, 3, 3), stride=(2, 2, 2), padding=(1, 1, 1))
        self.Mixed_4b = SepInception(in_planes=480, out_planes=[192, 96, 208, 16, 48, 64])
        self.Mixed_4c = SepInception(in_planes=512, out_planes=[160, 112, 224, 24, 64, 64])
        self.Mixed_4d = SepInception(in_planes=512, out_planes=[128, 128, 256, 24, 64, 64])
        self.Mixed_4e = SepInception(in_planes=512, out_planes=[112, 144, 288, 32, 64, 64])
        self.Mixed_4f = SepInception(in_planes=528, out_planes=[256, 160, 320, 32, 128, 128])

        self.block4 = nn.Sequential(
            self.MaxPool_4a,  # (480, 16, 14, 14)
            self.Mixed_4b,    # (512, 16, 14, 14)
            self.Mixed_4c,    # (512, 16, 14, 14)
            self.Mixed_4d,    # (512, 16, 14, 14)
            self.Mixed_4e,    # (528, 16, 14, 14)
            self.Mixed_4f)    # (832, 16, 14, 14)

        ###################################

        self.MaxPool_5a = nn.MaxPool3d(kernel_size=(2, 2, 2), stride=(2, 2, 2), padding=(0, 0, 0))
        self.Mixed_5b = SepInception(in_planes=832, out_planes=[256, 160, 320, 32, 128, 128])
        self.Mixed_5c = SepInception(in_planes=832, out_planes=[384, 192, 384, 48, 128, 128])

        self.block5 = nn.Sequential(
            self.MaxPool_5a,  # (832, 8, 7, 7)
            self.Mixed_5b,    # (832, 8, 7, 7)
            self.Mixed_5c)    # (1024, 8, 7, 7)

    def forward(self, x):
        x = self.block1(x)
        x = self.block2(x)
        x = self.block3(x)
        x = self.block4(x)
        x = self.block5(x)
        return x


import country
import inspect
import pytest

from datetime           import datetime
from location           import Location
from stage              import Criterium, IndividualTimeTrial, Prologue, RestDay, RoadStage, TeamTimeTrial
from stage_race         import Dauphine, StageRace, TourDeFrance, TourOfItaly
from stage_race_builder import StageRaceBuilder

class TestStageRaceBuilder:

    def test_stage_race_builder(self):

        france  = country.France()
        amiens  = Location("Amiens", france)
        boulogne = Location("Boulogne", france)
        grenoble = Location("Grenoble", france)
        lehavre = Location("Le Havre", france)
        letouquet = Location("Le Touquet", france)
        morzine = Location("Morzine", france)
        limoges = Location("Limoges", france)
        nantes  = Location("Nantes", france)
        paris   = Location("Paris", france)
        quimper = Location("Quimper", france)
        rennes  = Location("Rennes", france)
        rouen   = Location("Rouen", france)
        tours   = Location("Tours", france)

        builder = StageRaceBuilder(TourDeFrance(), datetime(2018,7,1))
        builder.prologue(paris, paris, 6.6)
        builder.criterium(paris, 256)
        builder.road_stage(paris, tours, 265)
        builder.road_stage(tours, limoges, 248)
        builder.rest_day(limoges)
        builder.road_stage(limoges, nantes, 259)
        builder.out_and_back_team_time_trial(nantes, 48)
        builder.road_stage(nantes, quimper, 289)
        builder.road_stage(quimper, rennes, 239)
        builder.out_and_back_individual_time_trial(rennes, 65)
        builder.enable_split_stages()
        builder.criterium(lehavre, 100)
        builder.road_stage(lehavre, rouen, 150)
        builder.disable_split_stages()
        builder.road_stage(rouen, amiens, 187.2)
        builder.enable_morning_stage()
        builder.road_stage(amiens, boulogne, 189)
        builder.individual_time_trial(boulogne, letouquet, 40)
        builder.rest_day(grenoble)
        builder.road_stage(grenoble, morzine, 257.3)
        tdf = builder.build()

        route = """P,1 July,Paris,6.6 km,Individual time trial
        1,2 July,Paris,256.0 km,Road stage
        2,3 July,Paris to Tours,265.0 km,Road stage
        3,4 July,Tours to Limoges,248.0 km,Road stage
        ,5 July,Rest day,Limoges
        4,6 July,Limoges to Nantes,259.0 km,Road stage
        5,7 July,Nantes,48.0 km,Team time trial
        6,8 July,Nantes to Quimper,289.0 km,Road stage
        7,9 July,Quimper to Rennes,239.0 km,Road stage
        8,10 July,Rennes,65.0 km,Individual time trial
        9a,11 July,Le Havre,100.0 km,Road stage
        9b,11 July,Le Havre to Rouen,150.0 km,Road stage
        10,12 July,Rouen to Amiens,187.2 km,Road stage
        11,13 July,Amiens to Boulogne,189.0 km,Road stage
        12,13 July,Boulogne to Le Touquet,40.0 km,Individual time trial
        ,14 July,Rest day,Grenoble
        13,15 July,Grenoble to Morzine,257.3 km,Road stage"""

        assert tdf.route == inspect.cleandoc(route)

    def test_morning_stages(self):

        italy  = country.Italy()
        palermo = Location("Palermo", italy)
        sciacca = Location("Sciacca", italy)

        builder = StageRaceBuilder(TourOfItaly(), datetime(1986,5,12))
        builder.enable_morning_stage()
        builder.out_and_back_prologue(palermo, 1)
        builder.road_stage(palermo, sciacca, 140)
        giro = builder.build()

        route = """P,12 May,Palermo,1.0 km,Individual time trial
        1,12 May,Palermo to Sciacca,140.0 km,Road stage"""

        assert giro.route == inspect.cleandoc(route)

    def test_prologue_exceptions(self):

        """A Prologue must be the first stage"""
        italy  = country.Italy()
        palermo = Location("Palermo", italy)
        sciacca = Location("Sciacca", italy)
        builder = StageRaceBuilder(TourOfItaly(), datetime(1986,5,12))
        builder.road_stage(palermo, sciacca, 140)
        with pytest.raises(Exception):
            builder.out_and_back_prologue(palermo, 1)

    def test_rest_day_exceptions(self):

        """A rest day cannot be the first stage"""
        italy  = country.Italy()
        palermo = Location("Palermo", italy)
        sciacca = Location("Sciacca", italy)
        builder = StageRaceBuilder(TourOfItaly(), datetime(1986,5,12))
        with pytest.raises(Exception):
            builder.rest_day(palermo)

        """A rest day cannot be the morning stage"""
        builder.enable_morning_stage()
        with pytest.raises(Exception):
            builder.rest_day(palermo)

        """A rest day cannot be the afternoon stage"""
        builder.out_and_back_prologue(palermo, 1)
        with pytest.raises(Exception):
            builder.rest_day(palermo)

    def test_build_exceptions(self):

        """build() throws when there are no stages"""
        builder = StageRaceBuilder(TourOfItaly(), datetime(1986,5,12))
        with pytest.raises(Exception):
            builder.build()

        italy  = country.Italy()
        palermo = Location("Palermo", italy)
        sciacca = Location("Sciacca", italy)

        builder = StageRaceBuilder(TourOfItaly(), datetime(1986,5,12))
        builder.enable_morning_stage()
        builder.out_and_back_prologue(palermo, 1)
        builder.road_stage(palermo, sciacca, 140)
        builder.rest_day()
        with pytest.raises(Exception):
            builder.build()


from SpeechOutputHelper import *

#changes per room
object_dict = {
    "Rope":"Rope"
}

def get_object_name(room_name):
    return object_dict.get(room_name, "unkn")

def StartAsylum(event, context):

    if event["request"]["type"] == "LaunchRequest":
        return on_launch(event["request"], event["session"])
    elif event["request"]["type"] == "IntentRequest":
        return on_intent(event["request"], event["session"])
    elif event["request"]["type"] == "SessionEndedRequest":
        return on_session_ended(event["request"], event["session"])

    return

def on_launch(launch_request, session):
    return get_welcome_response()

def get_welcome_response():
    session_attributes = {}

    card_title = "Asylum Room"
    speech_output = "Welcome to the Asylum. " \
                    "You are trapped, you must escape!" \
                    "The dirty stained walls may be grey, but the soul of this asylum is pitch black." \
                    "The woes from the inmates fade into eerie background music as you realize that if you don't move soon" \
                    "you will not live to see the outside of this asylum." \
                    "All of you are in tied with ropes. There is nothing in the room, but you realize the door is unlocked." \
                    "Either you figure out how to leave the room or danger will enter."
    reprompt_text = "What is you next bet?"

    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))

def on_intent(intent_request, session):
    intent = intent_request["intent"]
    intent_name = intent_request["intent"]["name"]

    if intent_name == "ExamineObject":
        return ExamineObject(intent)
    elif intent_name == "OrientView":
        return OrientView(intent)
    elif intent_name == "AMAZON.HelpIntent":
        return get_welcome_response()
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")

def OrientView(intent):
    return

def ExamineObject(intent):
    return


from audioop import avg
import random
def avg_grade(a: int, b: int) -> float:
    """This function returns the average of 3 random integers within a range, in the examples below
    the range will be (0, 100)
    >>>avg_grade(0,100)
    41.666666666666664
    >>>avg_grade(0,100)
    18.333333333333332
    >>>avg_grade(0,100)
    53.666666666666664"""
    num1 = random.randint(a, b)
    num2 = random.randint(a, b)
    num3 = random.randint(a, b)
    avg = (num1 + num2 + num3)/3
    return avg

print(avg_grade(0,100))
help(avg_grade)


"""
Given a CIDR (ex. /24), print out a subnet mask or wildcard mask

conver the CIDR to a string binary mask (network bits 1 and host bits 0)
"""
import sys

MASK_LEN = 32  # 255.255.255.255

def ip_mask(cidr):

    # Convert to binary mask
    host_bits = "0"*(MASK_LEN-cidr)
    net_bits = "1"*cidr
    binary = net_bits + host_bits
    print("BINARY: ", binary)

    # Split biary into 4 octets
    octets = list()
    octet = 8
    for i in range(0, MASK_LEN, octet):
        print("octet: ", i)
        octets.append(str(int(binary[i:octet+i], base=2)))
    print("Octets: ", octets)

    mask = ".".join(octets)
    return(mask)

def main():
    subnet = "1.1.1.1/30"
    cidr = int(subnet.split("/")[1])

    print("Mask: ", ip_mask(cidr))

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


import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Cabeceras
Cabeceras=['Symboling','Normalized-Losses','Make','Fuel-Type','Aspiration','num-of-doors','Body-Style','Drive-wels','engine-location','whel-base','length','width','height','curb-weight','engine-tpe','num-of-cylinders','engine-zize','fuel-system','bora','stroke','compression-ratio','horsepower','peak-rpm','city-mpg','highway-mpg','Price']
#Cargamos los datos
data = pd.read_csv(r"autos.csv", header=None, names = Cabeceras)

##### 1 #####
print('modelos de autos\n')
marcas = data['Make']
print(marcas.unique())

##### 2 #####
# Consumo de carburante en ciudad -> city-mpg
print('\n consumo de carburante de cada modelo \n ')
conscarb = data.groupby('Make')['city-mpg']
# Convertir city-mpg a float
data["city-mpg"]=data["city-mpg"].astype("float64")
print(conscarb.describe())

##### 3 #####
# Renombramos las variables
data.rename(columns={"city-mpg" : "Consumo-Ciudad"},inplace=True)
# Convertir de galones a litros.
data["Consumo-Ciudad"]=235/data["Consumo-Ciudad"]

##### 4 #####
# Calcular el precio por modelo
print('\nsacar el precio de cada modelo\n')

# Primero Sustiruir ? por '0'
data.loc[data['Price'] == '?', ['Price']] = '0'

# Convertir el precio a Float64
data["Price"]=data["Price"].astype("float64")
data.rename(columns={"Price" : "Precio"},inplace=True)
preciomarca = data.groupby('Make')['Precio']
print(preciomarca.describe())

Ejercicio Machine Learning Curso/Ej03_Explorar un dataframe.py


# Fuente: https://python.gotrained.com/google-places-api-extracting-location-data-reviews/

import requests
import json
import time
import csv

def pretty_print_request(req):
    #Fuente: https://stackoverflow.com/questions/20658572/python-requests-print-entire-http-request-raw
    print('{}\n{}\r\n{}\r\n\r\n{}'.format(
        '-----------START-----------',
        req.method + ' ' + req.url,
        '\r\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
        req.body,
    ))

class GooglePlaces(object):
    def __init__(self, apiKey):
        super(GooglePlaces, self).__init__()
        self.apiKey = apiKey

    def get_comuna_location(self, comuna):
        pass

    def search_places_by_query(self, query, types):
        endpoint_url = "https://maps.googleapis.com/maps/api/place/textsearch/json"
        places = []
        params = {
            'key': self.apiKey,
            'query': query,
            'types': types,
            'region': 'cl',
            'language': 'es-419',
            # 'location': location,
            # 'radius': radius
        }
        #debugear el request
        # req = requests.Request('GET', endpoint_url, params=params)
        # prepared = req.prepare()
        # pretty_print_request(prepared)
        # s = requests.Session()
        # res = s.send(prepared)
        res = requests.get(endpoint_url, params = params)
        results =  json.loads(res.content)
        # print(f"API response: {results}")
        places.extend(results['results'])
        time.sleep(2)
        while "next_page_token" in results:
            params['pagetoken'] = results['next_page_token'],
            res = requests.get(endpoint_url, params = params)
            results = json.loads(res.content)
            # print(f"API response: {results}")
            places.extend(results['results'])
            time.sleep(2)
        return places

    def search_places_by_coordinate(self, location, radius, types=[]):
        endpoint_url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
        places = []
        params = {
            'location': location,
            'radius': radius,
            'types': types,
            'key': self.apiKey
        }
        res = requests.get(endpoint_url, params = params)
        results =  json.loads(res.content)
        places.extend(results['results'])
        time.sleep(2)
        while "next_page_token" in results:
            params['pagetoken'] = results['next_page_token'],
            res = requests.get(endpoint_url, params = params)
            results = json.loads(res.content)
            places.extend(results['results'])
            time.sleep(2)
        return places

    def get_place_details(self, place_id, fields):
        endpoint_url = "https://maps.googleapis.com/maps/api/place/details/json"
        params = {
            'placeid': place_id,
            'fields': ",".join(fields),
            'key': self.apiKey
        }
        res = requests.get(endpoint_url, params = params)
        place_details =  json.loads(res.content)
        return place_details

if __name__ == "__main__":
    API_KEY = "Reemplazar este string"
    api = GooglePlaces(API_KEY)
    types = ["tourist_attraction", "city_hall", "university", "library", "shopping_mall", "museum", "stadium"] #https://developers.google.com/places/supported_types#table1
    fields = ["name", "formatted_address", "geometry", "type", "icon"]
    output_filename = "points_of_interest"
    # radius = 5000 #radio en el que se buscaran lugares dentro de la comuna (con centro en el location de comuna)

    #leemos comunas
    with open('comunas.json', 'r') as f:
        comunas = json.load(f)
    # comunas = ["Providencia"]

    points_of_interest = {}
    with open(output_filename+".csv", 'w', newline='', encoding='utf8') as csvfile:
        filewriter = csv.writer(csvfile, delimiter=',')
        filewriter.writerow(['Nombre', 'Comuna','Direccion', 'Tipos', 'Lng', 'Lat', 'Ciudad','Icono', 'Id'])
        for comuna in comunas:
            print(f"\ncomuna: {comuna}")
            query = f"places in '{comuna}'"
            # location = api.get_comuna_location(comuna)
            for tipo in types: #Solo se puede especificar un tipo a la vez
                print(f"--tipo: {tipo}")
                places = api.search_places_by_query(query, [tipo])

                points_of_interest[comuna] = {}
                for place in places:
                    # details = api.get_place_details(place['place_id'], fields) #no es necesario, usamos solo info básica que ya tenemos
                    try:
                        address = place['formatted_address']
                    except KeyError:
                        address = ""

                    try:
                        tipos = place['types']
                    except KeyError:
                        tipos = []

                    try:
                        icono = place['icon']
                    except KeyError:
                        icono = ""

                    try:
                        idd = place['place_id']
                    except KeyError:
                        idd = ""

                    try:
                        location = place['geometry']["location"]
                        lat = location["lat"]
                        lng = location["lng"]
                    except KeyError:
                        lat = ""
                        lng = ""

                    try:
                        name = place['name']
                        print(f"lugar: {name}")
                        try:
                            comuna = address.split(",")[-2].strip()
                        except IndexError:
                            pass
                        points_of_interest[comuna][name] = {}
                        points_of_interest[comuna][name]["id"] = idd
                        points_of_interest[comuna][name]["direccion"] = address
                        points_of_interest[comuna][name]["comuna"] = comuna
                        points_of_interest[comuna][name]["tipo"] = tipos
                        points_of_interest[comuna][name]["lat"] = lat
                        points_of_interest[comuna][name]["lng"] = lng
                        points_of_interest[comuna][name]["ciudad"] = "Santiago"
                        points_of_interest[comuna][name]["icono"] = icono
                        filewriter.writerow([name, comuna, address, tipos, lat, lng, "Santiago", icono, idd])
                    except KeyError:
                        name = ""

    # print(points_of_interest)
    with open(output_filename+".json", 'w', encoding='utf8') as f:
        json.dump(points_of_interest, f)


from functools import wraps
from time import sleep
from datetime import datetime, timedelta

from flask import current_app
from celery import current_task
from celery.utils.log import get_task_logger

from . import db, celery, providers
from .models import User, Account, Resume, Task
from .providers import ProviderError, TouchLimitError

logger = get_task_logger(__name__)

def resultify_task(func):
    @wraps(func)
    def resultify(*args, **kwargs):
        started = datetime.utcnow()
        result = func(*args, **kwargs)
        task = Task(
            identity=current_task.request.id, name=func.__name__,
            started_at=started, finished_at=datetime.utcnow(),
            success=result['success'], skipped=result['skipped'],
            total=result['total'])
        db.session.add(task)
        db.session.commit()
        return result
    return resultify

@celery.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
    sender.add_periodic_task(
        current_app.config['TOUCH_INTERVAL'], touch_resume.s())
    sender.add_periodic_task(
        current_app.config['REAUTH_INTERVAL'], refresh_tokens.s())
    sender.add_periodic_task(
        current_app.config['CLEANUP_TASKS_INTERVAL'],
        cleanup_tasks.s(current_app.config['TASKS_LIMIT']))
    sender.add_periodic_task(
        current_app.config['CLEANUP_RESUME_INTERVAL'], cleanup_resume.s())
    sender.add_periodic_task(
        current_app.config['CLEANUP_ACCOUNTS_INTERVAL'], cleanup_accounts.s())
    sender.add_periodic_task(
        current_app.config['CLEANUP_USERS_INTERVAL'], cleanup_users.s())

@celery.task
@resultify_task
def touch_resume():
    result = dict(total=0, success=0, skipped=0)
    resumes = Resume.query.filter_by(autoupdate=True).all()
    for resume in [r for r in resumes if r.account.provider in providers]:
        try:
            provider = providers[resume.account.provider]
            if resume.updelta < provider.touch_limit:
                result['skipped'] += 1
                logger.debug(f'Touch resume limit skip: {resume}')
                continue
            provider.touch(token=resume.account.access, resume=resume.identity)
            resume.published = datetime.utcnow()
        except TouchLimitError as e:  # pragma: no cover
            result['skipped'] += 1
            logger.debug(f'Touch resume limit error: {resume}, {e}')
        except ProviderError as e:
            result['skipped'] += 1
            logger.warning(f'Resume autoupdate disabled: {resume}, {e}')
            resume.autoupdate = False
        except Exception as e:  # pragma: no cover
            result['skipped'] += 1
            logger.exception(f'Touch resume error: {resume}, err={e}')
        else:
            result['success'] += 1
            logger.debug(f'Touch resume success: {resume}')
        finally:
            result['total'] += 1
            db.session.commit()
            sleep(0.3)

    return result

@celery.task
def refresh_tokens():
    result = dict(total=0, success=0, skipped=0)
    accounts = Account.query.all()
    for account in [acc for acc in accounts if acc.provider in providers]:
        try:
            provider = providers[account.provider]
            ids = provider.tokenize(account.refresh, refresh=True)

            account.access = ids['access_token']
            account.refresh = ids['refresh_token']

            delta = timedelta(seconds=ids['expires_in'])
            account.expires = datetime.utcnow() + delta

            db.session.add(account)
            db.session.commit()
        except ProviderError as e:  # pragma: no cover
            result['skipped'] += 1
            logger.warning(f'Refresh token skip: {account}, status={e}')
        except Exception as e:  # pragma: no cover
            result['skipped'] += 1
            logger.exception(f'Refresh token error: {account}, err={e}')
        else:
            result['success'] += 1
            logger.debug(f'Refresh token success: {account}')
        finally:
            result['total'] += 1
            sleep(0.3)

    return result

@celery.task
def cleanup_tasks(keep):
    tasks = Task.query.order_by('finished_at').all()
    for task in tasks[:-keep]:
        logger.info(f'Cleanup task: {task}')
        db.session.delete(task)
    db.session.commit()
    return (len(tasks) - keep) if len(tasks) >= keep else 0

@celery.task
def cleanup_resume():
    resumes = Resume.query.filter_by(autoupdate=False).all()
    for resume in resumes:
        logger.info(f'Cleanup resume: {resume}')
        db.session.delete(resume)
    db.session.commit()
    return len(resumes)

@celery.task
def cleanup_accounts():
    accounts = Account.query.filter(~Account.resume.any()).all()
    for account in accounts:
        logger.info(f'Cleanup account: {account}')
        db.session.delete(account)
    db.session.commit()
    return len(accounts)

@celery.task
def cleanup_users():
    users = User.query.filter(~User.accounts.any()).all()
    for user in users:
        logger.info(f'Cleanup user: {user}')
        db.session.delete(user)
    db.session.commit()
    return len(users)


from tkinter import *
from tkinter import ttk
from modulos import excel
from tkcalendar import DateEntry
from tkinter import messagebox as msb

def cuerpo(windows):
    windows.geometry("370x370")
    windows.resizable(0, 0)
    windows.title("Ingreso de Datos")

    # Limpiar lo que se ingreso en la casilla
    def clearTextInput():
        cuerpo_text.delete("1.0", "end")

    def getDato():
        fecha = cal.get_date()
        texto = cuerpo_text.get("1.0", "end-1c")
        lista = []

        if texto == '':
            msb.showerror('Campo Vacio!', 'Verifique que todos los campos estan con información')
        elif tipo_combobox.get() == '':
            msb.showerror('Error en "Tipo de Ingreso"!', 'Favor seleccionar un "Tipo de Ingreso"')
        elif texto[0] == '=' or texto[0] == '+' or texto[0] == '-' or texto[0] == '/' or texto[0] == '*':
            msb.showerror('OIE NO', 'Ese simbolo de inicio, no esta permitido')

        else:
            if tipo_combobox.get() == "Apunte":
                lista.append(fecha)
                lista.append(texto)
                # Ingresar funcion de excel
                excel.func_apunte(lista)
                clearTextInput()  # Limpia la casilla luego de guardar
                msb.showinfo('Felicidades!', 'Su "Apunte" a sido ingresado satisfactoriamente')

            elif tipo_combobox.get() == "Recordatorio":
                lista.append(fecha)
                lista.append(texto)
                # Ingresar funcion de excel
                excel.func_recordatorio(lista)
                clearTextInput()  # Limpia la casilla luego de guardar
                msb.showinfo('Felicidades!', 'Su "Recordatorio" a sido ingresado satisfactoriamente')

    def grab_date():
        cal.get_date()

    # CASILLA CON MENU DESPLEGABLE DE 2 OPCIONES
    tipo_label = Label(windows, text="Tipo de Ingreso")
    tipo_label.grid(row=2, column=1)

    tipo_combobox = ttk.Combobox(windows, width=17, state='readonly', values=["Apunte", "Recordatorio"])
    tipo_combobox.grid(row=2, column=2)
    tipo_combobox.bind("<<ComboboxSelected>>", lambda _: text_label.config(text=f'Ingrese el "{tipo_combobox.get()}"'))

    # CALENDARIO DESPLEGABLE
    cal_label = Label(windows, text='Seleccione la Fecha')
    cal_label.grid(row=4, column=1)

    cal = DateEntry(windows, state='readonly', locale='spa', date_pattern='dd/mm/y')
    cal.config(headersbackground='#364c55', foreground='#000', background='#fff', headersforeground='#fff',
               locale='spa')
    cal.grid(row=4, column=2)

    # CASILLA GRANDE PARA ESCRIBIR
    text_label = Label(windows)  # El nombre no varia segun la opcion seleccionada.
    text_label.grid(row=6, column=1, columnspan=2)

    cuerpo_text = Text(windows)
    cuerpo_text.grid(row=7, column=1, columnspan=2)
    cuerpo_text.config(width=40, heigh=10, padx=15, pady=15)

    # BOTON REGISTRO / SALIR
    registrar_button = Button(windows, text="Registrar", command=lambda: [getDato(), grab_date()])
    registrar_button.grid(row=9, column=1, columnspan=2)

    # ESPACIOS
    Label(windows).grid(row=1)
    Label(windows).grid(row=3)
    Label(windows).grid(row=5)
    Label(windows).grid(row=8)
    Label(windows).grid(column=0)