#! /usr/bin/env python3
import argparse
import numpy as np
import h5py
from CT_utils import *
from matplotlib import pyplot as plt
import copy
import random
from CTP_config import config
import pyVector
import os

if __name__ == "__main__":

    # Parsing command line
    parser = argparse.ArgumentParser(description='Program to create patient formatted file for Tmax estimation')
    parser.add_argument("dcm_dir", help="Directory path containing the DCM files of a patient", type=str)
    parser.add_argument("tmax_dir", help="Directory containing the Tmax value file", type=str)
    parser.add_argument("wind_cent", help="Windowing center value", type=float)
    parser.add_argument("wind_widt", help="Windowing width value", type=float)
    parser.add_argument("out_file", help="Output HDF5 file contaning processed data", type=str)
    parser.add_argument("--verbose","-v", help="Verbosity level of the code", default=True, type=bool)
    parser.add_argument("--size","-s", help="Spatial average filter width", default=2, type=int)
    parser.add_argument("--desample","-d", help="Spatial desampling", default=2, type=int)
    parser.add_argument("--raw", help="Provide raw CT data (1/0)", type=int)
    parser.add_argument("--SEP", help="Output SEP files", default=1, type=int)
    parser.add_argument("--slice", help="Use a subset of data by slicing (set to 1 to activate)", type=int)
    parser.add_argument("--min1", help="Minimum window value on axis #1 [mm]", type=float)
    parser.add_argument("--max1", help="Maximum window value on axis #1 [mm]", type=float)
    parser.add_argument("--min2", help="Minimum window value on axis #2 [mm]", type=float)
    parser.add_argument("--max2", help="Maximum window value on axis #2 [mm]", type=float)
    parser.add_argument("--i_min3", help="Minimum depth index (starts at 0) on axis #3 [mm]", type=int)
    parser.add_argument("--i_max3", help="Maximum depth index (starts at 0) on axis #3 [mm]", type=int)
    args = parser.parse_args()

    ##### Debugging tests
    # x = np.zeros((3,))
    # y = np.reshape(x, (x.shape[0],1,1))
    # print("x shape: ", x.shape)
    # print("y shape: ", y.shape)
    # print("x: ", x)
    # print("y: ", y)
    #
    # z = np.ones((3,2,3))
    # print("z shape: ", z.shape)
    # a1 = z * x
    # a2 = z * y
    # print("a1 shape: ", a1.shape)
    # print("a2 shape: ", a2.shape)

    # exit(0)
    # x = np.arange(0.0, 10.0, 0.75)
    # print("x[11]: ", x[11])
    # print("x shape: ", x.shape)
    # y = x[0:11]
    # print("y: ", y)
    # print("y shape: ", y.shape)
    # exit(0)

    # Processing parsing arguments
    # Display information
    verb = args.verbose

    # Other necessary arguments
    wind_c = args.wind_cent # Hounsfield units window center
    wind_w = args.wind_widt # Hounsfield units window width
    out_file = args.out_file
    size = args.size # Spatial average filter width
    desample = args.desample # Spatial average filter width
    raw = True if args.raw == 1 else False
    SEP = True if args.SEP == 1 else False

    # Paramter to extract a subset of the data
    if args.slice == 1: subset = True
    else: subset = False

    if verb:
        print("Window center [HU]: ", wind_c)
        print("Window width [HU]: ", wind_w)
        print("Output file: ", out_file)
        print("Spatial average filter width: ", args.size)
        if raw: print("User has requested to output raw data")
        if SEP: print("User has requested to output SEP files")

    # Getting file folders
    dmc_dir = args.dcm_dir
    tmax_dir = args.tmax_dir

    # Adding final slash if necessary
    if dmc_dir[-1] != "/":
        dmc_dir += "/"
    if tmax_dir[-1] != "/":
        tmax_dir += "/"

    if verb:
        print("DCM directory: ", dmc_dir)
        print("tmax directory: ", tmax_dir)

    # Reading Tmax file
    # if verb:
    #     print("Reading Tmax values at %s" % tmax_dir)
    # tmax, tmax_z_axis = read_Tmax(tmax_dir)
    # tmax_raw = copy.deepcopy(tmax)
    # tmax_z_axis_raw = copy.deepcopy(tmax_z_axis)
    # if verb:
    #     print("Tmax-map rotation")
    # tmax = tmax_rotation(tmax, ang)
    # exit(0)

    # Output file names
    # out_raw_file = "raw_"+out_file # Output file for raw
    # out_file_ctMasked = "ctMasked_"+out_file # Output file for CT data maked with the mask based on CT values
    # out_file_tmaxMasked = "tmaxMasked_"+out_file # Output file for CT data maked with mase based on TMax values
    # out_ctMask = "ctMask_"+out_file # Output file for the mask based on CT values
    # out_tmaxMask = "ctMask_"+out_file # Output file for the mask based on TMax values
    # out_train = "train_"+out_file # Output file for training format

    ############################################################################
    ######################### Ettore's processing steps ########################
    ############################################################################
    # Processing slices
    if verb:
        print("Reading data at: ",  dmc_dir)
    ct_image, x_axis_ct, y_axis_ct, z_axis_ct, time_axes = read_slices(dmc_dir, verbose=verb)

    # Saving initial "raw" data
    if raw:
        ct_image_raw = copy.deepcopy(ct_image)
        x_axis_ct_raw = copy.deepcopy(x_axis_ct)
        y_axis_ct_raw = copy.deepcopy(y_axis_ct)
        z_axis_ct_raw = copy.deepcopy(z_axis_ct)
        time_axis_raw = np.arange(55,)

    if verb:
        print("Image rotation")
    ct_image, ang = image4D_rotation(ct_image)
    if verb:
        print("Co-registering slices")
    ct_image_reg = image4D_registration(ct_image)

    if verb:
        print("Creating skull-stripping mask")
    inner_mask, use_Tmax = skull_strip_mask_4d(ct_image_reg)
    print("nb of non-zero element inner_mask: ", np.sum(inner_mask))

    if verb:
        print("Windowing slices with window centered at %s and width of %s"%(wind_c, wind_w))
    ct_image_reg_wind = window_image4D(ct_image_reg, wind_c, wind_w)

    # Space desampling (for now simple desampling)
    if verb:
        print("Applying a %s-point moving average on CT images and desampling by a factor of %s" % (size, desample) )
    ct_image_reg_wind = spatial_ave_image4d(ct_image_reg_wind, size=size)[:,:,::desample,::desample]
    x_axis_ct = x_axis_ct[::desample]
    y_axis_ct = y_axis_ct[::desample]
    inner_mask = inner_mask[:,::desample,::desample]

    dx = x_axis_ct[1]-x_axis_ct[0]
    dy = y_axis_ct[1]-y_axis_ct[0]
    dz = z_axis_ct[1]-z_axis_ct[0]

    # Time interpolation
    large_gap = False # Flag to check if a larger time sampling is deteched
    if np.diff(time_axes).max() > 4.0:
        large_gap = True
        print("WARNING! Large time sampling gap detected for %s" % dmc_dir)
    if verb:
        print("Performing time interpolation to regularize time sample")
    ct_image_reg_wind, time_axis = interpolate_time_image4d(ct_image_reg_wind, time_axes)
    n_rect = 6
    if verb:
        print("Performing time filtering with time filter length of %s" % n_rect)
    ct_image_reg_wind = filter_time_image4d(ct_image_reg_wind, n_rect)

    # Reading Tmax file
    if verb:
        print("Reading Tmax values at %s" % tmax_dir)
    tmax, tmax_z_axis = read_Tmax(tmax_dir)
    print("tmax min value: ",np.min(tmax))
    print("tmax max value: ",np.max(tmax))
    tmax_raw = copy.deepcopy(tmax)
    tmax_z_axis_raw = copy.deepcopy(tmax_z_axis)
    if verb:
        print("Tmax-map rotation")
    tmax = tmax_rotation(tmax, ang)

    ############################# Applying mask ################################
    # Creating the mask based on CT values
    print("ct_image_reg_wind shape: ", ct_image_reg_wind.shape)
    ct_avg = np.mean(ct_image_reg_wind,axis=0)
    ct_max = np.max(ct_image_reg_wind,axis=0)
    print("ct_max shape: ", ct_max.shape)
    print("ct_max min: ", np.min(ct_max))
    print("ct_max max: ", np.max(ct_max))
    print("config.ct_inf: ", config.ct_inf)
    print("config.ct_sup: ", config.ct_sup)
    mask_ct = 1.0*(ct_max > config.ct_inf) * (ct_max < config.ct_sup) # Create mask based on CT max/min values
    print("nb of non-zero element mask ct: ", np.sum(mask_ct))
    print("ct_image_reg_wind min: ", np.min(ct_image_reg_wind))
    print("ct_image_reg_wind max: ", np.max(ct_image_reg_wind))
    print("mask_ct shape: ", mask_ct.shape)
    print("ct_image_reg_wind shape: ", ct_image_reg_wind.shape)
    test = mask_ct*ct_image_reg_wind
    print("test shape: ", test.shape)
    print("test min: ", np.min(test))
    print("test max: ", np.max(test))
    print("mask_ct shape: ", mask_ct.shape)

    ########################## Extract a subset of the image ###################
    if subset:

        # Get min/max axes values
        min1=args.min1 if args.min1 != None else x_axis_ct[0]
        max1=args.max1 if args.max1 != None else x_axis_ct[len(x_axis_ct)-1]
        min2=args.min2 if args.min2 != None else y_axis_ct[0]
        max2=args.max2 if args.max2 != None else y_axis_ct[len(x_axis_ct)-1]
        i_min3=args.i_min3 if args.i_min3 != None else 0
        i_max3=args.i_max3 if args.i_max3 != None else len(z_axis_ct)

        print("User has requested to process a subset of the CT image")
        print("x min: ", min1, "[mm]")
        print("x max: ", max1, "[mm]")
        print("y min: ", min2, "[mm]")
        print("y max: ", max2, "[mm]")
        print("iz min: ", i_min3, "[sample]")
        print("iz max: ", i_max3, "[sample]")

        # Compute index for bounds
        i_min1 = np.argmin(np.abs(min1-x_axis_ct)) # Index on the x-axis for min x-value
        i_max1 = np.argmin(np.abs(max1-x_axis_ct)) # Index on the x-axis for max x-value
        i_min2 = np.argmin(np.abs(min2-y_axis_ct)) # Index on the y-axis for min y-value
        i_max2 = np.argmin(np.abs(max2-y_axis_ct)) # Index on the y-axis for max y-value
        if i_min1 >= i_max1 or i_min2 >= i_max2 or i_min3 > i_max3:
            sys.exit('Please provide valid bounds')

        if verb:
            print("i_min1: ", i_min1)
            print("i_max1: ", i_max1)
            print("i_min2: ", i_min2)
            print("i_max2: ", i_max2)
            print("i_min3: ", i_min3)
            print("i_max3: ", i_max3)

        # Update the axes
        print("Shape axes before windowing: ")
        print("x-axis shape: ", x_axis_ct.shape)
        print("y-axis shape: ", y_axis_ct.shape)
        print("z-axis shape: ", z_axis_ct.shape)
        print("z-tmax_z_axis: ", tmax_z_axis)
        print("type z-tmax_z_axis: ", type(tmax_z_axis))
        print("type z_axis_ct: ", type(z_axis_ct))
        x_axis_ct = x_axis_ct[i_min1:i_max1+1]
        y_axis_ct = y_axis_ct[i_min2:i_max2+1]
        z_axis_ct = z_axis_ct[i_min3:i_max3+1]
        tmax_z_axis = tmax_z_axis[i_min3:i_max3+1]
        print("Shape axes after windowing: ")
        print("x-axis shape: ", x_axis_ct.shape)
        print("y-axis shape: ", y_axis_ct.shape)
        print("z-axis shape: ", z_axis_ct.shape)
        print("z-tmax_z_axis: ", tmax_z_axis)
        print("type z-tmax_z_axis: ", type(tmax_z_axis))
        print("type z_axis_ct: ", type(z_axis_ct))

        # Extract the data
        print("Shape arrays before windowing: ")
        print("ct_image_reg_wind shape: ", ct_image_reg_wind.shape)
        print("tmax shape: ", tmax.shape)
        print("inner_mask shape: ", inner_mask.shape)
        print("use_Tmax shape: ", use_Tmax.shape)
        ct_image_reg_wind = ct_image_reg_wind[:,i_min3:i_max3+1,i_min2:i_max2+1,i_min1:i_max1+1]
        tmax = tmax[i_min3:i_max3+1,i_min2:i_max2+1,i_min1:i_max1+1]
        inner_mask = inner_mask[i_min3:i_max3+1,i_min2:i_max2+1,i_min1:i_max1+1]
        mask_ct = mask_ct[i_min3:i_max3+1,i_min2:i_max2+1,i_min1:i_max1+1]
        use_Tmax = use_Tmax[i_min3:i_max3+1]
        print("Shape arrays after windowing: ")
        print("ct_image_reg_wind shape: ", ct_image_reg_wind.shape)
        print("tmax shape: ", tmax.shape)
        print("inner_mask shape: ", inner_mask.shape)
        print("use_Tmax shape: ", use_Tmax.shape)

    print("-"*40)
    print("tmax max: ", np.max(tmax))
    print("tmax min: ", np.min(tmax))
    print("tmax avg: ", np.mean(tmax))
    tmax_qc = 1.0*(tmax > 400)
    print("nb elements greater than 400 in tmax: ", np.sum(tmax_qc))
    print("-"*40)

    ######################### Convert to training format #######################
    print("shape inner_mask: ", inner_mask.shape)
    print("shape mask_ct: ", mask_ct.shape)
    print("nb of non-zero element inner_mask: ", np.sum(inner_mask))
    # print("nb of non-zero element use_Tmax: ", np.sum(use_Tmax))
    print("nb of non-zero element mask_ct: ", np.sum(mask_ct))
    skull_mask = inner_mask*np.reshape(use_Tmax,(use_Tmax.shape[0],1,1))*mask_ct
    # skull_mask = inner_mask*mask_ct
    print("Shape use_Tmax: ", use_Tmax.shape)
    print("nb of non-zero element use_Tmax: ", np.sum(use_Tmax))
    print("nb of non-zero element skull_mask: ", np.sum(skull_mask))
    print("shape skull_mask: ", skull_mask.shape)
    n_train = int(np.sum(skull_mask)) # Compute the number of non-zero elements in the mask
    print("nb of training data point for this patient: ", n_train)

    data_train = np.zeros((n_train, 1, ct_image_reg_wind.shape[0])) # 2D array that contains the CT image for all voxels
    tmax_train = np.zeros((n_train, 1)) # 2D array that contains the TMax values for all voxels
    xyz_index = np.zeros((n_train, 3)) # 2D arrays that contain the (x,y,z) index
    nx = ct_image_reg_wind.shape[3]
    ny = ct_image_reg_wind.shape[2]
    nz = ct_image_reg_wind.shape[1]
    i_train = 0
    for iz in range(nz):
        for iy in range(ny):
            for ix in range(nx):
                if skull_mask[iz,iy,ix] > 0.0:
                    data_train[i_train, 0, :] = ct_image_reg_wind[:,iz,iy,ix]
                    tmax_train[i_train, 0] = tmax[iz,iy,ix]
                    xyz_index[i_train,2] = iz # Record the index on the z-axis for this example
                    xyz_index[i_train,1] = iy # Record the index on the y-axis for this example
                    xyz_index[i_train,0] = ix # Record the index on the x-axis for this example
                    i_train+=1

    # Apply mask to CT data
    print("Max value CT before mask: ", np.max(ct_image_reg_wind))
    print("Min value CT before mask: ", np.min(ct_image_reg_wind))
    ct_image_reg_wind_mask = ct_image_reg_wind*skull_mask
    tmax_mask = tmax*skull_mask
    print("Max value CT after mask: ", np.max(ct_image_reg_wind_mask))
    print("Min value CT after mask: ", np.min(ct_image_reg_wind_mask))

    # Apply mask one more time
    print("Applying mask twice: ")
    inner_mask_new, use_Tmax_new = skull_strip_mask_4d(ct_image_reg_wind)
    ct_image_reg_wind_new = ct_image_reg_wind*inner_mask_new
    print("Done applying mask twice")

    ############################################################################
    ############################# Saving files #################################
    ############################################################################

    ################################# Qc #######################################
    if verb:
        print("Shape 4D data: ", ct_image_reg_wind.shape)
        print("Shape 3D TMax: ", tmax.shape)
        print("Large gap?: ", large_gap)
        print("Shape of training data: ", data_train.shape)
        print("Shape of labels: ", tmax_train.shape)
        # print("nx: ", x_axis_ct.shape[0], "dx: ", x_axis_ct[1]-x_axis_ct[0], "ox: ", x_axis_ct[0])
        # print("ny: ", y_axis_ct.shape[0], "dy: ", y_axis_ct[1]-y_axis_ct[0], "oy: ", y_axis_ct[0])
        # print("nz: ", z_axis_ct.shape[0], "dz: ", z_axis_ct[1]-z_axis_ct[0], "oz: ", z_axis_ct[0])
        # print("nt: ", time_axis.shape[0], "dt: ", time_axis[1]-time_axis[0], "ot: ", time_axis[0])
        if raw:
            print("Shape 4D raw data: ", ct_image_raw.shape)
            print("Shape 3D raw TMax: ", tmax_raw.shape)
            print("raw nx: ", x_axis_ct_raw.shape[0], "raw dx: ", x_axis_ct_raw[1]-x_axis_ct_raw[0], "raw ox: ", x_axis_ct_raw[0])
            print("raw ny: ", y_axis_ct_raw.shape[0], "raw dy: ", y_axis_ct_raw[1]-y_axis_ct_raw[0], "raw oy: ", y_axis_ct_raw[0])
            print("raw nz: ", z_axis_ct_raw.shape[0], "raw dz: ", z_axis_ct_raw[1]-z_axis_ct_raw[0], "raw oz: ", z_axis_ct_raw[0])
            print("raw nt: ", time_axis_raw.shape[0], "raw dt: ", time_axis_raw[1]-time_axis_raw[0], "raw ot: ", time_axis_raw[0])

    ############################### Processed data #############################
    # HF files
    if verb:
        print("Writing output .h5 file: ", out_file)
    hf = h5py.File(out_file, 'w')

    # Data/Labels
    hf.create_dataset('4d_cube', data=ct_image_reg_wind) # 4D pre-processed data (not masked)
    hf.create_dataset('tmax', data=tmax) # TMax 3D map
    hf.create_dataset('data_train', data=data_train) # Data processed + masked reshaped in 3D for PyTorch
    hf.create_dataset('tmax_train', data=tmax_train) # Labeled processed + masked reshaped in 2D for PyTorch
    hf.create_dataset('xyz_index', data=xyz_index) # 3D Array containing indicied for training points
    hf.create_dataset('skull_mask', data=skull_mask) # Flag to check whether an inner brain portion has been found
    hf.create_dataset('4d_cube_m', data=ct_image_reg_wind_mask) # Flag to check whether an inner brain portion has been found
    hf.create_dataset('tmax_m', data=tmax_mask) # Flag to check whether an inner brain portion has been found
    hf.create_dataset('4d_cube_new', data=ct_image_reg_wind_new) # Flag to check whether an inner brain portion has been found
    # Axes
    hf.create_dataset('x_axis', data=x_axis_ct)
    hf.create_dataset('y_axis', data=y_axis_ct)
    hf.create_dataset('z_axis', data=z_axis_ct)
    hf.create_dataset('large_gap', data=large_gap) # Time-axis QC
    hf.create_dataset('time_axis', data=time_axis)
    hf.create_dataset('tmax_z_axis', data=tmax_z_axis)

    hf.create_dataset('mask_ct', data=mask_ct) # 3D mask based on TMax values
    hf.create_dataset('inner_mask', data=inner_mask) # Skull-stripping mask
    # hf.create_dataset('use_Tmax', data=use_Tmax) # Flag to check whether an inner brain portion has been found

    # Write raw data
    if raw:
        hf.create_dataset('4d_cube_raw', data=ct_image_raw)
        hf.create_dataset('x_axis_raw', data=x_axis_ct_raw)
        hf.create_dataset('y_axis_raw', data=y_axis_ct_raw)
        hf.create_dataset('z_axis_raw', data=z_axis_ct_raw)
        hf.create_dataset('time_axis_raw', data=time_axis_raw)
        hf.create_dataset('tmax_raw', data=tmax_raw)
        hf.create_dataset('tmax_z_axis_raw', data=tmax_z_axis_raw)
    # Close file
    hf.close()

    # Write SEP files
    if SEP:
        if verb:
            print("Writing file for processed data in SEP format")
        hf = h5py.File(out_file, 'r')

        # Get axis information
        ox = x_axis_ct[0]
        oy = y_axis_ct[0]
        oz = z_axis_ct[0]

        # Processed CT image
        imageCT = np.array(hf.get("4d_cube"), dtype=np.float32)
        vec = pyVector.vectorIC(imageCT)
        vec.writeVec(out_file+"_ct.H")
        command="echo 'o1="+str(ox)+" d1="+str(dx)+" o2="+str(oy)+" d2="+str(dy)+ " o3="+str(oz)+" d3="+str(dz)+"'>> "+out_file+"_ct.H"
        os.system(command)

        # TMax map
        tmax = np.array(hf.get("tmax"), dtype=np.float32)
        vec = pyVector.vectorIC(tmax)
        vec.writeVec(out_file+"_tmax.H")
        command="echo 'o1="+str(ox)+" d1="+str(dx)+" o2="+str(oy)+" d2="+str(dy)+ " o3="+str(oz)+" d3="+str(dz)+"'>> "+out_file+"_tmax.H"
        os.system(command)

        # Training data
        data_train = np.array(hf.get("data_train"), dtype=np.float32)
        vec = pyVector.vectorIC(data_train)
        vec.writeVec(out_file+"_data_train.H")

        # Training labels
        tmax_train = np.array(hf.get("tmax_train"), dtype=np.float32)
        vec = pyVector.vectorIC(tmax_train)
        vec.writeVec(out_file+"_tmax_train.H")

        # Position indices
        xyz_index = np.array(hf.get("xyz_index"), dtype=np.float32)
        vec = pyVector.vectorIC(xyz_index)
        vec.writeVec(out_file+"_xyz_index.H")

        # Skull mask
        skull_mask = np.array(hf.get("skull_mask"), dtype=np.float32)
        vec = pyVector.vectorIC(skull_mask)
        vec.writeVec(out_file+"_skull_mask.H")
        command="echo 'o1="+str(ox)+" d1="+str(dx)+" o2="+str(oy)+" d2="+str(dy)+ " o3="+str(oz)+" d3="+str(dz)+"'>> "+out_file+"_skull_mask.H"
        os.system(command)

        # Inner mask
        mask_ct = np.array(hf.get("mask_ct"), dtype=np.float32)
        vec = pyVector.vectorIC(mask_ct)
        vec.writeVec(out_file+"_mask_ct.H")
        command="echo 'o1="+str(ox)+" d1="+str(dx)+" o2="+str(oy)+" d2="+str(dy)+ " o3="+str(oz)+" d3="+str(dz)+"'>> "+out_file+"_mask_ct.H"
        os.system(command)

        # CT data after masking
        imageCT_masked = np.array(hf.get("4d_cube_m"), dtype=np.float32)
        vec = pyVector.vectorIC(imageCT_masked)
        vec.writeVec(out_file+"_ctm.H")
        command="echo 'o1="+str(ox)+" d1="+str(dx)+" o2="+str(oy)+" d2="+str(dy)+ " o3="+str(oz)+" d3="+str(dz)+"'>> "+out_file+"_ctm.H"
        os.system(command)

        # Tmax after masking
        tmax_m = np.array(hf.get("tmax_m"), dtype=np.float32)
        vec = pyVector.vectorIC(tmax_m)
        vec.writeVec(out_file+"_tmax_m.H")
        command="echo 'o1="+str(ox)+" d1="+str(dx)+" o2="+str(oy)+" d2="+str(dy)+ " o3="+str(oz)+" d3="+str(dz)+"'>> "+out_file+"_tmax_m.H"
        os.system(command)

        # Tmax after masking
        inner_mask = np.array(hf.get("inner_mask"), dtype=np.float32)
        vec = pyVector.vectorIC(inner_mask)
        vec.writeVec(out_file+"_inner_mask.H")
        command="echo 'o1="+str(ox)+" d1="+str(dx)+" o2="+str(oy)+" d2="+str(dy)+ " o3="+str(oz)+" d3="+str(dz)+"'>> "+out_file+"_inner_mask.H"
        os.system(command)

        # Tmax after masking
        cube_new = np.array(hf.get("4d_cube_new"), dtype=np.float32)
        vec = pyVector.vectorIC(cube_new)
        vec.writeVec(out_file+"_ctm_new.H")
        command="echo 'o1="+str(ox)+" d1="+str(dx)+" o2="+str(oy)+" d2="+str(dy)+ " o3="+str(oz)+" d3="+str(dz)+"'>> "+out_file+"_ctm_new.H"
        os.system(command)

        # SEP files
        if raw:
            if verb: print("Writing SEP files for raw data")
            hf_raw = h5py.File(out_file, 'r')
            imageCT_raw = np.array(hf_raw.get("4d_cube_raw"), dtype=np.float32)
            vec = pyVector.vectorIC(imageCT_raw)
            vec.writeVec(out_file+"_ct_raw.H")
            tmax_raw = np.array(hf_raw.get("tmax_raw"), dtype=np.float32)
            vec = pyVector.vectorIC(tmax_raw)
            vec.writeVec(out_file+"_tmax_raw.H")


