import os
from PIL import Image
import numpy as np
import sys
import pandas as pd
import pickle
import random
import matplotlib.pyplot as plt
import math
import requests
from io import BytesIO
from urllib.request import urlopen

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, MinMaxScaler, LabelEncoder

from keras.utils import to_categorical

import keras

class ezdata:
    def __init__(self,parameters=None,load=None):

        self.params      = None

        if parameters is None:
            if load is None:
                #print("[Fail] ezdata() : Please provide a parameter list to instantiate ezdata object !")
                #raise Exception("[Fail] ezdata() : Please provide a parameter list to instantiate ezdata object !")
                pass
                return
            else:
                self.load(load)
                return
        else:
            self.params = parameters

        if "name" not in self.params:
            self.params["name"] = "Noname"

        if "path" not in self.params:
            raise Exception("[Fail] ezdata(): Please provide a path !")
        else:
            #Images classification from directory
            if (os.path.isdir(self.params["path"])) and ("path_mask" not in self.params):
                self.import_classification_images(parameters)
                #self.type = "classification"
                return
            #Images segmentation from directory
            if (os.path.isdir(self.params["path"])) and (os.path.isdir(self.params["path_mask"])):
                self.import_segmentation_images(parameters)
                #self.type = "segmentation"
                return

            if (os.path.isfile(self.params["path"])):

                extension = os.path.splitext(self.params["path"])[1]
                if extension == ".csv":
                    #Table Classification or regression
                    self.import_table(parameters)
                    return
                if extension == ".npz":
                    self.from_npz(self.params)
                    return
                raise Exception('File extension/type not recognized ! Should be "csv" or "npz" !')
                return

            #Image classification from directory and csv index file
            if (os.path.isdir(self.params["path"])) and (os.path.isfile(self.params["path_index"])):
                self.import_classification_images_from_indexes()
                #self.type="classification"

        # if (self.params["type"].lower() == "classification") and (self.params["format"].lower()=="images"):
        #     self.import_classification_images(parameters)
        #     return
        #
        # if (self.params["type"].lower() == "classification") and (self.params["format"].lower()=="table"):
        #     self.import_classification_table(parameters)
        #     return

    def import_classification_images_from_index(self,parameters):
        print('TODO: import_classification_images_from_index()')
        return

    #SEGMENTATION IMAGES from DIRECTORY
    def import_segmentation_images(self,parameters):

        images =[]
        image_paths=[]
        masks =[]
        mask_paths=[]

        if not os.path.isdir(parameters["path"]):
            raise Exception("[Fail] ezdata.import_classification_images() : Path in parameters is not a directory !")

        if not os.path.isdir(parameters["path_mask"]):
            raise Exception("[Fail] ezdata.import_classification_images() : Path Mask in parameters is not a directory !")

        #Images
        print ('[X] Loading Images:', parameters["path"])
        i=0
        for filename in os.listdir(parameters["path"]):
            curimg = os.path.join(parameters["path"], filename)
            img = Image.open(curimg)
            images.append(img)
            image_paths.append(curimg)
            i=i+1
        tot=i
        print ('--- Total images :', str(tot))
        self.images = images
        self.image_paths = image_paths

        #Masks
        print ('[X] Loading Masks:', parameters["path_mask"])
        i=0
        for filename in os.listdir(parameters["path_mask"]):
            curimg = os.path.join(parameters["path_mask"], filename)
            img = Image.open(curimg)
            masks.append(img)
            mask_paths.append(curimg)
            i=i+1
        tot=i
        print ('--- Total images :', str(tot))
        self.masks = masks
        self.mask_paths = mask_paths

        print("\n")

        if "resize" in self.params:
          self.images_masks_to_keras(self.params["resize"])
        else:
          self.images_masks_to_keras()

    #CLASSIFICATION IMAGES from CSVTABLE annuaire

    #CLASSIFICATION - TABLES
    def import_table(self,parameters):

        table =[]
        table_path = []

        if not os.path.isfile(parameters["path"]):
            raise Exception("[Fail] ezdata.import_classification_table(): Path file in parameters doesn't exist !")

        print ('[X] Loading :', parameters["path"])

        #Delimiter
        if "table.delimiter" in parameters:
            table = pd.read_csv(parameters["path"],delimiter=parameters["table.delimiter"])
        else:
            found = False
            for delim in [",",";"," ","\t"]:
                table = pd.read_csv(parameters["path"],delimiter=delim)
                if table.columns.shape[0] != 1:
                    print("[Notice] Found a delimiter !")
                    found = True
                    break
            if not found:
                raise Exception("[Fail] ezdata.import_table() : No delimiter suitable for your table have been automatically found. Please provide one using 'table.delim' parameter.")

        if "table.target.column" in parameters:

            Y = table[parameters["table.target.column"]]
            table = table.drop(columns=parameters["table.target.column"])
        else:
            raise Exception("[Fail] ezdata.import_classification_table(): You didn't provide any Target columns into parameters. \n Please assign: 'table.target.column' into parameters list")

        if "table.drop.column" in parameters:
            table = table.drop(columns=parameters["table.drop.column"])

        X = table.values

        self.table      = table
        self.table_path = parameters["path"]
        self.X = X

        #Check the dtype of Y (to know whether it's number or string)
        print ("[X] Table conversion to Keras format: Done")
        print ("--- 'X' and 'y' tensors have been created into current ezdata object.")

        if "table.target.type" in parameters:
            if parameters["table.target.type"]=="string":
                encoder = LabelEncoder()
                Y = encoder.fit_transform(np.squeeze(Y))
                self.synsets = encoder.classes_
                print("--- 'synsets' have been create into current ezdata object.")
        else:
            if Y.dtype == "object":
                encoder = LabelEncoder()
                Y = encoder.fit_transform(np.squeeze(Y))
                self.synsets = encoder.classes_
                print("--- 'synsets' have been create into current ezdata object.")

        # if "table.target.type" in parameters:
        #     if parameters["table.target.type"]=="string":
        #         encoder = LabelEncoder()
        #         Y = encoder.fit_transform(np.squeeze(Y))
        #         self.synsets = encoder.classes_

        self.y = Y

        print("\n")

    # CLASSIFICATION - IMAGES
    def import_classification_images(self,parameters):
        images =[]
        labels =[]
        image_paths=[]
        synsets=[]

        if not os.path.isdir(parameters["path"]):
            raise Exception("[Fail] ezdata.import_classification_images() : Path in parameters is not a directory !")

        print ('[X] Loading :', parameters["path"])

        k=0
        tot=0
        for subdir in os.listdir(parameters["path"]):
            curdir = os.path.join(parameters["path"],subdir)
            i=0
            for filename in os.listdir(curdir):
                curimg = os.path.join(curdir, filename)
                img = Image.open(curimg)
                images.append(img)
                labels.append(k)
                image_paths.append(curimg)
                i=i+1
            synsets.append(subdir)
            k=k+1
            tot=tot+i
            print ('--- dir: ', subdir, '(',str(i),' images )')
        print ('--- Total images :', str(tot))
        self.images = images
        self.labels = labels
        self.image_paths = image_paths
        self.synsets = synsets
        print('--- Synsets have been generated')
        print("\n")

        if "resize" in self.params:
          self.images_to_keras(self.params["resize"])
        else:
          self.images_to_keras()

    def images_masks_to_keras(self,resize=None):

        #Images
        im=[]
        for image in self.images:
            r = image
            if resize is not None:
                r = image.resize((resize[0],resize[1]), Image.NEAREST)
            im.append(r)
        imgarray=list();
        for i in range(len(im)):
            tmp = np.array(im[i])
            imgarray.append(tmp)
        imgarray = np.asarray(imgarray)

        if len(imgarray.shape)==1:
            raise Exception("[Fail] images_to_keras() : Image size heterogeneity !  Size of images into the dataset are not the same. You should try to use 'resize' parameters to make them homogenous.")
        if len(imgarray.shape)==3:
            imgarray = np.expand_dims(imgarray,axis=3)
        self.X = imgarray.astype('float32')

        #Masks
        im=[]
        for image in self.masks:
            r = image
            if resize is not None:
                r = image.resize((resize[0],resize[1]), Image.NEAREST)
            im.append(r)
        imgarray=list();
        for i in range(len(im)):
            tmp = np.array(im[i])
            imgarray.append(tmp)
        imgarray = np.asarray(imgarray)

        if len(imgarray.shape)==1:
            raise Exception("[Fail] images_to_keras() : Masks size heterogeneity !  Size of Masks into the dataset are not the same. You should try to use 'resize' parameters to make them homogenous.")
        if len(imgarray.shape)==3:
            imgarray = np.expand_dims(imgarray,axis=3)
        self.y = imgarray.astype('float32')

        print ("[X] Images & Masks conversion to Keras format: Done")
        print ("--- 'X' and 'y' tensors have been created into current ezdata object.")
        print("\n")

    def images_to_keras(self,resize=None):

        im=[]
        for image in self.images:
            r = image
            if resize is not None:
                r = image.resize((resize[0],resize[1]), Image.NEAREST)
            im.append(r)
        imgarray=list();
        for i in range(len(im)):
            tmp = np.array(im[i])
            imgarray.append(tmp)
        imgarray = np.asarray(imgarray)

        if len(imgarray.shape)==1:
            raise Exception("[Fail] images_to_keras() : Image size heterogeneity !  Size of images into the dataset are not the same. You should try to use 'resize' parameters to make them homogenous.")

        if len(imgarray.shape)==3:
            imgarray = np.expand_dims(imgarray,axis=3)

        self.X = imgarray.astype('float32')
        self.y = np.asarray(self.labels)

        print ("[X] Images conversion to Keras format: Done")
        print ("--- 'X' and 'y' tensors have been created into current ezdata object.")
        print("\n")

    def gen_test(self,size=0.2,random_state=42):

        X_train,X_test,y_train,y_test = train_test_split(self.X,self.y,test_size=size,random_state=42)

        self.X = X_train
        self.y = y_train
        self.X_test = X_test
        self.y_test = y_test

        print ("[X] Test set generation (size = ,",str(size),",): Done")
        print ("--- Test set : ", self.X_test.shape[0], "images")
        print ("--- 'X_test' and 'y_test' tensors have been created into current ezdata object.")
        print("\n")

    #def preprocess(data,type=None,scaler=None):
    def preprocess(self,X=None,y=None):

        if X.lower() not in ["minmax","standard","mobilenet","vgg16","vgg19"]:
            raise Exception('[Fail] preprocess() : Only "minmax","standard","mobilenet","vgg16","vgg19" are accepted as preprocessing for X')

        if y is None:
            y="none"

        if y.lower() not in ["minmax","standard","categorical","none"]:
            raise Exception('[Fail] preprocess() : Only "minmax","standard","categorical" or "None" are accepted as preprocessing for Y')

        #X
        if X.lower() == "minmax":
            self.X = self.X.astype("float32")
            self.X,self.scalerX = self.minmax_scaling(self.X)

        if X.lower() == "standard":
            self.X = self.X.astype("float32")
            self.X,self.scalerX = self.standard_scaling(self.X)

        if X.lower() == "mobilenet":
            self.X = self.X.astype("float32")
            self.X = keras.applications.mobilenet.preprocess_input(self.X)
            self.scalerX = "mobilenet"

        if X.lower() == "vgg16":
            self.X = self.X.astype("float32")
            self.X = keras.applications.vgg16.preprocess_input(self.X)
            self.scalerX = "vgg16"

        if X.lower() == "vgg19":
            self.X = self.X.astype("float32")
            self.X = keras.applications.vgg19.preprocess_input(self.X)
            self.scalerX = "vgg19"

        if hasattr(self,"X_test"):
            self.X_test = self.X_test.astype("float32")
            if self.scalerX == "mobilenet":
                self.X_test = keras.applications.mobilenet.preprocess_input(self.X_test)
            elif self.scalerX == "vgg16":
                self.X_test = keras.applications.vgg16.preprocess_input(self.X_test)
            elif self.scalerX == "vgg19":
                self.X_test = keras.applications.vgg19.preprocess_input(self.X_test)

            else:
                self.X_test,_= self.scaler_scaling(self.X_test,self.scalerX)

        #Y
        if y.lower() == "minmax":
            self.y = self.y.astype("float32")
            self.y,self.scalerY = self.minmax_scaling(self.y)
            if hasattr(self,"y_test"):
                self.y_test = self.y_test.astype("float32")
                self.y_test,_= self.scaler_scaling(self.y_test,self.scalerY)

        if y.lower() == "standard":
            self.y = self.y.astype("float32")
            self.y,self.scalerY = self.standard_scaling(self.y)
            if hasattr(self,"y_test"):
                self.y_test = self.y_test.astype("float32")
                self.y_test,_= self.scaler_scaling(self.y_test,self.scalerY)

        if y.lower() == "categorical":
            self.y,self.scalerY = self.categorical_transform(self.y)
            if hasattr(self,"y_test"):
                self.y_test,_       = self.categorical_transform(self.y_test)

        if y.lower() == "none":
            self.scalerY = "none"

        print ("[X] Preprocessing using '",X,"' for X, and '",y,"' for Y.")
        print("\n")

    def minmax_scaling(self,data):
        scalers=[]

        if len(data.shape)==4:
            for i in range(data.shape[3]):
                scaler = MinMaxScaler()
                shape_before = data[:,:,:,i].shape
                a = data[:,:,:,i].reshape(-1,1)
                scalers.append(scaler.fit(a))
                b = scalers[i].transform(a)
                data[:,:,:,i] = b.reshape(shape_before)
                return data,scalers

        if len(data.shape)==2:
            scaler = MinMaxScaler()
            a = data
            scalers.append(scaler.fit(a))
            b = scaler.transform(a)
            data=b
            return data,[scaler]

    def standard_scaling(self,data):

        scalers=[]

        if len(data.shape)==4:
            for i in range(data.shape[3]):
                scaler = StandardScaler()
                shape_before = data[:,:,:,i].shape
                a = data[:,:,:,i].reshape(-1,1)
                scalers.append(scaler.fit(a))
                b = scalers[i].transform(a)
                data[:,:,:,i] = b.reshape(shape_before)
            return data,scalers

        if len(data.shape)==2:
            scaler = StandardScaler()
            a = data
            scalers.append(scaler.fit(a))
            b = scaler.transform(a)
            data=b
            return data,[scaler]

    def categorical_transform(self,data):
        #print ("[X] Preprocessing : Categorical")
        #print("\n")
        return to_categorical(data),"categorical"

    def scaler_scaling(self,data,scaler):

        self.X = self.X.astype("float32")

        for i in range(len(scaler)):
            if len(data.shape)==4:
                shape_before = data[:,:,:,i].shape
                a = data[:,:,:,i].reshape(-1,1)
                b = scaler[i].transform(a)
                data[:,:,:,i] = b.reshape(shape_before)
            if len(data.shape)==2:
                a = data
                b = scaler[i].transform(a)
                data = b
        return data,scaler

    def save(self,filename):
        filehandler = open(filename.strip()+".pkl","wb")
        pickle.dump(self,filehandler)
        filehandler.close()
        print("--- EZ data has been saved in     :",filename,".pkl")
        print("\n")

    def load(self,filename):
        filehandler = open(filename+".pkl", 'rb')
        tmp = pickle.load(filehandler)
        filehandler.close()
        self.__dict__.update(tmp.__dict__)

    def is_kernel(self):
        if 'IPython' not in sys.modules:
            # IPython hasn't been imported, definitely not
            return False
        from IPython import get_ipython
        # check for `kernel` attribute on the IPython instance
        return getattr(get_ipython(), 'kernel', None) is not None

    def show_images(self,n=16):
        #if not isinstance(int(math.sqrt(n)),int):
        #    raise Exception("[Fail] ezdata.show_images(): Please provide n as power of 2 ! (2, 4, 8, 16 ...)")

        if not math.sqrt(n).is_integer():
            raise Exception("[Fail] ezdata.show_images(): Please provide n as a perfect quare ! (2, 4, 9, 16, 25, 36, 49, 64 ...)")
        population = list(range(self.X.shape[0]))
        r = random.sample(population,n)
        fig,axes = plt.subplots(nrows = int(math.sqrt(n)),ncols = int(math.sqrt(n)))
        fig.tight_layout()
        for i in range(n):
            plt.subplot(math.sqrt(n),math.sqrt(n),i+1)

            if (self.X[r[i]].shape[2])==1:
                plt.imshow(np.squeeze(self.X[r[i]]),cmap="gray")
            else:
                plt.imshow(self.X[r[i]])
            #plt.title(self.y[r[i]])
            if hasattr(self,"scalerY"):
                if self.scalerY == "categorical":
                    plt.title(self.synsets[np.argmax(self.y[r[i]])])
                if self.scalerY == "none":
                    plt.title(self.y[r[i]])

            plt.axis("off")

        plt.show()

    def show_table(self,filename=None,head=None):
        from IPython.display import display
        if hasattr(self,"table"):
            if head==None:
                if not self.is_kernel():
                    print(self.table)
                else:
                    display(self.table)
            else:
                if not self.is_kernel():
                    print(self.table.head(head))
                else:
                    display(self.table.head(head))
        else:
            if filename is None:
                raise Exception('[Fail] ezdata.show_table() : Please provide a filename !')
            else:
                #d = pd.read_csv(filename)
                found = False
                for delim in [",",";"," ","\t"]:
                    d = pd.read_csv(filename,delimiter=delim)
                    if d.columns.shape[0] != 1:
                        #print("[Notice] Found a delimiter !")
                        found = True
                        break

                if head==None:
                    if not self.is_kernel():
                        print(d)
                    else:
                        display(d)
                else:
                    if not self.is_kernel():
                        print(d.head(head))
                    else:
                        display(d.head(head))

    def to_npz(self,filename):
        if hasattr(self,"synsets"):
            np.savez(filename+".npz",X=self.X,y=self.y,synsets=self.synsets)
        else:
            np.savez(filename+".npz",X=self.X,y=self.y)

    def from_npz(self,parameters):
        data = np.load(parameters["path"])
        if "X.key" in parameters:
            self.X = data[parameters["X.key"]]
        else:
            self.X = data["X"]

        if "y.key" in parameters:
            self.y = data[parameters["y.key"]]
        else:
            self.y = data["y"]
        if "synsets.key" in parameters:
            self.synsets = data[parameters["synsets.key"]]
        else:
            if "synsets" in data:
                self.synsets = data["synsets"]

        if "name" in parameters:
            self.name = parameters["name"]
        else:
            self.name = "NoName"
        print("[X] Loading from : " + parameters["path"])
        print("\n")

    #Download one image from url
    def image_from_url(self,url,img_size=(128,128)):

        #Get image from url
        response = requests.get(url)
        img = Image.open(BytesIO(response.content))

        #Resize the image
        resize = img.resize(img_size, Image.NEAREST)
        resize = np.asarray(resize)
        resize = resize.astype('float32')
        resize = np.expand_dims(resize,axis=0)
        return resize

    def make(self,test=None):

        if hasattr(self,"synsets"):
            if test is not None:
                self.gen_test(test)
                np.savez(self.params["name"]+"_test.npz",X=self.X_test,y=self.y_test,synsets=self.synsets)
                print("[X] Test set has been save into: " + self.params["name"]+"_test.npz")
            np.savez(self.params["name"]+"_train.npz",X=self.X,y=self.y,synsets=self.synsets)
            print("[X] Training set has been save into: " + self.params["name"]+"_train.npz")
        else:
            if test is not None:
                self.gen_test(test)
                np.savez(self.params["name"]+"_test.npz",X=self.X_test,y=self.y_test,synsets=self.synsets)
                print("[X] Test set has been save into: " + self.params["name"]+"_test.npz")
            np.savez(self.params["name"]+"_train.npz",X=self.X,y=self.y)
            print("[X] Training set has been save into: " + self.params["name"]+"_train.npz")

        print("\n")


