from pprint import pprint

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from sklearn.metrics import roc_auc_score, r2_score, f1_score, recall_score, precision_score
from sklearn.model_selection import TimeSeriesSplit
from imblearn.over_sampling import SMOTE

from wave_height.config import (DATA_DIR,
                                EMBED_DIM,
                                HORIZON,
                                TARGET,
                                THRESHOLD_PERCENTILE,
                                MC_N_TRIALS,
                                CV_N_FOLDS)
from wave_height.utils import remove_invalid_observations
from methods.embedding import MultivariateTDE
from methods.predict_proba_regression import mc_predict_proba
from methods.random_forest import predict_proba_from_trees

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)

df = pd.read_csv(DATA_DIR)
df.index = pd.to_datetime(df['time'])
df = df.drop('time', axis=1)
df = df.resample('H').mean()

#

cv = TimeSeriesSplit(n_splits=CV_N_FOLDS)

data_set = MultivariateTDE(data=df,
                           horizon=HORIZON,
                           k=EMBED_DIM,
                           target_col=TARGET)

LAG_COLUMNS = [f'{TARGET}-{i}' for i in range(1, EMBED_DIM + 1)]
TARGET_COLUMNS = [f'{TARGET}+{i}' for i in range(1, HORIZON + 1)]

data_set = data_set.dropna()

X = data_set.drop(TARGET_COLUMNS, axis=1)
Y = data_set[TARGET_COLUMNS]

y = Y.mean(axis=1)

METRICS = ['CLF_F1', 'CLF(SM)_F1', 'REG_F1',
           'CLF_REC', 'CLF(SM)_REC','REG_REC',
           'CLF_PREC', 'CLF(SM)_PREC', 'REG_PREC',
           'REG_R2',
           'CLF_AUC', 'CLF(SM)_AUC','REG_RF_AUC', 'REG_MC_AUC']

results = {m: [] for m in METRICS}
for train_index, test_index in cv.split(X):
    print('.')
    print('Subsetting iter data')
    X_train, X_test = X.iloc[train_index,:], X.iloc[test_index,:]
    y_train, y_test = y[train_index], y[test_index]

    print('Getting pars')
    y_std = y_train.std()
    thr = np.quantile(y_train, THRESHOLD_PERCENTILE)

    print('Removing invalid data')
    X_train, y_train = remove_invalid_observations(X=X_train, y=y_train,
                                                   lag_columns=LAG_COLUMNS,
                                                   decision_thr=thr)
    X_test, y_test = remove_invalid_observations(X=X_test, y=y_test,
                                                 lag_columns=LAG_COLUMNS,
                                                 decision_thr=thr)

    print('Training')
    classifier = RandomForestClassifier()
    classifier_sm = RandomForestClassifier()
    regressor = RandomForestRegressor()

    y_train_clf = (y_train >= thr).astype(int)
    y_test_clf = (y_test >= thr).astype(int)

    print('..Classifier')
    classifier.fit(X_train, y_train_clf)
    print('..Smoting')
    X_train_sm, y_train_clf_sm = SMOTE().fit_resample(X_train, y_train_clf)

    print('..Classifier w smote')
    classifier_sm.fit(X_train_sm, y_train_clf_sm)
    # importances = dict(zip(X_train.columns, classifier.feature_importances_))
    # pprint(importances)
    print('..Regressor')
    regressor.fit(X_train, y_train)

    print('..Predicting')
    y_pred_clf = classifier.predict(X_test)
    y_pred_clf_sm = classifier_sm.predict(X_test)
    y_prob_clf = classifier.predict_proba(X_test)
    y_prob_clf = np.array([x[1] for x in y_prob_clf])
    y_prob_clf_sm = classifier_sm.predict_proba(X_test)
    y_prob_clf_sm = np.array([x[1] for x in y_prob_clf_sm])
    y_pred_reg = regressor.predict(X_test)
    y_pred_reg_thr = (regressor.predict(X_test) > thr).astype(int)
    y_prob_reg_rf = predict_proba_from_trees(model=regressor, X=X_test, thr=thr)
    y_prob_reg_mc = mc_predict_proba(y_hat=y_pred_reg,
                                     scale=y_std,
                                     decision_thr=thr,
                                     n_trials=MC_N_TRIALS)

    print('..Scoring')
    results['CLF_F1'].append(f1_score(y_test_clf, y_pred_clf))
    results['CLF(SM)_F1'].append(f1_score(y_test_clf, y_pred_clf_sm))
    results['REG_F1'].append(f1_score(y_test_clf, y_pred_reg_thr))
    results['CLF_REC'].append(recall_score(y_test_clf, y_pred_clf))
    results['CLF(SM)_REC'].append(recall_score(y_test_clf, y_pred_clf_sm))
    results['REG_REC'].append(recall_score(y_test_clf, y_pred_reg_thr))
    results['CLF_PREC'].append(precision_score(y_test_clf, y_pred_clf))
    results['REG_PREC'].append(precision_score(y_test_clf, y_pred_reg_thr))
    results['CLF(SM)_PREC'].append(precision_score(y_test_clf, y_pred_clf_sm))

    results['REG_R2'].append(r2_score(y_test, y_pred_reg))

    results['CLF_AUC'].append(roc_auc_score(y_test_clf, y_prob_clf))
    results['CLF(SM)_AUC'].append(roc_auc_score(y_test_clf, y_prob_clf_sm))
    results['REG_RF_AUC'].append(roc_auc_score(y_test_clf, y_prob_reg_rf))
    results['REG_MC_AUC'].append(roc_auc_score(y_test_clf, y_prob_reg_mc))

    pprint(results)

#
pd.DataFrame(results).mean()


from scipy.interpolate import interp1d
import numpy as np
import pyglet
from board_colors import board_colors
from board_graphics import BoardBackground, BoardForeground

class ProbabilityDisplay:
  def __init__(self, window_size, board_size, initial_probabilities):
    self.window_size = window_size
    self.board_size = board_size
    self.window = ProbabilityDisplay.make_window(window_size)
    highest_probability_range = [1/len(board_colors), 1]
    self.highest_probability_to_opacity = interp1d(highest_probability_range, BoardForeground.opacity_range)
    self.update(initial_probabilities)

  def has_closed(self):
    return self.window.has_exit

  def update(self, probabilities):
    self.window.dispatch_events()
    background = BoardBackground(self.window_size)
    background.draw()
    self.draw_foreground(probabilities)
    self.window.flip()

  def draw_foreground(self, probabilities):
    foreground = BoardForeground(self.window_size, self.board_size)
    for x in range(self.board_size):
      for y in range(self.board_size):
        dominant_color = np.argmax(probabilities[x, y])
        opacity = self.highest_probability_to_opacity(np.max(probabilities[x, y]))
        foreground.add_color(dominant_color, x, y, opacity)
    foreground.draw()

  @staticmethod
  def make_window(window_size):
    try:
      config = pyglet.gl.Config(sample_buffers = 1, samples = 4)
      window = pyglet.window.Window(window_size, window_size, config = config)
    except pyglet.window.NoSuchConfigException:
      window = pyglet.window.Window(window_size, window_size)
    def on_close():
      window.has_exit = True
      window.close()
    window.on_close = on_close
    return window


# -*- coding: utf-8 -*-
"""metrics module
Define our metrics module that encapsulates attributes and methods related to
the metrics we use for our lunar anomalies project.
"""
import matplotlib.pyplot as plt
import numpy as np
from inspect import signature
from sklearn.metrics import average_precision_score, auc
from sklearn.metrics import precision_recall_curve, roc_curve
from sklearn.metrics import PrecisionRecallDisplay

class Curve:
    def __init__(
        self,
        y_test: [] = None,
        y_scores: [] = None,
        pos_label: int = None,
        feature_str: str = None,
        save_to_disk_fp: str = None,
    ):
        """Init method for our Curve class. This is intended to be the parent
        class for children classes like PrecisionRecallCurve and
        RecieverOperatorCharacteristicCurve.

        Args:
            y_test: the list of true labels
            y_scores: the list of model scores
            pos_label: the torch index to use as our positive class
            save_to_disk_fp: the string where to save the plot

        Returns:
            None

        """
        self.y_test = y_test
        self.y_scores = y_scores
        self.pos_label = pos_label
        self.feature_str = feature_str
        self.save_to_disk_fp = save_to_disk_fp

    def make_plot(
        self,
        show: bool = None,
        verbose: bool = False,
        plot_type: str = None,
    ):
        """Makes a Curve plot. This is intended to be overriden by Curve
        children classes like PrecisionRecallCurve or
        RecieverOperatingCharacteristicCurve.

        Args:
            show: Whether to show the plot on-scren via e.g. plt.show()
            verbose: Whether to enable verbose mode to print various
                information on screen.
            plot_type: String of plot type to use. Possible choices include
                "pr" and "roc".

        Returns:
           None
        """

        xlarge_fontsize = 24
        large_fontsize = 20
        medium_fontsize = 18

        if plot_type == "pr":
            self.x_axis_values = self.recalls
            self.y_axis_values = self.precisions
            self.x_axis_label = "Recall"
            self.y_axis_label = "Precision"
            self.plot_title = self.feature_str.title()

        elif plot_type == "roc":
            self.x_axis_values = self.fpr
            self.y_axis_values = self.tpr
            self.x_axis_label = "False Positive Rate"
            self.y_axis_label = "True Positive Rate"
            self.plot_title = f"ROC Curve. AUC={self.roc_auc:0.2f}"

        # Set plot title, labels.
        plt.title(self.plot_title, fontsize=xlarge_fontsize, fontweight="bold")
        plt.xlabel(self.x_axis_label, fontsize=large_fontsize, fontweight="bold")
        plt.ylabel(self.y_axis_label, fontsize=large_fontsize, fontweight="bold")

        # Set axes limits.
        plt.xlim([0.0, 1.0])
        if plot_type == "pr":
            plt.ylim([0.0, 1.05 * max(self.y_axis_values[:-2])])
        elif plot_type == "roc":
            plt.ylim([0.0, 1.05])
        # Hack for s3 ylim.
        if self.feature_str == "s3":
            plt.ylim([0.0, 5.0e-5])

        # Plot the curve.
        plt.plot(
            self.x_axis_values,
            self.y_axis_values,
            label="Model",
        )

        # Fill the area under the curve.
        plt.fill_between(
            self.x_axis_values,
            self.y_axis_values,
            alpha=0.2,
            color="b",
            interpolate=False,
        )

        # Horizontal line at the random baseline, if plot_type is "pr".
        if plot_type == "pr":
            plt.axhline(
                y=self.random_precision,
                color="#FF0000",
                linestyle="--",
                label="Random baseline",
            )

        # Show the AP versus random baseline improvement factor.
        plt.text(
            0.05,
            0.25,
            f"Improvement factor = {self.improvement_factor:0.2f}",
            fontsize=medium_fontsize,
            fontweight="bold",
            transform=plt.gca().transAxes,
        )

        # Show the AP.
        plt.text(
            0.05,
            0.15,
            f"Model average precision = {self.average_precision:0.2e}",
            fontsize=medium_fontsize,
            fontweight="normal",
            transform=plt.gca().transAxes,
        )

        # Show the random baseline.
        plt.text(
            0.05,
            0.05,
            f"Random baseline = {self.random_precision:0.2e}",
            fontsize=medium_fontsize,
            fontweight="normal",
            transform=plt.gca().transAxes,
        )

        # Make x, y axis labels, ticks bigger.
        plt.xlabel(self.x_axis_label, fontsize=large_fontsize, fontweight="bold")
        plt.ylabel(self.y_axis_label, fontsize=large_fontsize, fontweight="bold")
        plt.xticks(fontsize=large_fontsize)
        plt.yticks(fontsize=large_fontsize)

        # Make y axis have scientific notation.
        plt.ticklabel_format(axis="y", style="sci", scilimits=(0, 0))

        # Plot the legend, setting the order of the legend.
        handles, labels = plt.gca().get_legend_handles_labels()
        order = [0, 1]
        plt.legend(
            [handles[idx] for idx in order],
            [labels[idx] for idx in order],
            loc="upper right",
            fontsize=medium_fontsize,
        )

        # Save, show, close.
        if self.save_to_disk_fp is not None:
            plt.savefig(
                self.save_to_disk_fp,
                dpi=300,
                bbox_inches="tight",
            )
        if show:
            plt.show()
        plt.close()