""" Gamestate is a single snapshot in time of the game that represents all necessary information
        to make gameplay decisions
"""
from dataclasses import dataclass, field

import numpy as np

import melee
from melee import enums

@dataclass
class Position:
    """Dataclass for position types. Has (x, y) coords."""
    x: np.float32 = np.float32(0)
    y: np.float32 = np.float32(0)

Speed = Position
Cursor = Position

@dataclass
class ECB:
    """ECBs (Environmental collision box) info. It's a diamond with four points that define it."""
    top: Position = field(default_factory=Position)
    bottom: Position = field(default_factory=Position)
    left: Position = field(default_factory=Position)
    right: Position = field(default_factory=Position)

class GameState(object):
    """Represents the state of a running game of Melee at a given moment in time"""
    __slots__ = ('frame', 'stage', 'menu_state', 'submenu', 'player', 'players', 'projectiles', 'stage_select_cursor_x',
                 'stage_select_cursor_y', 'ready_to_start', 'distance', 'menu_selection', '_newframe', 'playedOn', 'startAt',
                 'consoleNick', 'is_teams', '_fod_platform_left', '_fod_platform_right', 'custom')
    def __init__(self):
        self.frame = -10000
        """int: The current frame number. Monotonically increases. Can be negative."""
        self.stage = enums.Stage.FINAL_DESTINATION
        """enums.Stage: The current stage being played on"""
        self.menu_state = enums.Menu.IN_GAME
        """enums.MenuState: The current menu scene, such as IN_GAME, or STAGE_SELECT"""
        self.submenu = enums.SubMenu.UNKNOWN_SUBMENU
        """(enums.SubMenu): The current sub-menu"""
        self.players = dict()
        """(dict of int - gamestate.PlayerState): Dict of PlayerState objects. Key is controller port"""
        self.player = self.players
        """(dict of int - gamestate.PlayerState): WARNING: Deprecated. Will be removed in version 1.0.0. Use `players` instead
                Dict of PlayerState objects. Key is controller port"""
        self.projectiles = []
        """(list of Projectile): All projectiles (items) currently existing"""
        self.stage_select_cursor_x = 0.0
        """(float): DEPRECATED. Use `players[X].cursor` instead. Will be removed in 1.0.0. Stage select cursor's X coordinate. Ranges from -27 to 27"""
        self.stage_select_cursor_y = 0.0
        """(float): DEPRECATED. Use `players[X].cursor` instead. Will be removed in 1.0.0. Stage select cursor's Y coordinate. Ranges from -19 to 19"""
        self.ready_to_start = False
        """(bool): Is the 'ready to start' banner showing at the character select screen?"""
        self.is_teams = False
        """(bool): Is this a teams game?"""
        self.distance = 0.0
        """(float): Euclidian distance between the two players. (or just Popo for climbers)"""
        self.menu_selection = 0
        """(int): The index of the selected menu item for when in menus."""
        self.startAt = ""
        """(string): Timestamp string of when the game started. Such as '2018-06-22T07:52:59Z'"""
        self.playedOn = ""
        """(string): Platform the game was played on (values include dolphin, console, and network). Might be blank."""
        self.consoleNick = ""
        """(string): The name of the console the replay was created on. Might be blank."""
        self._newframe = True
        self._fod_platform_left, self._fod_platform_right = 0, 0
        """(float): The current height of FoD platforms"""
        self.custom = dict()
        """(dict): Custom fields to be added by the user"""