import setuptools
from setuptools import find_packages

__description__ = "The scrapper gets monthly crude volume data for UStrade."
__repo_name__ = "ea_csb_etl"

requirements = [
    'selenium',
    'pandas',
    'sqlalchemy',
    'psycopg2-binary',
    'sqlalchemy',
    'python-dotenv',
]
setuptools.setup(
    name=__repo_name__,
    version='1.0.0',
    description=__description__,
    url=f'https://github.com/energyaspects/{__repo_name__}.git',
    author='ByteIQ Data Engineering Team',
    author_email='',
    package_dir={"": "src"},
    packages=find_packages(where="src"),
    python_requires='>=3.6',
    classifiers=[
        "Development Status :: 2 - Pre-Alpha",
        "Natural Language :: English",
        "Programming Language :: Python :: 3.6",
    ],
    install_requires=requirements,
    package_data={"": ["*"]},
    entry_points={
        'console_scripts': [
            "cpi_etl = macro.cpi_main.main:main",
            "gdp_etl = macro.gdp_main.main:main",
            "pcpi_etl = macro.pcpi_main.main:main",
            "retail_sales_etl = macro.retail_sales_main.main:main",
        ],
    },
)


from Process import *
from Resource import ResourceError
from scheduler import scheduler

class Shell:
    def __init__(self, input_path: str = None, output_path: str = None):
        self.__run(input_path, output_path)

    def _validate_command(self, command: list):
        command_argc = {"init": 1,
                        "cr": 3,
                        "de": 2,
                        "req": 3,
                        "rel": 3,
                        "to": 1,
                        "ps": 1,
                        "rls": 1}

        argc = len(command)
        if argc < 1:
            raise CommandError("ERROR: no command given")

        if len(command) == 1 and command[0] == "quit":
            raise QuitError

        if command[0] not in command_argc:
            raise ShellError("ERROR: command not found")

        if argc != command_argc[command[0]]:
            raise ShellError("ERROR: invalid command arguments")

    def _execute_command(self, command: list):
        commands = {"init": "Shell.init",
                    "cr": "Shell.create_process",
                    "de": "Shell.destroy_process",
                    "req": "Shell.request_resource",
                    "rel": "Shell.release_resource",
                    "to": "Shell.timeout",
                    "ps": "Shell.process_status",
                    "rls": "Shell.ready_list_status"}

        cmd = commands[command[0]]
        param_string = ""
        if (len(command[1:])):
            param_string = ", '" + "', '".join(command[1:]) + "'"

        exec(cmd + "(self" + param_string + ")")

        if(command[0] in ["init", "cr", "de", "req", "rel", "to"]):
            scheduler()

    def init(self):
        for child in self.init.tree.children:
            child.kill()

        PCB.CurrentProcess = self.init

    def create_process(self, PID: str, priority: str):
        priority = int(priority)

        if priority not in [0,1,2]:
            raise ProcessError("Priority must be 0, 1, or 2")

        PCB.CurrentProcess.child_process(PID, priority)

    def destroy_process(self, PID: str):
        if PID not in ProcessTable.table:
            raise ProcessError("ERROR: Process " + PID + " does not exist")

        process = ProcessTable.table[PID]

        if process.priority == 0:
            raise ProcessError("ERROR: Cannot delete the init process")

        if not PCB.CurrentProcess.has_child(process):
            raise ProcessError("ERROR: Process " + PID + " is not the current process nor a descendant of it")

        ProcessTable.table[PID].kill()

    def request_resource(self, RID: str, units: str):
        units = int(units)
        PCB.CurrentProcess.request(RID, units)

    def release_resource(self, RID: str, units: str):
        units = int(units)
        PCB.CurrentProcess.release(RID, units)

    def timeout(self):
        PCB.CurrentProcess.timeout()

    def process_status(self):
        print(ProcessTable())

    def ready_list_status(self):
        print(PCB.ReadyList)

    def __process_command(self, command):
        try:
            self._validate_command(command)
            self._execute_command(command)
            return PCB.CurrentProcess.PID
        except QuitError:
            return
        except CommandError:
            return "\n"
        except (ShellError, ResourceError, ProcessError) as e:
            print("*", e)
            return "error"

    def __run(self, input_path, output_path):

        self.init = PCB("init", 0)
        scheduler()

        if input_path is None:
            while (True):
                print("> ", end="")
                command_line = input()
                command = command_line.split()
                self.__process_command(command)
        else:
            output_list = []
            with open(input_path, mode="r") as in_file:
                line = ["init"]
                for command_line in in_file:
                    if command_line.strip() == '':
                        to_append = " ".join(line)
                        if to_append.strip() != '':
                            output_list.append(to_append)
                        line = []
                    else:
                        result = self.__process_command(command_line.split())
                        line.append(result)

                if len(line):
                    output_list.append(" ".join(line))

            output_str = "\n".join(output_list)
            if output_path is not None:
                with open(output_path, mode="w") as out_file:
                    out_file.write(output_str)
            else:
                print(output_str)