class RecieverOperatingCharacteristicCurve(Curve):
    def __init__(
        self,
        y_test: [] = None,
        y_scores: [] = None,
        pos_label: int = None,
        drop_intermediate: bool = True,
        save_to_disk_fp: str = None,
    ):
        """Init method for the RecieverOperatingCharacteristicCurve class.
        Args:
            y_test: the list of true labels
            y_scores: the list of model scores
            pos_label: the torch index to use as our positive class
            save_to_disk_fp: the string where to save the plot

        Returns:
            None
        """
        super().__init__(
            y_test, y_scores, pos_label=pos_label, save_to_disk_fp=save_to_disk_fp
        )
        self.drop_intermediate = drop_intermediate
        self.fpr, self.tpr, self.thresholds = roc_curve(
            self.y_test,
            self.y_scores,
            pos_label=self.pos_label,
            drop_intermediate=self.drop_intermediate,
        )
        self.roc_auc = auc(self.fpr, self.tpr)

    def make_plot(
        self,
        show: bool = None,
        verbose: bool = False,
        plot_type: str = "roc",
    ):
        """Makes a reciever operating characteristic plot. This overrides Curve's
        implementaiton of this method.

        Args:
            show: Whether to show the plot on-scren via e.g. plt.show()
            verbose: Whether to enable verbose mode to print various
                information on screen.
            plot_type: String of plot type to use. Possible choices include
                "pr" and "roc".

        Returns:
           None
        """
        super().make_plot(show=show, verbose=verbose, plot_type=plot_type)

class PrecisionRecallCurve(Curve):
    def __init__(
        self,
        y_test: [] = None,
        y_scores: [] = None,
        pos_label: int = None,
        feature_str: str = None,
        save_to_disk_fp: str = None,
    ):
        """Init method for our PrecisionRecallCurve class.

        Args:
            y_test: the list of true labels
            y_scores: the list of model scores
            pos_label: the torch index to use as our positive class
            save_to_disk_fp: the string where to save our PR curve

        Returns:
            None
        """
        super().__init__(
            y_test,
            y_scores,
            pos_label=pos_label,
            feature_str=feature_str,
            save_to_disk_fp=save_to_disk_fp,
        )

        self.precisions, self.recalls, self.thresholds = precision_recall_curve(
            y_test, y_scores, pos_label=self.pos_label
        )
        self.average_precision = average_precision_score(
            y_test, y_scores, pos_label=self.pos_label
        )
        self.dataset_size = len(y_scores)
        self.count_positives = np.count_nonzero(y_test)
        if pos_label == 0:
            self.count_positives = self.dataset_size - self.count_positives
        self.random_precision = float(self.count_positives / self.dataset_size)
        self.improvement_factor = float(self.average_precision / self.random_precision)

    def make_plot(
        self,
        show: bool = None,
        verbose: bool = False,
        plot_type: str = "pr",
    ):
        """Makes a precision recall curve plot. This overrides Curve's
        implementaiton of this method.

        Args:
            show: Whether to show the plot on-scren via e.g. plt.show()
            verbose: Whether to enable verbose mode to print various
                information on screen.
            plot_type: String of plot type to use. Possible choices include
                "pr" and "roc".

        Returns:
           None
        """
        super().make_plot(show=show, verbose=verbose, plot_type=plot_type)


import numpy as np
from scipy.stats import multivariate_normal
from sklearn.cluster import KMeans
import cv2
np.random.seed(0)

def EM_Segmentation(data, parameters, epsilon):
    mean_1 = parameters['mean_1']
    mean_2 = parameters['mean_2']
    covariance_1 = parameters['covariance_1']
    covariance_2 = parameters['covariance_2']
    mixing_coefficient_1 = parameters['mixing_coefficient_1']
    mixing_coefficient_2 = parameters['mixing_coefficient_2']
    # initialize loglikelihood
    N_1 = multivariate_normal.pdf(data, mean=mean_1, cov=covariance_1, allow_singular=True)
    N_2 = multivariate_normal.pdf(data, mean=mean_2, cov=covariance_2, allow_singular=True)
    sum_ = mixing_coefficient_1 * N_1 + mixing_coefficient_2 * N_2
    last_loglikelihood = sum(np.log(sum_))

    while(1):
        # Expectation Step
        N_1 = multivariate_normal.pdf(data, mean=mean_1, cov=covariance_1, allow_singular=True)
        N_2 = multivariate_normal.pdf(data, mean=mean_2, cov=covariance_2, allow_singular=True)
        sum_ = mixing_coefficient_1 * N_1 + mixing_coefficient_2 * N_2
        responsibility_1 = mixing_coefficient_1 * N_1 / sum_
        responsibility_2 = mixing_coefficient_2 * N_2 / sum_

        # Maximization Step
        mean_1 = np.sum(responsibility_1.reshape([-1,1]) * data, axis=0) / np.sum(responsibility_1)
        mean_2 = np.sum(responsibility_2.reshape([-1,1]) * data, axis=0) / np.sum(responsibility_2)
        covariance_1 = ((data - mean_1).T).dot((data - mean_1) * responsibility_1.reshape([-1,1])) / np.sum(responsibility_1)
        covariance_2 = ((data - mean_2).T).dot((data - mean_2) * responsibility_2.reshape([-1,1])) / np.sum(responsibility_2)
        mixing_coefficient_1 = np.sum(responsibility_1) / len(data)
        mixing_coefficient_2 = np.sum(responsibility_2) / len(data)

        # Evaluate
        N_1 = multivariate_normal.pdf(data, mean=mean_1, cov=covariance_1, allow_singular=True)
        N_2 = multivariate_normal.pdf(data, mean=mean_2, cov=covariance_2, allow_singular=True)
        sum_ = mixing_coefficient_1 * N_1 + mixing_coefficient_2 * N_2
        loglikelihood = sum(np.log(sum_))
        if (np.abs(loglikelihood - last_loglikelihood) < epsilon):
            break
        else:
            last_loglikelihood = loglikelihood

    parameters['mean_1'] = mean_1
    parameters['mean_2'] = mean_2
    parameters['covariance_1'] = covariance_1
    parameters['covariance_2'] = covariance_2
    parameters['mixing_coefficient_1'] = mixing_coefficient_1
    parameters['mixing_coefficient_2'] = mixing_coefficient_2

    return parameters

def segmentation(data, parameters):
    N_1 = multivariate_normal.pdf(data,
                                  mean=parameters['mean_1'],
                                  cov=parameters['covariance_1'],
                                  allow_singular=True)
    N_2 = multivariate_normal.pdf(data,
                                  mean=parameters['mean_2'],
                                  cov=parameters['covariance_2'],
                                  allow_singular=True)
    responsibility_1 = parameters['mixing_coefficient_1'] * N_1
    responsibility_2 = parameters['mixing_coefficient_2'] * N_2

    return responsibility_1 < responsibility_2

def writeToFile(data, indices, height, width):
    foreground_data = data.copy()
    background_data = data.copy()
    mask_data = data.copy()
    # assume the foreground' size is smaller than background's size
    if (sum(indices) > len(indices)/2.):
        fore_index = [not id for id in indices]
        back_index = indices.copy()
    else:
        back_index = [not id for id in indices]
        fore_index = indices.copy()

    background_data[fore_index] = 0.
    foreground_data[back_index] = 0.
    mask_data[fore_index] = 0.
    mask_data[back_index] = 255.

    print("start write foreground into image......")
    cv2.imwrite('data/foreground.jpg', foreground_data.reshape([height, width, -1]))
    print("succeed in saving foreground image into \"./data/foreground.jpg\"")

    print("start write background into image......")
    cv2.imwrite('data/background.jpg', background_data.reshape([height, width, -1]))
    print("succeed in saving background image into \"./data/background.jpg\"")

    print("start write mask into image......")
    cv2.imwrite('data/mask.jpg', mask_data.reshape([height, width, -1]))
    print("succeed in saving mask image into \"./data/mask.jpg\"")

def initParameters(data):
    kmeans = KMeans(n_clusters=2, random_state=0).fit(data)
    clusters = kmeans.labels_
    centroids = kmeans.cluster_centers_
    parameters = {}
    parameters['mean_1'] = centroids[0]
    parameters['mean_2'] = centroids[1]
    parameters['covariance_1'] = np.cov(data[clusters == 0].transpose())
    parameters['covariance_2'] = np.cov(data[clusters == 1].transpose())
    parameters['mixing_coefficient_1'] = 0.4
    parameters['mixing_coefficient_2'] = 0.6
    return parameters

def Process(data):
    height = data.shape[0]
    width = data.shape[1]
    data = data.reshape([-1, 3])
    init_parameters = initParameters(data)
    final_parameters = EM_Segmentation(data, init_parameters, epsilon=1e-4)
    indices = segmentation(data, final_parameters)
    writeToFile(data, indices, height, width)

if __name__ == "__main__":
    image = cv2.imread("data/cow.jpg", cv2.IMREAD_COLOR)
    print("image is loaded.")
    Process(image)


import numpy

import pandas as pd

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

from PIL import Image
import PIL.ImageOps

X= numpy.load("image.numpyz")['arr_0']
y = pd.read_csv("labels.csv")["labels"]

classes = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']

nclasses = len(classes)

X_train,X_test,y_train,y_test = train_test_split(X,y,train_size = 3500,test_size=500,random_state=42)

X_train_scaled = X_train/255
X_test_scaled = X_test/255

clf = LogisticRegression(solver="saga",multi_class="multinomial").fit(X_train_scaled,y_train)