class PlayerState(object):
    """ Represents the state of a single player """
    __slots__ = ('character', 'character_selected', 'x', 'y', 'percent', 'shield_strength', 'stock', 'facing',
                 'action', 'action_frame', 'invulnerable', 'invulnerability_left', 'hitlag_left', 'hitstun_frames_left',
                 'jumps_left', 'on_ground', 'speed_air_x_self', 'speed_y_self', 'speed_x_attack', 'speed_y_attack',
                 'speed_ground_x_self', 'cursor_x', 'cursor_y', 'coin_down', 'controller_status', 'off_stage', 'iasa',
                 'moonwalkwarning', 'controller_state', 'ecb_bottom', 'ecb_top', 'ecb_left', 'ecb_right',
                 'costume', 'cpu_level', 'is_holding_cpu_slider', 'nana', 'position', 'cursor', 'ecb', 'nickName', 'connectCode',
                 'team_id', 'is_powershield')
    def __init__(self):
        # This value is what the character currently is IN GAME
        #   So this will have no meaning while in menus
        #   Also, this will change dynamically if you change characters
        #       IE: Shiek/Zelda
        self.character = enums.Character.UNKNOWN_CHARACTER
        """(enum.Character): The player's current character"""
        # This value is what character is selected at the character select screen
        #   Don't use this value when in-game
        self.character_selected = enums.Character.UNKNOWN_CHARACTER
        self.position = Position()
        """(Position): x, y character position"""
        self.x = 0
        """(float): DEPRECATED. Use `position` instead. Will be removed in 1.0.0. The character's X position"""
        self.y = 0
        """(float): DEPRECATED. Use `position` instead. Will be removed in 1.0.0. The character's Y position"""
        self.percent = 0
        """(int): The player's damage"""
        self.shield_strength = 60.
        """(float): The player's shield strength (max 60). Shield breaks at 0"""
        self.is_powershield = False
        """(bool): Is the current action a Powershield? (not directly determinable via action states)"""
        self.stock = 0
        """(int): The player's remaining stock count"""
        self.facing = True
        """(bool): Is the character facing right? (left is False). Characters in Melee must always be facing left or right"""
        self.action = enums.Action.UNKNOWN_ANIMATION
        """(enum.Action): The current action (or animation) the character is in"""
        self.action_frame = 0
        """(int): What frame of the Action is the character in? Indexed from 1."""
        self.invulnerable = False
        """(bool): Is the player invulnerable?"""
        self.invulnerability_left = 0
        """(int): How many frames of invulnerability are left."""
        self.hitlag_left = 0
        """(bool): How many more frames of hitlag there is"""
        self.hitstun_frames_left = 0
        """(int): How many more frames of hitstun there is"""
        self.jumps_left = 0
        """(int): Number of jumps available. Including ground jump. Will be 2 for most characters on ground."""
        self.on_ground = True
        """(bool): Is the character on the ground?"""
        self.speed_air_x_self = 0
        """(float): Self-induced horizontal air speed"""
        self.speed_y_self = 0
        """(float): Self-induced vertical speed"""
        self.speed_x_attack = 0
        """(float): Attack-induced horizontal speed"""
        self.speed_y_attack = 0
        """(float): Attack-induced vertical speed"""
        self.speed_ground_x_self = 0
        """(float): Self-induced horizontal ground speed"""
        self.nana = None
        """(enums.PlayerState): Additional player state for Nana, if applicable.
                If the character is not Ice Climbers, Nana will be None.
                Will also be None if this player state is Nana itself.
                Lastly, the secondary climber is called 'Nana' here, regardless of the costume used."""
        self.cursor = Cursor()
        """(Position): x, y cursor position"""
        self.cursor_x = 0
        """(float): DEPRECATED. Use `cursor` instead. Will be removed in 1.0.0. Cursor X value"""
        self.cursor_y = 0
        """(float): DEPRECATED. Use `position` instead. Will be removed in 1.0.0. Cursor Y value"""
        self.coin_down = False
        """(bool): Is the player's character selection coin placed down? (Does not work in Slippi selection screen)"""
        self.controller_status = enums.ControllerStatus.CONTROLLER_UNPLUGGED
        """(enums.ControllerStatus): Status of the player's controller."""
        self.off_stage = False
        """(bool): Helper variable to say if the character is 'off stage'. """
        self.iasa = 0
        self.moonwalkwarning = False
        """(bool): Helper variable to tell you that if you dash back right now, it'll moon walk"""
        self.controller_state = melee.controller.ControllerState()
        """(controller.ControllerState): What buttons were pressed for this character"""
        self.ecb = ECB()
        self.ecb_right = (0, 0)
        """(float, float): Right edge of the ECB. (x, y) offset from player's center."""
        self.ecb_left = (0, 0)
        """(float, float): Left edge of the ECB. (x, y) offset from player's center."""
        self.ecb_top = (0, 0)
        """(float, float): Top edge of the ECB. (x, y) offset from player's center."""
        self.ecb_bottom = (0, 0)
        """(float, float): Bottom edge of the ECB. (x, y) offset from player's center."""
        self.costume = 0
        """(int): Index for which costume the player is wearing"""
        self.cpu_level = False
        """(bool): CPU level of player. 0 for a libmelee-controller bot or human player."""
        self.is_holding_cpu_slider = False
        """(bool): Is the player holding the CPU slider in the character select screen?"""
        self.nickName = ""
        """(string): The in-game nickname for the player. Might be blank."""
        self.connectCode = ""
        """(string): The rollback connect code for the player. Might be blank."""
        self.team_id = 0
        """(int): The team ID of the player. This is different than costume, and only relevant during teams."""