class ShellError(Exception):
    pass

class CommandError(Exception):
    pass

class QuitError(Exception):
    pass


N = int(input())
A = list(map(int,input().split()))
A_rev = list(reversed(A))
pivots = 0
max_arr, min_arr = [A[0]],[A[-1]]
# build max and min arrays
for i in range(1,N):
   max_arr.append(max(max_arr[i-1],A[i]))
   min_arr.append(min(min_arr[i-1],A_rev[i]))

min_arr = list(reversed(min_arr))
# find pivots
for i in range(N):
   if max_arr[i] <= A[i] and A[i] <= min_arr[i]:
      pivots += 1
print(pivots)


import json
import requests
import js2py

compare=js2py.require('compare-versions')

def package_json_comparev1v2(latest, current):
    return compare.satisfies(latest, current)

def package_json_parse(f):
    data=json.load(f)
    return data['dependencies']

def package_json_fetch_latest(name):
    url="https://registry.npmjs.org/{}".format(name)
    r=requests.get(url)
    response=r.text
    data=json.loads(response)
    return data["dist-tags"]['latest']

def package_json_check(modules):
    outdated=[]
    for name, version in modules.items():
        latest=package_json_fetch_latest(name)
        if package_json_comparev1v2(latest,version)==False:
            outdated.append((name,version,latest))
    return outdated