def get_prediction(image):
    image_pil = Image.open(image)
    image_bw = image_pil.convert("L")
    image_bw_resized = image_bw.resize((28,28),Image.ANTIALIAS)
    pixel_filter = 20
    min_pixel = numpy.percentile(image_bw_resized,pixel_filter)
    image_bw_resized_scaled = numpy.clip(image_bw_resized-min_pixel,0,255)
    max_pixel = numpy.max(image_bw_resized)
    image_bw_resized_scaled = numpy.asarray(image_bw_resized_scaled)/max_pixel
    test_sample = numpy.array(image_bw_resized_scaled).reshape(1,660)
    predict = clf.predict(test_sample)
    return predict[0]


from __future__ import absolute_import, division
import time
import psychopy
from psychopy import sound, gui, visual, core, data, event
import pandas as pd
import numpy as np  # whole numpy lib is available, prepend 'np.'
import os  # handy system and path functions
import matplotlib.pyplot as plt
import math
import serial  #connecting to the serial port (Arduino)
import random
#import csv
"""

created by criminal mastermind
p.ortegaauriol@auckland.ac.nz
06/22
 base_url: https://sarawia.duckdns.org
"""

_thisDir = os.path.dirname(os.path.abspath(__file__))
os.chdir(_thisDir)

class Experiment(object):
    print(os.getcwd())
    def __init__(self):
        # Arduino & Serial port configuration
        psychopy.prefs.hardware['audioLib'] = ['PTB', 'pyo', 'pygame']
        self.arduino = serial.Serial('COM7', 9600, timeout=0)
        self.line = self.arduino.readline()
        self.countdown_clock = core.Clock()
        self.trialClock = core.Clock()
        self.delay = []
        self.shock = []
        self.range = []
        self.threat_bedroom = []
        self.threat_dining = []
        self.threat_gar = []
        self.threat_kit = []
        self.threat_lo = []
        self.result = 0
        self.nthreat_bedroom = []
        self.nthreat_dining = []
        self.nthreat_gar = []
        self.nthreat_kit = []
        self.nthreat_lo = []

        self.background = []

        self.nothreat = []
        self.Task()

        #Panda data frame
        self.df = pd.DataFrame({"RT": [], "Trial": [], "Delay": [],"Threat": [], "PCode": [], "Session": [], 'Block': []})

        self.win = visual.Window(
            size= [1920, 1080],
            fullscr=self.expInfo['Full Screen'],
            winType='pyglet',
            monitor='testMonitor',
            screen=1,
            # monitor = 'Wired Display',
            color=[-1, -1, -1], colorSpace='rgb',
            # blendMode='avg', mouseVisible = False, allowGUI=False)
            blendMode='avg', allowGUI=False)
        #Instructions
        self.Break  = visual.ImageStim(self.win, image='Images/Instructions' + os.sep + 'Break.jpg')
        self.Correct  = visual.ImageStim(self.win, image='Images/Instructions' + os.sep + 'Correct.jpg')
        self.Incorrect  = visual.ImageStim(self.win, image='Images/Instructions' + os.sep + 'Incorrect.jpg')
        self.Instructions  = visual.ImageStim(self.win, image='Images/Instructions' + os.sep + 'Instructions.jpg')
        self.Trigger  = visual.ImageStim(self.win, image='Images/Instructions' + os.sep + 'Trigger.jpg')

        #Backgrounnd
        self.range.append(visual.ImageStim(self.win, image='Images/Background' + os.sep + 'Bedroom.jpg'))
        self.range.append(visual.ImageStim(self.win, image='Images/Background' + os.sep + 'Lounge.jpg'))
        self.range.append(visual.ImageStim(self.win, image='Images/Background' + os.sep + 'Kitchen.jpg'))
        self.range.append(visual.ImageStim(self.win, image='Images/Background' + os.sep + 'Garage.jpg'))
        self.range.append(visual.ImageStim(self.win, image='Images/Background' + os.sep + 'Dining Room.jpg'))

        #GO
        self.threat_bedroom.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Bedroom Machete L.jpg'))
        self.threat_bedroom.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Bedroom Machete R.jpg'))
        self.threat_bedroom.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Bedroom Pistol L.jpg'))
        self.threat_bedroom.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Bedroom Pistol R.jpg'))
        self.threat_bedroom.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Bedroom Rifle L.jpg'))
        self.threat_bedroom.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Bedroom Rifle R.jpg'))

        self.threat_dining.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Dining Room Machete L.jpg'))
        self.threat_dining.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Dining Room Machete R.jpg'))
        self.threat_dining.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Dining Room Pistol L.jpg'))
        self.threat_dining.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Dining Room Pistol R.jpg'))
        self.threat_dining.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Dining Room Rifle L.jpg'))
        self.threat_dining.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Dining Room Rifle R.jpg'))

        self.threat_gar.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Garage Machete L.jpg'))
        self.threat_gar.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Garage Machete R.jpg'))
        self.threat_gar.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Garage Pistol L.jpg'))
        self.threat_gar.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Garage Pistol R.jpg'))
        self.threat_gar.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Garage Rifle L.jpg'))
        self.threat_gar.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Garage Rifle R.jpg'))

        self.threat_kit.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Kitchen Machete L.jpg'))
        self.threat_kit.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Kitchen Machete R.jpg'))
        self.threat_kit.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Kitchen Pistol L.jpg'))
        self.threat_kit.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Kitchen Pistol R.jpg'))
        self.threat_kit.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Kitchen Rifle L.jpg'))
        self.threat_kit.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Kitchen Rifle R.jpg'))

        self.threat_lo.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Lounge Machete L.jpg'))
        self.threat_lo.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Lounge Machete R.jpg'))
        self.threat_lo.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Lounge Pistol L.jpg'))
        self.threat_lo.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Lounge Pistol R.jpg'))
        self.threat_lo.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Lounge Rifle L.jpg'))
        self.threat_lo.append(visual.ImageStim(self.win, image='Images/go' + os.sep + 'Lounge Rifle R.jpg'))

        #NOGO

        self.nthreat_bedroom.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Bedroom Cup L.jpg'))
        self.nthreat_bedroom.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Bedroom Cup R.jpg'))
        self.nthreat_bedroom.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Bedroom Keys L.jpg'))
        self.nthreat_bedroom.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Bedroom Keys R.jpg'))
        self.nthreat_bedroom.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Bedroom Phone L.jpg'))
        self.nthreat_bedroom.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Bedroom Phone R.jpg'))

        self.nthreat_dining.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Dining Room Cup L.jpg'))
        self.nthreat_dining.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Dining Room Cup R.jpg'))
        self.nthreat_dining.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Dining Room Keys L.jpg'))
        self.nthreat_dining.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Dining Room Keys R.jpg'))
        self.nthreat_dining.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Dining Room Phone L.jpg'))
        self.nthreat_dining.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Dining Room Phone R.jpg'))

        self.nthreat_gar.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Garage Cup L.jpg'))
        self.nthreat_gar.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Garage Cup R.jpg'))
        self.nthreat_gar.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Garage Keys L.jpg'))
        self.nthreat_gar.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Garage Keys R.jpg'))
        self.nthreat_gar.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Garage Phone L.jpg'))
        self.nthreat_gar.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Garage Phone R.jpg'))

        self.nthreat_kit.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Kitchen Cup L.jpg'))
        self.nthreat_kit.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Kitchen Cup R.jpg'))
        self.nthreat_kit.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Kitchen Keys L.jpg'))
        self.nthreat_kit.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Kitchen Keys R.jpg'))
        self.nthreat_kit.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Kitchen Phone L.jpg'))
        self.nthreat_kit.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Kitchen Phone R.jpg'))

        self.nthreat_lo.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Lounge Cup L.jpg'))
        self.nthreat_lo.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Lounge Cup R.jpg'))
        self.nthreat_lo.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Lounge Keys L.jpg'))
        self.nthreat_lo.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Lounge Keys R.jpg'))
        self.nthreat_lo.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Lounge Phone L.jpg'))
        self.nthreat_lo.append(visual.ImageStim(self.win, image='Images/NoGo' + os.sep + 'Lounge Phone R.jpg'))

        #self.nothreat = visual.ImageStim(self.win, image='Images' + os.sep + 'NonThreat.jpg')

        self.Workflow()

    def Task(self):
        # Participant information
        self.expInfo = {'Participant code': 0000,'Session':00, 'Age (Years)': 00, 'Gender': ['M', 'F', 'Other'],
                        'n_go_trials (per block)': 3, 'n_stop_trials (per block)': 1, 'n blocks': 3,
                          'practice trials': True, 'n practice go trials': 1,
                          'n practice stop trials': 1, 'Full Screen': False,
                        'Threat Mode': True, 'Threat Response': 0.5,
                        'Response End Time': 2, 'Delay_1': 1.5, 'Delay_2': 2, 'Delay_3': 2.5 }
        self.expName = 'Shoot'
        dlg = gui.DlgFromDict(dictionary=self.expInfo, title='Participant Information', tip=None)
        if dlg.OK == False:
            print('Closing port and exit')
            self.arduino.close()
            core.quit()
        self.expInfo['date'] = data.getDateStr()
        header = "RT    Trial   Delay   Threat   Code    Session "
        with open('DataFile' + str(self.expInfo['Participant code']) + str(self.expInfo['Session']) + '.txt', 'a') as b:
            b.write(header + "\n")
            b.close()
        return

    def Workflow(self):
        self.gen_trials()
        self.runExperiment()

    def gen_trials(self):
        print('Generating Trials')
        # Generate trials
        if self.expInfo['practice trials']:
            self.train_trial = [1] * self.expInfo['n practice go trials'] + [0] * self.expInfo['n practice stop trials']
            random.shuffle(self.train_trial)
        else:
            self.train_trial = []

        self.trials = [0] * self.expInfo['n_stop_trials (per block)'] + [1] * self.expInfo['n_go_trials (per block)']

        #Generating blocks
        if not self.expInfo['Threat Mode']:
            self.blocks = [0] * int(self.expInfo['n blocks'])
        else:
            self.blocks = [0] * int(math.ceil(self.expInfo['n blocks']/2)) + [1] * int(math.floor(self.expInfo['n blocks']/2))

        # Generate the random delays / trials
        self.times = [self.expInfo['Delay_1'], self.expInfo['Delay_2'],self.expInfo['Delay_3']]
        # Trials/delays * blocks
        self.trials = [self.trials]*len(self.blocks)

        background = []
        for sub in range(0, len(self.trials)):
            for n in range(len(self.trials[sub])):
                background.append(random.randint(0, int(len(self.range))-1))

        n = len(self.trials[0])
        self.background = [background[i:i + n] for i in range(0, len(background), n)]

        #Random shuffle the lists
        for i in self.trials:
            self.delay.append(random.choices(self.times, weights=[1, 1, 1], k=len(i)))
            if self.expInfo['Threat Mode']:
                self.shock.append([1]*int(len(i)/2) + [1]*int(len(i)/2))
            else:
                self.shock.append([0] * int(len(i)))

        self.trials = [random.sample(i, len(i)) for i in self.trials]
        self.shock = [random.sample(i, len(i)) for i in self.shock]
        random.shuffle(self.blocks)

        print('Practice Trials', self.train_trial)
        print('\nTrials', self.trials,'\nBlocks', self.blocks, '\nDelay', self.delay, '\nThreat', self.shock)
        print('Background = ', self.background)

    def waitSwitch(self):
        for lines in self.arduino.readline(): pass
        line = []
        print('Press Trigger to Start')
        while len(line) == 0:
            line = self.arduino.readline()
            core.wait(0.1)
        print('Switch Pressed')
        time.sleep(0.1)
        for lines in self.arduino.readline():pass
        return

    def countdown(self):  # give countdown and if finger is lifted say this is too soon and restart
        if self.expInfo['CountDown']:
            self.countdown_clock.reset()
            while int(self.countdown_clock.getTime()) < 4:
                pass
                #print(str(self.countdown_clock.getTime()))
            return

    def trigger(self):
        #line = self.arduino.readline()
        for lines in self.arduino.readline(): pass
        line = []
        while len(line) == 0:
            line = self.arduino.readline()
            if int(self.trialClock.getTime()) >= self.expInfo['Response End Time']:
                break
        self.RT =  self.trialClock.getTime()
        #if not len(line) == 0:
            #playsound(r"""D:/Work/Shoot or Don't Shoot/sound/Gunshot.mp3""")
        #time.sleep(1)
        return self.RT

    def electroshock(self):
        print('Send Shock')
        self.arduino.write([1])
        return

    def emg(self):
        self.arduino.write([2])
        return

    def classifier(self, trial, block):

        # Classify for Shock
        if self.RT > self.expInfo['Threat Response'] and trial == 1:
            self.Incorrect.draw()
            if block == 1:
                self.electroshock()
            self.win.flip()
            time.sleep(1)
            self.result = 0

        elif self.RT < self.expInfo['Response End Time'] and trial == 0:
            self.Incorrect.draw()
            if block == 1:
                self.electroshock()
            self.win.flip()
            time.sleep(1)
            self.result = 0

        else:
            # Build a classifier for the non-shock trials
            self.Correct.draw()
            self.win.flip()
            time.sleep(1)
            self.result = 1

    def runExperiment(self):
        print('Experiment')
        self.saveconfig()
        self.Instructions.draw()
        self.win.flip()
        self.waitSwitch()

        # Training Trials
        if self.train_trial:
            for k in np.arange(0, len(self.train_trial), 1):
                for lines in self.arduino.readline(): pass
                print('Practice Trial')
                self.range[0].draw()
                self.win.flip()
                time.sleep(2)
                if self.train_trial[k] == 0:
                    self.nthreat_bedroom[random.randint(0, 5)].draw()
                else:
                    self.threat_bedroom[random.randint(0, 5)].draw()
                self.win.flip()
                self.trialClock.reset()
                self.trigger()
                print('Practice RT = ', self.RT)
                time.sleep(2)
                self.win.flip()
                time.sleep(3)
            print('End of Practice Trials')
            self.Break.draw()
            self.win.flip()
            self.waitSwitch()

        # Experiment Trial
        for block in range(self.expInfo['n blocks']):

            #variables in the block
            trials = self.trials[block]
            delay = self.delay[block]
            background = self.background[block]
            for lines in self.arduino.readline(): pass
            for k in np.arange(0, len(trials), 1):

                print('\n Trial =', k, 'Threat = ', self.blocks[block], 'Shoot = ', trials[k])

                for lines in self.arduino.readline(): pass
                self.range[background[k]].draw()
                self.win.flip()
                time.sleep(delay[k])

                #given the background and trial type show an according threat/no threat image/
                if trials[k] == 0:
                    if background[k] == 0:
                        self.nthreat_bedroom[random.randint(0,5)].draw()
                    elif background[k] == 1:
                        self.nthreat_lo[random.randint(0, 5)].draw()
                    elif background[k] == 2:
                        self.nthreat_kit[random.randint(0, 5)].draw()
                    elif background[k] == 3:
                        self.nthreat_gar[random.randint(0, 5)].draw()
                    elif background[k] == 4:
                        self.nthreat_dining[random.randint(0, 5)].draw()

                elif trials[k] == 1:
                    if background[k] == 0:
                        self.threat_bedroom[random.randint(0, 5)].draw()
                    elif background[k] == 1:
                        self.threat_lo[random.randint(0, 5)].draw()
                    elif background[k] == 2:
                        self.threat_kit[random.randint(0, 5)].draw()
                    elif background[k] == 3:
                        self.threat_gar[random.randint(0, 5)].draw()
                    elif background[k] == 4:
                        self.threat_dining[random.randint(0, 5)].draw()

                self.win.flip()
                self.emg()
                self.trialClock.reset()
                self.trigger()
                #Process response time for shock or feedback
                print('RT = ', self.RT)

                # Keep the screen for a consistent time after trigger independently of the trial type.
                while True:
                    if int(self.trialClock.getTime()) >= self.expInfo['Response End Time']:
                        break
                #Classify the reaction time
                self.classifier(trials[k], self.blocks[block])

                # self.win.flip()
                #Save the trials/info
                self.savedata(self.RT, trials[k], delay[k], self.blocks[block], self.result, block)
                time.sleep(3)
            self.stats(block)
            self.Break.draw()
            self.win.flip()
            for lines in self.arduino.readline(): pass
            self.waitSwitch()
            for lines in self.arduino.readline(): pass

    def saveconfig(self):
        with open('config' + '.txt', 'a') as b:
            b.write('%s  \n%s  \n%s   \n%s\n' %
                    (self.trials, self.expInfo, self.delay, self.blocks))

    def savedata(self, RT, trial, delay, threat, result, block):
        # Save Variables into a file

        df2 = pd.DataFrame({"RT": [RT], "Trial": [trial], "Delay": [delay], "Threat": [threat],
                            "PCode": [self.expInfo['Participant code']], "Session": [self.expInfo['Session']],
                            "Outcome": [result], "Block":[block]})
        self.df = pd.concat([self.df, df2])
        self.df.to_csv('DataFile' + str(self.expInfo['Participant code']) + '_' + str(self.expInfo['Session']) + '.csv', index=False)

    def stats(self, block):
        # Descriptive statistics at the end of the block.

        # MEAN REACTION TIME OF TRIALS
        df1 = self.df[['RT', 'Trial']]
        df1 = df1.groupby(['Trial'], as_index=False).mean()
        #Trials which are only a go.
        df2 = self.df.RT.where(self.df.Trial != 0)
        df2 = df2.dropna(axis=0)

        # PIE DATA
        df3 = self.df[['RT', 'Outcome']]
        piedata = [df3.Outcome.where(df3.Outcome == 1).count(), df3.Outcome.where(df3.Outcome == 0).count()]

        #PIE PLOT
        plt.figure(figsize=(12, 6))  # set figure size
        plt.xticks(family='Arial', size=12)
        plt.yticks(family='Arial', size=12)
        labels = ['Success', 'Fail']
        #colors = sns.color_palette('pastel')[0:2]
        p2 = plt.pie(piedata, labels=labels, autopct='%.0f%%') #colors=colors
        plt.savefig(_thisDir + '\Plot_%s_%s' % (self.expInfo['Participant code'], self.expInfo['Session']))
        pieplot = visual.ImageStim(self.win, image=(_thisDir + '\Plot_%s_%s' % (self.expInfo['Participant code'],
                                    self.expInfo['Session']) + '.png'), pos=[0, 0], units='cm', color=[1, 1, 1])
        pieplot.draw()
        self.win.flip()
        time.sleep(8)
        # LinePlot
        plt.figure(figsize=(12, 6))
        plt.ylabel('Reaction Time', size=20, family='Arial')  # create plot
        plt.xlabel('Trial Number', size=20, family='Arial')
        n = [float(i) for i in df2]
        p1 = plt.plot(n, linewidth=3)
        plt.xlabel("Trial Number")
        plt.ylabel("Reaction Time (sec)")
        plt.axhline(0.5, color='red')
        plt.savefig(_thisDir + '\Plot_%s_%s' % (self.expInfo['Participant code'], self.expInfo['Session']))
        linerplot = visual.ImageStim(self.win, image=(_thisDir + '\Plot_%s_%s' % (self.expInfo['Participant code'],
                                        self.expInfo['Session']) + '.png'), pos=[0, 0], units='cm', color=[1, 1, 1])
        linerplot.draw()
        self.win.flip()
        time.sleep(8)

