import os
from multiprocessing import Pool,Lock
import cv2
import json
import ntpath
import imgaug.augmenters as iaa
from imgaug.augmentables.kps import Keypoint, KeypointsOnImage
from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
from flasker import angle_with_yaxis,returnCentre
import numpy as np
from sklearn.cluster import KMeans

folderDirectory="../object_detection_mobile_v2/dataset/images_seg_te/"
onlyfiles = [os.path.join(folderDirectory, f) for f in os.listdir(folderDirectory) if os.path.isfile(os.path.join(folderDirectory, f))]
rootPathCentreLabel="../object_detection_mobile_v2/dataset/labels_seg_tr/"
classes=["top","bottom","2","7","1"]
outdirectory ="../object_detection_mobile_v2/output_check/"
horizontalImages="../object_detection_mobile_v2/train_16_rotations_ratioCropped/"
weirdRotations=["IMG_1614.jpg"]
def returnAugmentationObjRot(angle):
    seq = iaa.Sequential(
        [

            iaa.Affine(
                rotate=(angle), # rotate by -x to +x degrees
            ),

        ])
    return seq
def returnAugmentationObj(angle,Scale):
    seq = iaa.Sequential(
        [

            iaa.Affine(
                rotate=(angle), # rotate by -x to +x degrees
                scale={"x": (Scale), "y": (Scale)}
            ),

        ])
    return seq
def returnAugmentationObjCrop(top,right,bott,left):
    seq = iaa.Sequential(
        [

            iaa.CropAndPad(px=(-top,
                -right,
                -bott,
                -left),
                keep_size=False,
            ),
            # iaa.Resize((256,256))
        ])
    return seq

def processImage(imagePath,all_annots_imagelist):
    imageFileName=ntpath.basename(imagePath)

    all_annots,imagelist=all_annots_imagelist[0],all_annots_imagelist[1]

    resize_dim=(256,256)
    img = cv2.imread(imagePath,cv2.IMREAD_COLOR)
    # img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    original_size=img.shape
    # img = cv2.resize(img,resize_dim)
    try:
        objects = all_annots[imagelist[imageFileName]]["frames"][imageFileName]
        rotateAndAug(img,objects,imageFileName)
    except KeyError:
        print(imageFileName,"No frames found")
    # lock.release()

def rotateAndAug(img,objs,imageFileName):
    newImg=img
    newObjects=objs
    BBoxs=[BoundingBox(x1=0, x2=0, y1=0, y2=0),BoundingBox(x1=0, x2=0, y1=0, y2=0),BoundingBox(x1=0, x2=0, y1=0, y2=0),BoundingBox(x1=0, x2=0, y1=0, y2=0)]
    p1=[0,0]
    p2=[0,0]
    for inde,obj in enumerate(objs):
        if obj["tags"][0] in classes:
            x1 = obj["box"]["x1"]
            y1 = obj["box"]["y1"]
            x2 = obj["box"]["x2"]
            y2 = obj["box"]["y2"]

            if obj["tags"][0] in ["top","2"]:
                BBoxs[0]=BoundingBox(x1=x1, x2=x2, y1=y1, y2=y2,label="top")
                p1 = returnCentre([x1,y1,x2,y2])
            elif obj["tags"][0] in ["bottom","7"]:
                BBoxs[1]=BoundingBox(x1=x1, x2=x2, y1=y1, y2=y2,label="bottom")
                p2 = returnCentre([x1,y1,x2,y2])
            elif obj["tags"][0] in ["1"]:
                BBoxs[2]=BoundingBox(x1=x1, x2=x2, y1=y1, y2=y2,label="influenza")
                p3 = returnCentre([x1,y1,x2,y2])
            BBoxs[3]=BoundingBox(x1=0, x2=obj["width"], y1=0, y2=obj["height"],label="entireimage")
    if max(p1)>0 and max(p2)>0:
        p1=np.array(p1)
        p2=np.array(p2)
        angleToRotate,im0,scale_percent,quad,_=angle_with_yaxis(p1,p2,img,[],0)
        angleToRotate=angleToRotate+90
        seqAug = returnAugmentationObj(angleToRotate,scale_percent)
        bbs = BoundingBoxesOnImage(BBoxs, shape=img.shape)
        newshape = [img.shape[0]*scale_percent,img.shape[1]*scale_percent]
        image_hor, bbs_hor = seqAug(image=img, bounding_boxes=bbs)

        X=max(bbs_hor.bounding_boxes[-1].x1,bbs_hor.bounding_boxes[-1].x2)
        x1_inf=bbs_hor.bounding_boxes[0].x1+118
        y1_inf=bbs_hor.bounding_boxes[0].y1
        x2_inf=min(bbs_hor.bounding_boxes[0].x2+150,X)
        y2_inf=bbs_hor.bounding_boxes[0].y2
        listOfbb=bbs_hor.bounding_boxes
        imggrayaug=cv2.cvtColor(image_hor, cv2.COLOR_BGR2GRAY)
        infCalculatedFlag=False

        if (y2_inf-y1_inf)>70:
            for i in range(3):
                yy=listOfbb[i].y2
                y=listOfbb[i].y1
                offset=((yy-y)-70)/2

                listOfbb[i].y2-=offset
                listOfbb[i].y1+=offset
            offset=((y2_inf-y1_inf)-70)/2
            y2_inf-=offset
            y1_inf+=offset

        if listOfbb[2].label==None:
            # print((x2_inf-x1_inf),imageFileName)
            if (x2_inf-x1_inf)>102:
                listOfbb[2]=(BoundingBox(x1=x1_inf,x2=x2_inf,y1=y1_inf,y2=y2_inf))
                bbs_hor =BoundingBoxesOnImage(listOfbb, shape=image_hor.shape)
                infCalculatedFlag=True
                listOfbb[2].label="influenza"
            elif (x2_inf-x1_inf)>0 and (x2_inf-x1_inf)<102:
                # print(removeInf,image_hor.shape,int(x2_inf-x1_inf))

                image_hor[:,int(x1_inf):int(x2_inf),:]=0
                # print(image_hor[:,removeInf:,:])
                # crop_right=int(x2_inf-x1_inf)
                # seqAug2 = returnAugmentationObjCrop(0,crop_right,0,0)
                # image_hor, bbs_hor =seqAug2(image=image_hor, bounding_boxes=bbs_hor)

        cnt=0
        for numRotation in range(16):
            if numRotation in [0,1,2,8,7,6,10,9,15,14]:

                angleToRotate=numRotation*22.5
                seqAug = returnAugmentationObjRot(angleToRotate)
                image_aug_, bbs_aug_ = seqAug(image=image_hor, bounding_boxes=bbs_hor)
                topBB=bbs_aug_.bounding_boxes[0]
                bottBB=bbs_aug_.bounding_boxes[1]
                p1=returnCentre([topBB.x1,topBB.y1,topBB.x2,topBB.y2])
                p2=returnCentre([bottBB.x1,bottBB.y1,bottBB.x2,bottBB.y2])
                centreRDT=returnCentre([p2[0],p2[1],p1[0],p1[1]])
                # print(centreRDT)
                leftLim=centreRDT[0]-640
                rightLim=centreRDT[0]+640
                topLim=centreRDT[1]-360
                botLim=centreRDT[1]+360
                crop_top=int(topLim) #int(Imagebb.y1)
                crop_right=int(-rightLim+image_aug_.shape[1])#int(-Imagebb.x2+image_aug.shape[1])
                crop_bott=int(-botLim+image_aug_.shape[0])#int(-Imagebb.y2+image_aug.shape[0])
                crop_left=int(leftLim)#int(Imagebb.x1)
                seqAug2 = returnAugmentationObjCrop(crop_top,crop_right,crop_bott,crop_left)
                image_aug, bbs_aug =seqAug2(image=image_aug_, bounding_boxes=bbs_aug_)

                image_with_bbs = bbs_aug.draw_on_image(image_aug)

    ###########UNCOMMENT FOR CREATING YOLO TRAINING FILES
                lock.acquire()
                with open("rdt_test_crop_rot.txt","a") as fout:
                    boxes=bbs_aug.bounding_boxes
                    fout.write(os.path.join(horizontalImages,str(numRotation)+"_"+imageFileName)+" ")
                    for bb in boxes:
                        if bb.label =="influenza":
                            annots=[str(x) for x in [bb.x1,bb.y1,bb.x2,bb.y2]]
                            annots=",".join(annots)+","+str(cnt)+" "
                            fout.write(annots)
                        if bb.label =="top":
                            annots=[str(x) for x in [bb.x1,bb.y1,bb.x2,bb.y2]]
                            annots=",".join(annots)+","+str(10+cnt)+" "
                            fout.write(annots)
                        if bb.label =="bottom":
                            annots=[str(x) for x in [bb.x1,bb.y1,bb.x2,bb.y2]]
                            annots=",".join(annots)+","+str(10*2+cnt)+" "
                            fout.write(annots)
                    fout.write("\n")
                cv2.imwrite(os.path.join(horizontalImages,str(numRotation)+"_"+imageFileName),image_aug)
                cv2.imwrite(os.path.join(outdirectory,str(numRotation)+"_"+"rot"+imageFileName),image_with_bbs)
                cnt+=1
                with open("anchors.txt","a") as fout:
                    for bb in bbs_aug.bounding_boxes[:-1]:

                        w=bb.x2-bb.x1
                        h=bb.y2-bb.y1
                        # bbox_size.append(np.array([w,h]))
                        fout.write(str(w)+","+str(h)+"\n")
                lock.release()
###################END BLOCK

    return newImg,newObjects