# with open('package.json','r') as f:
#     modules=package_json_parse(f)
#     outdated=package_json_check(modules)
#     print(outdated)


import array as arr
import random

array1 = arr.array('i', [])
array2 = arr.array('i', [])
for i in range(5):
    if i < 3:
        array1_number = int(input('Enter number to store in array : '))
        array1.append(array1_number)
    array2_number = random.randint(0, 100)
    array2.append(array2_number)
array1.extend(array2)
print(sorted(array1))


import requests
from bs4 import BeautifulSoup
import csv
import os

homeUrl = "http://books.toscrape.com/"

def allUrls(homeUrl):# retourne toutes les catégories
    page = requests.get(homeUrl)
    soup = BeautifulSoup(page.content, 'lxml')
    urls = []
    for a in soup.find('ul',{'class':'nav nav-list'}).li.find_all('a'):
        url = a.get('href').replace('catalogue/','http://books.toscrape.com/catalogue/')
        urls.append(url)
    categs = urls[1:]
    return categs
categs = allUrls(homeUrl)

def oneCateg(categs):# retourne une catégorie
    booksCategorie = ''
    for cat in categs:
        booksCategorie = cat
        return booksCategorie

booksCategorie = oneCateg(categs)

def catBooks(booksCategorie):# complete une liste (livresUrl) avec toutes les url d'une catégorie
    page = requests.get(booksCategorie)
    soup = BeautifulSoup(page.content,'lxml')

    # vérifit si une pagination est existante
    if soup.find('ul', class_ = 'pager'):
        nombreDePage = int(soup.find('li', class_='current').text[40])
    else:
        nombreDePage = 1

    # boucle sur chaque livre pour compléter son url en fonction de la pagination
    iterPages = 0
    livresUrl = []

    while iterPages < nombreDePage:
        for livre in soup.find_all('article'):
            livreUrl = livre.h3.a.get('href').replace('../../../', 'http://books.toscrape.com/catalogue/')
            livresUrl.append(livreUrl)
        iterPages += 1
        if iterPages >= 1 and nombreDePage > 1:
            nextPage = booksCategorie.replace('index.html','page-' + str(iterPages + 1) + '.html')
            page = requests.get(nextPage)
            soup = BeautifulSoup(page.content,'lxml')
    return livresUrl

livresUrl = catBooks(booksCategorie)

def oneBook(livresUrl):# retourne un livre de la liste des url d'une catgorie
    unLivre = ''
    for book in livresUrl:
        unLivre = book
        return unLivre

unLivre = oneBook(livresUrl)