if __name__ == "__main__":
    #parser = ArgumentParser(description=" FPS Shooter ")
    sa = Experiment()


from collections import defaultdict
from utils import timeit

@timeit
def get_data():
    data = []
    with open('input.txt') as input_file:
        for line in input_file:
            value = line.strip().split()
            data.append(value)
    return data

def execute(program, default_registers=None):

    # Do not modify the original program
    program = list(tuple(instruction) for instruction in program)

    registers = defaultdict(int)
    if default_registers is not None:
        registers.update(default_registers)
    instruction_pointer = 0

    while 0 <= instruction_pointer < len(program):

        instruction, *values = program[instruction_pointer]

        if instruction == 'cpy':
            x, y = values
            try:
                x = int(x)
            except ValueError:
                x = registers[x]
            registers[y] = x

        elif instruction == 'inc':
            x = values[0]
            registers[x] += 1

        elif instruction == 'dec':
            x = values[0]
            registers[x] -= 1

        elif instruction == 'jnz':
            x, y = values
            try:
                x = int(x)
            except ValueError:
                x = registers[x]
            if x != 0:
                try:
                    y = int(y)
                except ValueError:
                    y = registers[y]
                instruction_pointer += y - 1
        elif instruction == 'tgl':
            x = values[0]
            try:
                x = int(x)
            except ValueError:
                x = registers[x]

            if 0 <= instruction_pointer + x < len(program):
                instruction_, *values_ = program[instruction_pointer + x]
                if instruction_ in ('inc', 'dec', 'tgl'):
                    instruction_ = 'dec' if instruction_ == 'inc' else 'inc'
                elif instruction_ in ('cpy', 'jnz'):
                    instruction_ = 'cpy' if instruction_ == 'jnz' else 'jnz'

                program[instruction_pointer + x] = (instruction_, *values_)

        elif instruction == 'nop':
            pass

        elif instruction == 'mul':
            x, y, z = values
            try:
                x = int(x)
            except ValueError:
                x = registers[x]
            try:
                y = int(y)
            except ValueError:
                y = registers[y]
            registers[z] = x*y
        else:
            raise ValueError(f"Unknown instruction {(instruction, *values)} line {instruction_pointer}.")

        instruction_pointer += 1

    return registers

@timeit
def part_1(data):
    registers = execute(program=data, default_registers={'a': 7})
    return registers['a']

@timeit
def part_2(data):
    registers = execute(program=data, default_registers={'a': 12})
    return registers['a']

def main():
    data = get_data()

    data[3:10] = [
        ('mul', 'b', 'd', 'a'),
        ('cpy', '0', 'c'),
        ('cpy', '0', 'd'),
        ('nop',),
        ('nop',),
        ('nop',),
        ('nop',),
    ]

    part_1(data)
    part_2(data)

if __name__ == "__main__":
    main()


import datetime
import time

import tweepy as twitter

import keys
import random

auth = twitter.OAuthHandler(keys.api_key, keys.api_secret)
auth.set_access_token(keys.access_key, keys.access_secret)
api = twitter.API(auth)