class Projectile:
    """ Represents the state of a projectile (items, lasers, etc...) """
    def __init__(self):
        self.position = Position()
        """(Position): x, y projectile position"""
        self.x = 0
        """(float): DEPRECATED. Use `position` instead. Will be removed in 1.0.0. Projectile's X position"""
        self.y = 0
        """(float): DEPRECATED. Use `position` instead. Will be removed in 1.0.0. Projectile's Y position"""
        self.speed = Speed()
        """(Position): x, y projectile speed"""
        self.x_speed = 0
        """(float): DEPRECATED. Use `speed` instead. Will be removed in 1.0.0. Projectile's horizontal speed"""
        self.y_speed = 0
        """(float): DEPRECATED. Use `speed` instead. Will be removed in 1.0.0. Projectile's vertical speed"""
        self.owner = -1
        """(int): Player port of the projectile's owner. -1 for no owner"""
        self.type = enums.ProjectileType.UNKNOWN_PROJECTILE
        """(enums.ProjectileType): Which actual projectile type this is"""
        self.frame = 0
        """(int): How long the item has been out"""
        self.subtype = 0
        """(int): The subtype of the item. Many projectiles have 'subtypes' that make them different. They're all different, so it's not an enum"""

def port_detector(gamestate, character, costume):
    """Autodiscover what port the given character is on

    Slippi Online assigns us a random port when playing online. Find out which we are

    Returns:
        [1-4]: The given character belongs to the returned port
        0: We don't know.

    Args:
        gamestate: Current gamestate
        character: The character we know we picked
        costume: Costume index we picked
    """
    detected_port = 0
    for i, player in gamestate.players.items():
        if player.character == character and player.costume == costume:
            if detected_port > 0:
                return 0
            detected_port = i

    return detected_port


import os
import glob
import requests
import json
import cv2
import numpy as np
import re
import sys
import torch
from PIL import Image
from pprint import pprint
import base64
from io import BytesIO
import torchvision.transforms.functional as F
from torchvision.io import read_video, read_image, ImageReadMode
from torchvision.models.optical_flow import Raft_Large_Weights
from torchvision.models.optical_flow import raft_large
from torchvision.io import read_video, read_image, ImageReadMode
from torchvision.utils import flow_to_image
import cv2
from torchvision.io import write_jpeg
import pickle

import argparse