def rotate(img,objs,imageFileName):
    newImg=img
    newObjects=objs
    BBoxs=[BoundingBox(x1=0, x2=0, y1=0, y2=0),BoundingBox(x1=0, x2=0, y1=0, y2=0),BoundingBox(x1=0, x2=0, y1=0, y2=0),BoundingBox(x1=0, x2=0, y1=0, y2=0)]
    p1=[0,0]
    p2=[0,0]
    for inde,obj in enumerate(objs):
        if obj["tags"][0] in classes:
            x1 = obj["box"]["x1"]
            y1 = obj["box"]["y1"]
            x2 = obj["box"]["x2"]
            y2 = obj["box"]["y2"]

            if obj["tags"][0] in ["top","2"]:
                BBoxs[0]=BoundingBox(x1=x1, x2=x2, y1=y1, y2=y2,label="top")
                p1 = returnCentre([x1,y1,x2,y2])
            elif obj["tags"][0] in ["bottom","7"]:
                BBoxs[1]=BoundingBox(x1=x1, x2=x2, y1=y1, y2=y2,label="bottom")
                p2 = returnCentre([x1,y1,x2,y2])
            elif obj["tags"][0] in ["1"]:
                BBoxs[2]=BoundingBox(x1=x1, x2=x2, y1=y1, y2=y2,label="influenza")
                p3 = returnCentre([x1,y1,x2,y2])
            BBoxs[3]=BoundingBox(x1=0, x2=obj["width"], y1=0, y2=obj["height"],label="entireimage")
    if max(p1)>0 and max(p2)>0:
        p1=np.array(p1)
        p2=np.array(p2)
        angleToRotate,im0,scale_percent,quad,_=angle_with_yaxis(p1,p2,img,[],0)
        angleToRotate=angleToRotate+90
        seqAug = returnAugmentationObj(angleToRotate,scale_percent)
        bbs = BoundingBoxesOnImage(BBoxs, shape=img.shape)
        newshape = [img.shape[0]*scale_percent,img.shape[1]*scale_percent]
        image_aug, bbs_aug = seqAug(image=img, bounding_boxes=bbs)
        Imagebb=bbs_aug.bounding_boxes[-1]
        topBB=bbs_aug.bounding_boxes[0]
        bottBB=bbs_aug.bounding_boxes[1]
        p1=returnCentre([topBB.x1,topBB.y1,topBB.x2,topBB.y2])
        p2=returnCentre([bottBB.x1,bottBB.y1,bottBB.x2,bottBB.y2])
        centreRDT=returnCentre([p2[0],p2[1],p1[0],p1[1]])
        # print(centreRDT)
        leftLim=centreRDT[0]-640
        rightLim=centreRDT[0]+640
        topLim=centreRDT[1]-360
        botLim=centreRDT[1]+360
        crop_top=int(topLim) #int(Imagebb.y1)
        crop_right=int(-rightLim+image_aug.shape[1])#int(-Imagebb.x2+image_aug.shape[1])
        crop_bott=int(-botLim+image_aug.shape[0])#int(-Imagebb.y2+image_aug.shape[0])
        crop_left=int(leftLim)#int(Imagebb.x1)
        X=max(bbs_aug.bounding_boxes[-1].x1,bbs_aug.bounding_boxes[-1].x2)
        x1_inf=bbs_aug.bounding_boxes[0].x1+152
        y1_inf=bbs_aug.bounding_boxes[0].y1
        x2_inf=min(bbs_aug.bounding_boxes[0].x2+170,X)
        y2_inf=bbs_aug.bounding_boxes[0].y2
        listOfbb=bbs_aug.bounding_boxes
        imggrayaug=cv2.cvtColor(image_aug, cv2.COLOR_BGR2GRAY)
        infCalculatedFlag=False

        if (y2_inf-y1_inf)>90:
            for i in range(3):
                yy=listOfbb[i].y2
                y=listOfbb[i].y1
                offset=((yy-y)-90)/2

                listOfbb[i].y2-=offset
                listOfbb[i].y1+=offset
            offset=((y2_inf-y1_inf)-90)/2
            y2_inf-=offset
            y1_inf+=offset

        if listOfbb[2].label==None:

            listOfbb[2]=(BoundingBox(x1=x1_inf,x2=x2_inf,y1=y1_inf,y2=y2_inf))
            bbs_aug =BoundingBoxesOnImage(listOfbb, shape=image_aug.shape)
            infCalculatedFlag=True
            listOfbb[2].label="influenza"

        histg = cv2.calcHist([imggrayaug[int(y1_inf):int(y2_inf),int(x1_inf):int(bbs_aug.bounding_boxes[0].x2+170)]],[0],None,[2],[0,256])
        # print(X)
        factor=2
        if histg[1]!=0:
            factor=histg[0]/histg[1]
        else:
            pass

        if infCalculatedFlag:
            if factor<2:
                # listOfbb[2]=BoundingBox(x1=x1_inf,y1=y1_inf,x2=x2_inf,y2=y2_inf)
                bbs_aug =BoundingBoxesOnImage(listOfbb, shape=image_aug.shape)
                seqAug2 = returnAugmentationObjCrop(crop_top,crop_right,crop_bott,crop_left)
                image_aug, bbs_aug =seqAug2(image=image_aug, bounding_boxes=bbs_aug)
                image_with_bbs = bbs_aug.draw_on_image(image_aug)
                cv2.imwrite(os.path.join(outdirectory,"rot"+imageFileName),image_with_bbs)
            else:
                listOfbb[2]=BoundingBox(x1=0,y1=0,x2=0,y2=0,label=None)
                bbs_aug =BoundingBoxesOnImage(listOfbb, shape=image_aug.shape)
                seqAug2 = returnAugmentationObjCrop(crop_top,crop_right,crop_bott,crop_left)
                image_aug, bbs_aug =seqAug2(image=image_aug, bounding_boxes=bbs_aug)
                image_with_bbs = bbs_aug.draw_on_image(image_aug)
                cv2.imwrite(os.path.join(outdirectory,"rot"+imageFileName),image_with_bbs)
        else:
            # bbs_aug =BoundingBoxesOnImage(listOfbb, shape=image_aug.shape)
            seqAug2 = returnAugmentationObjCrop(crop_top,crop_right,crop_bott,crop_left)
            image_aug, bbs_aug =seqAug2(image=image_aug, bounding_boxes=bbs_aug)
            image_with_bbs = bbs_aug.draw_on_image(image_aug)
            cv2.imwrite(os.path.join(outdirectory,"rot"+imageFileName),image_with_bbs)
        # image_with_bbs = bbs.draw_on_image(img)
###########UNCOMMENT FOR CREATING YOLO TRAINING FILES
        lock.acquire()
        with open("rdt_train_crop.txt","a") as fout:
            boxes=bbs_aug.bounding_boxes
            fout.write(os.path.join(horizontalImages,imageFileName)+" ")
            for bb in boxes:
                if bb.label =="influenza":
                    annots=[str(x) for x in [bb.x1,bb.y1,bb.x2,bb.y2]]
                    annots=",".join(annots)+",0 "
                    fout.write(annots)
                if bb.label =="top":
                    annots=[str(x) for x in [bb.x1,bb.y1,bb.x2,bb.y2]]
                    annots=",".join(annots)+",1 "
                    fout.write(annots)
                if bb.label =="bottom":
                    annots=[str(x) for x in [bb.x1,bb.y1,bb.x2,bb.y2]]
                    annots=",".join(annots)+",2 "
                    fout.write(annots)
            fout.write("\n")
        cv2.imwrite(os.path.join(horizontalImages,imageFileName),image_aug)

        with open("anchors.txt","a") as fout:
            for bb in bbs_aug.bounding_boxes[:-1]:

                w=bb.x2-bb.x1
                h=bb.y2-bb.y1
                # bbox_size.append(np.array([w,h]))
                fout.write(str(w)+","+str(h)+"\n")
        lock.release()
###################END BLOCK

    return newImg,newObjects

def init(l):
    global lock
    lock = l

def main():
    l = Lock()
    all_annotations = []
    image_list_id = {}
    for ind,element in enumerate(os.listdir(rootPathCentreLabel)):
        with open(os.path.join(rootPathCentreLabel,element)) as fin:
            annotations = json.load(fin)
            all_annotations.append(annotations)
            for f in annotations["frames"].keys():
                image_list_id[f]=ind
    args = [(x,[all_annotations,image_list_id]) for x in onlyfiles]
    p = Pool(8,initializer=init, initargs=(l,))
    p.starmap(processImage,args)
    p.close()
    p.join()

if __name__ == "__main__":
    anchors=[]
    main()

    with open("anchors.txt") as fin:
        for line in fin:
            line=line.strip().split(",")
            anchors.append([float(line[0]),float(line[1])])

    # print(bbox_size)
    anchors=np.array(anchors)
    kmeans = KMeans(n_clusters=9)
    kmeans.fit(anchors)
    centroids = kmeans.cluster_centers_
    print(centroids)


import torch

class LSTM(torch.nn.Module):
    def __init__(self, input_size=4, hidden_size=10,
                 num_layers=2, output_size=2):
        super(LSTM, self).__init__()
        self.lstm = torch.nn.LSTM(
            input_size=input_size,
            hidden_size=hidden_size,
            num_layers=num_layers,
            batch_first=False,
            bias=False)
        self.fc = torch.nn.Linear(hidden_size, output_size)

    def forward(self, x, state=None):
        x, state = self.lstm(x, state)
        x = self.fc(x)
        return x, state


class LandsatMetadataWriter:
    """Writer for output metadata writing of Landsat datasets.

    Attributes
    ----------
    dataset_metadata : dict
        Dataset-specific values and information.
    sun_elevation : bool, optional
        Whether to include scene-specific value for sun_elevation
        (defaut is False).
    """
    def __init__(self, dataset_metadata, sun_elevation=False):
        self.dataset_metadata = dataset_metadata
        self.sun_elevation = sun_elevation

    def __call__(self, scene_id, band_ids, class_ids,
                 scene_metadata=None, **kwargs):
        """Create dictionary for all relevant metadata values for a Landsat
        scene.

        Parameters
        ----------
        scene_id : str
            Identifier for scene.
        band_ids : list
            Identifiers for bands.
        class_ids : list
            Identifiers for classes.
        scene_metadata : dict, optional
            Scene-specific Landsat metadata values, only needed if
            sun_elevation=True
        **kwargs
            All other (name, value) pairs to be saved

        Returns
        -------
        output_metadata : dict
            Scene-specific output metadata.
        """
        output_metadata = {
                'spacecraft_id': self.dataset_metadata['spacecraft_id'],
                'scene_id': scene_id,
                'bands': band_ids,
                'band_types': [
                    self.dataset_metadata['bands'][band]['type']
                    for band in band_ids
                ],
                'band_centres': [
                    self.dataset_metadata['bands'][band]['band_centre']
                    for band in band_ids
                ],
                'band_widths': [
                    self.dataset_metadata['bands'][band]['band_width']
                    for band in band_ids
                ],
                'classes': class_ids
            }
        if self.sun_elevation:
            output_metadata['sun_elevation'] = scene_metadata['SUN_ELEVATION']

        for band in band_ids:
            descriptive_names = [
                self.dataset_metadata['bands'][band_id].get('descriptive_name')
                for band_id in band_ids
                                ]
            band_positions = [
                    list(self.dataset_metadata['bands'].keys()).index(band_id)
                    for band_id in band_ids
                    ]
            named_bands = {
                          descriptive_name: band_pos
                          for descriptive_name, band_pos
                          in zip(descriptive_names, band_positions)
                          if descriptive_name is not None
                          }

            output_metadata['named_bands'] = named_bands

        # Add any extra user-supplied metadata
        output_metadata.update(kwargs)
        return output_metadata


#!/usr/bin/env python

import blinkt
import os

dir = "/home/pi/pixels/"

for i in range(0,8):
    if os.path.isfile(dir + str(i)):
        os.remove(dir + str(i))

for i in range(0,8):
    blinkt.set_pixel(i, 0, 0, 0)
    blinkt.clear()
    blinkt.show()


# [1] https://doi.org/10.1063/1.4937410
#     The consequences of improperly describing oscillator strengths
#     beyond the electric dipole approximation
#     Lestrange, Egidi, Li, 2015
# [2] https://doi.org/10.1016/0009-2614(95)01036-9
#     Ab initio calculation and display of the rotary strength tensor in
#     the random phase approximation. Method and model studies.
#     Pedersen, Hansen, 1995
# [3] https://pubs.acs.org/doi/pdf/10.1021/j100180a030.
#     Toward a Systematic Molecular Orbital Theory for Excited States
#     Foresman, Head-Gordon, Pople, Frisch, 1991

from typing import Literal, List, Optional, Tuple

import numpy as np
from numpy.typing import NDArray

from pysisyphus.elem_data import nuc_charges_for_atoms, MASS_DICT
from pysisyphus.Geometry import Geometry
from pysisyphus.helpers_pure import file_or_str
from pysisyphus.wavefunction.shells import Shells
from pysisyphus.wavefunction.helpers import BFType

Center = Literal["coc", "com"]