def twitter_bot_retweet(hashtag, delay):
    while True:
        print(f'\n{datetime.datetime.now}/n')

        for tweet in twitter.Cursor(api.search_tweets, q=hashtag, count=500).items(25):
            try:
                tweet_id = dict(tweet._json)['id']
                tweet_text = dict(tweet._json)['text']

                print('id: ' + str(tweet_id))
                print('text: ' + str(tweet_text))

                api.retweet(tweet_id)

            except twitter.TweepyException as error:
                print(error)

        time.sleep(delay)

def twitter_bot_like(hashtag, delay):
    while True:
        print(f'\n{datetime.datetime.now}/n')

        for tweet in twitter.Cursor(api.search_tweets, q=hashtag, count=1000).items(100):
            try:
                tweet_id = dict(tweet._json)['id']
                tweet_text = dict(tweet._json)['text']

                print('id: ' + str(tweet_id))
                print('text: ' + str(tweet_text))

                api.create_favorite(tweet_id)

            except twitter.TweepyException as error:
                print(error)

        time.sleep(delay)

hashtags = ['#etherium', '#solana', '#bitcoin', '#airdrop']

twitter_bot_retweet(random.choice(hashtags), 60)
twitter_bot_like(random.choice(hashtags), 45)


from datetime import datetime
from enum import Enum
from typing import List

from fastapi import HTTPException
from pydantic import BaseModel, validator, root_validator

class SystemItemType(str, Enum):
    FILE = "FILE"
    FOLDER = "FOLDER"

class SystemItemTag(str, Enum):
    Document = "Document"
    Template = "Template"
    Report = "Report"
    Export = "Export"
    Other = "Other"

class InternalItemData(BaseModel):
    id: str
    url: str | None = None
    date: datetime | None
    parent_id: str | None
    type: SystemItemType
    size: int | None = 0

    class Config:
        orm_mode = True

class ItemData(BaseModel):
    id: int
    date: datetime
    parent_id: int | None
    size: int
    url: str
    name: str
    tag: SystemItemTag
    type: SystemItemType

    class Config:
        orm_mode = True

class FolderItemRequest(BaseModel):
    parent_id: int | None = None
    name: str

    class Config:
        orm_mode = True

class FileItemRequest(BaseModel):
    id: int | None = None
    parent_id: int | None

    class Config:
        orm_mode = True

class ItemTagResponseData(BaseModel):
    items: List[ItemData]

class ItemResponseData(ItemData):
    children: List | None = []

    @validator("children")
    def replace_empty(cls, val):
        return val or None

    def get_child(self, index):
        if len(self.children) > index:
            return self.children[index]
        return None

class Error(BaseModel):
    code: int
    message: str

    class Config:
        orm_mode = True


from dataclasses import dataclass
from datetime import datetime

from .. import db

@dataclass
class StockTimeline(db.Model):
    __tablename__ = "stock_timeline"
    id: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
    product_id: int = db.Column(db.Integer, db.ForeignKey("product.id"), nullable=False)
    vending_machine_id: int = db.Column(db.Integer, db.ForeignKey("vending_machine.id"), nullable=False)
    quantity: int = db.Column(db.Integer)
    timestamp: datetime = db.Column(db.DateTime, default=datetime.utcnow)

    def to_dict(self):
        return {
            "id": self.id,
            "product_id": self.product_id,
            "vending_machine_id": self.vending_machine_id,
            "quantity": self.quantity,
            "timestamp": self.timestamp.isoformat(),
        }


import os

import torch
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass

from src.dataType import State, Action
from src.animator.animator import Animator
from src.const import VNF_SELECTION_IN_DIM, VNF_PLACEMENT_IN_DIM

@dataclass
class DebugInfo:
    timestamp: str
    episode: int
    mean_100_step: int
    std_100_step: int
    mean_100_change_slp_srv: float
    std_100_change_slp_srv: float
    mean_100_init_slp_srv: float
    std_100_init_slp_srv: float
    mean_100_final_slp_srv: float
    std_100_final_slp_srv: float
    srv_n: int
    mean_100_change_sfc_in_same_srv: float
    std_100_change_sfc_in_same_srv: float
    mean_100_init_sfc_in_same_srv: float
    std_100_init_sfc_in_same_srv: float
    mean_100_final_sfc_in_same_srv: float
    std_100_final_sfc_in_same_srv: float
    sfc_n: int
    mean_100_exploration: float
    std_100_exploration: float
    mean_100_reward: float
    std_100_reward: float

def setup_mp_env():
    os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID'
    os.environ['CUDA_VISIBLE_DEVICES'] = ''
    os.environ['OMP_NUM_THREADS'] = '1'

def print_debug_info(debug_info: DebugInfo, refresh: bool = False):
    debug_msg = "[{}] Episode {:05}, Step {:04.2f}\u00B1{:04.2f}, #SleepSrv ({:02.3f}\u00B1{:02.3f})({:02.3f}\u00B1{:02.3f}->{:02.3f}\u00B1{:02.3f}/{}), #SFCinSameSrv ({:02.3f}\u00B1{:02.3f})({:02.3f}\u00B1{:02.3f}->{:02.3f}\u00B1{:02.3f}/{}), Exploration: {:.3f}\u00B1{:02.3f}, Rewards: {:02.3f}\u00B1{:02.3f}".format(
        debug_info.timestamp, debug_info.episode, debug_info.mean_100_step, debug_info.std_100_step,
        debug_info.mean_100_change_slp_srv, debug_info.std_100_change_slp_srv, debug_info.mean_100_init_slp_srv, debug_info.mean_100_init_slp_srv, debug_info.mean_100_final_slp_srv, debug_info.std_100_final_slp_srv, debug_info.srv_n,
        debug_info.mean_100_change_sfc_in_same_srv, debug_info.std_100_change_sfc_in_same_srv, debug_info.mean_100_init_sfc_in_same_srv, debug_info.std_100_init_sfc_in_same_srv, debug_info.mean_100_final_sfc_in_same_srv, debug_info.std_100_final_sfc_in_same_srv, debug_info.sfc_n,
        debug_info.mean_100_exploration, debug_info.std_100_exploration, debug_info.mean_100_reward, debug_info.std_100_reward,
    )
    print(debug_msg, end='\r', flush=True)
    if refresh:
        print('\x1b[2K' + debug_msg, flush=True)

def convert_state_to_vnf_selection_input(state: State, max_vnf_num: int) -> torch.Tensor:
    vnf_selection_input = torch.zeros(max_vnf_num, VNF_SELECTION_IN_DIM, dtype=torch.float32)
    for vnf in state.vnfs:
        vnf_selection_input[vnf.id] = torch.tensor([
            vnf.cpu_req, vnf.mem_req, vnf.sfc_id,
            state.srvs[vnf.srv_id].cpu_cap, state.srvs[vnf.srv_id].mem_cap,
            state.srvs[vnf.srv_id].cpu_load, state.srvs[vnf.srv_id].mem_load,
            state.edge.cpu_cap, state.edge.mem_cap,
            state.edge.cpu_load, state.edge.mem_load,
        ])
    return vnf_selection_input

def convert_state_to_vnf_placement_input(state: State, vnf_id: int) -> torch.Tensor:
    vnf_placement_input = torch.zeros(len(state.srvs), VNF_PLACEMENT_IN_DIM, dtype=torch.float32)
    for srv in state.srvs:
        vnf_placement_input[srv.id] = torch.tensor([
            srv.cpu_cap, srv.mem_cap, srv.cpu_load, srv.mem_load,
            state.vnfs[vnf_id].cpu_req, state.vnfs[vnf_id].mem_req, state.vnfs[vnf_id].sfc_id,
            state.edge.cpu_cap, state.edge.mem_cap, state.edge.cpu_load, state.edge.mem_load
        ])
    return vnf_placement_input

def get_possible_actions(state: State, max_vnf_num: int) -> Dict[int, List[int]]:
    '''return possible actions for each state

    Args:
        state (State): state

    Returns:
        Dict[int, List[int]]: possible actions
                                    ex) {vnfId: [srvId1, srvId2, ...], vnfId2: [srvId1, srvId2, ...], ...}
    '''
    possible_actions = {}
    for vnf_idx in range(max_vnf_num):
        possible_actions[vnf_idx] = []
        if len(state.vnfs) <= vnf_idx: continue
        vnf = state.vnfs[vnf_idx]
        for srv in state.srvs:
            # 이미 설치된 srv로 이동하는 action 막기
            if vnf.srv_id == srv.id: continue
            # capacity 확인
            if srv.cpu_cap - srv.cpu_load < vnf.cpu_req or srv.mem_cap - srv.mem_load < vnf.mem_req: continue
            possible_actions[vnf.id].append(srv.id)
    return possible_actions