def get_args():
    parser = argparse.ArgumentParser()

    parser.add_argument('--prompt', dest='prompt', default="")
    parser.add_argument('--negative-prompt', dest='negative_prompt', default="")

    parser.add_argument('--init-image', dest='init_image', default="./init.png")
    parser.add_argument('--input-dir', dest='input_dir', default="./Input_Images")
    parser.add_argument('--output-dir', dest='output_dir', default="./output")

    parser.add_argument('--width', default=720, type=int)
    parser.add_argument('--height', default=1280, type=int)

    return parser.parse_args()

args = get_args()

device = "cuda" if torch.cuda.is_available() else "cpu"

model = raft_large(weights=Raft_Large_Weights.DEFAULT, progress=False).to(device)
model = model.eval()

# Replace with the actual path to your image file and folder

os.makedirs(args.output_dir, exist_ok=True)

def get_image_paths(folder):
    image_extensions = ("*.jpg", "*.jpeg", "*.png", "*.bmp")
    files = []
    for ext in image_extensions:
        files.extend(glob.glob(os.path.join(folder, ext)))
    return sorted(files)

y_paths = get_image_paths(args.input_dir)

def get_controlnet_models():
    url = "http://localhost:7860/controlnet/model_list"

    temporalnet_model = None
    temporalnet_re = re.compile("^temporalnetversion2 \[.{8}\]")

    ip2p_model = None
    ip2p_re = re.compile("^control_.*ip2p.* \[.{8}\]")

    tile_model = None
    tile_re = re.compile("^control_.*tile.* \[.{8}\]")

    depth_model = None
    depth_re = re.compile("^control_.*depth.* \[.{8}\]")

    lineart_model = None
    lineart_re = re.compile("^control_.*lineart.* \[.{8}\]")

    softedge_model = None
    softedge_re = re.compile("^control_.*softedge.* \[.{8}\]")

    response = requests.get(url)
    if response.status_code == 200:
        models = json.loads(response.content)
    else:
        raise Exception("Unable to list models from the SD Web API! "
                        "Is it running and is the controlnet extension installed?")

    for model in models['model_list']:
        if temporalnet_model is None and temporalnet_re.match(model):
            temporalnet_model = model
        elif ip2p_model is None and ip2p_re.match(model):
            ip2p_model = model
        elif tile_model is None and tile_re.match(model):
            tile_model = model
        elif depth_model is None and depth_re.match(model):
            depth_model = model
        elif lineart_model is None and lineart_re.match(model):
            lineart_model = model
        elif softedge_model is None and softedge_re.match(model):
            softedge_model = model

    assert temporalnet_model is not None, "Unable to find the temporalnet2 model!  Ensure it's copied into the stable-diffusion-webui/extensions/models directory!"
    assert ip2p_model is not None, "Unable to find the ip2p_model model!  Ensure it's copied into the stable-diffusion-webui/extensions/models directory!"
    assert depth_model is not None, "Unable to find the depth model!  Ensure it's copied into the stable-diffusion-webui/extensions/models directory!"
    assert tile_model is not None, "Unable to find the tile model!  Ensure it's copied into the stable-diffusion-webui/extensions/models directory!"
    assert lineart_model is not None, "Unable to find the lineart model!  Ensure it's copied into the stable-diffusion-webui/extensions/models directory!"
    assert softedge_model is not None, "Unable to find the lineart model!  Ensure it's copied into the stable-diffusion-webui/extensions/models directory!"
    return temporalnet_model, ip2p_model, depth_model, tile_model, lineart_model, softedge_model

TEMPORALNET_MODEL, IP2P_MODEL, DEPTH_MODEL, TILE_MODEL, LINEART_MODEL, SOFTEDGE_MODEL  = get_controlnet_models()

def send_request(last_image_path, optical_flow_path,current_image_path):
    url = "http://localhost:7860/sdapi/v1/txt2img"

    with open(last_image_path, "rb") as b:
       last_image_encoded = base64.b64encode(b.read()).decode("utf-8")

    # Load and process the last image
    last_image = cv2.imread(last_image_path)
    last_image = cv2.cvtColor(last_image, cv2.COLOR_BGR2RGB)

    # Load and process the optical flow image
    flow_image = cv2.imread(optical_flow_path)
    flow_image = cv2.cvtColor(flow_image, cv2.COLOR_BGR2RGB)

    # Load and process the current image
    with open(current_image_path, "rb") as b:
       current_image = base64.b64encode(b.read()).decode("utf-8")

    # Concatenating the three images to make a 6-channel image
    six_channel_image = np.dstack((last_image, flow_image))

    # Serializing the 6-channel image
    serialized_image = pickle.dumps(six_channel_image)

    # Encoding the serialized image
    encoded_image = base64.b64encode(serialized_image).decode('utf-8')

    data = {
        "init_images": [current_image],
        "inpainting_fill": 0,
        "inpaint_full_res": True,
        "inpaint_full_res_padding": 1,
        "inpainting_mask_invert": 1,
        "resize_mode": 0,
        "prompt": args.prompt,
        "negative_prompt": args.negative_prompt,
        "alwayson_scripts": {
            "ControlNet":{
                "args": [
                    {
                        "input_image": current_image,
                        "module": "lineart_realistic",
                        "model": LINEART_MODEL,
                        "weight": 0.35,
                        "guidance": 1,
                        "pixel_perfect": True,
                        "resize_mode": 0,
                        "control_mode": 0,
                   },
                    {
                        "input_image": encoded_image,
                        "model": TEMPORALNET_MODEL,
                        "module": "none",
                        "weight": 1.0,
                        "guidance_end": 0.4,
                        "guidance_start": 0,
                        # "processor_res": 512,
                        "pixel_perfect": True,
                        "threshold_a": 64,
                        "threshold_b": 64,
                        "resize_mode": 0,
                        "control_mode": 2,
                    },
                    {
                        "input_image": current_image,
                        "model": IP2P_MODEL,
                        "module": "none",
                        "weight": 1.0,
                        "guidance": 1,
                        "guidance_end": 0.6,
                        "guidance_start": 0,
                        "pixel_perfect": True,
                        "resize_mode": 0,
                        "control_mode": 0,
                    },
                    #{
                    #    "input_image": current_image,
                    #    "model": TILE_MODEL,
                    #    "module": "tile_colorfix",
                    #    "weight": 0.4,
                    #    "guidance": 1,
                    #   "pixel_perfect": True,
                    #    "resize_mode": 0,
                    #    "control_mode": 0,
                   # },

                ]
            }
        },
        "seed": 1849402459,
        "subseed": -1,
        "subseed_strength": -1,
        "sampler_index": "Euler a",
        "batch_size": 1,
        "n_iter": 1,
        "steps": 22,
        "cfg_scale": 4,
        "width": args.width,
        "height": args.height,
        "restore_faces": True,
        "include_init_images": True,
        "override_settings": {},
        "override_settings_restore_afterwards": True
    }
    response = requests.post(url, json=data)
    if response.status_code == 200:
        return response.content
    else:
        try:
            error_data = response.json()
            print("Error:")
            print(str(error_data))

        except json.JSONDecodeError:
            print(f"Error: Unable to parse JSON error data.")
        return None

def infer(frameA, frameB):

    input_frame_1 = read_image(str(frameA), ImageReadMode.RGB)

    input_frame_2 = read_image(str(frameB), ImageReadMode.RGB)

    #img1_batch = torch.stack([frames[0]])
    #img2_batch = torch.stack([frames[1]])

    img1_batch = torch.stack([input_frame_1])
    img2_batch = torch.stack([input_frame_2])

    weights = Raft_Large_Weights.DEFAULT
    transforms = weights.transforms()

    def preprocess(img1_batch, img2_batch):
        img1_batch = F.resize(img1_batch, size=[512, 512])
        img2_batch = F.resize(img2_batch, size=[512, 512])
        return transforms(img1_batch, img2_batch)

    img1_batch, img2_batch = preprocess(img1_batch, img2_batch)

    list_of_flows = model(img1_batch.to(device), img2_batch.to(device))

    predicted_flow = list_of_flows[-1][0]
    opitcal_flow_path = os.path.join(args.output_dir, f"flow_{i}.png")

    flow_img = flow_to_image(predicted_flow).to("cpu")
    flow_img = F.resize(flow_img, size=[args.height, args.width])

    write_jpeg(flow_img, opitcal_flow_path)

    return opitcal_flow_path

output_images = []
output_paths = []

# Initialize with the first image path

result = args.init_image
output_image_path = os.path.join(args.output_dir, f"output_image_0.png")

#with open(output_image_path, "wb") as f:
   # f.write(result)

last_image_path = args.init_image
for i in range(1, len(y_paths)):
    # Use the last image path and optical flow map to generate the next input
    optical_flow = infer(y_paths[i - 1], y_paths[i])

    # Modify your send_request to use the last_image_path
    result = send_request(last_image_path, optical_flow, y_paths[i])
    data = json.loads(result)

    for j, encoded_image in enumerate(data["images"]):
        if j == 0:
            output_image_path = os.path.join(args.output_dir, f"output_image_{i}.png")
            last_image_path = output_image_path
        else:
            output_image_path = os.path.join(args.output_dir, f"controlnet_image_{j}_{i}.png")

        with open(output_image_path, "wb") as f:
           f.write(base64.b64decode(encoded_image))
    print(f"Written data for frame {i}:")