def genData(unLivre,booksCategorie):# complete une liste avec toute les data du livre et sa categorie
    datas = []
    def prodUrl(unLivre):# retourne l'url du livre
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        prods = unLivre
        return prods

    prods = prodUrl(unLivre)
    datas.append(prods)

    def upc(unLivre):# retourne le code du livre
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        for upc in soup.find_all('tr'):
            if 'UPC' in upc.text:
                upcs = upc.td.text
        return upcs

    upcs = upc(unLivre)
    datas.append(upcs)

    def title(unLivre):# retourne le titre du livre
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        for title in soup.find_all('h1'):
            titre = title.text
        return titre

    titre = title(unLivre)
    datas.append(titre)

    def ttc(unLivre):# retourne le prix ttc du livre
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        for ttc in soup.find_all('tr'):
            if 'excl' in ttc.text:
                ttcs = ttc.td.text
        return ttcs

    ttcs = ttc(unLivre)
    datas.append(ttcs)

    def ht(unLivre):# retourne le prix ht du livre
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        for ht in soup.find_all('tr'):
            if 'excl' in ht.text:
                hts = ht.td.text
        return hts

    hts = ht(unLivre)
    datas.append(hts)

    def dispo(unLivre):# retourne le nombre de livres disponibles
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        for dispo in soup.find_all('tr'):
            if 'Availability' in dispo.text:
                dispos = dispo.td.text.split(' ')[2].replace('(','')
        return dispos

    dispos = dispo(unLivre)
    datas.append(dispos)

    def descript(unLivre):# retourne un résumé du livre
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        desc = soup.find_all('p',)[3]
        descripts = desc.text
        return descripts

    descripts = descript(unLivre)
    datas.append(descripts)

    def categorie(booksCategorie):# retourne la catégorie du livre
        page = requests.get(booksCategorie)
        soup = BeautifulSoup(page.content,'lxml')
        for cat in soup.ul.find_all('li'):
            if 'Home' not in cat.text and 'Books' not in cat.text:
                categorie = cat.text
        return categorie

    categorie = categorie(booksCategorie)
    datas.append(categorie)

    def eval(unLivre):# retourne l'appréciation du livre
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        for star in soup.find_all('p',limit = 4):
            try:
                note = star['class']
                if 'star-rating' in note:
                    note = note[1]

            except KeyError:
                pass
        return note

    note = eval(unLivre)
    datas.append(note)

    def img(unLivre):# retourne l'url de l'image du livre
        page = requests.get(unLivre)
        soup = BeautifulSoup(page.content,'lxml')
        img = soup.find('img')
        image = img['src'].replace('../..','http://books.toscrape.com')
        return image

    image = img(unLivre)
    datas.append(image)

    def path(categorie):# crée l'arborescence des dossiers et retourne le chemin relatif
        cat = categorie
        cat = ''.join([x for x in cat if x.isalnum()])
        path = 'data/' + cat + '/images/'
        # créer les repertoires du path
        if not os.path.exists(path):
            os.makedirs(path)
        return path

    path = path(categorie)
    datas.append(path)

    def imgLivre(image, path, titre):# définit les paramètres de création du fichier image du livre et crée le fichier
        imageGet = requests.get(image)
        soup = BeautifulSoup(imageGet.content,'lxml')
        titre = ''.join([x for x in titre if x.isalnum()]) + '.jpg'
        open(path + titre, 'wb').write(imageGet.content)
        return imageGet

    imageGet = imgLivre(image, path, titre)
    datas.append(imageGet)

    return datas

datas = genData(unLivre, booksCategorie)

def main():# appele les fonctions sus-jacente  en leur passant les parametres nécessaires en arguments et crée les fichiers csv
    categs = allUrls(homeUrl)
    for cat in categs:
        booksCategorie = catBooks(cat)
        page = requests.get(cat)
        soup = BeautifulSoup(page.content,'lxml')
        for oneCat in soup.ul.find_all('li'):
            if 'Home' not in oneCat.text and 'Books' not in oneCat.text:
                categorie = oneCat.text

        # création du fichier csv pour chaque catégorie en complètant uniquement l'entête
        en_tete = ['product_page_url' , 'universal_product_code' , 'title' , 'price_including_tax' , 'price_excluding_tax' , 'number_available' ,'product_description' , 'category' , 'review_rating' , 'image_url']
        categorie = ''.join([x for x in categorie if x.isalnum()])
        csvFile = categorie + '.csv'
        path = 'data/' + categorie + '/'
        if not os.path.exists(path):
            os.makedirs(path)
        with open(path + csvFile, 'w', errors = 'replace') as csvFile:
            scribe = csv.writer(csvFile , delimiter = ";")
            scribe.writerow(en_tete)

        for book in booksCategorie:# récupère les data de chaque livre et complète le fichier csv de chaque catégorie
                livres = oneBook(booksCategorie)
                datas = genData(book, cat)
                page = requests.get(cat)
                soup = BeautifulSoup(page.content,'lxml')
                for oneCat in soup.ul.find_all('li'):
                    if 'Home' not in oneCat.text and 'Books' not in oneCat.text:
                        categorie = oneCat.text
                categorie = ''.join([x for x in categorie if x.isalnum()])
                csvFile = categorie + '.csv'
                path = 'data/' + categorie + '/'
                with open(path + csvFile, 'a', errors = 'replace') as csvFile:
                    scribe = csv.writer(csvFile , delimiter = ";")
                    scribe.writerow(datas[0:-2])

main()

print("Traitement termine avec succes ! ...")


"""
This script is used to create the game dynamic
for the Black Jack Game.

Author: Nicolae Istrate
"""

import classes

# Create elements in the game

my_deck = classes.Deck()
my_deck.shuffle()

stay = False
dealer_won = False

player_cards = []
dealer_cards = []

player = classes.Player("Jack")
dealer = classes.Player("Dealer")

player_cards.append(my_deck.deal_one())
dealer_cards.append(my_deck.deal_one())
player_cards.append(my_deck.deal_one())
dealer_special_card = my_deck.deal_one()

player_hand_value = classes.hand_value(player_cards)
dealer_hand_value = classes.hand_value(dealer_cards)

print(f'{player.name}`s hand value is {player_hand_value}')
print(f'{dealer.name}`s hand value is {dealer_hand_value}')

# Player's turn

while not stay:
    if player_hand_value > 21:
        print(f'{player.name} has lost the GAME')
        stay = True
        dealer_won = True
        break

    turn_value = input("Type 'Hit' for new card or 'Stay' to end your turn:")

    if turn_value == 'Stay':
        print('Your turn has ended\n\t'f'{player.name}`s hand value is {player_hand_value}')
        print(f'\t{dealer.name}`s hand value is {dealer_hand_value}')
        stay = True
        break
    if turn_value == 'Hit':
        player_cards.append(my_deck.deal_one())
        player_hand_value = classes.hand_value(player_cards)
        print(f'\t{player.name}`s hand value is {player_hand_value}')

# Dealer's turn
if dealer_won == False:
    print('Dealer`s Turn')
    dealer_threshold = 21 - 7 # can add a probability function that calculates the likelihood of getting a good card

    while dealer_hand_value < dealer_threshold:
        dealer_cards.append(my_deck.deal_one())
        dealer_hand_value = classes.hand_value(dealer_cards)
        print(f'Dealer adds card: hand value = {dealer_hand_value}')

    # End Game dynamics
    dealer_cards.append(dealer_special_card)
    dealer_hand_value = classes.hand_value(dealer_cards)
    print('Dealer Cards:')
    for card in dealer_cards:
        print(f'   {card}')

    print(f'Dealer hand value = {dealer_hand_value}')
    player_diff = 21 - player_hand_value

    dealer_diff = 21 - dealer_hand_value
    if dealer_hand_value > 21:
        print(f'{player.name} has WON the GAME')
    elif dealer_diff > player_diff:
        print(f'{player.name} has WON the GAME')
    elif dealer_diff < player_diff:
        print(f'{dealer.name} has Won the GAME')
    else:
        print('The GAME is TIED')


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('elcid', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='travel',
            name='did_not_travel',
            field=models.NullBooleanField(default=False),
        ),
    ]


"""
Description: Manages the invoices
             Support CRUD Operation of invoices
             Xero API
"""

import json
from connection import Connection
from util import send_get_request, parse_xml, send_put_request, send_post_request
from config import INVOICE_API_URL, INVOICE_CREATE