class Wavefunction:
    def __init__(
        self,
        atoms: Tuple[str],
        coords: NDArray[float],
        charge: int,
        mult: int,
        unrestricted: bool,
        occ: Tuple[int],
        C: NDArray[float],
        bf_type: BFType,
        shells: Optional[Shells] = None,
    ):
        self.atoms = atoms
        self.coords = np.array(coords).flatten()
        assert 3 * len(self.atoms) == len(self.coords)

        self.charge = charge
        self.mult = mult
        if self.mult != 1:
            unrestricted = True
        self.unrestricted = unrestricted
        self.occ = occ
        if not self.unrestricted:
            assert self.occ[0] == self.occ[1]
        # MOs are stored in columns
        self.C = np.array(C)
        # Always keep α and β coefficients separate. If we get only one set
        # of MO coefficients (one square matrix with ndim == 2) we assume a
        # restricted calculation and use the same set for alpha and beta electrons.
        if C.ndim == 2:
            self.C = np.array((self.C, self.C.copy()))
        self.bf_type = bf_type
        self.shells = shells

        self._masses = np.array([MASS_DICT[atom.lower()] for atom in self.atoms])

    @property
    def atom_num(self):
        return len(self.atoms)

    @property
    def masses(self):
        return self._masses

    @property
    def nuc_charges(self):
        return nuc_charges_for_atoms(self.atoms)

    @property
    def masses(self):
        return np.ones(len(self.atoms))

    @property
    def mo_num(self):
        return self.C.shape[1]

    @staticmethod
    @file_or_str(".json")
    def from_orca_json(text):
        from pysisyphus.io.orca import wavefunction_from_json

        wf = wavefunction_from_json(text)
        return wf

    @staticmethod
    @file_or_str(".json")
    def from_orca_molden(text):
        from pysisyphus.io.orca import wavefunction_from_molden

        wf = wavefunction_from_molden(text)
        return wf

    @property
    def C_occ(self):
        occ_a, occ_b = self.occ
        C_a, C_b = self.C
        return C_a[:, :occ_a], C_b[:, :occ_b]

    @property
    def C_virt(self):
        occ_a, occ_b = self.occ
        C_a, C_b = self.C
        return C_a[:, occ_a:], C_b[:, occ_b:]

    @property
    def P(self):
        return [C_occ @ C_occ.T for C_occ in self.C_occ]

    def P_exc(self, trans_dens):
        """
        Eqs. (2.25) and (2.26) in [3].
        """
        trans_dens *= 2 ** 0.5 / 2
        occ_a, occ_b = self.occ
        assert occ_a == occ_b
        occ = occ_a
        occupations = np.zeros(self.mo_num)
        occupations[:occ_a] = 2
        P = np.diag(occupations)
        dP_oo = -np.einsum("ia,ja->ij", trans_dens, trans_dens)
        dP_vv = np.einsum("ia,ic->ac", trans_dens, trans_dens)
        P[:occ, :occ] += 2 * dP_oo
        P[occ:, occ:] += 2 * dP_vv
        C, _ = self.C
        # The density matric is currently still in the MO basis. Transform
        # it to the AO basis and return.
        return C @ P @ C.T

    @property
    def S(self):
        # Check what type of basis functions we are using.
        return {
            BFType.CARTESIAN: lambda: self.shells.S_cart,
            BFType.PURE_SPHERICAL: lambda: self.shells.S_sph,
        }[self.bf_type]()

    def S_with_shells(self, other_shells):
        return {
            BFType.CARTESIAN: lambda: self.shells.get_S_cart(other_shells),
            BFType.PURE_SPHERICAL: lambda: self.shells.get_S_sph(other_shells),
        }[self.bf_type]()

    def S_with(self, other):
        other_shells = other.shells
        return self.S_with_shells(other_shells)

    def S_MO_with(self, other):
        assert (not self.unrestricted) and (
            self.mult == 1
        ), "Currently only Cα is considered!"
        S_AO = self.S_with(other)
        C = self.C[0]
        C_other = other.C[0]
        return C.T @ S_AO @ C_other

    @property
    def ao_centers(self) -> List[int]:
        return list(
            {
                BFType.CARTESIAN: lambda: self.shells.cart_ao_centers,
                BFType.PURE_SPHERICAL: lambda: self.shells.sph_ao_centers,
            }[self.bf_type]()
        )

    @property
    def ao_center_map(self) -> dict[int, List[int]]:
        ao_center_map = dict()
        for i, aoc in enumerate(self.ao_centers):
            ao_center_map.setdefault(aoc, list()).append(i)
        return ao_center_map

    def get_origin(self, kind="coc"):
        kind = kind.lower()
        assert kind in ("com", "coc")

        coords3d = self.coords.reshape(-1, 3).copy()
        _factors = {
            "coc": self.nuc_charges,  # Center of charge
            "com": self.masses,  # Center of mass
        }
        factors = _factors[kind]
        tot_factors = factors.sum()

        return np.sum(coords3d * factors[:, None], axis=0) / tot_factors

    def dipole_ints(
        self, origin: Optional[NDArray] = None, kind: Center = "coc"
    ) -> NDArray[float]:
        if origin is None:
            origin = self.get_origin(kind=kind)

        dipole_ints = {
            BFType.CARTESIAN: lambda *args: self.shells.get_dipole_ints_cart(*args),
            BFType.PURE_SPHERICAL: lambda *args: self.shells.get_dipole_ints_sph(*args),
        }[self.bf_type](origin)
        return dipole_ints

    def dipole_moment(
        self,
        P: NDArray[float] = None,
        origin: Optional[NDArray] = None,
        kind: Center = "coc",
    ) -> NDArray[float]:
        # Make a copy, as the coordinates must be give w.r.t. the origin, which
        # may be != (0., 0., 0.).
        coords3d = self.coords.reshape(-1, 3).copy()
        nuc_charges = self.nuc_charges

        if P is None:
            P = self.P

        if origin is None:
            origin = self.get_origin(kind=kind)

        # origin = (-1.487808,  3.034774,  0.292895)
        origin = np.array(origin, dtype=float)
        coords3d -= origin[None, :]
        dipole_ints = self.dipole_ints(origin)
        electronic = np.sum(
            [np.einsum("xij,ji->x", dipole_ints, P_) for P_ in P], axis=0
        )
        nuclear = np.einsum("i,ix->x", nuc_charges, coords3d)
        molecular = nuclear - electronic

        return molecular

    def transition_dipole_moment(
        self,
        # trans_dens: NDArray[float],
        trans_dens_a: NDArray[float],
        trans_dens_b: NDArray[float] = None,
    ) -> NDArray[float]:
        """
        Transition dipole moments from transition density matrices.

        Eq. (33) in [1].

        Parameters
        ----------
        trans_dens_a
            Numpy array containing transition density matrices of shape
            (nstates, occ, virt) or (occ, virt) in the α-electron space.
        trans_dens_b
            See trans_dens_a. Optional. If not provided, trans_dens_a is used.

        Returns
        -------
        tdms
            Numpy array of shape (nstates, 3) containing the Cartesian transition
            dipole moments in the length gauge.
        """

        origin = self.get_origin(kind="coc")
        dipole_ints = self.dipole_ints(origin)

        # Deal with unrestricted transition density matrices that contain
        # only one state.
        def atleast_3d(tden):
            if tden.ndim == 2:
                tden = tden[None, :]
            return tden

        trans_dens_a = atleast_3d(trans_dens_a)
        if trans_dens_b is None:
            trans_dens_a = 1 / 2 ** 0.5 * trans_dens_a
            trans_dens_b = trans_dens_a
        trans_dens_b = atleast_3d(trans_dens_b)

        # Expected shape: (nstates, occ, virt)
        assert trans_dens_a.ndim == trans_dens_b.ndim == 3

        def get_tdm(
            C: NDArray[float], occ: NDArray[int], trans_dens: NDArray[float]
        ) -> NDArray[float]:
            dipole_ints_mo = np.einsum(
                "jl,ilm,mk->ijk", C[:, :occ].T, dipole_ints, C[:, occ:]
            )

            # Then contract with dipole integrals. See Eq. (18) in [2].
            #
            # j : Cartesian direction
            # k : occ. MO space
            # l : virt. MO space
            # i : Excited state number
            tdm = np.einsum("jkl,ikl->ij", dipole_ints_mo, trans_dens)
            return tdm

        # Transitions between α -> α and β -> β
        C_a, C_b = self.C
        occ_a, occ_b = self.occ
        tdms_a = get_tdm(C_a, occ_a, trans_dens_a)
        tdms_b = get_tdm(C_b, occ_b, trans_dens_b)
        tdms = tdms_a + tdms_b
        return tdms

    def oscillator_strength(
        self, exc_ens: NDArray[float], trans_moms: NDArray[float]
    ) -> NDArray[float]:
        exc_ens = np.atleast_1d(exc_ens)
        if trans_moms.ndim == 1:
            trans_moms = trans_moms[None, :]
        fosc = 2 / 3 * exc_ens * (trans_moms ** 2).sum(axis=1)
        return fosc

    def as_geom(self):
        return Geometry(self.atoms, self.coords)

    def __str__(self):
        is_restricted = "unrestricted" if self.unrestricted else "restricted"
        return (
            f"Wavefunction({self.atom_num} atoms, charge={self.charge}, {is_restricted}, "
            f"mult={self.mult})"
        )


from pyoptools.raytrace.component import Component
from pyoptools.raytrace.surface import Aspherical, Plane
from pyoptools.raytrace.shape import Circular
from pyoptools.misc.Poly2D import *

class PowellLens(Component):
    """**Class to define a powell Lens**.

    *Attributes:*

    *radius*
        diameter/2. of the lens in the part of the cylinder
    *thickness*
        Thickness of the lens measured in the center
    *Conicity K*
        Conicity of the aspherical surface
    *curvature R*
        curvature of the aspherical surface
    *material*
        to calculate the refraction index of the lens (inherited from component)

    The origin of the coordinate system is located at the center of the lens
    in the optical axis (center between vertex).
    """

    def __init__(self, radius=4.445, thickness=7.62, K=-4.302, R=3.00, *args, **kwargs):
        Component.__init__(self, *args, **kwargs)
        self.radius = radius
        self.thickness = thickness
        self.K = K
        self.R = R

        __a_surf = Aspherical(
            shape=Circular(radius=self.radius),
            Ax=0,
            Ay=self.R,
            Kx=-1,
            Ky=self.K,
            poly=poly2d((0, 0)),
        )

        self.surflist["S1"] = (__a_surf, (0, 0, 0), (0, 0, 0))

        __p_surf = Plane(shape=Circular(radius=(self.radius)))

        self.surflist["B1"] = (__p_surf, (0, 0, self.thickness), (0, 0, 0))


X = int(input())

a = [64]

import heapq

temp = 0

while(True):

    if temp == X:
        break

    if sum(a) > X:

        mini_bar = heapq.heappop(a)

        nxt_bar = mini_bar // 2

        if nxt_bar > 0:

            heapq.heappush(a,nxt_bar)

            if sum(a) > X:
                continue
            else:
                heapq.heappush(a, nxt_bar)

    temp = sum(a)

print(len(a))


import numpy as np
import h5py

def initialize_parameters_deep(layer_dims):
    np.random.seed(1)
    parameters = {}
    L = len(layer_dims)  # number of layers in the network

    for l in range(1, L):
        parameters['W' + str(l)] = np.random.randn(layer_dims[l], layer_dims[l - 1]) / np.sqrt(layer_dims[l - 1])
        parameters['b' + str(l)] = np.zeros((layer_dims[l], 1))

        assert (parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l - 1]))
        assert (parameters['b' + str(l)].shape == (layer_dims[l], 1))

    return parameters

def sigmoid(Z):
    """
    Implements the sigmoid activation in numpy

    Arguments:
    Z -- numpy array of any shape

    Returns:
    A -- output of sigmoid(z), same shape as Z
    cache -- returns Z as well, useful during backpropagation
    """

    A = 1 / (1 + np.exp(-Z))
    cache = Z

    return A, cache

def relu(Z):
    """
    Implement the RELU function.

    Arguments:
    Z -- Output of the linear layer, of any shape

    Returns:
    A -- Post-activation parameter, of the same shape as Z
    cache -- a python dictionary containing "A" ; stored for computing the backward pass efficiently
    """

    A = np.maximum(0, Z)

    assert (A.shape == Z.shape)

    cache = Z
    return A, cache

def relu_backward(dA, cache):
    """
    Implement the backward propagation for a single RELU unit.

    Arguments:
    dA -- post-activation gradient, of any shape
    cache -- 'Z' where we store for computing backward propagation efficiently

    Returns:
    dZ -- Gradient of the cost with respect to Z
    """

    Z = cache
    dZ = np.array(dA, copy=True)  # just converting dz to a correct object.

    # When z <= 0, you should set dz to 0 as well.
    dZ[Z <= 0] = 0                                      # dL/dZ, derivative of relu function

    assert (dZ.shape == Z.shape)

    return dZ

def sigmoid_backward(dL_dA, cache):
    """
    Implement the backward propagation for a single SIGMOID unit.

    Arguments:
    dA -- post-activation gradient, of any shape
    cache -- 'Z' where we store for computing backward propagation efficiently

    Returns:
    dZ -- Gradient of the cost with respect to Z
    """

    Z = cache

    a = 1 / (1 + np.exp(-Z))
    dA_dZ = a * (1 - a)         # dL/dZ, derivative of sigmoid function

    dL_dZ = dL_dA * dA_dZ

    assert (dL_dZ.shape == Z.shape)

    return dL_dZ

def compute_cost(AL, Y):
    m = Y.shape[1]
    # Compute cross-entropy loss from aL and y.
    cost = -1 / m * np.sum(np.multiply(Y, np.log(AL)) + np.multiply((1 - Y), np.log(1 - AL)))
    cost = np.squeeze(cost)
    assert (cost.shape == ())
    return cost