import cv2
import numpy as np
from matplotlib import pyplot as plt

def subimg(x,y,img):
	a = x-8
	b = y-8
	c = 0
	d = 0
	if a<0:
		c = -a
		a = 0
	if b<0:
		d = -b
		b = 0
	c = x+7+c
	d = y+7+d
	return img[a:c,b:d]

#def findCorners (mag,angle,thresh):

img = cv2.imread('cubes.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

corners = cv2.goodFeaturesToTrack(gray,50,0.01,10)
corners = np.int0(corners)

for i in corners:
	x,y = i.ravel()
	roi = subimg(x,y,gray)
	sx = cv2.Sobel(roi,cv2.CV_64F,1,0,ksize=5)
	sy = cv2.Sobel(roi,cv2.CV_64F,0,1,ksize=5)
	mag,angle = cv2.cartToPolar(sx,sy,angleInDegrees=True)
	#matches = findCorners(mag,angle,roi)
	cv2.circle(img,(x,y),3,255,-1)

plt.imshow(img),plt.show()


import joblib
from preprocessing.cleaning_data import preprocess

lr_from_joblib = joblib.load('My_model.pkl')
encod = joblib.load("Encoded.pkl")

def predict(data_input: dict):
    df = preprocess(data_input)
    data_encoded = encod.transform(df)
    prediction = lr_from_joblib.predict(data_encoded)
    return round(prediction[0], 2)


import re
import argparse
import datetime

from django.core.management.base import BaseCommand, CommandError

from ...types import QueueName
from ...utils import get_backend
from ...backends.base import BackendWithPause

DURATION_PATTERN = r'^((?P<hours>\d+)h)?((?P<minutes>\d+)m)?((?P<seconds>\d+)s)?$'
TIME_FORMAT = r'%Y-%m-%dT%H:%M:%S%z'

def utcnow() -> datetime.datetime:
    return datetime.datetime.now(datetime.timezone.utc)

def parse_duration_to_time(duration: str) -> datetime.datetime:
    match = re.match(DURATION_PATTERN, duration)
    if match is None:
        raise ValueError(
            f"Unknown duration format {duration!r}. Try something like '1h2m3s'.",
        )

    delta = datetime.timedelta(
        hours=int(match['hours'] or 0),
        minutes=int(match['minutes'] or 0),
        seconds=int(match['seconds'] or 0),
    )

    return utcnow() + delta

def parse_time(date_string: str) -> datetime.datetime:
    return datetime.datetime.strptime(date_string, TIME_FORMAT)

class Command(BaseCommand):
    help = """
    Command to pause work on a redis-backed queue.

    New jobs can still be added to the queue, however no jobs will be pulled off
    the queue for processing.
    """  # noqa:A003 # inherited name

    def add_arguments(self, parser: argparse.ArgumentParser) -> None:
        parser.add_argument(
            'queue',
            action='store',
            help="The queue to pause.",
        )

        group = parser.add_mutually_exclusive_group(required=True)
        group.add_argument(
            '--for',
            dest='until',
            action='store',
            type=parse_duration_to_time,
            help=(
                "The duration to pause the queue for. Specify a value like 1h2m3s, "
                "all levels of precision are optional, so 5m and 1h are both valid."
            ),
        )
        group.add_argument(
            '--until',
            action='store',
            type=parse_time,
            help=(
                "The time at which the queue should reactivate. Specify as an "
                "ISO 8601 value, specifically one parsable via datetime.strptime "
                f"using {TIME_FORMAT.replace('%', r'%%')!r}, such as {utcnow():{TIME_FORMAT}}."
            ),
        )

    def handle(self, queue: QueueName, until: datetime.datetime, **options: object) -> None:
        if until < utcnow():
            raise CommandError("Refusing to pause until a time in the past.")

        backend = get_backend(queue)

        if not isinstance(backend, BackendWithPause):
            raise CommandError(
                "Configured backend '{}.{}' doesn't support pausing".format(
                    type(backend).__module__,
                    type(backend).__name__,
                ),
            )

        backend.pause(queue, until)

        self.stdout.write(f"Paused queue {queue} until {until.isoformat(' ')}.")


# Example by 404kuso
# https://github.com/discord-py-ui/discord-ui/tree/main/examples/cpgs.py
#
#       This is just a simple cog command example for application commands
# Note:
#       If you want to test this, replace '785567635802816595' in guild_ids=[] with a guild id of
#       your choice, because guild slash commands are way faster than globals

# import discord package
import discord
# import commands extention
from discord.ext import commands
from discord_ui import (
    UI, cogs, SlashOption,
    # interaction types for type hinting
    SlashInteraction, AutocompleteInteraction, ContextInteraction,
    # overridden message object for type hinting
    Message
)

# initialize bot
bot = commands.Bot(" ")

# create the cog
class ExampleCog(commands.Cog):
    # add slashcommand to cog
    @cogs.slash_command("my_command", "this is an example cog command", guild_ids=[785567635802816595])
    # callback for the command
    async def my_command(self, ctx: SlashInteraction):
        ...

    # method that generates choices for the 'hello world' command
    async def my_generator(self, ctx: AutocompleteInteraction):
        return [("hello", "1"), ("world", "2")]

    # add subslash command to the cog
    @cogs.subslash_command("hello", "world", "example subcommand", [
        # simple option that uses autocompletion
        SlashOption(str, "argument", "option that autogenerates somethning", choice_generator=my_generator)
    ])
    # callback for the commmand
    async def my_subcommand(self, ctx: SlashInteraction, argument: str):
        ...

    # add message command to cog
    @cogs.message_command("message", guild_ids=[785567635802816595])
    # callbackfor the command
    async def my_message_command(self, ctx: ContextInteraction, message: Message):
        ...

    # add user command to cog
    @cogs.user_command("user", guild_ids=[785567635802816595])
    # callback for the command
    async def my_user_command(self, ctx: ContextInteraction, member: discord.Member):
        ...

# add the cog to the bot
bot.add_cog(ExampleCog())

# login
bot.run("your token")


import numpy as np
import matplotlib.pyplot as plt

numbers = np.linspace(-10, 10, 201)
sin_numbers = np.sin(numbers)
cos_numbers = np.cos(numbers)

plt.plot(numbers, sin_numbers, label = 'sin')
plt.plot(numbers, cos_numbers, label = 'cos')
plt.legend()
plt.show()


import cv2
import numpy as np

ims = cv2.imread("newcircle.png")
img = cv2.resize(ims, (960, 540))
# pre process the frame ti remove noise and improve contrast
frame = cv2.GaussianBlur(img, (5, 5), 0)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_yellow = np.array([58, 95, 45])
upper_yellow = np.array([58, 100, 50])
edges = cv2.Canny(gray, 150, 75)
# use houghtransform to detect lines and draw them
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 5)
if lines is not None:
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)

mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
mask = cv2.bitwise_not(mask)
result = cv2.bitwise_and(img, img, mask=mask)

for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)

#cv2.imshow("edges", edges)
cv2.imshow("Image", img)
# cv2.imshow("yellow",mask)
#cv2.imshow("mask", mask)
cv2.waitKey(0)
cv2.destroyAllWindows()


import abc
import collections

import six

from hypocrite import location
from hypocrite import linelist

_unset = object()

# Represent a token
Token = collections.namedtuple('Token', ['type_', 'value'])

# Known token types
TOK_WORD = 'word'
TOK_CHAR = 'char'
TOK_STR = 'str'

class Continue(Exception):
    """
    A specialized exception indicating that the loop should be
    continued.
    """

    pass

class ParseException(Exception):
    """
    Exceptions related to hypocrite, such as parse errors.
    """

    pass

def split_toks(toks, delims, include_delim=False):
    """
    Helper to split a list of tokens on a specific set of delimiters,
    similar to ``str.split()``.

    :param list toks: The list of tokens to split.
    :param set delims: The delimiters to use to split the tokens.
    :param bool include_delim: If ``True``, then the value yielded
                               will be a 2-element tuple, with the
                               second element containing the
                               delimiter.

    :returns: An iterator that yields lists of tuples.
    """

    # Stack of tokens seen so far
    stack = []

    for current in toks:
        # Have we encountered a delimiter?
        if current in delims:
            # Yield the value, then reset the stack and keep going
            yield (stack, current) if include_delim else stack
            stack = []
            continue

        # Add the token to the stack
        stack.append(current)

    # Yield any outstanding tokens
    yield (stack, None) if include_delim else stack