def get_info_from_logits(logits: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
    probs = logit_to_prob(logits)
    dist = torch.distributions.Categorical(probs=probs)
    actions = dist.sample().to(torch.int32)
    logpas = dist.log_prob(actions)
    is_exploratory = actions != torch.argmax(logits, dim=1)
    return actions, logpas, is_exploratory

def logit_to_prob(logits: torch.Tensor) -> torch.Tensor:
    probs = torch.zeros_like(logits)
    # 0인 값은 prob을 0으로 유지하고, 나머지 값을 확률로 변경
    for i in range(logits.shape[0]):
        probs[i, logits[i] != 0] = torch.softmax(logits[i, logits[i] != 0], dim = 0)
    return probs

def get_device():
    return torch.device("cuda" if torch.cuda.is_available() else "cpu")

def get_zero_util_cnt(state: State) -> int:
    cnt = 0
    for srv in state.srvs:
        if len(srv.vnfs) == 0:
            cnt += 1
    return cnt

def get_sfc_cnt_in_same_srv(state: State) -> int:
    cnt = 0
    for sfc in state.sfcs:
        if len(sfc.vnfs) == 0:
            continue
        cnt += 1
        srv_id = sfc.vnfs[0].srv_id
        for vnf in sfc.vnfs:
            if srv_id != vnf.srv_id:
                cnt -= 1
                break
    return cnt

def save_animation(
        srv_n: int, sfc_n: int, vnf_n: int,
        srv_mem_cap: int, srv_cpu_cap: int,
        history: List[Tuple[State, Optional[Action]]],
        path=f'./result/anim.mp4'):
    animator = Animator(srv_n=srv_n, sfc_n=sfc_n, vnf_n=vnf_n,
                        srv_mem_cap=srv_mem_cap, srv_cpu_cap=srv_cpu_cap, history=history)
    animator.save(path)


from django.shortcuts import render, get_object_or_404, redirect
from .models import Usuario
from .forms import UsuarioForm

def inicio(request) :
  usuarios = Usuario.objects.all()
  context = {
    'usuarios' : usuarios
  }
  return render(request, 'usuarios/inicio.html', context)

def detail(request, id) :
  detail_usuario = get_object_or_404(Usuario , pk = id)
  context = {
    'detail_usuario' : detail_usuario
  }
  return render(request , 'usuarios/detail.html', context)

def create_usuario(request) :
  if request.method == 'POST' :
    usuario_form = UsuarioForm(request.POST)
    if usuario_form.is_valid() :
        usuario_form.save()
        return redirect('aplication:inicio')
  else :
    usuario_form = UsuarioForm()
  return render(request , 'usuarios/create.html' , {'usuario_form' : usuario_form})

def update_usuario(request, id) :
  usuario = get_object_or_404(Usuario, id = id)
  if request.method == "POST" :
    usuario_form = UsuarioForm(request.POST , instance = usuario)
    if usuario_form.is_valid() :
        usuario_form.save()
        return redirect('aplication:inicio')
  else :
    usuario_form = UsuarioForm()
    return render(request, 'usuarios/editar.html', {'usuario_form' : usuario_form} )

def delete_usuario(request, id) :
  usuario = get_object_or_404(Usuario, id = id)

  if usuario :
    usuario.delete()

  return redirect('aplication:inicio')


import cv2 as cv
import numpy as np
import os

def dummy_resize(img, size):
    _sz = np.shape(img)[:-1]
    field = np.zeros((max(_sz), max(_sz), 3), dtype=np.uint8)
    if _sz[0] > _sz[1]:
        field[:, (_sz[0]-_sz[1])//2:(_sz[0]+_sz[1])//2+(_sz[1] % 2), :] = img
    else:
        field[(_sz[1]-_sz[0])//2:(_sz[1]+_sz[0])//2+(_sz[0] % 2), :, :] = img
    return resize(field, size)

def is_image(name):
    image_formats = ['jpg', 'png', 'tif', 'bmp']
    return os.path.splitext(name)[1][1:].lower() in image_formats

def put_on_color_field(images, background):
    shape = np.shape(images[0])
    if background == 'black':
        field = np.zeros(shape, dtype=np.uint8)
    elif background == 'white':
        field = 255*np.ones(shape, dtype=np.uint8)
    elif background == 'gray':
        field_color = np.mean([np.mean(img[img != 0]) for img in images])
        field = field_color * np.ones(shape, dtype=np.uint8)
    else:
        raise NameError('incorrect background name!')
    result = []
#    print(np.mean(field))
    for img in images:
        img[img < 3] = field[img < 3]
        result.append(np.uint8(img))
    return result

def put_on_square_field(img, field_size, x0, y0, size):
    result = np.zeros((field_size, field_size, 3), dtype=np.uint8)
    resized_img = cv.resize(img, (size, size))
    result[x0:x0+size, y0:y0+size] = resized_img
    return result

def read_images(path):
    names = np.sort([name for name in os.listdir(path) if is_image(name)])
    images = [cv.imread(os.path.join(path, name)) for name in names]
    return images, names

def read_one_image(path, name):
    return cv.imread(os.path.join(path, name))

def read_images_names(path):
    return np.sort([name for name in os.listdir(path) if is_image(name)])

def remove_chromakey(img, sens=35, chanel_to_remove='green'):
    reds = img[:, :, 2]
    greens = img[:, :, 1]
    blues = img[:, :, 0]
    # Refactoring in future
    if chanel_to_remove == 'green':
        mask = (greens < sens) | (reds > greens) | (blues > greens)
    elif chanel_to_remove == 'blue':
        mask = (blues < sens) | (reds > blues) | (greens > blues)
    elif chanel_to_remove == 'red':
        mask = (reds < sens) | (blues > reds) | (greens > reds)
    else:
        raise TypeError("Chanel {} not found!".format(chanel_to_remove))
    empty_img = np.zeros_like(img)
    empty_img[mask, 0] = 255
    result = np.zeros_like(img)
    for index in range(3):
        result[:, :, index] = img[:, :, index]*np.where(mask, 1, 0)
    return result

def resize(img, size):
    return cv.resize(img, (size, size), interpolation=cv.INTER_CUBIC)

def save_images(path, images, names):
    [cv.imwrite(os.path.join(path, nm), img) for nm, img in zip(names, images)]
    return 0

def save_one_image(path, image, name):
    cv.imwrite(os.path.join(path, name), image)
    return 0

def select_square(img0, return_params=False):
    img_size = np.shape(img0)[:-1]
    max_size = max(img_size)
    img = np.zeros((max_size, max_size, 3), dtype=np.uint8)
    img[max_size // 2 - img_size[0] // 2:
        max_size // 2 + img_size[0] // 2 + img_size[0] % 2,
        max_size // 2 - img_size[1] // 2:
        max_size // 2 + img_size[1] // 2 + img_size[1] % 2] = img0
    mask = cv.medianBlur(img[:, :, 0], 3) > 15
    minmax = np.argwhere(mask == 1)
    x_min, y_min = np.min(minmax, axis=0)
    x_max, y_max = np.max(minmax, axis=0)
    sz = [x_max-x_min, y_max-y_min]
#    Info: will be removed soon
#    print(x_min, x_max, y_min, y_max, sz)
    if sz[0] > sz[1]:
        x0 = x_min
        y0 = y_min-(sz[0]-y_max+y_min)//2
        _size = sz[0]
    else:
        x0 = x_min-(sz[1]-x_max+x_min)//2
        y0 = y_min
        _size = sz[1]
    if return_params:
        return {'x0': x0, 'y0': y0, 'size': _size}
    else:
        return img[x0:x0+_size, y0:y0+_size, :]


import os
import numpy as np
from typing import Tuple, Dict
from nuscenes.utils.data_classes import Box, PointCloud, RadarPointCloud
from nuscenes.utils.geometry_utils import view_points, transform_matrix
from functools import reduce

from pyquaternion import Quaternion

# Taken from mrnabati/CenterFusion

class RadarPointCloudWithVelocity(RadarPointCloud):
    """
    A RadarPointCloud class where Radar velocity values are correctly
    transformed to the target coordinate system
    """
    @classmethod
    def rotate_velocity(cls, pointcloud, transform_matrix):
        n_points = pointcloud.shape[1]
        third_dim = np.zeros(n_points)
        pc_velocity = np.vstack((pointcloud[[8, 9], :], third_dim, np.ones(n_points)))
        pc_velocity = transform_matrix.dot(pc_velocity)

        ## in camera coordinates, x is right, z is front
        pointcloud[[8, 9], :] = pc_velocity[[0, 2], :]

        return pointcloud

    @classmethod
    def from_file_multisweep(cls,
                             nusc: 'NuScenes',
                             sample_rec: Dict,
                             chan: str,
                             ref_chan: str,
                             nsweeps: int = 5,
                             min_distance: float = 1.0) -> Tuple['PointCloud', np.ndarray]:
        """
        Return a point cloud that aggregates multiple sweeps.
        As every sweep is in a different coordinate frame, we need to map the coordinates to a single reference frame.
        As every sweep has a different timestamp, we need to account for that in the transformations and timestamps.
        :param nusc: A NuScenes instance.
        :param sample_rec: The current sample.
        :param chan: The lidar/radar channel from which we track back n sweeps to aggregate the point cloud.
        :param ref_chan: The reference channel of the current sample_rec that the point clouds are mapped to.
        :param nsweeps: Number of sweeps to aggregate.
        :param min_distance: Distance below which points are discarded.
        :return: (all_pc, all_times). The aggregated point cloud and timestamps.
        """
        # Init.
        points = np.zeros((cls.nbr_dims(), 0))
        all_pc = cls(points)
        all_times = np.zeros((1, 0))

        # Get reference pose and timestamp.
        ref_sd_token = sample_rec['data'][ref_chan]
        ref_sd_rec = nusc.get('sample_data', ref_sd_token)
        ref_pose_rec = nusc.get('ego_pose', ref_sd_rec['ego_pose_token'])
        ref_cs_rec = nusc.get('calibrated_sensor', ref_sd_rec['calibrated_sensor_token'])
        ref_time = 1e-6 * ref_sd_rec['timestamp']

        # Homogeneous transform from ego car frame to reference frame.
        ref_from_car = transform_matrix(ref_cs_rec['translation'], Quaternion(ref_cs_rec['rotation']), inverse=True)
        ref_from_car_rot = transform_matrix([0.0, 0.0, 0.0], Quaternion(ref_cs_rec['rotation']), inverse=True)

        # Homogeneous transformation matrix from global to _current_ ego car frame.
        car_from_global = transform_matrix(ref_pose_rec['translation'], Quaternion(ref_pose_rec['rotation']),
                                           inverse=True)
        car_from_global_rot = transform_matrix([0.0, 0.0, 0.0], Quaternion(ref_pose_rec['rotation']),
                                               inverse=True)

        # Aggregate current and previous sweeps.
        sample_data_token = sample_rec['data'][chan]
        current_sd_rec = nusc.get('sample_data', sample_data_token)
        for _ in range(nsweeps):
            # Load up the pointcloud and remove points close to the sensor.
            current_pc = cls.from_file(os.path.join(nusc.dataroot, current_sd_rec['filename']))
            current_pc.remove_close(min_distance)

            # Get past pose.
            current_pose_rec = nusc.get('ego_pose', current_sd_rec['ego_pose_token'])
            global_from_car = transform_matrix(current_pose_rec['translation'],
                                               Quaternion(current_pose_rec['rotation']), inverse=False)
            global_from_car_rot = transform_matrix([0.0, 0.0, 0.0],
                                                   Quaternion(current_pose_rec['rotation']), inverse=False)

            # Homogeneous transformation matrix from sensor coordinate frame to ego car frame.
            current_cs_rec = nusc.get('calibrated_sensor', current_sd_rec['calibrated_sensor_token'])
            car_from_current = transform_matrix(current_cs_rec['translation'], Quaternion(current_cs_rec['rotation']),
                                                inverse=False)
            car_from_current_rot = transform_matrix([0.0, 0.0, 0.0], Quaternion(current_cs_rec['rotation']),
                                                    inverse=False)

            # Fuse four transformation matrices into one and perform transform.
            trans_matrix = reduce(np.dot, [ref_from_car, car_from_global, global_from_car, car_from_current])
            velocity_trans_matrix = reduce(np.dot, [ref_from_car_rot, car_from_global_rot, global_from_car_rot,
                                                    car_from_current_rot])
            current_pc.transform(trans_matrix)

            # Do the required rotations to the Radar velocity values
            current_pc.points = cls.rotate_velocity(current_pc.points, velocity_trans_matrix)

            # Add time vector which can be used as a temporal feature.
            time_lag = ref_time - 1e-6 * current_sd_rec['timestamp']  # Positive difference.
            times = time_lag * np.ones((1, current_pc.nbr_points()))
            all_times = np.hstack((all_times, times))

            # Merge with key pc.
            all_pc.points = np.hstack((all_pc.points, current_pc.points))

            # Abort if there are no previous sweeps.
            if current_sd_rec['prev'] == '':
                break
            else:
                current_sd_rec = nusc.get('sample_data', current_sd_rec['prev'])

        return all_pc, all_times

def points_in_box(box: Box, points, wlh_factor: float = 1.0):
    """
    Checks whether points are inside the box.

    Picks one corner as reference (p1) and computes the vector to a target point (v).
    Then for each of the 3 axes, project v onto the axis and compare the length.
    Inspired by: https://math.stackexchange.com/a/1552579
    :param box: <Box>.
    :param points: <np.float: 3, n>.
    :param wlh_factor: Inflates or deflates the box.
    :return: <np.bool: n, >.
    """
    corners = box.corners(wlh_factor=wlh_factor)

    p1 = corners[:, 0]
    p_x = corners[:, 4]
    p_y = corners[:, 1]

    i = p_x - p1
    j = p_y - p1

    v = points - p1.reshape((-1, 1))

    iv = np.dot(i, v)
    jv = np.dot(j, v)

    mask_x = np.logical_and(0 <= iv, iv <= np.dot(i, i))
    mask_y = np.logical_and(0 <= jv, jv <= np.dot(j, j))
    mask = np.logical_and(mask_x, mask_y)

    return mask


# -*- coding: utf-8 -*-
from django.contrib.sites.models import Site
from django.db import models
from django.db.models import Q
from django.utils import six

from cms.cache.permissions import get_permission_cache, set_permission_cache
from cms.exceptions import NoPermissionsException
from cms.models.query import PageQuerySet
from cms.publisher import PublisherManager
from cms.utils import get_cms_setting
from cms.utils.i18n import get_fallback_languages

class PageManager(PublisherManager):
    """Use draft() and public() methods for accessing the corresponding
    instances.
    """

    def get_queryset(self):
        """Change standard model queryset to our own.
        """
        return PageQuerySet(self.model)

    def drafts(self):
        return super(PageManager, self).drafts()

    def public(self):
        return super(PageManager, self).public()

    # !IMPORTANT: following methods always return access to draft instances,
    # take care on what you do one them. use Page.objects.public() for accessing
    # the published page versions

    # Just some of the queryset methods are implemented here, access queryset
    # for more getting more supporting methods.

    # TODO: check which from following methods are really required to be on
    # manager, maybe some of them can be just accessible over queryset...?

    def on_site(self, site=None):
        return self.get_queryset().on_site(site)

    def published(self, site=None):
        return self.get_queryset().published(site=site)

    def get_home(self, site=None):
        return self.get_queryset().get_home(site)

    def search(self, q, language=None, current_site_only=True):
        """Simple search function

        Plugins can define a 'search_fields' tuple similar to ModelAdmin classes
        """
        from cms.plugin_pool import plugin_pool

        qs = self.get_queryset()
        qs = qs.public()

        if current_site_only:
            site = Site.objects.get_current()
            qs = qs.filter(site=site)

        qt = Q(title_set__title__icontains=q)

        # find 'searchable' plugins and build query
        qp = Q()
        plugins = plugin_pool.get_all_plugins()
        for plugin in plugins:
            cmsplugin = plugin.model
            if not (
                hasattr(cmsplugin, 'search_fields') and
                hasattr(cmsplugin, 'cmsplugin_ptr')
            ):
                continue
            field = cmsplugin.cmsplugin_ptr.field
            related_query_name = field.related_query_name()
            if (
                related_query_name and
                related_query_name != '+'
            ):
                for field in cmsplugin.search_fields:
                    qp |= Q(**{
                        'placeholders__cmsplugin__{0}__{1}__icontains'.format(
                            related_query_name,
                            field,
                        ): q})
        if language:
            qt &= Q(title_set__language=language)
            qp &= Q(cmsplugin__language=language)

        qs = qs.filter(qt | qp)

        return qs.distinct()

class TitleManager(PublisherManager):
    def get_title(self, page, language, language_fallback=False):
        """
        Gets the latest content for a particular page and language. Falls back
        to another language if wanted.
        """
        try:
            title = self.get(language=language, page=page)
            return title
        except self.model.DoesNotExist:
            if language_fallback:
                try:
                    titles = self.filter(page=page)
                    fallbacks = get_fallback_languages(language)
                    for lang in fallbacks:
                        for title in titles:
                            if lang == title.language:
                                return title
                    return None
                except self.model.DoesNotExist:
                    pass
            else:
                raise
        return None

    # created new public method to meet test case requirement and to get a list of titles for published pages
    def public(self):
        return self.get_queryset().filter(publisher_is_draft=False, published=True)

    def drafts(self):
        return self.get_queryset().filter(publisher_is_draft=True)

    def set_or_create(self, request, page, form, language):
        """
        set or create a title for a particular page and language
        """
        base_fields = [
            'slug',
            'title',
            'meta_description',
            'page_title',
            'menu_title'
        ]
        advanced_fields = [
            'redirect',
        ]
        cleaned_data = form.cleaned_data
        try:
            obj = self.get(page=page, language=language)
        except self.model.DoesNotExist:
            data = {}
            for name in base_fields:
                if name in cleaned_data:
                    data[name] = cleaned_data[name]
            data['page'] = page
            data['language'] = language
            if page.has_advanced_settings_permission(request):
                overwrite_url = cleaned_data.get('overwrite_url', None)
                if overwrite_url:
                    data['has_url_overwrite'] = True
                    data['path'] = overwrite_url
                else:
                    data['has_url_overwrite'] = False
                for field in advanced_fields:
                    value = cleaned_data.get(field, None)
                    data[field] = value
            return self.create(**data)
        for name in base_fields:
            if name in form.base_fields:
                value = cleaned_data.get(name, None)
                setattr(obj, name, value)
        if page.has_advanced_settings_permission(request):
            if 'overwrite_url' in cleaned_data:
                overwrite_url = cleaned_data.get('overwrite_url', None)
                obj.has_url_overwrite = bool(overwrite_url)
                obj.path = overwrite_url
            for field in advanced_fields:
                if field in form.base_fields:
                    value = cleaned_data.get(field, None)
                    setattr(obj, field, value)
        obj.save()
        return obj

################################################################################
# Permissions
################################################################################

class BasicPagePermissionManager(models.Manager):
    """Global page permission manager accessible under objects.

    !IMPORTANT: take care, PagePermissionManager and GlobalPagePermissionManager
    both inherit from this manager
    """

    def with_user(self, user):
        """Get all objects for given user, also takes look if user is in some
        group.
        """
        return self.filter(Q(user=user) | Q(group__user=user))

    def with_can_change_permissions(self, user):
        """Set of objects on which user haves can_change_permissions. !But only
        the ones on which is this assigned directly. For getting reall
        permissions use page.permissions manager.
        """
        return self.with_user(user).filter(can_change_permissions=True)

class GlobalPagePermissionManager(BasicPagePermissionManager):

    def user_has_permission(self, user, site_id, perm):
        """
        Provide a single point of entry for deciding whether any given global
        permission exists.
        """
        # if the user has add rights to this site explicitly
        this_site = Q(**{perm: True, 'sites__in': [site_id]})
        # if the user can add to all sites
        all_sites = Q(**{perm: True, 'sites__isnull': True})
        return self.with_user(user).filter(this_site | all_sites)

    def user_has_add_permission(self, user, site_id):
        return self.user_has_permission(user, site_id, 'can_add')

    def user_has_change_permission(self, user, site_id):
        return self.user_has_permission(user, site_id, 'can_change')

    def user_has_view_permission(self, user, site_id):
        return self.user_has_permission(user, site_id, 'can_view')

class PagePermissionManager(BasicPagePermissionManager):
    """Page permission manager accessible under objects.
    """

    def subordinate_to_user(self, user):
        """Get all page permission objects on which user/group is lover in
        hierarchy then given user and given user can change permissions on them.

        !IMPORTANT, but exclude objects with given user, or any group containing
        this user - he can't be able to change his own permissions, because if
        he does, and removes some permissions from himself, he will not be able
        to add them anymore.

        Example:
                                       A
                                    /    \
                                  user    B,E
                                /     \
                              C,X     D,Y

            Gives permission nodes C,X,D,Y under user, so he can edit
            permissions if he haves can_change_permission.

        Example:
                                      A,Y
                                    /    \
                                  user    B,E,X
                                /     \
                              C,X     D,Y

            Gives permission nodes C,D under user, so he can edit, but not
            anymore to X,Y, because this users are on the same level or higher
            in page hierarchy. (but only if user have can_change_permission)

        Example:
                                        A
                                    /      \
                                  user     B,E
                                /     \      \
                              C,X     D,Y    user
                                            /    \
                                           I      J,A

            User permissions can be assigned to multiple page nodes, so merge of
            all of them is required. In this case user can see permissions for
            users C,X,D,Y,I,J but not A, because A user in higher in hierarchy.

        If permission object holds group, this permission object can be visible
        to user only if all of the group members are lover in hierarchy. If any
        of members is higher then given user, this entry must stay invisible.

        If user is superuser, or haves global can_change_permission permissions,
        show him everything.

        Result of this is used in admin for page permissions inline.
        """
        from cms.models import GlobalPagePermission, Page

        if user.is_superuser or \
                GlobalPagePermission.objects.with_can_change_permissions(user):
            # everything for those guys
            return self.all()

        # get user level
        from cms.utils.permissions import get_user_permission_level

        try:
            user_level = get_user_permission_level(user)
        except NoPermissionsException:
            return self.none()
            # get current site
        site = Site.objects.get_current()
        # get all permissions
        page_id_allow_list = Page.permissions.get_change_permissions_id_list(user, site)

        # get permission set, but without objects targeting user, or any group
        # in which he can be
        qs = self.filter(
            page__id__in=page_id_allow_list,
            page__level__gte=user_level,
        )
        qs = qs.exclude(user=user).exclude(group__user=user)
        return qs

    def for_page(self, page):
        """Returns queryset containing all instances somehow connected to given
        page. This includes permissions to page itself and permissions inherited
        from higher pages.

        NOTE: this returns just PagePermission instances, to get complete access
        list merge return of this function with Global permissions.
        """
        # permissions should be managed on the draft page only
        page = page.get_draft_object()
        from cms.models import (ACCESS_DESCENDANTS, ACCESS_CHILDREN,
            ACCESS_PAGE_AND_CHILDREN, ACCESS_PAGE_AND_DESCENDANTS, ACCESS_PAGE)

        if page.depth is None or page.path is None or page.numchild is None:
            raise ValueError("Cannot use unsaved page for permission lookup, missing MPTT attributes.")

        paths = [
            page.path[0:pos]
            for pos in range(0, len(page.path), page.steplen)[1:]
        ]
        parents = Q(page__path__in=paths) & (Q(grant_on=ACCESS_DESCENDANTS) | Q(grant_on=ACCESS_PAGE_AND_DESCENDANTS))
        direct_parents = Q(page__pk=page.parent_id) & (Q(grant_on=ACCESS_CHILDREN) | Q(grant_on=ACCESS_PAGE_AND_CHILDREN))
        page_qs = Q(page=page) & (Q(grant_on=ACCESS_PAGE_AND_DESCENDANTS) | Q(grant_on=ACCESS_PAGE_AND_CHILDREN) |
                                  Q(grant_on=ACCESS_PAGE))
        query = (parents | direct_parents | page_qs)
        return self.filter(query).order_by('page__depth')

class PagePermissionsPermissionManager(models.Manager):
    """Page permissions permission manager.

    !IMPORTANT: this actually points to Page model, not to PagePermission.
    Seems this will be better approach. Accessible under permissions.

    Maybe this even shouldn't be a manager - it mixes different models together.
    """
    # we will return this in case we have a superuser, or permissions are not
    # enabled/configured in settings
    GRANT_ALL = 'All'

    def get_publish_id_list(self, user, site):
        """
        Give a list of page where the user has publish rights or the string "All" if
        the user has all rights.
        """
        return self.__get_id_list(user, site, "can_publish")

    def get_change_id_list(self, user, site):
        """
        Give a list of page where the user has edit rights or the string "All" if
        the user has all rights.
        """
        return self.__get_id_list(user, site, "can_change")

    def get_add_id_list(self, user, site):
        """
        Give a list of page where the user has add page rights or the string
        "All" if the user has all rights.
        """
        return self.__get_id_list(user, site, "can_add")

    def get_delete_id_list(self, user, site):
        """
        Give a list of page where the user has delete rights or the string "All" if
        the user has all rights.
        """
        return self.__get_id_list(user, site, "can_delete")

    def get_advanced_settings_id_list(self, user, site):
        """
        Give a list of page where the user can change advanced settings or the
        string "All" if the user has all rights.
        """
        return self.__get_id_list(user, site, "can_change_advanced_settings")

    def get_change_permissions_id_list(self, user, site):
        """Give a list of page where the user can change permissions.
        """
        return self.__get_id_list(user, site, "can_change_permissions")

    def get_move_page_id_list(self, user, site):
        """Give a list of pages which user can move.
        """
        return self.__get_id_list(user, site, "can_move_page")

    def get_view_id_list(self, user, site):
        """Give a list of pages which user can view.
        """
        return self.__get_id_list(user, site, "can_view")

    def get_restricted_id_list(self, site):
        from cms.models import (GlobalPagePermission, PagePermission,
            MASK_CHILDREN, MASK_DESCENDANTS, MASK_PAGE)

        global_permissions = GlobalPagePermission.objects.all()
        if global_permissions.filter(Q(sites__in=[site]) | Q(sites__isnull=True)
                ).filter(can_view=True).exists():
            # user or his group are allowed to do `attr` action
            # !IMPORTANT: page permissions must not override global permissions
            from cms.models import Page

            return Page.objects.filter(site=site).values_list('id', flat=True)
            # for standard users without global permissions, get all pages for him or
        # his group/s
        qs = PagePermission.objects.filter(page__site=site, can_view=True).select_related('page')
        qs.order_by('page__path')
        # default is denny...
        page_id_allow_list = []
        for permission in qs:
            if permission.grant_on & MASK_PAGE:
                page_id_allow_list.append(permission.page_id)
            if permission.grant_on & MASK_CHILDREN:
                page_id_allow_list.extend(permission.page.get_children().values_list('id', flat=True))
            elif permission.grant_on & MASK_DESCENDANTS:
                page_id_allow_list.extend(permission.page.get_descendants().values_list('id', flat=True))
                # store value in cache
        return page_id_allow_list

    def __get_id_list(self, user, site, attr):
        if site and not isinstance(site, six.integer_types):
            site = site.pk
        from cms.models import (GlobalPagePermission, PagePermission,
            MASK_PAGE, MASK_CHILDREN, MASK_DESCENDANTS)

        if attr != "can_view":
            if not user.is_authenticated() or not user.is_staff:
                return []
        if user.is_superuser or not get_cms_setting('PERMISSION'):
            # got superuser, or permissions aren't enabled? just return grant
            # all mark
            return PagePermissionsPermissionManager.GRANT_ALL
            # read from cache if possible
        cached = get_permission_cache(user, attr)
        if cached is not None:
            return cached
            # check global permissions
        global_perm = GlobalPagePermission.objects.user_has_permission(user, site, attr).exists()
        if global_perm:
            # user or his group are allowed to do `attr` action
            # !IMPORTANT: page permissions must not override global permissions
            return PagePermissionsPermissionManager.GRANT_ALL
            # for standard users without global permissions, get all pages for him or
        # his group/s
        qs = PagePermission.objects.with_user(user)
        qs.filter(**{'page__site_id': site}).order_by('page__path').select_related('page')
        # default is denny...
        page_id_allow_list = []
        for permission in qs:
            if getattr(permission, attr):
                # can add is special - we are actually adding page under current page
                if permission.grant_on & MASK_PAGE or attr is "can_add":
                    page_id_allow_list.append(permission.page_id)
                if permission.grant_on & MASK_CHILDREN and not attr is "can_add":
                    page_id_allow_list.extend(permission.page.get_children().values_list('id', flat=True))
                elif permission.grant_on & MASK_DESCENDANTS:
                    page_id_allow_list.extend(permission.page.get_descendants().values_list('id', flat=True))
                    # store value in cache
        set_permission_cache(user, attr, page_id_allow_list)
        return page_id_allow_list

{'GlobalPagePermission': 'cms.models.GlobalPagePermission', 'PagePermission': 'cms.models.PagePermission', 'MASK_CHILDREN': 'cms.models.MASK_CHILDREN', 'MASK_DESCENDANTS': 'cms.models.MASK_DESCENDANTS', 'MASK_PAGE': 'cms.models.MASK_PAGE', 'Page': 'cms.models.Page'}.GRANT_ALL


import numpy as np
import torch
import torch.nn as nn

# mix up
def mixup_data(x, y, alpha=0.4, device='cuda'):
    '''
    Compute the mixup data. Return mixed inputs, pairs of targets, and lambda
    '''
    if alpha > 0.:
        lam = np.random.beta(alpha, alpha)
    else:
        lam = 1.

    batch_size = x.size()[0]
    index = torch.randperm(batch_size).to(device)

    mixed_x = lam * x + (1 - lam) * x[index,:]
    y_a, y_b = y, y[index]
    return mixed_x, y_a, y_b, lam

# cutmix
def cutmix_data(x, y, alpha=1., device='cuda'):
    """
    x: Batch of images. A 4-D torch.Tensor
    y: Batch of masks. A 3D torch.Tensor

    alpha == 1 => uniform distribution
    """
    indices = torch.randperm(x.size(0)).to(device)
    shuffled_x = x[indices]
    shuffled_y = y[indices]

    lam = np.random.beta(alpha, alpha)

    image_h, image_w = x.shape[2:]
    cx = np.random.uniform(0, image_w)
    cy = np.random.uniform(0, image_h)
    w = image_w * np.sqrt(1 - lam)
    h = image_h * np.sqrt(1 - lam)

    x0 = int(np.round(max(cx - w / 2, 0)))
    x1 = int(np.round(min(cx + w / 2, image_w)))
    y0 = int(np.round(max(cy - h / 2, 0)))
    y1 = int(np.round(min(cy + h / 2, image_h)))

    x[:, :, y0:y1, x0:x1] = shuffled_x[:, :, y0:y1, x0:x1]
    y[:, y0:y1, x0:x1] = shuffled_y[:, y0:y1, x0:x1]

    return x, y

def half_cutmix_data(x, y, p=0.5, device='cuda'):
    """
    x: Batch of images. A 4-D torch.Tensor
    y: Batch of masks. A 3D torch.Tensor
    """
    if np.random.uniform() < 0.5:
        return x, y

    indices = torch.randperm(x.size(0)).to(device)
    shuffled_x = x[indices]
    shuffled_y = y[indices]

    image_h, image_w = x.shape[2:]
    choice = np.random.choice(["H", "W"])
    if choice == "H":
        x[:, :, :int(image_h/2), :] = shuffled_x[:, :, :int(image_h/2), :]
        y[:, :int(image_h/2), :] = shuffled_y[:, :int(image_h/2), :]
    else:
        x[:, :, :, :int(image_w/2)] = shuffled_x[:, :, :, :int(image_w/2)]
        y[:, :, :int(image_w/2)] = shuffled_y[:, :, :int(image_w/2)]

    return x, y

def mixup_criterion(y_a, y_b, lam):
    return lambda criterion, pred: lam * criterion(pred, y_a) + (1 - lam) * criterion(pred, y_b)


import cv2
import numpy as np
import argparse
import os

def draw_mask(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        param['drawing'] = True
        param['current_contour'].append((x, y))
    elif event == cv2.EVENT_MOUSEMOVE:
        if param['drawing'] == True:
            cv2.circle(param['mask'], (x, y), 5, 255, -1)
            param['current_contour'].append((x, y))
    elif event == cv2.EVENT_LBUTTONUP:
        param['drawing'] = False
        cv2.circle(param['mask'], (x, y), 5, 255, -1)
        param['current_contour'].append((x, y))
        param['contours'].append(param['current_contour'])
        param['current_contour'] = []

def create_colored_mask(mask):
    blue_mask = np.zeros(mask.shape + (3,), dtype=np.uint8)
    blue_mask[mask == 255] = (255, 0, 0)  # Set the mask color to blue (BGR)
    return blue_mask

def add_glow_effect(mask, intensity=10, kernel_size=21):
    blur_mask = cv2.GaussianBlur(mask, (kernel_size, kernel_size), 0)
    glow_mask = cv2.addWeighted(mask, 1, blur_mask, intensity, 0)
    return glow_mask

def main(image_path, mask_path, overlay_path):
    image = cv2.imread(image_path)
    if image is None:
        print('Error: Image not found.')
        return

    height, width = image.shape[:2]
    fixed_height = 720
    fixed_width = int(width * (fixed_height / height))
    resized_image = cv2.resize(image, (fixed_width, fixed_height))

    mask = np.zeros(resized_image.shape[:2], dtype=np.uint8)

    cv2.namedWindow('Image with Mask')
    param = {
        'drawing': False,
        'current_contour': [],
        'contours': [],
        'mask': mask
    }
    cv2.setMouseCallback('Image with Mask', draw_mask, param)

    while True:
        display_image = cv2.addWeighted(resized_image, 0.7, cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR), 0.3, 0)
        cv2.imshow('Image with Mask', display_image)

        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            break

    filled_mask = np.zeros_like(mask)
    for contour in param['contours']:
        cv2.fillPoly(filled_mask, np.array([contour], dtype=np.int32), 255)

    original_size_mask = cv2.resize(filled_mask, (width, height))
    colored_mask = create_colored_mask(original_size_mask)
    glow_mask = add_glow_effect(colored_mask)

    overlay_image = cv2.addWeighted(image, 0.7, glow_mask, 0.3, 0)

    mask_dir = os.path.dirname(mask_path)
    if not os.path.exists(mask_dir):
        os.makedirs(mask_dir)

    overlay_dir = os.path.dirname(overlay_path)
    if not os.path.exists(overlay_dir):
        os.makedirs(overlay_dir)

    cv2.imwrite(mask_path, original_size_mask)
    print(f'Saved binary mask as a black and white image: {mask_path}')

    cv2.imwrite(overlay_path, overlay_image)
    print(f'Saved overlay image: {overlay_path}')

    cv2.destroyAllWindows()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Draw a mask on an image and save it.')
    parser.add_argument('image_path', help='Path to the input image.')
    parser.add_argument('mask_path', help='Path to save the binary mask.')
    parser.add_argument('overlay_path', help='Path to save the overlay image.')
    args = parser.parse_args()

    main(args.image_path, args.mask_path, args.overlay_path)