def load_data():
    train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")
    train_set_x_orig = np.array(train_dataset["train_set_x"][:])  # your train set features
    train_set_y_orig = np.array(train_dataset["train_set_y"][:])  # your train set labels

    test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
    test_set_x_orig = np.array(test_dataset["test_set_x"][:])  # your test set features
    test_set_y_orig = np.array(test_dataset["test_set_y"][:])  # your test set labels

    classes = np.array(test_dataset["list_classes"][:])  # the list of classes

    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))

    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes


from PyQt5.QtWidgets import QFrame, QTableView, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, QComboBox,QLineEdit, QMessageBox, QAction
from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, QObject
from dane.zrodla import Wykaz, get_warstwa, getPolaczenie2

class WykModel(QAbstractTableModel):

    def __init__(self, parent=None):
        QAbstractTableModel.__init__(self,parent)
        self._wyk = []
        self._wybrany = None

    def setWykaz(self, wykaz):
        self._wyk = wykaz

    def endResetModel(self):
        self._wybrany = None
        QAbstractTableModel.endResetModel(self)

    def ident(self):
        if self._wybrany is None:
            return -1
        return self._wybrany[0].toInt()[0]

    def ostatni(self):
        return (self._wybrany[0].toInt()[0],str(self._wybrany[1].value()))

    def rowCount(self, *args, **kwargs):
        return len(self._wyk)

    def columnCount(self, *args, **kwargs):
        return 1

    def data(self, indeks, rola = Qt.DisplayRole):
        if rola == Qt.DisplayRole and indeks.column() == 0 and indeks.row() < len(self._wyk):
            self._wybrany = self._wyk[indeks.row()]
            return self._wybrany[1]
        return None

    def headerData(self, sekcja, orientacja, rola = Qt.DisplayRole):
        if orientacja == Qt.Vertical:
            return None
        if sekcja > 0:
            raise Exception("headerData: indeks %d poza zakresem [0,%d]"%(sekcja,len(self._nag)-1))
        if rola == Qt.DisplayRole:
            if sekcja == 0:
                return u'Nazwa'
            else:
                return None

def listaStart(con,nazwa):
    sql = 'select distinct start from '+nazwa+' order by start'
    rt = []
    for w in con.wszystkie(sql):
        rt.append(w[0])
    return rt

class WykDialog(QFrame):

    def __init__(self, con, nazwa, win, parent=None):
        QFrame.__init__(self,parent)
        self._con = con
        self._nazWyk = nazwa
        self._win = win
        self._wyk = Wykaz(con,nazwa)
        self.vbox = QVBoxLayout(self)
        self._tab = QTableView(self)
        self._mwyk = WykModel(self)
        self._mwyk.setWykaz(self._wyk)
        self._tab.setModel(self._mwyk)
        self.vbox.addWidget(self._tab)
        edwgt = QWidget()
        hed = QHBoxLayout()
        edwgt.setLayout(hed)
        self._cbstart = QComboBox(edwgt)
        self._skroty = listaStart(self._con, self._nazWyk)
        self._cbstart.addItems(self._skroty)
        hed.addWidget(self._cbstart)
        self._cbstart.currentIndexChanged.connect(self._zmWyk)
        self._edtxt = QLineEdit(edwgt)
        hed.addWidget(self._edtxt)
        btnUsu = QPushButton(u'Usuń')
        btnUsu.clicked.connect(self._usunZaz)
        hed.addWidget(btnUsu)
        btnDod = QPushButton(u'Dodaj')
        btnDod.clicked.connect(self._dodajNowy)
        hed.addWidget(btnDod)
        btnZm = QPushButton(u'Zmień')
        btnZm.clicked.connect(self._zmianaNaz)
        hed.addWidget(btnZm)
        btnEx = QPushButton(u'Zamknij')
        btnEx.clicked.connect(self._zamknij)
        hed.addWidget(btnEx)
        self.vbox.addWidget(edwgt)
        if len(self._skroty) > 0:
            self._cbstart.setCurrentIndex(1);
        self._tab.selectionModel().currentRowChanged.connect(self._zmBiezWier)

    def _zamknij(self,arg):
        self._win.usun(self)

    def _zmWyk(self,et):
        self._mwyk.beginResetModel()
        self._wyk.wypelnij(str(self._cbstart.currentText()))
        self._mwyk.endResetModel()
        self._edtxt.setText('')

    def _zmBiezWier(self,biez,poprz):
        self._edtxt.setText(biez.data())

    def _zmianaNaz(self,arg):
        sm = self._tab.selectionModel()
        indeks = sm.currentIndex()
        if indeks.isValid():
            n = self._wyk[indeks.row()]
            wid = n[0].toInt()[0]
            wn = str(n[1].value())
        else:
            return
        if not sm.hasSelection() :
            QMessageBox.information(self,'Zmiana',u'Proszę wybrać nazwę do zmiany')
            return
        odp = QMessageBox.question(self,'Zmiana',u'Czy na pewno chcesz zmienić nazwę '+wn+' na '+self._edtxt.text()+' ?',QMessageBox.Yes | QMessageBox.No)
        if odp != QMessageBox.Yes:
            return
        if self._wyk.zmien(wid,str(self._edtxt.text())):
            self._mwyk.beginResetModel()
            self._wyk.wypelnij()
            self._mwyk.endResetModel()
            self._tab.selectionModel().clearSelection()
        else:
            QMessageBox.warning(self,'Zmiana',u'Podana nazwa już znajduje się w wykazie')

    def _dodajNowy(self,arg):
        odp = QMessageBox.question(self,'Dodawanie',u'Czy na pewno chcesz dodać nazwę '+self._edtxt.text()+' ?',QMessageBox.Yes | QMessageBox.No)
        if odp != QMessageBox.Yes:
            return
        if self._wyk.dodaj(str(self._edtxt.text())):
            self._mwyk.beginResetModel()
            self._wyk.wypelnij()
            self._mwyk.endResetModel()
            self._tab.selectionModel().clearSelection()
        else:
            QMessageBox.warning(self,'Dodawanie',u'Podana nazwa już znajduje się w wykazie')

    def _usunZaz(self,arg):
        sm = self._tab.selectionModel()
        indeks = sm.currentIndex()
        if indeks.isValid():
            n = self._wyk[indeks.row()]
            wid = n[0].toInt()[0]
        else:
            return
        if not sm.hasSelection() :
            QMessageBox.information(self,'Usuwanie',u'Proszę wybrać nazwę do usunięcia')
            return
        odp = QMessageBox.question(self,'Usuwanie',u'Czy na pewno chcesz usunąć nazwę '+self._edtxt.text()+' ?',QMessageBox.Yes | QMessageBox.No)
        if odp != QMessageBox.Yes:
            return
        self._wyk.usun(wid)
        self._mwyk.beginResetModel()
        self._wyk.wypelnij()
        self._mwyk.endResetModel()
        self._tab.selectionModel().clearSelection()

class WykazAkcja(QAction):

    def __init__(self,et,nazwa,iface,window):
        QAction.__init__(self,et,window)
        self.triggered.connect(self.wykonaj)
        self._win = window
        self._iface = iface
        self._naz = nazwa

    def wykonaj(self):
        st = get_warstwa('stanowiska')
        if st is None:
            QMessageBox.warning(self._win,u'Wykazy',u'Wykazy wymagają otwartej warstwy "stanowiska"')
            return
        self._win.dodaj(WykDialog(getPolaczenie2(st),self._naz,self._win))

class FkWykazAkcja(QAction):
    def __init__(self,et,nazwa,iface,window):
        QAction.__init__(self,et,window)
        self.triggered.connect(self.wykonaj)
        self._win = window
        self._iface = iface
        self._naz = nazwa

    def wykonaj(self):
        st = get_warstwa('stanowiska')
        if st is None:
            QMessageBox.warning(self._win,u'Wykazy',u'Wykazy wymagają otwartej warstwy "stanowiska"')
            return
        else:
            con = getPolaczenie2(st)
            con.jeden('select count(*) from '+self._naz)
        #self._win.dodaj(WykDialog(getPolaczenie2(st),self._naz,self._win))


import itertools
from decimal import Decimal
from unittest import mock

import pytest
from anymail.exceptions import AnymailError
from django.urls import reverse
from django.test import override_settings
from model_bakery import baker

from documents.models import Document, DocumentSendLog
from Traidoo import errors

pytestmark = pytest.mark.django_db

@pytest.fixture(autouse=True)
def banking_alias():
    with mock.patch(
        "payments.mixins.MangopayMixin.get_wallet_banking_alias"
    ) as get_wallet_banking_alias:
        get_wallet_banking_alias.return_value = {
            "iban": "FR7618829754160173622224251",
            "bic": "CMBRFR2BCME",
            "id": "234514543",
            "owner_name": "Test Test",
        }
        yield get_wallet_banking_alias

@pytest.fixture(autouse=True)
def user_wallet():
    with mock.patch("payments.mixins.MangopayMixin.get_user_wallet") as get_user_wallet:
        get_user_wallet.return_value = {
            "Id": "wallet-1",
            "Currency": "EUR",
            "Description": "Default",
        }
        yield get_user_wallet

@pytest.fixture(autouse=True)
def render_pdf():
    with mock.patch("documents.models.Document.render_pdf") as render:
        render.return_value = "PDF"
        yield render

def test_documents_stored_in_storage(bucket, client, order, order_items, buyer):
    buyer.is_cooperative_member = False
    buyer.save()
    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))

    documents = Document.objects.filter(order=order)

    assert documents.count() == 8

    blob = bucket.return_value.blob
    for document in documents:
        blob.assert_any_call(f"documents/{order.id}/{document.pdf_file_name}".encode())

    upload_from_string = blob.return_value.upload_from_string
    assert upload_from_string.call_count == 8
    upload_from_string.assert_called_with("PDF", "application/pdf")

def test_do_not_duplicate_documents(bucket, client, order, order_items, buyer):
    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))
    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))
    documents = Document.objects.filter(order=order)
    assert documents.count() == 7

@override_settings(FEATURES={"routes": True})
def test_documents_stored_in_storage_with_third_party_delivery(
    bucket,
    products,
    delivery_options,
    order,
    order_items,
    client,
    buyer,
    traidoo_region,
):
    buyer.is_cooperative_member = False
    buyer.save()

    products[0].third_party_delivery = True
    products[0].save()

    order_items[0].delivery_option = delivery_options[1]
    order_items[0].save()

    order.recalculate_items_delivery_fee()
    order_items[0].refresh_from_db()

    user = baker.make_recipe("users.user", region=traidoo_region)
    baker.make("jobs.Job", user=user, order_item=order_items[0])

    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))

    documents = Document.objects.filter(order=order)
    assert documents.count() == 8
    blob = bucket.return_value.blob
    for document in documents:
        blob.assert_any_call(f"documents/{order.id}/{document.pdf_file_name}".encode())

    upload_from_string = blob.return_value.upload_from_string
    assert upload_from_string.call_count == 8
    upload_from_string.assert_called_with("PDF", "application/pdf")

def test_do_not_render_credit_note_when_local_platform_not_defined(
    order, order_items, client, traidoo_settings
):

    traidoo_settings.platform_user = None
    traidoo_settings.save()
    response = client.post(
        reverse("task", kwargs={"order_id": order.id, "document_set": "all"})
    )
    assert response.status_code == 200
    assert (
        Document.objects.filter(
            document_type=Document.TYPES.get_value("credit_note"), order_id=order.id
        ).count()
        == 0
    )

def test_do_not_render_credit_note_when_local_share_not_defined(
    order, order_items, client, traidoo_settings
):

    traidoo_settings.central_share = None
    traidoo_settings.save()
    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))
    assert (
        Document.objects.filter(
            document_type=Document.TYPES.get_value("credit_note"), order_id=order.id
        ).count()
        == 0
    )

def test_do_not_render_credit_note_when_central_logistics_not_set(
    order, order_items, client, traidoo_settings
):

    traidoo_settings.enable_platform_fee_share = False
    traidoo_settings.save()
    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))
    assert (
        Document.objects.filter(
            document_type=Document.TYPES.get_value("credit_note"), order_id=order.id
        ).count()
        == 0
    )