class Directive(object):
    """
    Wrap a directive declaration.  Directives have a name, a value
    key, an initial value for that key, and a callable implementing
    the directive's behavior.
    """

    def __init__(self, directive, value, init, impl):
        """
        Initialize a ``directive`` instance.

        :param str directive: The directive, e.g., 'file' for a
                              ``%file`` directive.
        :param str value: The value key.  This is where the value
                          produced by the directive is to be stored.
                          May be ``None`` if the directive produces no
                          independent values of its own.
        :param init: The initial value for the directive value.  If it
                     is ``_unset``, the directive produces no
                     independent values of its own; if it is callable,
                     it will be called with no arguments and the
                     return value will be the initial value;
                     otherwise, it is used verbatim.  Be careful to
                     use a callable for mutable objects such as
                     dictionaries.
        :param impl: A callable implementing the directive.  This
                     callable is expected to take the variables
                     ``values`` (a dictionary), ``start_coord`` (the
                     coordinates the directive started at), and
                     ``toks`` (a list of tokens).  The callable is
                     expected to return ``None`` or another callable
                     accepting ``end_coord`` (the coordinates the
                     directive ended at), ``buf`` (a list of lines),
                     and ``toks`` (a list of tokens), which may also
                     return either ``None`` or another callable.
        """

        self.directive = directive
        self.value = value
        self.init = init
        self.impl = impl

    def __call__(self, values, start_coord, toks):
        """
        Call the implementation of the directive.

        :param dict values: The values dictionary that the directive's
                            return value may be placed in.
        :param start_coord: The coordinates the directive started at.
        :type start_coord: ``hypocrite.location.Coordinate``

        :param list toks: A list of tokens.

        :returns: Either ``None`` or another callable accepting
                  ``end_coord`` (the coordinates the directive ended
                  at), ``buf`` (a list of lines), and ``toks`` (a list
                  of tokens), which may also return either ``None`` or
                  another similar callable.
        """

        return self.impl(values, start_coord, toks)

    def initial(self):
        """
        Return the initial value to store for the directive.
        """

        return self.init() if callable(self.init) else self.init

@six.add_metaclass(abc.ABCMeta)
class PerFileParser(object):
    """
    Track the state of parsing a percent-directive file.
    """

    @abc.abstractproperty
    def DIRECTIVES(self):
        """
        A class-level dictionary.  This should be initialized to an empty
        dictionary, and will be filled in using the ``@directive()``
        class method.
        """

        pass  # pragma: no cover

    @staticmethod
    def _tokenize(text, coord):
        """
        Given directive text, not including the leading '%' character,
        decompose it into a sequence of tokens.

        :param str text: The text to tokenize.
        :param coord: The coordinates of the line.
        :type coord: ``hypocrite.location.Coordinate``

        :returns: An iterator over the sequence of tokens in the text.
        """

        # Tokenizing state and initialized buffer
        state = None
        buf = ''

        # Step through the text a character at a time
        for c in text:
            # None state indicates we're handling whitespace (which is
            # ignored)
            if state is None:
                if c.isspace():
                    # More whitespace
                    pass
                elif c == '"':
                    # Introduce a string token (delimited by
                    # double-quotes)
                    state = TOK_STR
                    buf = ''
                elif c == '_' or c.isalpha():
                    # Found a word
                    state = TOK_WORD
                    buf = c
                else:
                    # Some other character; yield a CHAR token
                    yield Token(TOK_CHAR, c)

            elif state == TOK_STR:
                # Processing a string.  Note that escapes are NOT honored
                if c == '"':
                    # Found the end of the string!
                    yield Token(state, buf)
                    state = None
                else:
                    # Add the character to the buffer
                    buf += c

            elif c.isspace():
                # Plain old whitespace, ending a WORD token
                yield Token(state, buf)
                state = None

            else:
                # Can't be in any other state
                assert state == TOK_WORD

                if c == '_' or c.isalnum():
                    # Still a WORD token
                    buf += c
                else:
                    # Oh, end of the WORD token
                    yield Token(state, buf)
                    if c == '"':
                        # WORD ended on a STR token
                        state = TOK_STR
                        buf = ''
                    else:
                        # Some other character
                        state = None
                        yield Token(TOK_CHAR, c)

        if state == TOK_STR:
            # Last STR token was missing a close quote!
            raise ParseException(
                'Unclosed string encountered at %s' % coord
            )
        elif state is not None:
            # Have a WORD pending in the buffer
            yield Token(state, buf)

    @classmethod
    def directive(cls, init=_unset, name=None, key=_unset):
        """
        Declare a directive.  This is a decorator that marks a function or
        class as implementing a directive.

        :param init: The initial value to store for the directive.  If
                     a callable, will be called with no arguments to
                     produce the initial value; use this when the
                     value should be initialized to mutable objects,
                     such as dictionaries.
        :param str name: The directive name.  This appears after the
                         ``%`` character to identify the directive.
                         If not provided, defaults to the name of the
                         class or function.
        :param str key: The value key the directive stores its data
                        under.  Defaults to ``name``.  May be set to
                        ``None`` to inhibit initializing the value.

        :returns: A function decorator.
        """

        def decorator(func):
            # Pick the directive and value key
            directive = name or func.__name__
            value = directive if key is _unset else key

            # Save the directive
            cls.DIRECTIVES[directive] = Directive(
                directive, value, init, func
            )

            return func

        # Return the decorator
        return decorator

    @classmethod
    def _values(cls):
        """
        Initialize a values dictionary for all directives.

        :returns: A dictionary of values.
        :rtype: ``dict``
        """

        return {
            directive.value: directive.initial()
            for directive in cls.DIRECTIVES.values()
            if directive.init is not _unset
        }

    def __init__(self):
        """
        Initialize a ``PerFileParser`` instance.
        """

        self._deferred = None
        self._buf = None
        self._comment_pfx = None
        self._continued = None
        self._start_coord = None
        self._lines = 0

    def _parse_directive(self, coord, line):
        """
        Parse a line looking for a directive.  This is the core parsing
        functionality.  This routine recognizes both C-style comments
        ("/* */") and one-line comments ("//"); the former are
        replaced with spaces anywhere they are encountered, while the
        latter are simply stripped from the line.  Line continuations,
        identified as backslashes ("\\") at the end of a line, are
        also recognized.

        :param coord: The coordinates of the line.
        :type coord: ``hypocrite.location.Coordinate``
        :param str line: The line to parse.

        :returns: A tuple of the line number the directive started on
                  (which, thanks to comments and continuations, may
                  not be the same as ``coord``) and a list of tokens
                  parsed from the directive line.

        :raises Continue:
            Indicates that further input is required.  This typically
            means the line was empty or that a C-style comment
            spanning multiple lines was encountered.

        :raises ParseException:
            An error occurred while parsing the input file.
        """

        # Handle any continuation
        if self._continued is not None:
            line = self._continued + ' ' + line
            self._continued = None

        # Handle any hanging comment
        if self._comment_pfx is not None:
            # Comment started above; does it end here?
            end = line.find('*/')
            if end < 0:
                # Nope
                raise Continue()

            # Comment has ended, pretend it was a space and reset
            # the comment state
            line = self._comment_pfx + ' ' + line[end + 2:]
            self._comment_pfx = None

        # Strip out any other comments on the line
        while True:
            # Does the line contain any comments?
            pos = [x for x in (line.find('/*'), line.find('//')) if x >= 0]
            if not pos:
                break

            # What's the first one?
            comment = min(pos)

            # Handle the simple case of a one-line comment
            if line[comment:comment + 2] == '//':
                line = line[:comment]

                # Can't be any more comments, so exit the comment
                # loop
                break

            # OK, a C-style comment; does it end on this line?
            end = line.find('*/', comment + 2)
            if end < 0:
                # Nope; can't continue until we have more
                self._comment_pfx = line[:comment]
                if self._start_coord is None:
                    self._start_coord = coord
                raise Continue()

            # Replace the comment with a space
            line = line[:comment] + ' ' + line[end + 2:]

            # Loop around for any more comments

        # Strip off remaining whitespace and skip empty lines
        line = line.strip()
        if not line:
            raise Continue()

        # If it has a continuation, process that
        if line[-1] == '\\':
            self._continued = line[:-1]
            if self._start_coord is None:
                self._start_coord = coord
            raise Continue()

        # Now we have a line; pick the correct line number
        if self._start_coord:
            coord = self._start_coord
            self._start_coord = None

        # It's supposed to be a directive, so check that it is
        if line[0] != '%':
            raise ParseException('Invalid directive at %s' % coord)

        # Tokenize the line and return the starting line number and
        # the tokens
        return coord, list(self._tokenize(line[1:], coord))

    def _parse_line(self, coord, line, values):
        """
        Parse a line.  This wraps the ``_parse_directive()`` routine,
        handling deferred processing.  Deferred processing allows
        directives to include content that spans multiple lines;
        examples include the ``%preamble`` and ``%test`` directives.

        :param coord: The coordinates of the line.
        :type coord: ``hypocrite.location.Coordinate``
        :param str line: The line to parse.
        :param dict values: The directive values being accumulated by
                            the parsing process.

        :raises Continue:
            Indicates that further input is required.  This typically
            means the line was empty or that a C-style comment
            spanning multiple lines was encountered.

        :raises ParseException:
            An error occurred while parsing the input file.
        """

        # Keep track of how many lines have been processed
        self._lines += 1

        # If we don't have a pending deferred callable, that means
        # we're looking for directives...
        if self._deferred is None:
            # Parse out a directive
            dir_coord, tokens = self._parse_directive(coord, line)

            # Is it a valid directive?
            if (not tokens or tokens[0].type_ != TOK_WORD or
                    tokens[0].value not in self.DIRECTIVES):
                raise ParseException(
                    'Invalid directive at %s' % dir_coord
                )

            # Process the directive
            self._deferred = self.DIRECTIVES[tokens[0].value](
                values, dir_coord, tokens[1:]
            )
            self._buf = linelist.LineList() if self._deferred else None

        # OK, we're accumulating lines looking for an end directive
        elif (self._comment_pfx is not None or
              self._continued is not None or line.lstrip().startswith('%')):
            # Parse out a directive
            dir_coord, tokens = self._parse_directive(coord, line)

            # Is it a close directive?
            if not tokens or tokens[0] != (TOK_CHAR, '}'):
                raise ParseException(
                    'Invalid directive at %s' % dir_coord
                )

            # Run the deferred callable
            self._deferred = self._deferred(dir_coord, self._buf, tokens[1:])
            self._buf = linelist.LineList() if self._deferred else None

        else:
            # Just accumulate another line
            self._buf.append(line[:-1] if line.endswith('\n') else line, coord)

    def parse(self, stream, path=None):
        """
        Parse a percent-directive file.

        :param stream: A stream, as opened with ``open()``.  The
                       stream should be opened in text mode with
                       universal newlines.
        :param str path: The path of the file being parsed.  If not
                         provided, ``stream.name`` will be used.

        :returns: A dictionary of values developed from parsing the
                  directives contained within the input file.

        :raises AttributeError:
            The provided ``stream`` has no ``name`` attribute and
            ``path`` was not provided.

        :raises ParseException:
            An error occurred while parsing the input file.
        """

        # Figure out the path
        if path is None:
            path = stream.name

        # Start with the initialized values
        values = self._values()

        # Parse the stream
        for lno, line in enumerate(stream):
            try:
                self._parse_line(
                    location.Coordinate(path, lno + 1), line, values
                )
            except Continue:
                # Special exception indicating an extended line
                continue

        # Was there a line continuation?
        if self._continued is not None:
            raise ParseException(
                'Trailing directive continuation at end of file; '
                'starts at %s' % self._start_coord
            )

        # Were we in the middle of a comment?
        if self._comment_pfx is not None:
            raise ParseException(
                'Unclosed comment at end of file; starts at %s' %
                self._start_coord
            )

        # How about the middle of a directive?
        if self._deferred:
            # Give the deferred routine a chance to complain
            self._deferred(
                location.Coordinate(path, self._lines), self._buf, None
            )

            # But complain anyway if it doesn't
            raise ParseException('Unclosed directive at end of file')

        return values