class Invoices:
    """
    Creates a data pipeline for the Xero Invoices
    """

    def __init__(self):
        # This is a connection object which is ready to consume the API
        self.conn = Connection()

    def get(self):
        """
        Retrieves invoices
        :return: List of invoices
        """
        # Refresh token
        self.conn.get_or_refresh_token()
        headers = {'authorization': "Bearer %s" % self.conn.token,
                   'Content-Type': 'application/json',
                   'Xero-tenant-id': self.conn.tenant_id}
        res = send_get_request(url=INVOICE_API_URL, headers=headers)
        # Parses the XML to Python Dictionary
        invoices = parse_xml(res.text)
        invoices = invoices['Response']['Invoices']['Invoice']

        return invoices

    def post(self):
        """
        Updates invoices
        :return:
        """
        pass

    def put(self):
        """
        Creates Invoices
        :return:
        """
        # Refresh token
        self.conn.get_or_refresh_token()
        headers = {'authorization': "Bearer %s" % self.conn.token,
                   'Content-Type': 'application/json',
                   'Xero-tenant-id': self.conn.tenant_id}

        res = send_put_request(url=INVOICE_API_URL, headers=headers, data=json.dumps(INVOICE_CREATE))
        # print(res.text)
        invoices = parse_xml(res.text)
        invoices = invoices['Response']['Invoices']['Invoice']
        return invoices

# inv = Invoices()
# invoices_list = inv.get()

# print("Fetching Invoices...")
# print(f"Invoice Count: {len(invoices_list)}")
# print(invoices_list)

# print("Creating Invoices")
# invoices_list = inv.put()
# print(invoices_list)

# invoices_list = inv.get()
# print(f"Invoice Count: {len(invoices_list)}")

from config import *

def get_or_refresh_token():
    """
    Gets or Refresh token
    :return: token
    """
    # headers = {'authorization': "Basic %s" % b64_client_id_secret,
    #            'Content-Type': 'application/x-www-form-urlencoded'}
    data = {}

    data['grant_type'] = "client_credentials"
    data['client_id'] = CLIENT_ID
    data['client_secret'] = CLIENT_SECRET

    res = send_post_request(url=TOKEN_URI, headers=None, data=json.dumps(data))
    json_result = json.loads(res.text)
    print(json_result)
get_or_refresh_token()


import pytest

from configs import MAIN_BRANCH
from services.github_service import GitHubRestApi
from utils.faker import random_str

def test_create_pull_request(user_data, repository, branch_for_repo_with_commit):
    branch, _ = branch_for_repo_with_commit
    gh_service = GitHubRestApi()

    pr_title = random_str()
    res = gh_service.create_pull_request(user_data["login"], repository["name"], branch["ref"], MAIN_BRANCH, pr_title)

    assert res.status_code == 201
    res = res.json()

    assert res["title"] == pr_title
    assert res["base"]["ref"] == MAIN_BRANCH
    assert res["head"]["ref"] == branch["ref"].split("/")[-1]

def test_create_pull_request_same_tree(user_data, repository, branch_for_repo):
    gh_service = GitHubRestApi()

    pr_title = random_str()
    res = gh_service.create_pull_request(user_data["login"], repository["name"], branch_for_repo["ref"], MAIN_BRANCH,
                                         pr_title)

    assert res.status_code == 422

def test_list_pull_requests(user_data, repository, open_pull_request):
    gh_service = GitHubRestApi()
    res = gh_service.list_pull_requests(user_data["login"], repository["name"])

    assert res.status_code == 200

    act_pr = None
    for pr in res.json():
        if pr["title"] == open_pull_request["title"]:
            act_pr = pr
            break

    assert act_pr
    assert act_pr["base"]["ref"] == open_pull_request["base"]["ref"]
    assert act_pr["head"]["ref"] == open_pull_request["head"]["ref"]

def test_list_pull_requests_fake_repo(user_data):
    gh_service = GitHubRestApi()
    res = gh_service.list_pull_requests(user_data["login"], random_str())

    assert res.status_code == 404

def test_close_pull_request(user_data, repository, open_pull_request):
    gh_service = GitHubRestApi()

    new_state = "closed"
    res = gh_service.update_pull_request(user_data["login"], repository["name"], open_pull_request["number"], new_state)
    assert res.status_code == 200

    res = res.json()
    assert res["state"] == new_state

def test_update_pr_wrong_state(user_data, repository, open_pull_request):
    gh_service = GitHubRestApi()

    res = gh_service.update_pull_request(user_data["login"], repository["name"], open_pull_request["number"],
                                         random_str())
    assert res.status_code == 200
    assert res.json()["state"] == "open"

@pytest.mark.skip("TODO: currently failing because of 'cannot review own pull request' validation")
def test_approve_pull_request(user_data, repository, open_pull_request):
    gh_service = GitHubRestApi()

    result = "APPROVE"
    res = gh_service.create_pr_review(user_data["login"], repository["name"], open_pull_request["number"], result)
    assert res.status_code == 200


import pygame, time                      # import the pygame library which has many functions we will need later

SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 500
pygame.init()                           # initializing the pygame window
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))    # creating screen upon which we can place images

# importing images
red_dvd = pygame.image.load("/home/jeremy/Pictures/red_dvd.png")
blue_dvd = pygame.image.load("/home/jeremy/Pictures/blue_dvd.png")
green_dvd = pygame.image.load("/home/jeremy/Pictures/green_dvd.png")

# dictionary to deal with selecting color
color_select = {0: red_dvd, 1:blue_dvd, 2:green_dvd}

black = (0,0,0)                         # define black as black RGB color
x,y = 0,0                               # base x and y pixel coordinates are 0,0
dx,dy = 1,1                             # moving box will go one pixel at a time
color = 0                               # current color will be red

done = False                            # while loop exit condition

while not done:
    for event in pygame.event.get():    # whenever pygame recognizes an event (IE: mouse movement, clicking on the window x
        if event.type == pygame.QUIT:   # if user clicked the red box to close the window
            done = True                 # exit the loop
        if event.type == pygame.MOUSEBUTTONUP:  # if user clicks
            color += 1
    x += dx
    y += dy

    if x + dx < 0 or x + dx + 100 > SCREEN_WIDTH :
        dx = -dx
    if y + dy < 0 or y + dy + 100 > SCREEN_HEIGHT:
        dy = -dy

    screen.fill(black)                  # fill screen with black pixels

    screen.blit(color_select[color%3], (x,y))
    time.sleep(0.01)

    pygame.display.flip()               # update display with current picture


from django.contrib import admin
from django.contrib.auth.models import User, Group
# Register your models here.
from .models import EmailList

admin.site.site_header = 'PODCAST'
admin.site.site_title = 'PODCAST'
admin.site.index_title = 'site administration'

@admin.register(EmailList)
class EmailListAdmin(admin.ModelAdmin):
    list_display = ['id', 'email', 'phone', 'pod_type', 'created', 'updated']
    list_filter = ['pod_type', 'email', 'phone']
    search_fields = ['phone', 'email']
    date_hierarchy = 'created'

admin.site.unregister(User)
admin.site.unregister(Group)


# N: クエリ処理する列のサイズ
N = ...

data = [0]*(N+1)

def init(A):
    data[1:] = A
    for i in range(1, N):
        if i + (i & -i) <= N:
            data[i + (i & -i)] += data[i]

def add(k, x):
    while k <= N:
        data[k] += x
        k += k & -k

def get(k):
    s = 0
    while k:
        s += data[k]
        k -= k & -k
    return s

# 二分探索
N0 = 2**(N-1).bit_length()
def lower_bound(x):
    w = i = 0
    k = N0
    while k:
        if i+k <= N and w + data[i+k] <= x:
            w += data[i+k]
            i += k
        k >>= 1
    return i+1


import numpy as np
from torch.utils.data.sampler import SubsetRandomSampler
from torch.utils.data import DataLoader