def test_do_not_render_credit_note_when_local_platform_share_zero(
    order, order_items, client, traidoo_settings
):
    traidoo_settings.central_share = Decimal("100")
    traidoo_settings.save()
    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))
    assert (
        Document.objects.filter(
            document_type=Document.TYPES.get_value("credit_note"), order_id=order.id
        ).count()
        == 0
    )

def test_documents_sent_to_user_emails_and_invoice_emails(
    send_task,
    buyer,
    seller,
    client,
    order,
    order_items,
    central_platform_user,
    platform_user,
    logistics_user,
):
    buyer.invoice_email = "second-buyer@example.com"
    buyer.save()
    seller.invoice_email = "second-seller@example.com"
    seller.save()

    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))

    assert send_task.call_count == 7

    for email in {
        buyer.email,
        buyer.invoice_email,
        seller.email,
        seller.invoice_email,
        central_platform_user.email,
        platform_user.email,
        logistics_user.email,
    }:
        assert (
            mock.call(
                reverse(
                    "mail-documents", kwargs={"order_id": order.id, "email": email}
                ),
                queue_name="documents-emails",
            )
            in send_task.mock_calls
        )
        assert DocumentSendLog.objects.filter(
            email=email, order_id=order.id, sent=False
        ).exists()

def test_keep_email_send_log_after_exception(
    send_task,
    buyer,
    seller,
    client,
    order,
    order_items,
    central_platform_user,
    platform_user,
    logistics_user,
):

    send_task.side_effect = [True, True, AnymailError("Boom")]
    with pytest.raises(AnymailError):
        client.post(
            reverse("task", kwargs={"order_id": order.id, "document_set": "all"})
        )
    assert DocumentSendLog.objects.count() == 2

def test_use_mangopay_iban_alias_in_order_confirmation(client, order, order_items):
    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))

    order_confirmation = Document.objects.get(document_type="Order Confirmation Buyer")
    assert order_confirmation.seller["iban"] == "FR7618829754160173622224251"
    assert order_confirmation.seller["bic"] == "CMBRFR2BCME"
    assert order_confirmation.bank_account_owner == "Test Test"

    invoices = Document.objects.filter(document_type__contains="Invoice")

    for invoice in invoices:
        assert invoice.seller["iban"] == (
            "Bitte nutzen Sie die Kontodaten in der Bestellzusammenfassung "
            "zur Zahlung aller Rechnungen dieser Bestellung."
        )
        assert not invoice.seller["bic"]

def test_fail_tasks_when_buyer_does_not_have_mangopay_account(order, client):
    previous_user_id = order.buyer.mangopay_user_id
    order.buyer.mangopay_user_id = None
    order.buyer.save()

    with pytest.raises(errors.PaymentError):
        client.post(
            reverse("task", kwargs={"order_id": order.id, "document_set": "all"})
        )

    order.buyer.mangopay_user_id = previous_user_id
    order.buyer.save()

def test_hide_logistics_iban_in_delivery_documents(client, order, order_items):
    client.post(reverse("task", kwargs={"order_id": order.id, "document_set": "all"}))

    for document in Document.objects.filter(document_type__contains="Delivery"):
        assert document.seller["iban"] is None

def test_create_logistics_invoice_for_neighbouring_logistic_company(
    client, order_with_neighbour_product, traidoo_region, neighbour_region
):
    client.post(
        reverse(
            "task",
            kwargs={"order_id": order_with_neighbour_product.id, "document_set": "all"},
        )
    )
    logistic_invoices = Document.objects.filter(
        order=order_with_neighbour_product,
        document_type=Document.TYPES.get_value("logistics_invoice"),
    )

    assert logistic_invoices.count() == 2

    assert set(invoice.seller["company_name"] for invoice in logistic_invoices) == {
        traidoo_region.setting.logistics_company.company_name,
        neighbour_region.setting.logistics_company.company_name,
    }

def test_send_delivery_documents_to_both_logistics_companies_for_cross_region_orders(
    order_with_neighbour_product, buyer, other_region_product, client, send_task
):

    logistics_company_from_producer_region = (
        other_region_product.region.setting.logistics_company
    )
    logistics_company_of_buyer = (
        order_with_neighbour_product.region.setting.logistics_company
    )

    client.post(
        reverse(
            "task",
            kwargs={"order_id": order_with_neighbour_product.id, "document_set": "all"},
        )
    )

    for email in [
        logistics_company_from_producer_region.email,
        logistics_company_of_buyer.email,
    ]:
        assert (
            mock.call(
                reverse(
                    "mail-documents",
                    kwargs={
                        "order_id": order_with_neighbour_product.id,
                        "email": email,
                    },
                ),
                queue_name="documents-emails",
            )
            in send_task.mock_calls
        )

def test_create_buyer_delivery_overview_only_for_buyer_logistics_company(
    order_with_neighbour_product, client
):
    client.post(
        reverse(
            "task",
            kwargs={"order_id": order_with_neighbour_product.id, "document_set": "all"},
        )
    )

    delivery_documents = Document.objects.filter(
        document_type=Document.TYPES.get_value("delivery_overview_buyer")
    )
    assert delivery_documents.count() == 1
    document = delivery_documents.first()

    assert (
        document.seller["email"]
        == order_with_neighbour_product.region.setting.logistics_company.email
    )

def test_do_not_duplicate_send_documents_tasks(client, order, order_items, send_task):
    DocumentSendLog.objects.create(email=order.buyer.email, order_id=order.id)
    response = client.post(
        reverse("task", kwargs={"order_id": order.id, "document_set": "all"})
    )

    assert response.status_code == 200
    assert (
        mock.call(
            reverse(
                "mail-documents",
                kwargs={"order_id": order.id, "email": order.buyer.email},
            ),
            queue_name="documents-emails",
        )
        not in send_task.mock_calls
    )


import re
import inspect
from pymongo import MongoClient

class MongoDBService(object):
    ID_FIELD = "_id"
    KEY_FUNC = "unique_key"

    def __init__(self, db_uri=""):
        self.client = MongoClient(db_uri if db_uri else "mongodb://localhost:27017/default")

    def get_collection(self, cls_or_instance):
        database = self.client.get_default_database()
        collection = self.get_collection_name(cls_or_instance)
        return database[collection]

    def save(self, instance):
        collection = self.get_collection(instance)
        _id = None

        if hasattr(instance, self.ID_FIELD) and getattr(instance, self.ID_FIELD):
            _id = instance._id
        elif hasattr(instance, self.KEY_FUNC):
            key = getattr(instance, self.KEY_FUNC)()
            same = collection.find_one({self.KEY_FUNC: key})
            if same:
                _id = same._id

        instance_dic = self.object_to_dict(instance)
        if _id:
            collection.update_one({"_id": _id}, instance_dic)
        else:
            collection.insert_one(instance_dic)

    @classmethod
    def object_to_dict(cls, instance):
        dic = {}
        for a in inspect.getmembers(instance, lambda a: not inspect.isroutine(a)):
            if not a[0].startswith("_"):
                dic[a[0]] = a[1]

        if hasattr(instance, cls.ID_FIELD) and instance._id:
            dic[cls.ID_FIELD] = instance._id
        if hasattr(instance, cls.KEY_FUNC):
            key = getattr(instance, cls.KEY_FUNC)()
            if key:
                dic[cls.KEY_FUNC] = key

        return dic

    @classmethod
    def get_collection_name(cls, cls_or_instance):
        cls_name = ""
        if type(cls_or_instance) is type:
            cls_name = cls_or_instance.__name__
        else:
            cls_name = type(cls_or_instance).__name__

        collection_name = cls.__camel_to_snake(cls_name)
        return collection_name

    @classmethod
    def __camel_to_snake(cls, name):
        n1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)  # Ab -> A_b
        n2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', n1)  # aB -> a_B
        n3 = n2.lower()  # A_b & a_B -> a_b & a_b
        return n3


import click
from pprint import pformat
from crud.cli.utils import ClickEndpoint, CLICK_MAPPING
from wuphf.abc import Messenger

@click.command(short_help="Send items via Messenger endpoint")
@click.argument('messenger', type=ClickEndpoint(expects=Messenger))
@click.option('--data', type=CLICK_MAPPING)
@click.option('--target', '-t', type=click.STRING,
              help="Optional target, if not using a dedicated messenger")
@click.option('--msg_t', '-m', type=click.STRING,
              help="Optional message template")
@click.pass_context
def wsend(ctx, messenger, data, target, msg_t):
    """Send data or chained items via Messenger endpoint

    \b
    $ wuphf-cli send -t test@example.com gmail:user:pword "msg_text: Hello 123"
    """
    click.echo(click.style('Send Data to Target via Messenger', underline=True, bold=True))

    click.echo(pformat(data))
    click.echo(target)

    if data:
        out = messenger.send(data, target=target, msg_t=msg_t)

    if ctx.obj.get("items"):
        for item in ctx.obj.get("items"):
            out = messenger.send(item.asdict(), target=target, msg_t=msg_t)


import cv2
import os
import math
import pixelDensity
from random import shuffle
import pylab as pl
import numpy as np
import csv
import statistics

#Reads all of the labelled images
def readLabelledData():
	labelled_data = []
	num_files = len(os.listdir('labelled'))
	print('Reading labelled data:')
	for i, file in enumerate(os.listdir('labelled')):
		print(round((i/num_files)*100,2),  end="\r")
		if file.endswith('.pgm'):
			img = cv2.imread('labelled/' + file, 0)
			utf = file[:4]
			labelled_data.append((utf,img))
	return labelled_data

#Reads all of the font images
def readFontData():
	labelled_data = []
	num_files = len(os.listdir('labelled/font_data'))
	print('Reading font data:')
	for i, file in enumerate(os.listdir('labelled/font_data')):
		print(round((i/num_files)*100,2),  end="\r")
		if file.endswith('.pgm'):
			img = cv2.imread('labelled/font_data/' + file, 0)
			utf = file[:4]
			labelled_data.append((utf,img))
	return labelled_data

#Generate a histogram of all of the characters
def generateHistogram(total_data):
	histogram = {}
	for i, (utf,image) in enumerate(total_data):
		if utf in histogram:
			histogram[utf] = histogram[utf] + 1
		else:
			histogram[utf] = 1
	return histogram

#Normalize the histogram between 0 and 1
def normalizedHistogram(histogram):
	normalizedHistogram = {}
	max_value = histogram[max(histogram, key=histogram.get)]
	for key in histogram:
		normalizedHistogram[key] = histogram[key]/max_value
		#print(key + ' ' + repr(normalizedHistogram[key]))
	return normalizedHistogram

#Export the histogram to a csv
def exportHistogram(histogram):
	with open('histogram.csv', 'w', newline='') as csvfile:
		wr = csv.writer(csvfile)
		for key in histogram:
			wr.writerow([key, histogram[key]])

#Returns statistical information about the histogram
def histogramInformation(histogram):
	numbers = [histogram[key] for key in histogram]
	h_mean = statistics.mean(numbers)
	h_median = statistics.median(numbers)
	h_min = min(numbers)
	h_max = max(numbers)
	info = 'Histogram info:\n' + 'Labelled images: '+ repr(sum(numbers)) + '\nClasses: ' + repr(len(histogram)) +'\nMean: ' + repr(h_mean) + '\nMedian: ' + repr(h_median)+'\nMinimum: ' + repr(h_min) + '\nMaximum: ' + repr(h_max)

	return info

def plotHistogram(histogram):
	X = np.arange(len(histogram))
	pl.bar(X, sorted(histogram.values()), align='center', width=0.5)
	pl.xticks(X, histogram.keys())
	ymax = max(histogram.values()) + 1
	pl.ylim(0, ymax)
	pl.show()

if __name__ == "__main__":
	labelled_data = readLabelledData()

	total_data = labelled_data
	histogram = generateHistogram(total_data)
	#print(histogramInformation(histogram))
	plotHistogram(histogram)

	font_data = readFontData()
	total_data = labelled_data + font_data
	histogram = generateHistogram(total_data)
	plotHistogram(histogram)

	norm_histogram = normalizedHistogram(histogram)
	#print(repr(len(total_data)) + ' labelled images')
	#print(repr(len(histogram)) + ' classes')
	exportHistogram(histogram)