from sanic import Sanic
from sanic.response import json, redirect
from sanic_redis_ext import RedisExtension

from conf import app as app_conf
from helpers import get_cdn_host, get_from_cache, prepare_cdn_addr, store_in_cache

app = Sanic()
app.config.from_object(app_conf)
RedisExtension(app)

@app.route("/")
async def handle(request):
    resource = request.args.get('video')
    if not resource:
        return json(
            {"error": "video parameter is required in get params"},
            status=400
        )

    cdn_host = get_cdn_host(request.app)
    if not cdn_host:
        return redirect(resource)

    if not request.app.config.USE_CACHE:
        return redirect(prepare_cdn_addr(resource, cdn_host))

    cached_value = await get_from_cache(request.app, resource, cdn_host)
    if cached_value:
        return redirect(cached_value)

    redirect_addr = await store_in_cache(request.app, resource, cdn_host)
    return redirect(redirect_addr)

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8000)


from itertools import permutations

with open('input.txt', 'r') as file:
  data = list(file.read().splitlines())

def solve(input):
  positions = [(-8, -9,  -7), (-5,  2,  -1), (11,  8, -14), ( 1, -4, -11)]
  velocities = [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]

  for _ in range(1000):
    for one, two in permutations([0, 1, 2, 3], 2):
      v1 = velocities[one]
      p1 = positions[one]
      p2 = positions[two]

      dx = 1 if p1[0] < p2[0] else -1 if p1[0] > p2[0] else 0
      dy = 1 if p1[1] < p2[1] else -1 if p1[1] > p2[1] else 0
      dz = 1 if p1[2] < p2[2] else -1 if p1[2] > p2[2] else 0

      velocities[one] = (v1[0] + dx, v1[1] + dy, v1[2] + dz)

    for one in range(4):
      p1 = positions[one]
      v1 = velocities[one]
      positions[one] = (
        p1[0] + v1[0],
        p1[1] + v1[1],
        p1[2] + v1[2]
      )

  energy = 0

  for one in range(4):
    pot = abs(positions[one][0]) + abs(positions[one][1]) + abs(positions[one][2])
    kin = abs(velocities[one][0]) + abs(velocities[one][1]) + abs(velocities[one][2])
    total = pot * kin
    energy += total

  return energy

print(solve(data))


# ================================================== DOWNLOAD AND IMPORT PACKAGES ================================================== #
# !/usr/bin/env python

# make sure to install these packages before running:
# pip install pandas
# pip install sodapy
# pip install streamlit
# pip install matplotlib

import streamlit as st
import pandas as pd
import numpy as np
from pandas.io.json import json_normalize
import json
import requests
# import matplotlib.pyplot as plt

# ================================================== GET DATA FROM API ================================================== #
def pulldata():

    # URL and auth are standard API parameters. But the 'params' parameter is unique to every web service that the API is calling.
    # For example, Socrata (where OpenData is hosted) has a $query parameter that tells you how to use it. This is built into this example.
    #https://dev.socrata.com/docs/queries/query.html

    # ========== OPTION 1 ========== #
    URL = 'https://data.cityofnewyork.us/resource/833y-fsy8.json'
    payload = {'$select':'occur_date, latitude, longitude, vic_age_group', '$limit':'5000'}
    raw = requests.get(url=URL, params=payload, auth=('oddqm5a1h906snethsz3yxxy', '5z3gwa8zfaxtjdcxn67yqptce7h6ra2nhdka92o0wjsu9d63bw'))

    # ========== OPTION 2 ========== #
    # URL = 'https://data.cityofnewyork.us/resource/833y-fsy8.json?$select= occur_date,latitude,longitude&$limit=50000'
    # raw = requests.get(url=URL, auth=('oddqm5a1h906snethsz3yxxy', '5z3gwa8zfaxtjdcxn67yqptce7h6ra2nhdka92o0wjsu9d63bw'))

    # ========== CONVERT INTO DATAFRAME ========== #
    # raw.content
    raw_json = json.loads(raw.content)
    raw_df = json_normalize(raw_json)
    return raw_df

# ================================================== PROCESS DATA ================================================== #
processed_df = pulldata()

# split year value out of year string and put it in a new column

processed_year = processed_df['occur_date'].str.split('-', n=1, expand=True)[0].astype(int)
year_list = processed_year.unique()
firstyear = min(year_list)
lastyear = max(year_list)

processed_df.insert(1, 'occur_year', processed_year)

# convert longitude and latitude from string to int
processed_df['latitude'] = processed_df['latitude'].astype(float)
processed_df['longitude'] = processed_df['longitude'].astype(float)

# count number of shootings per year
def countfrequencyincol(df, column_name):
    return df.groupby(column_name).size()

def selectrows(df, filter_by, column_name):
    rows_selected = df.loc[df[column_name] == filter_by]
    return rows_selected

agegroup18_24 = selectrows(processed_df, '18-24', 'vic_age_group')

# ================================================== COMPUTING ================================================== #

shootingcount_peryear = countfrequencyincol(processed_df, 'occur_year')
shootingcount_peryear_18_24 = countfrequencyincol(agegroup18_24, 'occur_year')

# ================================================== OUTPUT ON SCREEN ================================================== #

# ========== SIDE BAR ========== #

if st.checkbox('Show raw data'):
    raw_df

if st.checkbox('Show processed data'):
    processed_df

# ========== CHARTS ========== #

shootingcount_peryear = shootingcount_peryear.rename("total")
shootingcount_peryear_18_24 = shootingcount_peryear_18_24.rename("18-24")

shootingsperyear = pd.concat([shootingcount_peryear, shootingcount_peryear_18_24], axis=1)
st.line_chart(shootingsperyear)

# ========== CHARTS BY AGE ========== #

# st.multiselect('victim age group', options={'<18', '18-24', '25-44', '45-64', '65+'})
# st.line_chart(shootingcount_peryear_18_24)

# ========== MAP ========== #

# select in sidebar for YEAR
year_selected = st.selectbox('choose year', processed_df['occur_year'].unique())

rows_index_selected = processed_df['occur_year'] == year_selected
processed_df_selected = processed_df[rows_index_selected]
st.map(processed_df_selected.loc[:,'latitude':'longitude'])

# ========== MAIN WINDOW ========== #


from random import random

from drf_spectacular.utils import extend_schema, extend_schema_view
from rest_framework import status, viewsets
from rest_framework.decorators import action

from .models import Recipe
from .serializers import RecipeSerializer

@extend_schema_view(
    list=extend_schema(
        description='Example 1: Document the API at the class level.',
    ),
    partial_update=extend_schema(
        exclude=True,
        description='This will not be in the specs because we used the exclude option above.'
    ),

)
class RecipeViewSet(viewsets.ModelViewSet):
    """
    Endpoints for listing, creating, viewing, updating, and deleting recipes.

    If you need some inspiration for recipes, try [The Spruce Eats](https://www.thespruceeats.com/)
    """
    queryset = Recipe.objects.all()
    serializer_class = RecipeSerializer

    # Note, this method is unnecessary. It's here as an example.
    def create(self, request, *args, **kwargs):
        """
        Example 2: Document the API in a docstring. This option might be the most limiting.
        """
        return super().create(request, args, kwargs)

    @extend_schema(
        description='Return a _random_ recipe.\n'
                    '\n'
                    '**Note:** Does not use a cryptographically secure PRNG.'
    )
    @action(detail=False)
    def random(self):
        return random.choice(self.queryset)