def Dataloader(Dataset, batch_size, validation_split = .2, shuffle_dataset = True, random_seed = 42):
    dataset_size = len(Dataset)
    indices = list(range(dataset_size))
    train_split = int(np.floor(validation_split*dataset_size))

    np.random.seed(random_seed)
    np.random.shuffle(indices)

    validation_indices, train_indices = indices[:train_split], indices[train_split:]

    train_sampler, validation_sampler = [SubsetRandomSampler(train_indices),
                                         SubsetRandomSampler(validation_indices)]

    train_loader, validation_loader = [DataLoader(Dataset, batch_size = batch_size, sampler = train_sampler),
                                       DataLoader(Dataset, batch_size = batch_size, sampler = validation_sampler)]

    dataloaders = {"train": train_loader, "val": validation_loader}
    datasets_sizes = {"train": len(train_indices), "val": len(validation_indices)}

    return dataloaders, datasets_sizes


import tensorflow as tf
import tensorflow_addons as tfa
from collections.abc import Iterable

def upsample(x: tf.Tensor, use_conv: bool = False) -> tf.Tensor:
    batch_size, height, width, channels = x.shape
    x = tf.keras.layers.UpSampling2D(interpolation='nearest')(x)
    if use_conv:
        x = tf.keras.layers.Conv2D(channels, 3, padding='same')(x)
    assert(x.shape == [batch_size, height * 2, width * 2, channels])
    return x