while True:
    lst = list(map(int,input().split()))
    # 다 000이면 멈춰
    if lst.count(0) == 3:
        break
    # 그게 아니라면
    else:
        lst.sort()
        if lst[2] >= lst[0] + lst[1]:
            print('Invalid')
        else:
            # 세 변이 같을 때
            if len(set(lst)) == 1:
                print('Equilateral')

            # 두 변이 같을 떄
            elif len(set(lst)) == 2:
                print('Isosceles')

            # 세 변이 다를 때
            else:
                print('Scalene')


import os
import webapp2
import jinja2

from google.appengine.ext import db

template_dir = os.path.join(os.path.dirname(__file__))
jinja_environment = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir),
                               autoescape = True)

class BaseHandler(webapp2.RequestHandler):

    def write(self, *a, **kw):
        self.response.out.write(*a, **kw)

    def render_str(self,template, **params):
        template = jinja_environment.get_template(template)
        return template.render(params)

    def render(self, template, **kw):
        self.write(self.render_str(template, **kw))

class Artwork(db.Model):
    title=db.StringProperty(required = True)
    art = db.TextProperty(required= True)
    created = db.DateTimeProperty(auto_now_add=True)

class MainPage(BaseHandler):
    def render_main(self,title="",art="",error=""):
        arts =  db.GqlQuery("Select * from Artwork Order By created Desc")
        self.render('/templates/asciichan.html',title = title, art = art, arts=arts, error = error)

    def get(self):
        self.render_main()

    def post(self):
        title = self.request.get('title')
        art = self.request.get('art')

        if title and art:
            a = Artwork(title=title, art=art)
            a.put()
            self.redirect('/asciichan')
        else:
            error="Please Fill out both fields"
            self.render_main(title,art,error)

app = webapp2.WSGIApplication([("/asciichan",MainPage)
                              ], debug=True)


'''
import copy

복사받고 싶은 리스트 = copy.deepcopy(복사하고 싶은 리스트)

a = [1,2,3,4]
b = copy.deepcopy(a) -> b = [1,2,3,4]

'''

from collections import deque
import copy
import sys
input = sys.stdin.readline

dx = [-1,1,0,0]
dy = [0,0,-1,1]

def bfs():
    queue = deque()
    #queue에 2의 위치 전부 append
    test_map = copy.deepcopy(lab_map)
    for i in range(n):
        for k in range(m):
            if test_map[i][k] == 2:
                queue.append((i,k))

    while queue:
        x,y = queue.popleft()

        for i in range(4):
          nx = x + dx[i]
          ny = y + dy[i]
          if 0 <= nx < n and 0 <= ny < m:
            if test_map[nx][ny] == 0:
                test_map[nx][ny] =2
                queue.append((nx,ny))

    global result
    count = 0
    for i in range(n):
        for k in range(m):
            if test_map[i][k] == 0:
                count +=1

    result = max(result, count)

def make_wall(count):
    if count == 3:
        bfs()
        return
    for i in range(n):
        for k in range(m):
            if lab_map[i][k] == 0:
                lab_map[i][k] = 1
                make_wall(count+1)
                lab_map[i][k] = 0

n, m = map(int,input().split())
lab_map = [list(map(int,input().split())) for _ in range(n)]

result = 0
make_wall(0)

print(result)


from fastapi import APIRouter, Depends, Request, HTTPException
from routes import api, upload, line, \
    payment, email, sms, logistic, \
    member, websocket
from modules.TOOLS import parse_params_to_sql
import json
router = APIRouter()

# api紀錄操作使用
async def api_record(request: Request, user: dict = Depends(member.get_current_active_user)):
    content = ""
    if request.path_params :
        content = parse_params_to_sql(request.query_params)
    else:
        _payload = {}
        try:
            _payload = dict(await request.form())
            _payload.update(await request.json())
        except Exception as e:
            pass
        content = json.dumps(_payload)

    # api 紀錄操縱人
    record = {
        "username": user.username,
        "ip": request.client.host,
        "path": request.url.path,
        "method": request.method,
        "payload":  content
    }
    print(record)

# api權限確認
async def routes_permission_check(request: Request, user: dict = Depends(member.get_current_active_user)):
    #  有無帶參  帶參單一查詢、 不帶參多重查詢
    if not request.query_params:
        if request.url.path[1:].replace('/', ':') + ":" + request.method + ':ALL' not in user.scope:
            raise HTTPException(status_code=401, detail="No permission")
    else:
        if request.url.path[1:].replace('/', ':') + ":" + request.method not in user.scope:
            raise HTTPException(status_code=401, detail="No permission")

# a
router.include_router(
    api.router,
    prefix="/api",

    # dependencies=[Depends(api_record), Depends(routes_permission_check)]
)

router.include_router(
    upload.router,
    prefix="/upload"
)

router.include_router(
    line.router,
    prefix="/line"
)

router.include_router(
    email.router,
    prefix="/email"
)

router.include_router(
    sms.router,
    prefix="/sms"
)

router.include_router(
    logistic.router,
    prefix="/logistic"
)

router.include_router(
    payment.router,
    prefix="/payment"
)

router.include_router(
    member.router,
    prefix="/member"
)

router.include_router(
    websocket.router,
    prefix="/ws"
)


import os
import shutil

#path = desktop
path = input("enter the name of the directory to be sorted : ")

list_of_files = os.listdir(path)

for file in list_of_files:
     name, ext = os.path.splitext(file)
     myext = ext[1:]

     if myext == '':
          continue

     if os.path.exists(path+'/'+myext):
          shutil.move(path+'/'+file ,  path+'/'+myext+'/'+file)
     else:
          os.makedirs(path+'/'+myext)
          shutil.move(path+'/'+file, path+'/'+myext+'/'+file)


number_reverse1 = {}
number_reverse2 = {}

def is_palindrome(number):
    number_str = str(number)
    length = len(number_str)
    for i in range(0, len(number_str) // 2):
        if number_str[i] != number_str[length - 1 - i]:
            return False

    return True

def reverse(number):
    if number_reverse1.get(number):
        return number_reverse1.get(number)

    if number_reverse2.get(number):
        return number_reverse2.get(number)

    reverse = 0
    number_copy = number
    while number_copy > 0:
        digit = number_copy % 10
        reverse = reverse * 10 + digit
        number_copy = number_copy // 10

    number_reverse1[number] = reverse
    number_reverse2[reverse] = number
    return reverse

def is_lychrel(number):
    for i in range(50):
        number += reverse(number)
        if is_palindrome(number):
            return False

    return True

def count_lychrel_numbers():
    count = 0
    for i in range(1, 10**4):
        if is_lychrel(i):
            count += 1

    return count

print(count_lychrel_numbers())  # 249

## better and improved version

def reverse(number): return int( str(number)[::-1] )

def is_lychrel(number):
    for i in range(50):
        number += reverse(number)
        if number==reverse(number):
            return 0
    return 1

print(sum(is_lychrel(number) for number in range(10**4)))


from django.shortcuts import render_to_response
from django.template import RequestContext

from crowdsourcing.models import Survey

def home(request):
    latest_survey = None
    surveys = Survey.live.order_by('-survey_date')
    if surveys:
        latest_survey = surveys[0]
    return render_to_response(
        "home.html",
        {"latest_survey": latest_survey},
        RequestContext(request))


import os
import gc
import copy
import time
import random
import glob
import string
import wandb
import shutil

# For data manipulation
import numpy as np
import pandas as pd

# Pytorch Imports
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.utils.data import Dataset, DataLoader
from torch.cuda.amp import autocast, GradScaler

# Utils
from tqdm import tqdm
from collections import defaultdict

# Sklearn Imports
from sklearn.metrics import mean_squared_error, accuracy_score
from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold, train_test_split

# PytorchVideo Imports
import pytorchvideo
from pytorchvideo.transforms import (
    UniformCropVideo,
    ApplyTransformToKey,
    Normalize,
    RandomShortSideScale,
    RemoveKey,
    ShortSideScale,
    UniformTemporalSubsample
)
from torchvision.transforms._transforms_video import (
    CenterCropVideo,
    NormalizeVideo,
)
from pytorchvideo.data.encoded_video import EncodedVideo
from torchvision.transforms import (
    Compose,
    Lambda,
    RandomCrop,
    RandomHorizontalFlip
)
from pytorchvideo.models import create_res_basic_head

# # For colored terminal text
# from colorama import Fore, Back, Style
#
# b_ = Fore.BLUE
# y_ = Fore.YELLOW
# sr_ = Style.RESET_ALL
#
# # Suppress warnings
# import warnings
#
# warnings.filterwarnings("ignore")

# For descriptive error messages
os.environ['CUDA_LAUNCH_BLOCKING'] = "1"

Config = {"seed": 2022,
          "data_path": "/content/dataset",
          "epochs": 15,
          "size": 768,
          "train_batch_size": 22,
          "valid_batch_size": 22,
          "num_workers": 12,
          "lr": 1e-4,
          "scheduler": 'CosineAnnealingLR',
          "min_lr": 1e-6,
          "T_0": 20,
          "T_max": 500,
          "weight_decay": 1e-6,
          "n_fold": 5,
          "n_accumulate": 1,
          "num_labels": 600,
          "margin": 0.5,
          "clip_duration": 2,
          "device": torch.device("cuda:0" if torch.cuda.is_available() else "cpu"),
          'wandb': True,
          'apex': True,
          'n_accum': 1,
          "debug": False
          }

def set_seed(seed=42):
    '''Sets the seed of the entire notebook so results are the same every time we run.
    This is for REPRODUCIBILITY.'''
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    # When running on the CuDNN backend, two further options must be set
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    # Set a fixed value for the hash seed
    os.environ['PYTHONHASHSEED'] = str(seed)

set_seed(Config['seed'])

# TODO: Fix the "files" path here
files = glob.glob("/content/data/**/**/*.mp4")
labels = [file.split("/")[-2] for file in files]
print(f"No of videos: {len(files)}")

df = pd.DataFrame({"file_path": files, "labels": labels})
train_df, val_df = train_test_split(df, test_size=0.2, stratify=df['labels'])

# TODO: Local dataset creation to be kept or removed?
for label in np.unique(labels):
    os.makedirs(f"dataset/train/{label}", exist_ok=True)
    os.makedirs(f"dataset/val/{label}", exist_ok=True)

for _, row in train_df.iterrows():
    label = row.file_path.split("/")[-2]
    file_name = row.file_path.split("/")[-1]
    shutil.copy(row["file_path"], f"dataset/train/{label}/{file_name}")

for _, row in val_df.iterrows():
    label = row.file_path.split("/")[-2]
    file_name = row.file_path.split("/")[-1]
    shutil.copy(row["file_path"], f"dataset/val/{label}/{file_name}")

side_size = 256
mean = [0.45, 0.45, 0.45]
std = [0.225, 0.225, 0.225]
crop_size = 256
num_frames = 32
sampling_rate = 2
frames_per_second = 30
alpha = 4

class PackPathway(torch.nn.Module):
    """
    Transform for converting video frames as a list of tensors
    """

    def __init__(self):
        super().__init__()

    def forward(self, frames: torch.Tensor):
        fast_pathway = frames
        # Perform temporal sampling from the fast pathway

        slow_pathway = torch.index_select(
            frames,
            1,
            torch.linspace(
                0, frames.shape[1] - 1, frames.shape[1] // alpha
            ).long(),
        )

        frame_list = [slow_pathway, fast_pathway]
        return frame_list

# TODO: Can explain these transformations either in code/ppt/doc
train_transform = ApplyTransformToKey(
    key="video",
    transform=Compose(
        [
            UniformTemporalSubsample(num_frames),
            Lambda(lambda x: x / 255.0),
            NormalizeVideo(mean, std),
            ShortSideScale(
                size=side_size
            ),
            CenterCropVideo(crop_size),
            PackPathway()
        ]
    )
)

# The duration of the input clip is also specific to the model.
Config['clip_duration'] = (num_frames * sampling_rate) / frames_per_second

train_dataset = pytorchvideo.data.Kinetics(
    data_path=os.path.join(Config['data_path'], "train"),
    clip_sampler=pytorchvideo.data.make_clip_sampler("random", Config["clip_duration"]),
    transform=train_transform,
    decode_audio=False
)

val_dataset = pytorchvideo.data.Kinetics(
    data_path=os.path.join(Config["data_path"], "val"),
    clip_sampler=pytorchvideo.data.make_clip_sampler("random", Config["clip_duration"]),
    transform=train_transform,
    decode_audio=False
)

# Creating dataloaders using PyTorch Dataloader
train_loader = torch.utils.data.DataLoader(
    train_dataset,
    batch_size=Config["train_batch_size"],
    num_workers=Config["num_workers"],
)

val_loader = torch.utils.data.DataLoader(
    val_dataset,
    batch_size=Config["valid_batch_size"],
    num_workers=Config["num_workers"],
)

class videoModel(nn.Module):
    def __init__(self):
        super(videoModel, self).__init__()
        model_name = "slowfast_r50"
        self.model = torch.hub.load(
            'facebookresearch/pytorchvideo',
            model=model_name,
            pretrained=False
        )
        self.model.blocks[-1] = create_res_basic_head(
            in_features=2304,
            out_features=Config["num_labels"],
            pool=None
        )

    def forward(self, x):
        output = self.model(x)
        return output

model = videoModel()
model.to(Config['device'])

def criterion(outputs, labels):
    return nn.CrossEntropyLoss()(outputs, labels)

optimizer = optim.Adam(model.parameters(), lr=Config['lr'],
                       weight_decay=Config['weight_decay'])
scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=Config['T_max'],
                                           eta_min=Config['min_lr'])