def downsample(x: tf.Tensor, use_conv: bool = False):
    batch_size, height, width, channels = x.shape
    if use_conv:
        x = tf.keras.layers.Conv2D(channels, 3, strides=2, padding='same')(x)
    else:
        x = tf.keras.layers.AveragePooling2D(strides=2, padding='same')(x)
    assert(x.shape == [batch_size, height // 2, width // 2, channels])
    return x

def attention_block(x: tf.Tensor) -> tf.Tensor:
    """
    Implementing self-attention block, as mentioned in
    https://arxiv.org/pdf/1809.11096.pdf
    """

    x = tfa.layers.GroupNormalization(groups=32, axis=-1)(x)

    q = AttentionVectorLayer()(x)
    v = AttentionVectorLayer()(x)
    k = AttentionVectorLayer()(x)

    h = tf.keras.layers.Attention()([q, v, k])

    return x + h

def deep_resblock(
        x: tf.Tensor,
        noise_embedding: tf.Tensor,
        n_out_channels: bool = None,
        dropout: float = 0.) -> tf.Tensor:
    """
    Reuse the resblock definitions from https://arxiv.org/pdf/1809.11096.pdf
    Slight tweak to use ConditionalInstanceNormalization and pre-activation
    as described in https://arxiv.org/pdf/1907.05600.pdf
    """
    if not n_out_channels:
        n_out_channels = x.shape[-1]

    track_a = tf.keras.layers.Conv2D(n_out_channels, 1, padding='same')(x)

    track_b = tfa.layers.GroupNormalization(groups=32, axis=-1)(x)
    track_b = tf.keras.activations.swish(track_b)
    track_b = tf.keras.layers.Conv2D(n_out_channels, 1, padding='same')(track_b)
    track_b = ConditionalInstanceNormalization()([track_b, noise_embedding])
    track_b = tf.keras.activations.swish(track_b)
    track_b = tf.keras.layers.Conv2D(n_out_channels, 3, padding='same')(track_b)
    track_b = tf.keras.layers.Dropout(dropout)(track_b)
    track_b = tfa.layers.GroupNormalization(groups=32, axis=-1)(x)
    track_b = tf.keras.activations.swish(track_b)
    track_b = tf.keras.layers.Conv2D(n_out_channels, 3, padding='same')(track_b)
    track_b = ConditionalInstanceNormalization()([track_b, noise_embedding])
    track_b = tf.keras.activations.swish(track_b)
    track_b = tf.keras.layers.Conv2D(n_out_channels, 1, padding='same')(track_b)

    return track_a + track_b

def resblock(
        x: tf.Tensor,
        noise_embedding: tf.Tensor,
        n_out_channels: bool = None,
        dropout: float = 0.) -> tf.Tensor:
    """
    Reuse the resblock definitions from https://arxiv.org/pdf/1809.11096.pdf
    Slight tweak to use ConditionalInstanceNormalization and pre-activation
    as described in https://arxiv.org/pdf/1907.05600.pdf
    """
    if not n_out_channels:
        n_out_channels = x.shape[-1]

    track_a = tf.keras.layers.Conv2D(n_out_channels, 1, padding='same')(x)

    track_b = tfa.layers.GroupNormalization(groups=32, axis=-1)(x)
    track_b = tf.keras.activations.swish(track_b)
    track_b = tf.keras.layers.Conv2D(n_out_channels, 3, padding='same')(track_b)
    track_b = tf.keras.layers.Dropout(dropout)(track_b)
    track_b = ConditionalInstanceNormalization()([track_b, noise_embedding])
    track_b = tf.keras.activations.swish(track_b)
    track_b = tf.keras.layers.Conv2D(n_out_channels, 3, padding='same')(track_b)

    return track_a + track_b

def up_deep_resblock(x: tf.Tensor, skip_x: tf.Tensor, noise_embedding: tf.Tensor, n_out_channels: bool = None,
        dropout: float = 0.) -> tf.Tensor:
    if not n_out_channels:
        n_out_channels = x.shape[-1]

    skip_x = skip_x / tf.math.sqrt(2.) # downscale the skip connection by 1 / sqrt(2)
    x = tf.keras.layers.Concatenate(axis=-1)([x, skip_x])

    return deep_resblock(x, noise_embedding, n_out_channels=n_out_channels, dropout=dropout)

def up_resblock(x: tf.Tensor, skip_x: tf.Tensor, noise_embedding: tf.Tensor, n_out_channels: bool = None,
        dropout: float = 0.) -> tf.Tensor:
    if not n_out_channels:
        n_out_channels = x.shape[-1]

    skip_x = skip_x / tf.math.sqrt(2.)
    x = tf.keras.layers.Concatenate(axis=-1)([x, skip_x])

    return resblock(x, noise_embedding, n_out_channels=n_out_channels, dropout=dropout)

class AttentionVectorLayer(tf.keras.layers.Layer):
    """
    Building the query, key or value for self-attention
    from the feature map
    """
    def __init__(self, **kwargs):
        super(AttentionVectorLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        self.n_channels = input_shape[-1]
        self.w = self.add_weight(
            shape=(self.n_channels, self.n_channels),
            initializer=tf.keras.initializers.VarianceScaling(scale=1., mode='fan_avg', distribution='uniform'),
            trainable=True,
            name='attention_w'
        )
        self.b = self.add_weight(
            shape=(self.n_channels,),
            initializer='zero',
            trainable=True,
            name='attention_b'
        )

    def call(self, x: tf.Tensor) -> tf.Tensor:
        return tf.tensordot(x, self.w, 1) + self.b

    def get_config(self) -> dict:
        return {}

    @classmethod
    def from_config(cls, config):
        return cls(**config)

class ConditionalInstanceNormalization(tf.keras.layers.Layer):
    """
    The goal of conditional instance normalization is to make the
    model aware of the amount of noise to be removed (i.e how many
    steps in the noise diffusion process are being considered). The
    implementation was informed by the appendix in
    https://arxiv.org/pdf/1907.05600.pdf and implementation at
    https://github.com/ermongroup/ncsn/blob/master/models/cond_refinenet_dilated.py
    """
    def __init__(self, **kwargs):
        super(ConditionalInstanceNormalization, self).__init__(**kwargs)

    def build(self, input_shape):
        self.batch_size = input_shape[0][0]
        self.height = input_shape[0][1]
        self.width = input_shape[0][2]
        self.n_channels = input_shape[0][3]
        self.embedding_dim = input_shape[1][1]
        self.w1 = self.add_weight(
            shape=(self.embedding_dim, self.n_channels),
            initializer=tf.keras.initializers.RandomNormal(mean=1., stddev=0.02),
            trainable=True,
            name='conditional_w1'
        )
        self.b = self.add_weight(
            shape=(self.embedding_dim, self.n_channels),
            initializer="zero",
            trainable=True,
            name='conditional_b'
        )
        self.w2 = self.add_weight(
            shape=(self.embedding_dim, self.n_channels),
            initializer=tf.keras.initializers.RandomNormal(mean=1., stddev=0.02),
            trainable=True,
            name='conditional_w2'
        )

    def call(self, inputs: Iterable) -> tf.Tensor:
        x, noise_embedding = inputs
        feature_map_means = tf.math.reduce_mean(x, axis=(1, 2), keepdims=True)
        feature_map_std_dev = tf.math.reduce_std(x, axis=(1, 2), keepdims=True) + 1e-5
        m = tf.math.reduce_mean(feature_map_means, axis=-1, keepdims=True)
        v = tf.math.reduce_std(feature_map_means, axis=-1, keepdims=True) + 1e-5
        gamma = tf.expand_dims(tf.expand_dims(tf.tensordot(noise_embedding, self.w1, 1), 1), 1)
        beta = tf.expand_dims(tf.expand_dims(tf.tensordot(noise_embedding, self.b, 1), 1), 1)
        alpha = tf.expand_dims(tf.expand_dims(tf.tensordot(noise_embedding, self.w2, 1), 1), 1)
        instance_norm = (x - feature_map_means) / feature_map_std_dev
        x = gamma * instance_norm + beta + alpha * (feature_map_means - m) / v
        return x

    def get_config(self) -> dict:
        return {}

    @classmethod
    def from_config(cls, config):
        return cls(**config)

class NoiseEmbedding(tf.keras.layers.Layer):
    """
    Implementation of noise embedding taken from Wavegrad
    implementation at https://github.com/lmnt-com/wavegrad/blob/master/src/wavegrad/model.py
    """
    def __init__(self, dim, **kwargs):
        super(NoiseEmbedding, self).__init__(**kwargs)
        self.dim = dim

    def call(self, inputs: tf.Tensor) -> tf.Tensor:
        assert(len(inputs.shape) == 2)
        half_dim = self.dim // 2
        encoding = tf.range(half_dim, dtype=tf.float32) * tf.math.log(1e4) / half_dim
        encoding = tf.math.exp(encoding * -1)
        encoding = inputs * tf.expand_dims(encoding, 0)
        encoding = tf.concat([tf.math.sin(encoding), tf.math.cos(encoding)], -1)
        assert(encoding.shape == (inputs.shape[0], self.dim))
        return encoding

    def get_config(self) -> dict:
        return {
            'dim': self.dim
        }

    @classmethod
    def from_config(cls, config):
        return cls(**config)


# -*- coding: utf-8 -*-

import os
import shutil
import urllib.request
import urllib.error
import urllib.parse

from fabric.api import local, lcd

from .base import BuilderBase
from buildtools.defines import (PLUGINS_DIR,
                                PLUGINS_LIST)
from buildtools.versions import (readAppInfo,
                                 getPluginVersionsPath,
                                 downloadAppInfo)

class BuilderPlugins(BuilderBase):
    """
    Create archives with plug-ins
    """
    def __init__(self,
                 updatedOnly=False,
                 build_dir=PLUGINS_DIR,
                 plugins_list=PLUGINS_LIST):
        super(BuilderPlugins, self).__init__(build_dir)
        self._all_plugins_fname = u'outwiker-plugins-all.zip'
        self._plugins_list = plugins_list
        self._updatedOnly = updatedOnly

    def get_plugins_pack_path(self):
        return self._getSubpath(self._all_plugins_fname)

    def clear(self):
        super(BuilderPlugins, self).clear()
        self._remove(self.get_plugins_pack_path())

    def _build(self):
        # Path to archive with all plug-ins
        full_archive_path = self.get_plugins_pack_path()

        for plugin in self._plugins_list:
            # Path to plugin.xml for current plugin
            xmlplugin_path = getPluginVersionsPath(plugin)

            localAppInfo = readAppInfo(xmlplugin_path)
            assert localAppInfo is not None
            assert localAppInfo.currentVersion is not None

            skip_plugin = False

            # Check for update
            if self._updatedOnly:
                url = localAppInfo.updatesUrl
                try:
                    siteappinfo = downloadAppInfo(url)
                    if localAppInfo.currentVersion == siteappinfo.currentVersion:
                        skip_plugin = True
                except (urllib.error.URLError, urllib.error.HTTPError):
                    pass

            # Archive a single plug-in
            if not skip_plugin:
                version = str(localAppInfo.currentVersion)
                archive_name = u'{}-{}.zip'.format(plugin, version)

                # Subpath to current plug-in archive
                plugin_dir_path = self._getSubpath(plugin)

                # Path to future archive
                archive_path = self._getSubpath(plugin, archive_name)
                os.mkdir(plugin_dir_path)
                shutil.copy(xmlplugin_path, plugin_dir_path)

                # Archive a single plug-in
                with lcd("plugins/{}".format(plugin)):
                    local('7z a -r -aoa -xr!*.pyc -xr!.ropeproject -x!doc "{}" ./*'.format(archive_path))

            # Add a plug-in to full archive
            with lcd("plugins/{}".format(plugin)):
                local('7z a -r -aoa -xr!*.pyc -xr!.ropeproject -w../ "{}" ./*'.format(full_archive_path))

    def _getSubpath(self, *args):
        """
        Return subpath inside current build path (inside 'build' subpath)
        """
        return os.path.join(self.build_dir, *args)


from core.settings.base import DEFAULT_CLIENT_ID, DEFAULT_CLIENT_SECRET

class ClientGenerator:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

    def process_view(self, request, *args, **kwargs):
        post_dict = request.POST.copy()
        if (
            post_dict.get("client_id") == "undefined"
            or post_dict.get("client_id") is None
        ):
            post_dict["client_id"] = DEFAULT_CLIENT_ID
            post_dict["client_secret"] = DEFAULT_CLIENT_SECRET
        else:
            post_dict["client_id"] = post_dict.get("client_id", DEFAULT_CLIENT_ID)
            post_dict["client_secret"] = post_dict.get(
                "client_secret", DEFAULT_CLIENT_SECRET
            )
        request.POST = post_dict


def insert(words: list[str]) -> list[str]:
    word: str = input("Insert a word you would like to store: ")
    if word not in words:
        words.append(word)
    return words

def search(words: list[str]) -> list[str]:
    letter: str = input("Insert a letter you would like to search: ")
    num_of_appear: int = int(input("Insert number of appearances: "))
    count = 0
    words_with_letter = []
    for word in words:
        if letter in word:
            for char in word:
                if char == letter:
                    count += 1
        if count == num_of_appear:
            words_with_letter.append(word)
        count = 0
    return words_with_letter

words_list = []
while True:
    action: str = input("Would you like to insert, to search or to quit? ")
    if action == 'insert':
        words_list = insert(words_list)
        print(words_list)
    elif action == 'search':
        print(search(words_list))
    elif action == 'quit':
        break
    else:
        print('Invalid input')