def train_one_epoch(model, optimizer, scheduler, dataloader, device, epoch):
    model.train()

    dataset_size = 0
    running_loss = 0.0

    bar = tqdm(enumerate(dataloader), total=len(train_df) // Config['train_batch_size'])

    for step, x in bar:
        videos = [video.to(Config['device']) for video in x['video']]
        labels = x['label'].to(device, dtype=torch.long)

        batch_size = len(videos)
        outputs = model(videos)
        loss = criterion(outputs=outputs, labels=labels)
        loss = loss / Config['n_accumulate']

        loss.backward()

        if (step + 1) % Config['n_accumulate'] == 0:
            optimizer.step()

            # Zero the parameter gradients
            optimizer.zero_grad()

            if scheduler is not None:
                scheduler.step()

        running_loss += (loss.item() * batch_size)
        dataset_size += batch_size

        epoch_loss = running_loss / dataset_size
        bar.set_postfix(
            Epoch=epoch, Train_Loss=epoch_loss,
            LR=optimizer.param_groups[0]['lr']
        )
    gc.collect()

    return epoch_loss

@torch.inference_mode()
def valid_one_epoch(model, dataloader, device, epoch):
    model.eval()

    dataset_size = 0
    running_loss = 0.0
    targets = []
    outs = []

    bar = tqdm(enumerate(dataloader), total=len(val_df) // Config["valid_batch_size"])
    for step, x in bar:
        videos = [video.to(Config['device']) for video in x["video"]]
        labels = x['label'].to(device, dtype=torch.long)

        batch_size = len(videos)

        outputs = model(videos)
        loss = criterion(outputs, labels)
        outs.append(outputs.detach())
        targets.extend(labels)

        running_loss += (loss.item() * batch_size)
        dataset_size += batch_size

        epoch_loss = running_loss / dataset_size

        bar.set_postfix(Epoch=epoch, Valid_Loss=epoch_loss,
                        LR=optimizer.param_groups[0]['lr'])

    outs = torch.vstack(outs)
    outs = outs.to('cpu')
    targets = torch.tensor(targets, device='cpu')
    epoch_acc = accuracy(outs, targets, topk=(1, 5))
    gc.collect()

    return epoch_loss, epoch_acc

def accuracy(output: torch.Tensor, target: torch.Tensor, topk=(1,)):
    """
    Computes the accuracy over the k top predictions for the specified values of k
    In top-5 accuracy you give yourself credit for having the right answer
    if the right answer appears in your top five guesses.

    ref:
    - https://pytorch.org/docs/stable/generated/torch.topk.html
    - https://discuss.pytorch.org/t/imagenet-example-accuracy-calculation/7840
    - https://gist.github.com/weiaicunzai/2a5ae6eac6712c70bde0630f3e76b77b
    - https://discuss.pytorch.org/t/top-k-error-calculation/48815/2
    - https://stackoverflow.com/questions/59474987/how-to-get-top-k-accuracy-in-semantic-segmentation-using-pytorch

    :param output: output is the prediction of the model e.g. scores, logits, raw y_pred before normalization or getting classes
    :param target: target is the truth
    :param topk: tuple of topk's to compute e.g. (1, 2, 5) computes top 1, top 2 and top 5.
    e.g. in top 2 it means you get a +1 if your models's top 2 predictions are in the right label.
    So if your model predicts cat, dog (0, 1) and the true label was bird (3) you get zero
    but if it were either cat or dog you'd accumulate +1 for that example.
    :return: list of topk accuracy [top1st, top2nd, ...] depending on your topk input
    """
    with torch.no_grad():
        # ---- get the topk most likely labels according to your model
        # get the largest k \in [n_classes] (i.e. the number of most likely probabilities we will use)
        maxk = max(topk)  # max number labels we will consider in the right choices for out model
        batch_size = target.size(0)

        # get top maxk indicies that correspond to the most likely probability scores
        # (note _ means we don't care about the actual top maxk scores just their corresponding indicies/labels)
        _, y_pred = output.topk(k=maxk, dim=1)  # _, [B, n_classes] -> [B, maxk]
        y_pred = y_pred.t()  # [B, maxk] -> [maxk, B] Expects input to be <= 2-D tensor and transposes dimensions 0 and 1.

        # - get the credit for each example if the models predictions is in maxk values (main crux of code)
        # for any example, the model will get credit if it's prediction matches the ground truth
        # for each example we compare if the model's best prediction matches the truth. If yes we get an entry of 1.
        # if the k'th top answer of the model matches the truth we get 1.
        # Note: this for any example in batch we can only ever get 1 match (so we never overestimate accuracy <1)
        target_reshaped = target.view(1, -1).expand_as(y_pred)  # [B] -> [B, 1] -> [maxk, B]
        # compare every topk's model prediction with the ground truth & give credit if any matches the ground truth
        correct = (
                y_pred == target_reshaped)  # [maxk, B] were for each example we know which topk prediction matched truth
        # original: correct = pred.eq(target.view(1, -1).expand_as(pred))

        # -- get topk accuracy
        list_topk_accs = []  # idx is topk1, topk2, ... etc
        for k in topk:
            # get tensor of which topk answer was right
            ind_which_topk_matched_truth = correct[:k]  # [maxk, B] -> [k, B]
            # flatten it to help compute if we got it correct for each example in batch
            flattened_indicator_which_topk_matched_truth = ind_which_topk_matched_truth.reshape(
                -1).float()  # [k, B] -> [kB]
            # get if we got it right for any of our top k prediction for each example in batch
            tot_correct_topk = flattened_indicator_which_topk_matched_truth.float().sum(dim=0,
                                                                                keepdim=True)  # [kB] -> [1]
            # compute topk accuracy - the accuracy of the mode's ability to get it right within it's top k guesses/preds
            topk_acc = tot_correct_topk / batch_size  # topk accuracy for entire batch
            list_topk_accs.append(topk_acc)
        return list_topk_accs  # list of topk accuracies for entire batch [topk1, topk2, ... etc]

def run_training(model, optimizer, scheduler, device, num_epochs):
    # To automatically log gradients
    #     wandb.watch(model, log_freq=100)

    if torch.cuda.is_available():
        print("[INFO] Using GPU: {}\n".format(torch.cuda.get_device_name()))

    start = time.time()
    best_model_wts = copy.deepcopy(model.state_dict())
    best_5_acc = 0.0

    for epoch in range(1, num_epochs + 1):
        gc.collect()
        train_epoch_loss = train_one_epoch(model, optimizer, scheduler,
                                           dataloader=train_loader,
                                           device=Config['device'], epoch=epoch)

        val_epoch_loss, val_acc = valid_one_epoch(model, val_loader,
                                                  device=Config['device'],
                                                  epoch=epoch)

        val_1_acc, val_5_acc = val_acc[0].item(), val_acc[1].item()

        #         # Log the metrics
        #         wandb.log({"Train Loss": train_epoch_loss})
        #         wandb.log({"Valid Loss": val_epoch_loss})
        #         wandb.log({"Top 1 Accuracy": val_1_acc})
        #         wandb.log({"Top 5 Accuracy": val_5_acc})

        # deep copy the model
        if val_5_acc >= best_5_acc:
            print(f"{b_}Validation Acc Improved ({best_5_acc} ---> {val_5_acc})")
            best_5_acc = val_5_acc
            best_model_wts = copy.deepcopy(model.state_dict())
            PATH = "Acc{:.4f}_epoch{:.0f}.bin".format(best_5_acc, epoch)
            torch.save(model.state_dict(), PATH)
            # Save a model file from the current directory
            print(f"Model Saved{sr_}")

        print()

    end = time.time()
    time_elapsed = end - start
    print('Training complete in {:.0f}h {:.0f}m {:.0f}s'.format(
        time_elapsed // 3600, (time_elapsed % 3600) // 60, (time_elapsed % 3600) % 60))
    print("Best Top5 Accuracy: {:.4f}".format(best_5_acc))

    # load best model weights
    model.load_state_dict(best_model_wts)

    return model

model = run_training(model, optimizer, scheduler,
                     device=Config['device'],
                     num_epochs=Config['epochs'])


'''
Author: keqin
Time: 2019-06-11

Follower_server:
There can be many follower_servers in a program.
The follower_server can connect with clients and leader_servers.
The follower_server assign client_id to clients when a new connection is created.
It forwards preempt/release request of clients to leader_servers and forwards the response of leader_server to clients.
And it responses to check request of clients.
When lock_map changes, it change its local lock_map according to leader_server's message.
'''
from socket import *
import threading
from threading import Thread

# class Follower_Server(Thread):
class Follower_Server():

    def __init__(self,selfport,leaderport):
        super().__init__()
        self.selfport = selfport
        self.leaderport = leaderport
        self.lock_map = []
        self.clients = []
        self.connections = []
        self.followerid = None

    def _connect_with_leaderserver(self,host,port):
        print("start to connect with leader_server")
        leader_socket = socket(AF_INET,SOCK_STREAM)
        leader_socket.connect((host, port))
        senddata = "NewFollower"
        leader_socket.sendall(senddata.encode())
        print("follower send data")
        data = leader_socket.recv(1024).decode('utf-8')
        msg = data.split(":")
        if msg[0] == "FollowerId":
            FollowerId = int(msg[1])
            self.followerid = FollowerId
        return leader_socket, FollowerId

    def _forward_down(self,leader_socket):
        '''
        forward messsage of leader_server to clients
        :return:
        '''
        while True:
            data = leader_socket.recv(1024).decode()
            if not data:
                continue
            msg = data.split(":")

            if msg[0] == 'UpdateLockmap':
                self.lock_map.append({'name':msg[1],'client':msg[2]})
                print("UpdateLockmap")
                continue
            if msg[0] == 'RemoveLockmap':
                self.lock_map.remove({'name':msg[1],'client':msg[2]})
                print("RemoveLockmap")
            if msg[0] == 'PreemptLock Success' or msg[0] == 'PreemptLock Failed' or msg[0] == 'ReleaseLock Success' or msg[0] == 'ReleaseLock Failed':
                client_id = msg[1]
                for client in self.clients:
                    if client['client_id'] == int(client_id):
                        client['socket'].sendall((msg[0]).encode())

    def _new_client(self,c_socket):
        client_id = self.followerid*1000 + len(self.clients) + 1
        self.clients.append({'client_id':client_id,'socket':c_socket})
        return client_id

    def _forward_up(self,leader_socket,c_socket):
        while True:
            data = c_socket.recv(1024).decode()
            if not data:
                continue
            if data == 'NewClient':
                client_id = self._new_client(c_socket)
                c_socket.sendall(("ClientId:%d"%(client_id)).encode())
                continue

            msg = data.split(":")
            if msg[0] == "PreemptLock":
                leader_socket.sendall(("PreemptLock:%s:%d"%(msg[1], int(msg[2]))).encode())
                continue

            if msg[0] == "ReleaseLock":
                leader_socket.sendall(("ReleaseLock:%s:%d"%(msg[1], int(msg[2]))).encode())
                continue

            if msg[0] == "CheckLock":
                if self.lock_map:
                    for lock in self.lock_map:
                        if lock['name'] == msg[1]:
                            # lock_name = lock['name']
                            client_id = lock['client']
                            break
                    c_socket.sendall(("CheckLock:Lock:%d"%(int(client_id))).encode())
                else:
                    c_socket.sendall(("there is no locks in server").encode())

    def run(self):
        host = '127.0.0.1'

        # connect to leader_server
        leader_socket, follower_id = self._connect_with_leaderserver(host,self.leaderport)
        print("leader socket and follower_id")
        print(leader_socket,follower_id)
        forward_down = threading.Thread(target=self._forward_down, args=(leader_socket,))
        forward_down.setDaemon(True)
        forward_down.start()

        # bind self socket
        s = socket(AF_INET,SOCK_STREAM)
        s.bind((host,self.selfport))
        s.listen(3)
        print(s, "listening##########################")

        while True:
            c_soc, addr = s.accept()
            print("connect with ",addr)
            forward_up = threading.Thread(target=self._forward_up,args=(leader_socket,c_soc))
            forward_up.setDaemon(True)
            forward_up.start()
#
# f_server = Follower_Server(9001,9000)
# f_server.run()


"""
1. utils functions
"""
import time
import math
import shlex
import datetime
import collections
import subprocess
import numpy as np

# system
def get_time():
    """
    return accurate time point in format: Year-Month-Day-Hour:Minute:Second.unique_labels
    """
    return datetime.datetime.fromtimestamp(time.time()).strftime('%Y_%m_%d_%H_%M_%S_%f')

def get_user_name():
    cmd = "whoami"
    process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    out, err = process.communicate()
    return out

def get_array_list(runs):
    rlist = []
    if not isinstance(runs,str):
        return None
    for each in runs.split(","):
        if each == "":
            continue
        elif "-" in each:
            start,end = each.split("-")
            rlist.extend(range(int(start),int(end)+1))
        else:
            rlist.append(int(each))
    return rlist

def get_process_params(params_list=None,params_dict=None,dname=None):
    class Params:
        def __init__(self,status=False,params={},launch={}):
            self.status = status
            self.params = params
            self.launch = launch

    if params_dict and dname:
        p = Params()
        inputs = params_dict.get(dname)
        if inputs:
            p.status = inputs.get("status") or True
            p.params = inputs.get("params") or {}
            p.launch = inputs.get("launch") or {}
            return p
        return p

    p = Params()
    if not isinstance(params_list,list):
        return p
    if len(params_list)==0:
        p.status = True
        return p

    p.status = True
    for one_args in params_list:
        if ";" in one_args:
            one_args = one_args.split(";")
        else:
            one_args = [one_args]
        for key_val in one_args:
            key,val = key_val.split("=")
            if val.lower()=="none":
                p.params[key] = None
            elif val.lower()=="true":
                p.params[key] = True
            elif val.lower()=="false":
                p.params[key] = False
            else:
                try:
                    p.params[key] = int(val)
                except:
                    try:
                        p.params[key] = float(val)
                    except:
                        p.params[key] = val
    return p

def get_params_from_text(fname):
    process = {}
    class Params:
        def __init__(self,status=False,params={},launch={}):
            self.status = status
            self.params = params
            self.launch = launch

    with open(fname,"r") as f:
        content = f.readlines()

    for line in content:
        if line.startswith("- "):
            action = line.strip().split("-")[1].strip()
            process[action] = Params()
    return process

## python tools
def dict_merge(x1, x2):
    for key, val in x2.iteritems():
        if isinstance(val, collections.Mapping):
            x1[key] = dict_merge(x1.get(key, {}), val)
        else:
            x1[key] = val
    return x1

def dict_append(x1, x2):
    for key, val in x2.iteritems():
        if isinstance(val, collections.Mapping):
            x1[key] = dict_append(x1.get(key, {}), val)
        else:
            if isinstance(x1[key],list):
                if isinstance(val,list):
                    x1[key].extend(val)
                else:
                    x1[key].append(val)
            else:
                if isinstance(val,list):
                    x1[key] = [x1[key]] + val
                else:
                    x1[key] = [x1[key], val]
    return x1

## math tools
def dotproduct(x, y):
    return sum((a*b) for a, b in zip(x, y))

def length(x):
    return math.sqrt(dotproduct(x, x))

def angle(x, y):
    """
    Returns value in degree.
    """
    return math.acos(dotproduct(x, y) / (length(x) * length(y))) * 180. / np.pi

def phi2quaternion(phi, rotAxis="x"):
    """
    phi: in degree unit
    """
    angle = phi*np.pi/180.
    if rotAxis.lower() == "x":
        return (np.cos(angle/2.), np.sin(angle/2.), 0., 0.)
    elif rotAxis.lower() == "y":
        return (np.cos(angle/2.), 0., np.sin(angle/2.), 0.)
    elif rotAxis.lower() == "z":
        return (np.cos(angle/2.), 0., 0., np.sin(angle/2.))
    else:
        return None

def quaternion2rotation(quaternion):
    rot = np.zeros([3,3])
    (q0, q1, q2, q3) = quaternion
    q01 = q0*q1
    q02 = q0*q2
    q03 = q0*q3
    q11 = q1*q1
    q12 = q1*q2
    q13 = q1*q3
    q22 = q2*q2
    q23 = q2*q3
    q33 = q3*q3

    rot[0, 0] = (1. - 2.*(q22 + q33))
    rot[0, 1] = 2.*(q12 - q03)
    rot[0, 2] = 2.*(q13 + q02)
    rot[1, 0] = 2.*(q12 + q03)
    rot[1, 1] = (1. - 2.*(q11 + q33))
    rot[1, 2] = 2.*(q23 - q01)
    rot[2, 0] = 2.*(q13 - q02)
    rot[2, 1] = 2.*(q23 + q01)
    rot[2, 2] = (1. - 2.*(q11 + q22))
    return rot

def meshgrid2D(size, center=None):
    (nx, ny) = size
    if center is None:
        cx = (nx-1.)/2.
        cy = (ny-1.)/2.
    else:
        (cx,cy) = center

    x = np.arange(nx) - cx
    y = np.arange(ny) - cy
    xaxis, yaxis = np.meshgrid(x, y, indexing='ij')
    return xaxis, yaxis

def meshgrid3D(size, center=None):
    (nx, ny, nz) = size
    if center is None:
        cx = (nx-1.)/2.
        cy = (ny-1.)/2.
        cz = (nz-1.)/2.
    else:
        (cx,cy,cz) = center

    x = np.arange(nx)-cx
    y = np.arange(ny)-cy
    z = np.arange(nz)-cz
    xaxis, yaxis, zaxis = np.meshgrid(x,y,z, indexing='ij')
    return xaxis, yaxis, zaxis

def make2DRadius(size, center=None):
    xaxis, yaxis = meshgrid2D(size, center=center)
    radius = np.sqrt(xaxis**2 + yaxis**2)
    return radius, xaxis, yaxis

def make3DRadius(size, center=None):
    xaxis, yaxis, zaxis = meshgrid2D(size, center=center)
    radius = np.sqrt(xaxis**2 + yaxis**2 + zaxis**2)
    return radius, xaxis, yaxis, zaxis

def eulerAngles2rotation(_theta, mode="rad"):
    """
    _theta = (angle 1, angle 2, angle 3)
    """
    if mode == "rad":
        theta = _theta
    else:
        theta = np.array(_theta)/180.0*np.pi

    Rx = np.array([[1,         0,                  0               ],
                   [0,         np.cos(theta[0]), -np.sin(theta[0]) ],
                   [0,         np.sin(theta[0]),  np.cos(theta[0]) ]])

    Ry = np.array([[np.cos(theta[1]),    0,      np.sin(theta[1])  ],
                   [0,                   1,                    0   ],
                   [-np.sin(theta[1]),   0,      np.cos(theta[1])  ]])

    Rz = np.array([[np.cos(theta[2]),    -np.sin(theta[2]),       0],
                   [np.sin(theta[2]),     np.cos(theta[2]),       0],
                   [0,                   0,                       1]])

    R = np.dot(Rz, np.dot( Ry, Rx ))
    return R


'''
Programa para testar validação de dados de entrada
Autor: Douglas Silva
Data: 13/06/2023

Write a program that asks users for their sandwich preferences. The program should use PyInputPlus
to ensure that they enter valid input, such as:

Using inputMenu() for a bread type: wheat, white, or sourdough.
Using inputMenu() for a protein type: chicken, turkey, ham, or tofu.
Using inputYesNo() to ask if they want cheese.
If so, using inputMenu() to ask for a cheese type: cheddar, Swiss, or mozzarella.
Using inputYesNo() to ask if they want mayo, mustard, lettuce, or tomato.
Using inputInt() to ask how many sandwiches they want. Make sure this number is 1 or more.
Come up with prices for each of these options, and have your program display a total cost after
the user enters their selection.
'''

import pyinputplus as pyip

sandwhich = dict()
prices = {'wheat' : 1, 'white' : 1, 'sourdough' : 2,
          'chicken' : 2, 'turkey' : 2, 'ham' :2 , 'tofu': 1.5,
          'cheddar' : 1.5, 'Swiss' : 1.5, 'mozzarella': 1.5,
          'mayo' : 1, 'mustard' : 1, 'lettuce' : 1, 'tomato': 1}
price = 0
itemPrice = 0
bread = pyip.inputMenu(['wheat', 'white', 'sourdough'], numbered=True, prompt='Choose your bread: \n')
sandwhich.setdefault(bread, 1)
protein = pyip.inputMenu(['chicken', 'turkey', 'ham', 'tofu'], numbered=True, prompt='Choose your protein: \n')
sandwhich.setdefault(protein, 1)
wantCheese = pyip.inputYesNo(prompt='Do you want cheese? \n')
if wantCheese == 'yes':
    cheese = pyip.inputMenu(['cheddar', 'Swiss', 'mozzarella'], numbered=True, prompt='Choose your cheese: \n')
    sandwhich.setdefault(cheese, 1)
for complement in ['mayo', 'mustard', 'lettuce', 'tomato']:
    wantComplement = pyip.inputYesNo(prompt='Do you want %s ? \n' %(complement))
    if wantComplement == 'yes':
        sandwhich.setdefault(complement, 1)
qntySandwhiches = pyip.inputInt('How many sandwhiches do you want ? \n')
for sandwhichItem, value in sandwhich.items():
    sandwhich[sandwhichItem] = value * qntySandwhiches
    itemPrice = prices.get(sandwhichItem)*sandwhich.get(sandwhichItem)
    price += itemPrice

print(f'You ordered {qntySandwhiches} of the following sandwhich:')
for sandwhichItem in sandwhich.keys():
    print(sandwhichItem)
print(20*'-')
print(f'The price of your order is {price}')


'''

Problem title:  Multiples of 3 and 5
Summary: Find sum of all the multiples of 3 or 5 below 1000

'''

def problem_1(number):
	summation=0
	for x in range(1,number):
		if x%3==0:
			summation+=x
		elif x%5==0:
			summation+=x
	print("The sum is: " + str(summation))


import json

from django.http import JsonResponse

from .models import Course
from ..core.models import Comment

def api_date_range(request):
    data = json.loads(request.body)

    comments = Comment.objects.filter(course__code=data['course_code'])

    comments = comments.filter(date__range=[data['start_date'], data['end_date']])

    positive_comments = 0
    negative_comments = 0
    positive_percentage_by_range = 0
    negative_percentage_by_range = 0

    if comments.count() != 0:
        positive_comments = comments.filter(rating='positive').count()
        negative_comments = comments.filter(rating='negative').count()
        positive_percentage_by_range = round((positive_comments/comments.count())*100,1)
        negative_percentage_by_range = round((negative_comments/comments.count())*100,1)

    context = {
        'positive_comments_by_range': positive_comments,
        'positive_percentage_by_range': positive_percentage_by_range,
        'negative_comments_by_range': negative_comments,
        'negative_percentage_by_range': negative_percentage_by_range
    }

    return JsonResponse(context)

def api_remove_course(request):
    data = json.loads(request.body)

    course = Course.objects.get(code=data['course_code'])

    course.delete()

    return JsonResponse({'success': True})