#!/usr/bin/env python3

##########################
#    CLASSES             #
##########################

class gene:
    """Class made for storing exons, mRNAs and CDSs within genes"""

    def __init__(self, species, number, chromosome, start, end, strand, original_id):

        # Define gene attributes
        self.species = str(species)
        self.number = str(number)
        self.chromosome = str(chromosome)
        self.start = int(start)
        self.end = int(end)
        self.strand = str(strand)
        self.original_id = str(original_id)

        # Initialize attributes for exons

        self.exons = dict()

        # Initialize attributes for mRNAs

        self.mRNAs = dict()

        # Initialize attributes for CDSs

        self.CDSs = dict()

        self.newnumber = "0"*(7-len(self.number)) + self.number

        self.name = self.species + "GEN" + self.newnumber

    def add_exon(self, start, end, oldname):

        # Assign number

        n = len(self.exons) + 1

        # Name it

        name = self.species + "EXO" + self.newnumber  + "." + str(n)

        # Convert to within-gene coordinate

        start = int(start) - self.start
        end = int(end) - self.start

        # Add to dict

        self.exons[name] = [int(start), int(end), oldname ]

    def add_mrna(self, start, end , oldname ):

        # Assign number
        n = len(self.mRNAs) + 1
        # Name it

        name = self.species + "MRN" + self.newnumber + "." + str(n)

        # Convert to within-gene coordinate

        start = int(start) - self.start
        end = int(end) - self.start

        # Add to dict

        self.mRNAs[name] = [int(start), int(end), oldname ]

    def add_cds(self, start, end, oldname ):

        # Assign number
        n = len(self.CDSs) + 1
        # Name it

        name = self.species + "CDS" + self.newnumber + "." + str(n)

        # Convert to within-gene coordinate

        start = int(start) - self.start
        end = int(end) - self.start

        # Add to dict

        self.CDSs[name] = [int(start) , int(end), oldname ]

    # Method to get longest (specified) feature ID

    def get_longest(self, feature):

        dictionary = {"CDS": self.CDSs ,"MRNA": self.mRNAs , "EXON": self.exons}
        longest_len = 0
        longest_ids = None
        for key in dictionary[feature]:

            length = dictionary[feature][key][1] - dictionary[feature][key][0]

            if length > longest_len:
                longest_ids = ( key , dictionary[feature][key][2] )

        return longest_ids

    # Method to print OLDNAME -> NEWNAME table

    def get_rename_table( self ):

        # Format:
        # OLDNAME FATURE NEWNAME
        outstring = ""
        # gene
        g = "{0} gene {1}".format( self.original_id, self.name )
        outstring = outstring + g + "\n"
        # exons
        for entry in self.exons:
            e = "{0} exon {1}".format( self.exons[entry][2], entry )
            outstring = outstring + e + "\n"

        # mrnas
        for entry in self.mRNAs:
            e = "{0} mRNA {1}".format( self.mRNAs[entry][2], entry )
            outstring = outstring + e + "\n"

        # cdss
        for entry in self.CDSs:
            e = "{0} CDS {1}".format( self.CDSs[entry][2], entry )
            outstring = outstring + e + "\n"

        return outstring

class gff3_entry:
    """Class for containing gff information. Only CDS, mRNA, exon and gene entries are kept"""

    def __init__(self, line):

        sline = line.split()
        self.chromosome = sline[0]
        self.source = sline[1]
        self.feature = sline[2]
        self.start = sline[3]
        self.end = sline[4]

        self.score = sline[5]
        self.strand = sline[6]
        self.phase = sline[7]

        # Define accepted features
        self.unsupported = False
        accepted_features = ["gene", "mRNA", "CDS", "exon"]
        if self.feature not in accepted_features:
            self.unsupported = True

        if not self.unsupported:

            attributes = sline[8].split(";")
            # Make attributes explicit

            att_dict = {}
            for i in attributes:

                attribute = i.split("=")[0]
                # We lose some information here
                if attribute == "ID" or attribute == "Parent":
                    att_dict[attribute] = i.split("=")[1].split(":")[1]

            # Handle attributes to allow for proper nesting structure ( genes(mRNA(CDS, exon) )
            # Second level(CDS, exon) has to be initialized with none and then added after reading gff
            self.id = att_dict["ID"]

            if self.feature == "exon":
                # Initinalize
                self.gene = None
                self.exon = self.id
                self.mRNA = att_dict["Parent"]
                self.CDS = None

            elif self.feature == "mRNA":
                # MRNA
                self.gene = att_dict["Parent"]
                self.exon = None
                self.mRNA = self.id
                self.CDS = None

            elif self.feature == "CDS":
                self.gene = None
                self.exon = None
                self.mRNA = att_dict["Parent"]
                self.CDS = self.id

            elif self.feature == "gene":
                self.gene = self.id
                self.exon = None
                self.mRNA = None
                self.CDS = None

    def get_entry(self):

        """
        Method for returning information in gff3 format.
        General annotation except IDs is not returned (it is lost in reading the entry)
        """
        # Collapse attributes
        # Some information has been lost when coercing into gff3_entry class
        attributes = "ID={0};gene={1};mRNA={2};exon={3};CDS={4}".format(self.id,
                                                                        self.gene,
                                                                        self.mRNA,
                                                                        self.exon,
                                                                        self.CDS)
        # Gather info
        entry = "{0} {1} {2} {3} {4} {5} {6} {7} {8}".format(self.chromosome,
                                                     self.source,
                                                     self.feature,
                                                     self.start,
                                                     self.end,
                                                     self.score,
                                                     self.strand,
                                                     self.phase,
                                                     attributes)
        # Return entry
        return entry

    def add_gene_feature( self, feature , gene_id):

        """
        Add a gene feature to gff3 entry.

        This is intended for exons and CDS as
        they lack an explicit link to their
        gene.

        Parameters:

        feature  For safety purposes (dont wanna modify genes or mRNAs).
                 It is either exon or CDS.

        gene_id  The gene id to be associated with either the exin or the CDS.
        """

        # This function is intended for modifying exons and CDS as they lack a gene-link
        if feature == "exon" or feature == "CDS":
            self.gene = gene_id

        else:
            print( "Error: Only exon and CDS entries are modifiable with add_gene_feature() method." )


#! /usr/bin/python

import numpy as np
from numpy import cos, sin
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pcl
from pcl.registration import icp, gicp, icp_nl

theta = [0., 0., np.pi]
rot_x = [[1,              0,              0],
         [0,              cos(theta[0]), -sin(theta[0])],
         [0,              sin(theta[0]),  cos(theta[0])]]
rot_y = [[cos(theta[1]),  0,              sin(theta[1])],
         [0,              1,              0],
         [-sin(theta[1]),  0,             cos(theta[1])]]
rot_z = [[cos(theta[2]), -sin(theta[1]),  0],
         [sin(theta[2]),  cos(theta[1]),  0],
         [0,              0,              1]]
transform = np.dot(rot_x, np.dot(rot_y, rot_z))

source = np.random.randn(100, 3)
source_pc = pcl.PointCloud(source.astype(np.float32))
target = np.dot(transform, source.T).T
target_pc = pcl.PointCloud(target.astype(np.float32))

converged, transf, estimate, fitness = icp(source_pc, target_pc, max_iter=10000)

print(converged, transf, estimate, fitness)
result = estimate.to_array()

fig = plt.figure()
ax = fig.add_subplot(221, projection='3d')
ax.scatter(source[:,0], source[:,1], source[:,2])
ax = fig.add_subplot(222, projection='3d')
ax.scatter(target[:,0], target[:,1], target[:,2])
ax = fig.add_subplot(212, projection='3d')
ax.scatter(source[:,0], source[:,1], source[:,2], 'b')
ax.scatter(result[:,0], result[:,1], result[:,2], 'r')

plt.show()


#Imports:
import os
import glob
import argparse
import numpy as np
from pathlib import Path
from tqdm import tqdm
import warnings
import torch
import yaml

from src.Rect_to_seg_helper import *
from src.SAM_helper import *
#########################################################################################################################
def run(img_directory,annotation_directory,saving_path,sam_checkpoint_path,smooth):
    '''This code converts YOLO-style rectangle annotations to segmentation annotations.
       It takes the bounding box coordinates provided in the YOLO format and generates corresponding segmentation masks.
       The output of the script will be json files saved in the spacified path.
         Parameters:
             img_directory: The directory of the annotated images.
             annotation_directory:The directory of the annotations crosponding to the images.
             saving_path: The path where the results will be saved in.
             sam_checkpoint_path: The path to SAM checkpoint.
             '''
    torch.cuda.empty_cache()
    print('The process of converting rectangle annotations to segmentations has begun.')

    #load the model
    print('Loading The Model...........')
    predictor=model_loader_predictor(sam_checkpoint=sam_checkpoint_path)
    print('The Model is loaded')

    all_annotations=glob.glob(os.path.join(annotation_directory,'*.json'))
    print(f'Total number of JSON files: {len(all_annotations)}.')

    missing_images=[]
    files_with_exceptions=[]
    print('Code execution will start now.')
    for num, annotation_file in tqdm(enumerate(all_annotations), total=len(all_annotations), desc="Processing"):
        try:
    #for i,annotation_file in enumerate(all_annotations):

            #get image path:
            img_file= os.path.join(img_directory,Path(annotation_file).stem+'.png')
            #check if the image exists:
            if not os.path.exists(img_file):

                warnings.warn(f"This file does not  exist: {img_file}.", UserWarning)
                missing_images.append(img_file)
                continue
            #read image:
            image,img_dim=image_reader(img_file)

            #predict the image:
            sam_predictor(image,predictor)

            #read the json file and get the annotated objects:
            classes_dict=get_points_from_json(annotation_file)
            if not classes_dict:#check if the file is empty
                continue

            #initiate a json object to store the segmentation annotations:
            data_example, image_name= json_file_data_format(img_path=img_file,img_height=img_dim[0],img_width=img_dim[1])

            for key in classes_dict.keys():

                bboxes=np.vstack(classes_dict[key])
                #generate the masks of interest:
                masks=generate_masks_from_bboxes(bboxes,predictor,image)
                #get a list of segmentations:
                polygons=get_segmentations_from_mask(masks,smooth)

                #append to the annotations to the json file:
                for obj in polygons:

                    obj=np.vstack(obj).squeeze()
                    #elemenat files that have one dim
                    if np.ndim(obj)==1:
                        continue

                    #fill the annotation data
                    data_example['shapes'].append({'label':key,
                    'points':obj.tolist(), 'group_id': None,
                    'shape_type':"polygon",
                    "flags": {}})

            #write the annotations into json file:
            write_json(saving_path,image_name,data_example)
            print(f'This is file number: {num} | Progress: {(num/len(all_annotations))*100}%')
        except Exception as e:
            print(e)
            warnings.warn(f"This file has an Exception check it: {annotation_file}.", UserWarning)
            files_with_exceptions.append(annotation_file)
            continue

    os.mkdir(os.path.join(saving_path,'missing_and_exception_files'))
    f_missing_name=os.path.join(saving_path,'missing_and_exception_files','missing_images')
    f_with_exceptions_name=os.path.join(saving_path,'missing_and_exception_files','files_with_exceptions')

    text_writer(f_missing_name,missing_images)
    text_writer(f_with_exceptions_name,files_with_exceptions)

    print('The process has been successfully completed!! Thanks for using CSSRI tools....')

def parse_config(config_path):
    with open(config_path, 'r') as file:
        return yaml.safe_load(file)

if __name__ == "__main__":
    #parser = argparse.ArgumentParser(description="CSSRI tool for converting YOLO-style rectangle annotations to segmentation annotations.")
    # parser.add_argument("img_directory", type=str, help="path to the source directory where you have the images.")
    # parser.add_argument("annotation_directory", type=str, help="path to the source directory where you have the annotations.")
    # parser.add_argument("saving_path", type=str, help="Path where the json files will be saved in.")
    # parser.add_argument("sam_checkpoint_path", type=str, help="Path to sam checkpoint.")
    # parser.add_argument("--smooth", action='store_true', help="Optional argument to apply smoothening to the polygons.")

    parser = argparse.ArgumentParser(description="CSSRI tool for converting YOLO-style rectangle annotations to segmentation annotations.")
    parser.add_argument('--config', type=str, help='Path to the configuration file')
    args = parser.parse_args()

    config = parse_config(args.config)

    #run(args.img_directory, args.annotation_directory, args.saving_path, args.sam_checkpoint_path,args.smooth)
    run(config['img_directory'], config['annotation_directory'], config['saving_path'], config['sam_checkpoint_path'], config.get('smooth', False))


import unittest
import interpolation
import numpy as np
from numpy import genfromtxt
import sys
import os.path

nan = np.nan
basepath = os.path.dirname(__file__)

sparse_array = np.array([[37.454012, 95.071431, 73.199394, 59.865848, nan],
                         [15.599452, 5.808361, 86.617615, 60.111501, 70.807258],
                         [2.058449, 96.990985, nan, 21.233911, 18.182497],
                         [nan, 30.424224, 52.475643, 43.194502, 29.122914],
                         [61.185289, 13.949386, 29.214465, nan, 45.606998]
                         ])

output_array = np.array([[37.454012, 95.071431, 73.199394, 59.865848, nan],
                         [15.599452, 5.808361, 86.617615, 60.111501, 70.807258],
                         [2.058449, 96.990985, 59.112448, 21.233911, 18.182497],
                         [31.621869, 30.424224, 52.475643, 43.194502, 29.122914],
                         [61.185289, 13.949386, 29.214465, 37.4107315, 45.606998]])

class TestInterpolation(unittest.TestCase):

    def test_parseMatrix_ok(self):

        fp = os.path.abspath(os.path.join(
            basepath, "..", "example_data/input_test_data.csv"))

        result = interpolation.parseMatrix(fp)
        raw = genfromtxt(fp, delimiter=',')

        np.testing.assert_array_equal(raw, result)

    def test_parseMatrix_no_missing(self):

        fp = os.path.abspath(os.path.join(
            basepath, "..", "example_data/interpolated_test_data.csv"))

        with self.assertRaises(ValueError) as context:
            interpolation.parseMatrix(fp)

        self.assertTrue(
            "This array does not contain any 'nan' values" in str(context.exception))

    def test_interpolateMatrix_ok(self):

        interpolation.interpolateMatrix(sparse_array)

        fp = os.path.abspath(os.path.join(
            basepath, "..", "output.csv"))

        raw = genfromtxt(fp, delimiter=',')

        np.testing.assert_array_equal(output_array, raw)

    def test_interpolateMatrix_not_ndarray(self):

        test_list = [1, 2, 3]

        with self.assertRaises(ValueError) as context:
            interpolation.interpolateMatrix(test_list)

        self.assertTrue(
            "The array should be an numpy ndarray" in str(context.exception))

    def test_interpolateMatrix_invalid_method(self):

        with self.assertRaises(ValueError) as context:
            interpolation.interpolateMatrix(sparse_array,int_method="test")

        self.assertTrue(
            "The interpolation method must be one of: linear, cubic, nearest. 'test' is invalid" in str(context.exception))

if __name__ == '__main__':
    unittest.main()


import discord
import time
import asyncio
import json
from discord.ext import commands
from rolecommands import roles_command, addrole_command, removerole_command
from apod import apodLoad, apodSend
from purge import purge
from iss import send_iss

intents = discord.Intents.all()
client = commands.Bot(intents=intents, command_prefix='!')
client.remove_command('help')

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

@client.event
async def on_ready():
    print("AstroBot is online!")
    await client.wait_until_ready()

    try:
        synced = await client.tree.sync()
        print(f"Synced {len(synced)} commands")

    except Exception as e:
        print(f"Error syncing commands: {e}")

    isImg = None

    while not client.is_closed():
        t = time.localtime()
        current_time = time.strftime("%H:%M:%S", t)

        if current_time == "11:58:00":
            if isImg is None:
                isImg = apodLoad(config["NASA API KEY"])
        if current_time == "12:00:00":
            if isImg is not None:
                await apodSend(client, config, isImg)
                isImg = None

        await asyncio.sleep(1)

@client.tree.command(name='ping', description="Ping the bot! (Just to test)")
async def ping(interaction: discord.Interaction):
    await interaction.response.send_message(f"{interaction.user.mention} pong!", ephemeral=True)

@client.tree.command(name='iss', description="Find out where the ISS is currently overhead!")
async def iss(interaction: discord.Interaction):
    await send_iss(interaction, client, config["ISS CHANNEL ID"])

@client.tree.command(name='roles', description="View all available roles in the server.")
async def roles(interaction: discord.Interaction):
    await roles_command(interaction, client)

@client.tree.command(name='addrole', description="Assign yourself a role.")
async def roles(interaction: discord.Interaction, rolename: str):
    await addrole_command(interaction, rolename, client)

@client.tree.command(name='removerole', description="Remove a role from your account.")
async def roles(interaction: discord.Interaction, rolename: str):
    await removerole_command(interaction, rolename, client)

@client.event
async def on_message(message: discord.Message):
    try:
        print(f"User {message.author} just sent this message in {message.channel.name}: {message.content}")
    except AttributeError as e:
        print(f"Error displaying message sent by {message.author}: {e}")

    if message.author == client.user:
        return

    elif message.content.startswith('-apod-load'):
        if not message.author.guild_permissions.administrator:
            await message.reply('Sorry, you do not have permission to use this command!')
            return

        apodLoad(config["NASA API KEY"])

    elif message.content.startswith('-apod-send-img'):
        if not message.author.guild_permissions.administrator:
            await message.reply('Sorry, you do not have permission to use this command!')
            return

        await apodSend(client, config, isImg=True)

    elif message.content.startswith('-apod-send-vid'):
        if not message.author.guild_permissions.administrator:
            await message.reply('Sorry, you do not have permission to use this command!')
            return

        await apodSend(client, config, isImg=False)

    elif message.content.startswith('-purge'):
        if not message.author.guild_permissions.administrator:
            await message.reply('Sorry, you do not have permission to use this command!')
            return
        str = message.content[7:]
        await purge(message, str)

client.run(config["TOKEN"])


import cv2
import numpy as np
import read_stardict
import pytesseract
import spacy
import re
import string

class OCR:
    """
    Interface for the class:
    ocr = OCR(filename, hsv_lower, hsv_upper)
    ocr.recognize() returns a list of detected highlighted English words

    hsv_lower and hsv_upper is a list that defines specified hsv color range
    """

    def __init__(self, image_file, hsv_lower, hsv_upper):
        self.image = image_file #cv2.imread(image_file)
        self.hsv_lower = hsv_lower
        self.hsv_upper = hsv_upper
        self.dic = read_stardict.Dictionary('stardict-lazyworm-ec-2.4.2/')

        self.rgb = cv2.cvtColor(self.image.copy(), cv2.COLOR_BGR2RGB)

        # rgb to HSV color spave conversion
        hsv_img = cv2.cvtColor(self.image, cv2.COLOR_BGR2HSV)
        HSV_lower = np.array(hsv_lower, np.uint8)  # Lower HSV value
        HSV_upper = np.array(hsv_upper, np.uint8)  # Upper HSV value

        # Threshold
        frame_threshed = cv2.inRange(hsv_img, HSV_lower, HSV_upper)

        # find connected components
        self.contours, self.hierarchy, = cv2.findContours(frame_threshed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

        self.sp = spacy.load('en_core_web_sm')

    def find_and_format_word(self, word):
        if not word:
            return '', ''
        lemma_word = self.sp(word)
        if lemma_word[0].lemma_ == word:
            chinese_text = self.dic.lookup(word)
        else:
            chinese_text = self.dic.lookup(lemma_word[0].lemma_)
        if chinese_text:
            formated_chinese = chinese_text.replace('\n', ' ')
            return formated_chinese, chinese_text
        return '', ''

    # get the thresholded image
    def threshold_image(self, img, v):
        gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
        ret, th = cv2.threshold(gray, v, 255, cv2.THRESH_BINARY)
        return th

    def calc_areas(self):
        areas = []
        for cnt in self.contours:
            area = cv2.contourArea(cnt)
            areas.append(area)
        self.areas = np.array(areas)

    def warp_image(self, rgb_image):
        warped_images = []
        for cnt in self.contours:
            area = cv2.contourArea(cnt)
            if area > np.mean(self.areas):

                rect = cv2.minAreaRect(cnt)
                big_rect = (rect[0], (1.5 * rect[1][0], 1.5 * rect[1][1]), rect[2])
                box = cv2.boxPoints(big_rect)
                box = np.int0(box)

                width = int(big_rect[1][0])
                height = int(big_rect[1][1])

                src_pts = box.astype("float32")
                # coordinate of the points in box points after the rectangle has been
                # straightened
                dst_pts = np.array([[0, height - 1],
                                    [0, 0],
                                    [width - 1, 0],
                                    [width - 1, height - 1]], dtype="float32")
                # the perspective transformation matrix
                M = cv2.getPerspectiveTransform(src_pts, dst_pts)

                # directly warp the rotated rectangle to get the straightened rectangle
                warped = cv2.warpPerspective(rgb_image, M, (width, height))
                if width < height:
                    warped = np.rot90(warped)
                warped_images.append(warped)
        return warped_images

    def remove_non_english(self, warped, v):
        '''
        Input:
        warped, single bounded image for a potential word
        v is the value for thresholding, can be 120, 150, or 180

        Return,
        a English word from a dictionary or None
        '''
        th = self.threshold_image(warped, v)
        candidate = pytesseract.image_to_string(th)
        regex = re.compile('[%s]' % re.escape(string.punctuation))
        candidate = regex.sub('', candidate)
        words = [] or re.split(r'\—|\s+|\n', candidate)
        print(words)
        longest_word = ''
        definition = ''
        for idx, word in enumerate(words):
            formatted_chinese, chinese = self.find_and_format_word(word)
            if chinese:
                if len(longest_word) < len(word):
                    longest_word = word
                    definition = formatted_chinese
        return longest_word, definition

    def recognize(self):
        v = [120, 150, 180]
        """
        :return: a list of list of English words and their definitions
        """
        ans = []
        self.calc_areas()
        warped_images = self.warp_image(self.rgb)
        for warped in warped_images:
            target_word, target_definition = '', ''
            for val in v:
                word, definition = self.remove_non_english(warped, val)
                if len(target_word) < len(word):
                    target_word = word
                    target_definition = definition
            if target_word != '' and target_definition != '':
                ans.append([target_word, target_definition])
        return ans


import os
import json
import numpy as np
from enum import IntEnum
import random
from mopgrid.simerrors import SimulationError, SimulationErrorCode

class CellType(IntEnum):
    EMPTY = 0
    WALL = 1
    DIRTY = 2

class Coords:
    def __init__(self, row, col):
        self.row = row
        self.col = col

    def __str__(self):
        return "[" + str(self.row) + ", " + str(self.col) + "]"

class AgentState:
    def __init__(self, agent_id, loc):
        self.agent_id = agent_id
        self.loc = loc

    def move_to(self, to_loc):
        self.loc = to_loc

class Command:
    def __init__(self, agent_id, command, location=None):
        self.agent_id = agent_id
        self.command = command
        self.location = location
        self.status = False
        self.failure_reason = None

def clean_command(agent_id, loc):
    return Command(agent_id=agent_id, command="clean", location=loc)

def moveto_command(agent_id, loc):
    return Command(agent_id=agent_id, command="move_to", location=loc)

class Space:
    def __init__(self, size=Coords(10, 10), dirty_prob=0.3, wall_prob=0.2):
        self.size = size
        self.dirty_prob = dirty_prob
        self.wall_prob = wall_prob
        self.space = np.zeros([size.row, size.col], dtype=int)
        self.agent_space = np.zeros([size.row, size.col], dtype=int)
        self.random_wall()
        self.random_dirty()
        self.agents = {}

    def random_wall(self):
        for y in range(self.size.row):
            for x in range(self.size.col):
                r = random.random()
                if r <= self.wall_prob:
                    self.space[y, x] = CellType.WALL

    def random_dirty(self):
        for y in range(self.size.row):
            for x in range(self.size.col):
                if self.space[y, x] != CellType.WALL:
                    r = random.random()
                    if r <= self.dirty_prob:
                        self.space[y, x] = CellType.DIRTY

    def query(self, loc):
        return self.space[loc.row, loc.col]

    def is_dirty(self, loc):
        return self.query(loc) == CellType.DIRTY

    def is_wall(self, loc):
        return self.query(loc) == CellType.WALL

    def is_clean(self, loc):
        return not self.is_dirty(loc)

    def has_agent(self, loc):
        val = self.query(loc)
        if val > 2 and val % 2 == 1:
            return True
        else:
            return False

    def can_place_agent(self, loc):
        if self.query(loc) == CellType.EMPTY or self.is_dirty(loc):
            return True
        return False

    def where_am_i(self, agent_id):
        a = self.agents[agent_id]
        if a is not None:
            return a.loc
        else:
            return None

    def init_agent(self):
        count_tries = 0
        while count_tries < 10:
            row = random.randint(0, self.size.row - 1)
            col = random.randint(0, self.size.col - 1)
            loc = Coords(row, col)

            if self.can_place_agent(loc):
                agent_id = -1
                if len(self.agents.keys()) == 0:
                    agent_id = 3
                else:
                    agent_id = max(self.agents.keys()) + 2
                print("agent added = " + str(agent_id))
                self.agents[agent_id] = AgentState(agent_id, loc)
                self.agent_space[loc.row, loc.col] = agent_id
                return agent_id
            count_tries += 1

    def check_range(self, loc):
        if loc.row < 0 or loc.row >= self.size.row or loc.col < 0 or loc.col >= self.size.col:
            raise SimulationError("Row/col is out of range: " + str(loc),
                                  SimulationErrorCode.SIM_ERR_OUT_OF_RANGE, loc)

    def move_to(self, agent_id, to_loc):
        self.check_range(to_loc)
        if agent_id in self.agents:
            a = self.agents[agent_id]
            if abs(to_loc.row - a.loc.row) < 2 and abs(to_loc.col - a.loc.col) < 2:
                if not self.is_wall(to_loc):
                    if self.is_clean(to_loc) or self.is_dirty(to_loc):
                        self.agent_space[a.loc.row, a.loc.col] = CellType.EMPTY
                        self.agent_space[to_loc.row, to_loc.col] = agent_id
                        a.move_to(to_loc)
                    else:
                        raise SimulationError("There is already an agent there!",
                                              SimulationErrorCode.SIM_ERR_AGENT_COLLISION, to_loc)
                else:
                    raise SimulationError("Cannot move into a wall!",
                                          SimulationErrorCode.SIM_ERR_MOVE_TO_WALL, to_loc)
            else:
                raise SimulationError("New location is not adjacent!",
                                      SimulationErrorCode.SIM_ERR_LOCATION_NOT_ADJACENT, to_loc)
        else:
            raise SimulationError("Agent does not exist!",
                                  SimulationErrorCode.SIM_ERR_NO_SUCH_AGENT, to_loc)

    def clean(self, agent_id, to_loc):
        self.check_range(to_loc)
        if agent_id in self.agents:
            a = self.agents[agent_id]
            if a.loc.row == to_loc.row and a.loc.col == to_loc.col:
                if self.is_dirty(to_loc):
                    self.space[to_loc.row, to_loc.col] = CellType.EMPTY
                else:
                    raise SimulationError("Location is not dirty!", SimulationErrorCode.SIM_ERR_LOCATION_NOT_DIRTY,
                                          to_loc)
            else:
                raise SimulationError("Agent is not at the location to clean!",
                                      SimulationErrorCode.SIM_ERR_AGENT_NOT_AT_LOCATION, to_loc)
        else:
            raise SimulationError("Agent does not exist!",
                                  SimulationErrorCode.SIM_ERR_NO_SUCH_AGENT, to_loc)

    def total_dirty(self):
        count = 0
        for i in range(self.size.row):
            for j in range(self.size.col):
                if self.is_dirty(Coords(i, j)):
                    count += 1
        return count

    def has_dirty(self):
        # can improve by returning after finding first dirty cell
        return self.total_dirty() > 0

def sample_grid():
    gpath = os.path.join(os.getcwd(), "..", "test", "data", "sample0.json")
    with open(gpath, "r") as f:
        gstr = f.read()
        g = json.loads(gstr)
    return g

if __name__ == "__main__":
    s = Space()
    print(s.space)


import logging

from flask import jsonify, request

from app import app, api
from app.resources.appointment import AppointmentsResource, AppointmentsItemResource
from app.resources.patient import PatientsResource, PatientsItemResource
from app.resources.provider import ProvidersResource, ProvidersItemResource

logger = logging.getLogger(__name__)

API_PREFIX = '/v1'

@app.route('/')
def index():
    return jsonify({'index': 'page'})

api.add_resource(AppointmentsResource, f'{API_PREFIX}/appointments')
api.add_resource(AppointmentsItemResource, f'{API_PREFIX}/appointments/<int:appointment_id>')

api.add_resource(PatientsResource, f'{API_PREFIX}/patients')
api.add_resource(PatientsItemResource, f'{API_PREFIX}/patients/<int:patient_id>')

api.add_resource(ProvidersResource, f'{API_PREFIX}/providers')
api.add_resource(ProvidersItemResource, f'{API_PREFIX}/providers/<int:provider_id>')

###############################
# Notification Webhook Endpoint
###############################

@app.route('/receive_notifications', methods=['POST'])
def webhook_notification_receiver():
    """
    Endpoint to receive notifications. Aware of separation of concern issues

    Only putting it here as this is a prototype and want to show we recieved
    a POST request from a webhook
    """
    logger.info(request.values)
    return jsonify({'all': 'good'})


import numpy as np
import cv2
import math
import time
from scipy.interpolate import UnivariateSpline, interp1d
from scipy import interpolate
from scipy import optimize
from scipy import integrate
from scipy import signal
from scipy import stats as st

def integrateImage(image_list, spline_x, spline_y, t_vals, arc_points):
        """
        Compute numerical integral of pixel intensity in an image along the given spline curve.
        Input:
        image_list (list): python list containing np.arrays of each image channel to be integrated
        spline_x (scipy.interpolate.UnivariateSpline): spline curve of x pixel positions (parameterized by t)
        spline_y (scipy.interpolate.UnivariateSpline): spline curve of y pixel positions (parameterized by t)
        t_vals (np.array): values of t that define points to take samples from
        arc_points (np.array): arc-length values of curve at points defined from spline(t_vals)

        Output:
        [total_val, ROI_length, width]
        total_val (np.array): array representing integrated values corresponding to  all points in arc_points
        ROI_length (np.array): image representing the straightened region of interest that we integrate. Useful for alignment.
        width (np.array): width distribution of food (deprecated)
        """
        x_deriv = spline_x.derivative()
        y_deriv = spline_y.derivative()

        average_val = []
        t_max = max(t_vals)
        ##Create sub-pixel sample points along skeleton
        radii = np.linspace(-25,25, 300)

        total_val = np.zeros((len(arc_points),len(image_list)))
        total_green_val = np.zeros(len(arc_points))
        global ROI, z, w
        ROI = np.zeros((300,len(arc_points)))
        ROI_green = np.zeros((300,len(arc_points)))
        i = 0
        theta_prev = 0
        for point_num in range(len(arc_points)): #for every sample point along arc
            t_current = t_vals[point_num]
            x = spline_x(t_current)
            y = spline_y(t_current)
            dy_dx = y_deriv(t_current)/x_deriv(t_current) #xy derivative gained from paramaterization... could result in error if denom is zero.
            #test.append(dy_dx)

            theta = np.arctan(dy_dx)
            theta_normal = theta + np.pi/2

            if point_num > 0:
                if theta_normal - theta_prev >= np.pi/2:
                    theta_normal = theta_normal - np.pi
                elif theta_prev - theta_normal >= np.pi/2:
                    theta_normal = theta_normal + np.pi
            theta_prev = theta_normal
            #want 150 sample points along normal line
            #15 px in both directions
            xs = radii * np.cos(theta_normal) + x
            ys = radii * np.sin(theta_normal) + y
            #plt.plot(xs,ys,"blue")
            #return
            floor_x = np.floor(xs-0.5)
            ceil_x = np.ceil(xs-0.5)
            floor_y = np.floor(ys-0.5)
            ceil_y = np.ceil(ys-0.5)

            #create block diagonal
            length = len(xs) * 2
            diag_mat = np.zeros((length, length,len(image_list)))
            #diag_mat_green = np.zeros((length, length))

            #global evens, lin
            evens = np.linspace(0,length-2, int(length/2))
            odds = evens + 1

            evens = evens.astype(int)
            odds = odds.astype(int)

            floor_x = floor_x.astype(int)
            floor_y = floor_y.astype(int)
            ceil_x = ceil_x.astype(int)
            ceil_y = ceil_y.astype(int)
            for image_idx in range(len(image_list)):
                diag_mat[evens, evens,image_idx] = image_list[image_idx][floor_y,floor_x]
                diag_mat[evens, odds,image_idx] = image_list[image_idx][ceil_y,floor_x]
                diag_mat[odds, evens,image_idx] = image_list[image_idx][floor_y,ceil_x]
                diag_mat[odds, odds,image_idx] = image_list[image_idx][ceil_y,ceil_x]
            #create flattened array
            xs = xs-0.5-floor_x
            ys = ys -0.5-floor_y
            one_minus_xs = 1-xs
            one_minus_ys = 1-ys
            interp_xs = np.array((one_minus_xs, xs)).T.flatten()#is two stacked on top of eo
            interp_ys = np.array((one_minus_ys, ys)).T.flatten()
            for image_idx in range(len(image_list)):
                total_val[point_num,image_idx] = (np.dot(interp_xs @ diag_mat[:,:,image_idx], interp_ys))
            #total_green_val[point_num] = (np.dot(interp_xs @ diag_mat_green, interp_ys))

            ##For visualizing spread of intensity
            diag_y_mat = np.zeros((length, int(length/2)))
            lin = np.linspace(0,int(length/2)-1, int(length/2))
            lin = lin.astype(int)
            diag_y_mat[evens,lin] = interp_ys[evens]
            diag_y_mat[odds,lin] = interp_ys[odds]
            #smoothed_signal = signal.savgol_filter(interp_xs @ diag_mat[:,:,1] @ diag_y_mat, 50, 3)

            ROI[:,i] = interp_xs @ diag_mat[:,:,0] @ diag_y_mat
            #ROI_green[:,i] = interp_xs @ diag_mat_green @ diag_y_mat

            i+=1

        SROI = ROI.copy()
        SROIG = ROI_green.copy()
        flatten = ROI.flatten()
        mode = st.mode(np.rint(flatten[flatten > 20]))[0][0]
        w = np.count_nonzero(ROI, axis = 0)
        #ROI[ROI == 0] = -mode
        width = countWidth(ROI)
        ROI_length = np.zeros((SROI.shape[0], math.floor(arc_points.max())+1))
        #ROI_green_length = np.zeros((SROIG.shape[0], math.floor(arc_points.max())+1))
        #plt.imshow(SROI)
        #plt.show()
        for row in range(SROI.shape[0]):
            #plt.plot(arc_points, ROI[row,:])
            #plt.show()
            func = interp1d(arc_points, SROI[row,:])
            ROI_length[row,:] = func(np.linspace(0,math.floor(arc_points.max()), math.floor(arc_points.max())+1))

            func_green = interp1d(arc_points, SROIG[row,:])

        return [total_val, ROI_length, width]

def arcLengthSpline(spline_x, spline_y, x_vals, y_vals):
    """
    Given splines of x and y return np array containing (x,y) of equally spaced points along curve
    """
    arc_points = np.zeros(len(x_vals)) #arc_points is list of cumulative arc lengts
    radii = np.linspace(-25,25, 300)
    i = 0
    theta_prev = 0
    for point_num in range(1,len(x_vals)): #for every sample point along arc
        x = x_vals[point_num] # current x coordinate
        y = y_vals[point_num] # current y coordinate

        arc_points[point_num] = arc_points[point_num-1] + math.sqrt((x-x_vals[point_num-1])**2 + (y-y_vals[point_num-1])**2) # populate cumulative arc length for each point
    return arc_points

def pointsOnSpline(spline_x, spline_y, t_max, resolution):
    """
    Given scipy spline objects of the t-parameterized curve of both x and y, and query t values, return numpy array representing points along body
    Input:
        spline_x (scipy.interpolate.UnivariateSpline) spline fit of x
        spline_y (scipy.interpolate.UnivariateSpline) spline fit of y
        resolution (int) number of points between pixels
        t_max (int) t-value to interpolate to
    Output:
        pts_on_curve (np.array)
    """
    t_on_curve = np.linspace(0,int(t_max), int(t_max*resolution))
    pts_on_curve = np.array([spline_x(t_on_curve), spline_y(t_on_curve)]).T
    return t_on_curve, pts_on_curve

def fitSpline(skeleton_points):
    '''
    Given a list of points representing skeleton ordered from head to tail or tail to head, return scipy spline fit
    Input:
        skeleton_points (np.array): Ordered array containing (x,y) of points along skeleton.

    Output:
        list: [spline_x, spline_y, t_vals, x_vals, y_vals]
        spline_x (scipy.interpolate.UnivariateSpline) spline fit of x
        spline_y (scipy.interpolate.UnivariateSpline) spline fit of y
    '''
    x_vals = []
    y_vals = []
    t_vals = []

##Fit skeleton to spline curve
    for point_num in range(len(skeleton_points)-1): #Arrange x, y values in increasing order
        x_vals.append(skeleton_points[point_num][1]) #look here for flipped x,y
        y_vals.append(skeleton_points[point_num][0])
        t_vals.append(point_num)
    t_vals.append(len(skeleton_points)) # assign parameter t to each point
    x_vals.append(skeleton_points[-1][1])
    y_vals.append(skeleton_points[-1][0])
    spline_x = UnivariateSpline(t_vals, x_vals) # fit x values to spline
    #global x_deriv, y_deriv
    x_deriv = spline_x.derivative() # x derivative
    spline_y = UnivariateSpline(t_vals,y_vals) #fit y values to spline
    y_deriv = spline_y.derivative() #y derivative

    #ax2.plot(spline_x(t_vals), spline_y(t_vals))

    return [spline_x, spline_y, t_vals, x_vals, y_vals]

#intestine_start_pos = 470
#intestine_max_pos = 570

def correlation_lags(in1_len, in2_len, mode='full'):
    # calculate lag ranges in different modes of operation
    if mode == "full":
        # the output is the full discrete linear convolution
        # of the inputs. (Default)
        lags = np.arange(-in2_len + 1, in1_len)
    elif mode == "same":
        # the output is the same size as `in1`, centeresshs
        # with respect to the 'full' output.
        # calculate the full output
        lags = np.arange(-in2_len + 1, in1_len)
        # determine the midpoint in the full output
        mid = lags.size // 2
        # determine lag_bound to be used with respect
        # to the midpoint
        lag_bound = in1_len // 2
        # calculate lag ranges for even and odd scenarios
        if in1_len % 2 == 0:
            lags = lags[(mid-lag_bound):(mid+lag_bound)]
        else:
            lags = lags[(mid-lag_bound):(mid+lag_bound)+1]
    elif mode == "valid":
        # the output consists only of those elements that do not
        # rely on the zero-padding. In 'valid' mode, either `in1` or `in2`
        # must be at least as large as the other in every dimension.

        # the lag_bound will be either negative or positive
        # this let's us infer how to present the lag range
        lag_bound = in1_len - in2_len
        if lag_bound >= 0:
            lags = np.arange(lag_bound + 1)
        else:
            lags = np.arange(lag_bound, 1)
    return lags

def bilinear_interpolation(x, y, points):
    '''Interpolate (x,y) from values associated with four points.

    The four points are a list of four triplets:  (x, y, value).
    The four points can be in any order.  They should form a rectangle.

        >>> bilinear_interpolation(12, 5.5,
        ...                        [(10, 4, 100),
        ...                         (20, 4, 200),
        ...                         (10, 6, 150),
        ...                         (20, 6, 300)])
        165.0

    '''
    # See formula at:  http://en.wikipedia.org/wiki/Bilinear_interpolation

    points = sorted(points)               # order points by x, then by y
    (x1, y1, q11), (_x1, y2, q12), (x2, _y1, q21), (_x2, _y2, q22) = points

    if x1 != _x1 or x2 != _x2 or y1 != _y1 or y2 != _y2:
        raise ValueError('points do not form a rectangle')
    if not x1 <= x <= x2 or not y1 <= y <= y2:
        raise ValueError('(x, y) not within the rectangle')

    return (q11 * (x2 - x) * (y2 - y) +
            q21 * (x - x1) * (y2 - y) +
            q12 * (x2 - x) * (y - y1) +
            q22 * (x - x1) * (y - y1)
           ) / ((x2 - x1) * (y2 - y1) + 0.0)

def interpolateIntensity(values, xpoints, max_arc_length,spacing): #only for first frame now
    """
    Interpolate the array "values" at integer arc length inputs.
    Input:
    values (np.array): array representing the food distribution function evaluated at non equispaced intervals (non equispaced due to how we step along the spline curve of worm)
    xpoints (np.array): array representing the arc length values of each corresponding value
    max_arc_length (int): integer representing the rounded max domain of sequence. We create an array of length "max_arc_length" for the output interpolated sequence.
    spacing (int): integer representing how many inter-integer points we want to output.

    Output:
    interpolated_vals (np.array): array representing the food distribution at standardized domain values. Useful for kymograph representation.
    """

    row_vec = np.zeros((max_arc_length*spacing+400))
    if xpoints[0] > 0:
        initial_l = xpoints[0]
        xpoints = np.pad(xpoints, [(math.ceil(initial_l),0)],mode = 'linear_ramp')
        for val in range(len(values)):
            values[val] = np.pad(values[val], [(math.ceil(initial_l),0)],mode='constant')

    diff = math.ceil(max_arc_length - xpoints.max()) #max arc length for first frame is always gonna be lower by 10%. Diff is positive
    if diff > 0: #fill with zeros
        xpoints = np.pad(xpoints, [(0,diff)], mode='linear_ramp',end_values = ((0,xpoints.max() + diff)))
        for val in range(len(values)):
            values[val] = np.pad(values[val], [(0,int(diff))],mode = 'constant')

        #print("change?")
    #plt.plot(xpoints,total_val)
    #plt.show()
    dict_func = {}
    for val in range(len(values)):
        dict_func[val] = interp1d(xpoints, values[val])

    '''Change based on expected length'''
    xnew = np.linspace(1,max_arc_length,max_arc_length*spacing)
    interpolated_vals = []
    for val in range(len(values)):
        row_vec[200:max_arc_length*spacing+200] = dict_func[val](xnew)
        interpolated_vals.append(row_vec.copy())
    return interpolated_vals.copy()

def countWidth(FI):
    #split down middle,
    FI = FI.copy()
    width = np.zeros(FI.shape[1])
    half1 = FI.shape[0] // 2
    half2 = FI.shape[0] - half1
    for col_num in range(FI.shape[1]):
        col = FI[:,col_num]
        col[col < 0] = -1
        col[col > 0] = 0
        col_first_half = col[:half1]
        num_zeros_first_half = len(col_first_half) - len(np.trim_zeros(col_first_half,'b'))
        col_second_half = col[half2:]
        num_zeros_second_half = len(col_second_half) - len(np.trim_zeros(col_second_half,'f'))
        width[col_num] = num_zeros_first_half + num_zeros_second_half
    return width

def displayThreshold(image, spline_x, spline_y, t_vals, x_vals,y_vals):
        x_deriv = spline_x.derivative()
        y_deriv = spline_y.derivative()

        average_val = []
        t_max = max(t_vals)
        x1_vals = x_vals[:]
        y1_vals = y_vals[:]
        t1_vals = t_vals[:]
        x_vals = [] #x coordinate list of points to be sampled along arc
        y_vals = [] #y coordinate list of points to be sampled along arc
        t_vals = [] #t paramaterization
        ##Create sub-pixel sample points along skeleton
        for sample_pt in range(t_max*4): #currently we have one sample point per pixel gained from the skeleton, but since we have the spline fit we can sample subpixel points along arc.
            x_vals.append(float(spline_x(sample_pt*0.25)))
            y_vals.append(float(spline_y(sample_pt*0.25)))
            t_vals.append(sample_pt*0.25)
        #self.t_vals = t_vals
        #self.x_vals = x_vals
        #self.y_vals = y_vals
        #times = []
        #test = []
        arc_points = np.zeros(len(x_vals)) #arc_points is list of cumulative arc length
        arc_points[0] = 0
        #splx = UnivariateSpline(t_vals,x_vals)
        #sply = UnivariateSpline(t_vals,y_vals)
        #dx = splx.derivative()
        #dy = sply.derivative()
        radii = np.linspace(-25,25, 300)

        total_val = np.zeros(len(x_vals))
        global ROI, z, w
        ROI = np.zeros((300,len(x_vals)))
        i = 0
        switch = True
        for point_num in range(len(x_vals)): #for every sample point along arc
            #print(len(x_vals))
            x = x_vals[point_num] # current x coordinate
            y = y_vals[point_num] # current y coordinate
            #if point_num == 1720:
                #print(x,y)
            if point_num ==0:
                arc_points[point_num] = 0
            else:
                arc_points[point_num] = arc_points[point_num-1] + math.sqrt((x-x_vals[point_num-1])**2 + (y-y_vals[point_num-1])**2) # populate cumulative arc length for each point
            t_current = t_vals[point_num]
            dy_dx = y_deriv(t_current)/x_deriv(t_current) #xy derivative gained from paramaterization... could result in error if denom is zero.
            #test.append(dy_dx)

            theta = np.arctan(dy_dx)
            if switch == True:
                print(theta)
                switch = False
            theta_normal = theta + np.pi/2

            if point_num > 0:
                if theta_normal - theta_prev >= np.pi/2:
                    theta_normal = theta_normal - np.pi
                elif theta_prev - theta_normal >= np.pi/2:
                    theta_normal = theta_normal + np.pi
            theta_prev = theta_normal
            #want 150 sample points along normal line
            #15 px in both directions
            xs = radii * np.cos(theta_normal) + x
            ys = radii * np.sin(theta_normal) + y
            #plt.plot(xs,ys,"blue")
            #return
            floor_x = np.floor(xs-0.5)
            ceil_x = np.ceil(xs-0.5)
            floor_y = np.floor(ys-0.5)
            ceil_y = np.ceil(ys-0.5)

            #create block diagonal
            length = len(xs) * 2
            diag_mat = np.zeros((length, length))

            #global evens, lin
            evens = np.linspace(0,length-2, int(length/2))
            odds = evens + 1

            evens = evens.astype(int)
            odds = odds.astype(int)

            floor_x = floor_x.astype(int)
            floor_y = floor_y.astype(int)
            ceil_x = ceil_x.astype(int)
            ceil_y = ceil_y.astype(int)
            #for i in range(len(xs)):
                #print(i)
                #diag_mat[i*2, i*2] = img[int(floor_y[i]),int(floor_x[i])]
                #diag_mat[i*2, i*2+1] = img[int(ceil_y[i]),int(floor_x[i])]
                #diag_mat[i*2+1, i*2] = img[int(floor_y[i]),int(ceil_x[i])]
                #diag_mat[i*2+1, i*2+1] = img[int(ceil_y[i]),int(ceil_x[i])]
            diag_mat[evens, evens] = image[floor_y,floor_x]
            diag_mat[evens, odds] = image[ceil_y,floor_x]
            diag_mat[odds, evens] = image[floor_y,ceil_x]
            diag_mat[odds, odds] = image[ceil_y,ceil_x]

            #create flattened array
            xs = xs-0.5-floor_x
            ys = ys -0.5-floor_y
            one_minus_xs = 1-xs
            one_minus_ys = 1-ys
            interp_xs = np.array((one_minus_xs, xs)).T.flatten()#is two stacked on top of eo
            interp_ys = np.array((one_minus_ys, ys)).T.flatten()
            total_val[point_num] = (np.dot(interp_xs @ diag_mat, interp_ys))

            ##For visualizing spread of intensity
            diag_y_mat = np.zeros((length, int(length/2)))
            lin = np.linspace(0,int(length/2)-1, int(length/2))
            lin = lin.astype(int)
            diag_y_mat[evens,lin] = interp_ys[evens]
            diag_y_mat[odds,lin] = interp_ys[odds]
            smoothed_signal = signal.savgol_filter(interp_xs @ diag_mat @ diag_y_mat, 50, 3)

            ROI[:,i] = interp_xs @ diag_mat @ diag_y_mat

            i+=1

        flatten = ROI.flatten()
        #mode = st.mode(np.rint(flatten[flatten > 20]))[0][0] + threshold
        #ROI[ROI < mode] = 0 #try no threshold
        return ROI

def correlate2d(mat1,mat2):
    """
    Compute 2d cross correlation between 2 arrays, only along columns. mat2 is sliding on mat1

    """
    #region 1, mat1 is sliding onto mat2
    mat1_length = mat1.shape[1]
    mat2_length = mat2.shape[1]
    mat2 = mat2-mat2.mean()

    if mat1_length < mat2_length:
        z = np.zeros((mat1.shape[0],(mat2_length-mat1_length)*2))
        print(z.shape)
        mat1 = np.concatenate((z,mat1,z),axis = 1)
        #print(mat1.shape,mat2.shape)
        mat1_length = mat1.shape[1]
    #print(mat1_length, mat2_length)

    corr = np.zeros((mat1_length-mat2_length))
    #for i in range(1,mat2_length):
    #    res = np.sum(np.multiply(mat1[:,:i],mat2[:,-i:]))
    #    #print(res)
    #    corr[i-1] = res
    for i in range(mat1_length-mat2_length):
        res = np.sum(np.multiply(mat1[:,i:i+mat2_length]-mat1[:,i:i+mat2_length].mean(), mat2))
        res = res/math.sqrt(np.sum(np.multiply(np.power(mat1[:,i:i+mat2_length]-mat1[:,i:i+mat2_length].mean(),2), np.power(mat2,2))))

        corr[i] = res
    #for i in range(1,mat2_length):
    #    res = np.sum(np.multiply(mat1[:,-i:],mat2[:,:i]))
    #    corr[i+mat1_length-1] = res
    return corr


import os

import urllib.request
import urllib.error
from html_parser import HTMLParser

def health_check():
    """
    Run set of health checks contained in this file

    :return response, code: string and integer response from health request to service
    """
    s_resp, s_code = service_health_check()
    c_resp, c_code = connection_health_check()

    # If there is an internal server error we report that as more fundamental than other checks
    # Otherwise report the outbound connection result whether positive/negative.
    if s_code != 200:
        return s_resp, s_code
    else:
        return c_resp, c_code

def service_health_check():
    """
    Verify that service is running by parsing local file

    :return: JSON string specifying whether service is working
    """
    url = 'file:' + os.path.join('test_files', 'basic_test.html')
    parser = HTMLParser(url=url)
    response = parser.text()

    expected_response = {'tell': 2, 'the': 1, 'audience': 1, 'what': 2, "youre": 1, 'going': 1,
                         'to': 1, 'say': 2, 'it': 1, 'then': 1, 'them': 1, "youve": 1, 'said': 1}

    if expected_response != response:
        return {"health": "HTML Parser service not running"}, 503

    return {"health": "HTML Parser service is good"}, 200

def connection_health_check():
    """
    Verify outbound connection from service.
    Assumption made that BBC news will always be up and accessible

    :return: JSON string specifying health of outbound connection
    """
    try:
        HTMLParser(url='https://www.bbc.co.uk/news')
    except ValueError:
        return {"health": "URL provided is not valid"}, 504
    except urllib.error.URLError:
        return {"health": "URL provided does not return response"}, 504

    return {"health": "HTML Parser service is good"}, 200


import re
from dataclasses import dataclass, field
from ipaddress import IPv4Address

from .connection import CiscoConnection
from .models import *
from .base import CiscoBase
from ..ssh.error import *

class CiscoRouter(CiscoBase):

    def __init__(self, host, discover=True):
        super().__init__(host, discover)

        if discover:
            self.Connection.connect()

            self.OSPFNeighbors = []
            self._discover_ospf()

            self.Connection.close()

    def _discover_ospf(self):
        for i in self.Connection.command('sh ip ospf neigh | i Gi*').split('\r\n'):
            if len(i.split(' ')) > 1:
                res = []
                for s in i.split(' '):
                    if s != '':
                        res.append(s)
                NeighborID, Priority, State, DeadTime, IPv4Address, Interface = res
                self.OSPFNeighbors.append(OSPFNeighbor(self.Hostname, NeighborID, Priority, State, DeadTime, IPv4Address, Interface))


"""
A module for cropping data from the VGG Face 2 dataset,
available at http://www.robots.ox.ac.uk/~vgg/data/vgg_face2/

The website contains not only images but also face bounding boxes
that we use to crop each image. We then resize each image
to a default of 160 x 160 x 3, which is the input
for the FaceNet model available from
https://github.com/nyoki-mtl/keras-facenet
"""
import os
import tensorflow as tf
import numpy as np
import pandas as pd
import h5py
from tqdm import tqdm
from skimage.util import img_as_ubyte
from utils import set_up_environment, maximum_center_crop, prewhiten, l2_normalize, read_sampled_identities

from PIL import Image

from absl import app, flags

VGG_BASE = '/projects/leelab3/image_datasets/vgg_face/'
#VGG_BASE = '/data/vggface'

FLAGS = flags.FLAGS
flags.DEFINE_string('image_directory',
                    os.path.join(VGG_BASE, 'test'),
                    'Top level directory for images')
flags.DEFINE_string('output_directory',
                    os.path.join(VGG_BASE, 'test_preprocessed_sampled'),
                    'Top level directory to output adversarially-modified images')
flags.DEFINE_string('bbox_file',
                    os.path.join(VGG_BASE, 'bb_landmark/loose_bb_test.csv'),
                    'CSV file containing bounding boxes for each desired image')
flags.DEFINE_string('sampled_identities',
                    'sampled_identities.txt',
                    'txt file generated by sample_identities.py to preprocess')
flags.DEFINE_string('op',
                   'preprocess',
                    'One of `preprocess` or `write_embeddings` - operation mode for script')
flags.DEFINE_integer('resize_dimension',
                     160,
                     'Dimension to resize all images to')
flags.DEFINE_string('visible_devices', '0', 'CUDA parameter')
flags.DEFINE_integer('batch_size',
                     64,
                     'Batch size to use for creating embeddings')
flags.DEFINE_string('model_path',
                    'keras-facenet/model/facenet_keras.h5',
                    'Path to keras model')

flags.DEFINE_boolean('process_train', False, 'Turn on this flag to process the training set')

def preprocess():
    """
    Pre-processes the VGG Face 2 dataset by cropping, resizing and
    writing as h5 files, which should be faster to read than
    numpy arrays or jpg files.
    """
    # Bounding box data is from
    # http://www.robots.ox.ac.uk/~vgg/data/vgg_face2/meta_infor.html
    # CSV file is of the form: NAME_ID, X, Y, W, H
    bbox_df = pd.read_csv(FLAGS.bbox_file)

    if FLAGS.sampled_identities != "":
        sampled = read_sampled_identities(FLAGS.sampled_identities)
        sampled = pd.DataFrame(np.array([["{}/{}".format(k, v.split(".")[0]) for v in sampled[k]] for k in sampled]).flatten())
        # do a join to filter selected identities and frames
        bbox_df = pd.merge(left=bbox_df, right=sampled, left_on='NAME_ID', right_on=0)

    image_batch = []
    for index, row in tqdm(bbox_df.iterrows()):
#         name_id, x, y, w, h, _ = row
        name_id, x, y, w, h = row
        current_identity = name_id.split('/')[0]
        x = max(x, 0)
        y = max(y, 0)
        # Read in the image
        image_path = os.path.join(FLAGS.image_directory, name_id + '.jpg')
        image = Image.open(image_path).crop((x, y, x + w, y + h)).resize(size=(FLAGS.resize_dimension,
                                                                              FLAGS.resize_dimension))
        resized_image = np.array(image)
        ubyte_image    = img_as_ubyte(resized_image)
        image_batch.append(ubyte_image)
        # When we are done with a batch of images (one identity)...
        if index == len(bbox_df) - 1 or \
           current_identity != bbox_df.loc[index + 1, 'NAME_ID'].split('/')[0]:
            image_batch = np.stack(image_batch, axis=0)
            os.makedirs(os.path.join(FLAGS.output_directory,
                                     current_identity), exist_ok=True)
            # ...we save the batch of images belonging to that identity to an
            # h5 file.
            file_path = os.path.join(FLAGS.output_directory, current_identity, 'images.h5')
            with h5py.File(file_path, 'w') as dataset_file:
                dataset_file.create_dataset('images', data=image_batch)

            image_batch = []

def write_embeddings():
    """
    Runs the embedding model over the pre-processed dataset and saves the embeddings into h5py datasets.
    """
    set_up_environment(visible_devices=FLAGS.visible_devices)
    model = tf.keras.models.load_model(FLAGS.model_path)

    if FLAGS.sampled_identities != "":
        sampled = read_sampled_identities(FLAGS.sampled_identities)

    identities = os.listdir(FLAGS.image_directory)
    for identity in tqdm(identities):
        # bypass identities not in sample, if a sampled file is provided
        if FLAGS.sampled_identities != "" and not (identity in sampled):
            continue

        image_file = os.path.join(FLAGS.image_directory,
                                  identity,
                                  'images.h5')

        with h5py.File(image_file, 'r') as f:
            images = f['images'][:]

        images_whitened = prewhiten(images).astype(np.float32)
        embeddings = model.predict(images_whitened, batch_size=FLAGS.batch_size)
        normalized_embeddings = l2_normalize(embeddings)

        os.makedirs(os.path.join(FLAGS.output_directory,
                                 identity),
                    exist_ok=True)

        embedding_path = os.path.join(FLAGS.output_directory,
                                      identity,
                                      'embeddings.h5')
        with h5py.File(embedding_path, 'w') as dataset_file:
            dataset_file.create_dataset('embeddings', data=normalized_embeddings)

def main(argv=None):
    '''
    Call either preprocess or write_embeddings and print error if not one of these
    '''
    try:
        func = globals()[FLAGS.op]
    except KeyError:
        raise Exception("FLAGS.op must be one of `preprocess` or `write_embeddings`, currently is {}".format(FLAGS.op))

    func()

if __name__ == '__main__':
    app.run(main)


def SelectionSort(list1,k):
    for i in range((k)):
        minpos=i
        for j in range(i,(k)):
           if list1[j]<list1[minpos]:
                minpos=j
        temp=list1[i]
        list1[i]=list1[minpos]
        list1[minpos]=temp
num=int(input())
list1=[int(input()) for i in range(num)]
SelectionSort(list1,num)
print(list1)


from abc import ABC, abstractmethod
import cvxpy as cvx

__all__ = ['DefaultReturns', ]

class BaseReturns(ABC):
    """Estimated returns """

    def __init__(self,  w_benchmark=0., cash_ticker='_CASH', **kwargs):
        """Args:

            w_benchmark:  benchmark weight single column data frame
            cash_ticker: the cash_ticker
        """
        self.w_benchmark = w_benchmark
        self.cash_ticker = cash_ticker

    @abstractmethod
    def expr(self, t, w_plus, z, v, theta):
        """Returns the estimate at time t of alpha at time tau.

        Args:
            t: time
            w_plus: post-trade weights
            z: trade weights
            v: portfolio dollar value
            theta: int: how many extra step extra to predict, default to 0 for single period
        """
        # TO DO to put back benchmark
        pass

class DefaultReturns(BaseReturns):
    def __init__(self, returns, deltas, gamma_decay, **kwargs):
        """
        Args:
            returns: dictionary as_of_time: pd.DataFrame(forecast_time, ticker)
            deltas: dictionary as_of_time: pd.DataFrame(forecast_time, ticker)
        """
        super().__init__(**kwargs)
        self.returns = returns
        self.deltas = deltas
        self.gamma_decay = gamma_decay

    def expr(self, t, w_plus, z, v, theta=0):
        returns = self.returns[t].iloc[theta].values
        deltas = self.deltas[t].iloc[theta].values

        #####
        # alpha = cvx.mul_elemwise(returns, w_plus)
        # alpha -= cvx.mul_elemwise(deltas, cvx.abs(w_plus))
        # estimate = cvx.sum_entries(alpha)
        ######
        # estimate = returns.T * w_plus
        #####

        estimate = cvx.mul_elemwise(returns, w_plus)
        estimate -= cvx.mul_elemwise(deltas, cvx.abs(w_plus))
        estimate = cvx.sum_entries(estimate)
        if theta > 0 and self.gamma_decay is not None:
            estimate *= theta ** (-self.gamma_decay)
        return estimate


import os
import sys
import pickle
import numpy as np
import pandas as pd
import dill
from sklearn.metrics import r2_score

from src.exception import CustomException
from src import logger

def save_object(file_path, obj):
    try:
        dir_path = os.path.dirname(file_path)

        os.makedirs(dir_path, exist_ok=True)

        with open(file_path, "wb") as file_obj:
            pickle.dump(obj, file_obj)

    except Exception as e:
        raise CustomException(e, sys)

def evaluate_model(X_train,y_train,X_test,y_test,models):
    try:
        report = {}
        for i in range(len(models)):
            model = list(models.values())[i]
            # Train model
            model.fit(X_train,y_train)

            # Predict Testing data
            y_test_pred =model.predict(X_test)

            # Get R2 scores for train and test data
            #train_model_score = r2_score(ytrain,y_train_pred)
            test_model_score = r2_score(y_test,y_test_pred)

            report[list(models.keys())[i]] =  test_model_score

        return report

    except Exception as e:
        logger.info('Exception occured during model training')
        raise CustomException(e,sys)

def create_directories(path_to_directories: list, verbose=True):
    """create list of directories

    Args:
        path_to_directories (list): list of path of directories
        ignore_log (bool, optional): ignore if multiple dirs is to be created. Defaults to False.
    """
    for path in path_to_directories:
        os.makedirs(path, exist_ok=True)
        if verbose:
            logger.info(f"created directory at: {path}")
def load_object(file_path):
    try:
        with open(file_path, "rb") as file_obj:
            return dill.load(file_obj)

    except Exception as e:
        raise CustomException(e, sys)


import types

import numpy as np
import scipy.integrate as integrate

from pgmpy.factors.base import BaseFactor
from pgmpy.factors.distributions import GaussianDistribution, CustomDistribution

class ContinuousFactor(BaseFactor):
    """
    Base class for factors representing various multivariate
    representations.
    """

    def __init__(self, variables, pdf, *args, **kwargs):
        """
        Parameters
        ----------
        variables: list or array-like
            The variables for which the distribution is defined.

        pdf: function
            The probability density function of the distribution.

        Examples
        --------
        >>> import numpy as np
        >>> from scipy.special import beta
        >>> from pgmpy.factors.continuous import ContinuousFactor
        # Two variable dirichlet distribution with alpha = (1,2)
        >>> def dirichlet_pdf(x, y):
        ...     return (np.power(x, 1) * np.power(y, 2)) / beta(x, y)
        >>> dirichlet_factor = ContinuousFactor(['x', 'y'], dirichlet_pdf)
        >>> dirichlet_factor.scope()
        ['x', 'y']
        >>> dirichlet_factor.assignment(5,6)
        226800.0
        """
        if not isinstance(variables, (list, tuple, np.ndarray)):
            raise TypeError(
                f"variables: Expected type list or array-like, got type {type(variables)}"
            )

        if len(set(variables)) != len(variables):
            raise ValueError("Variable names cannot be same.")

        variables = list(variables)

        if isinstance(pdf, str):
            if pdf == "gaussian":
                self.distribution = GaussianDistribution(
                    variables=variables,
                    mean=kwargs["mean"],
                    covariance=kwargs["covariance"],
                )
            else:
                raise NotImplementedError(
                    f"{pdf} distribution not supported. Please use CustomDistribution"
                )

        elif isinstance(pdf, CustomDistribution):
            self.distribution = pdf

        elif callable(pdf):
            self.distribution = CustomDistribution(
                variables=variables, distribution=pdf
            )

        else:
            raise ValueError(
                f"pdf: Expected type: str or function, Got: {type(variables)}"
            )

    @property
    def pdf(self):
        """
        Returns the pdf of the ContinuousFactor.
        """
        return self.distribution.pdf

    @property
    def variable(self):
        return self.scope()[0]

    def scope(self):
        """
        Returns the scope of the factor.

        Returns
        -------
        list: List of variable names in the scope of the factor.

        Examples
        --------
        >>> from pgmpy.factors.continuous import ContinuousFactor
        >>> from scipy.stats import multivariate_normal
        >>> normal_pdf = lambda x: multivariate_normal(x, [0, 0], [[1, 0], [0, 1]])
        >>> phi = ContinuousFactor(['x1', 'x2'], normal_pdf)
        >>> phi.scope()
        ['x1', 'x2']
        """
        return self.distribution.variables

    def get_evidence(self):
        return self.scope()[1:]

    def assignment(self, *args):
        """
        Returns a list of pdf assignments for the corresponding values.

        Parameters
        ----------
        *args: values
            Values whose assignment is to be computed.

        Examples
        --------
        >>> from pgmpy.factors.continuous import ContinuousFactor
        >>> from scipy.stats import multivariate_normal
        >>> normal_pdf = lambda x1, x2: multivariate_normal.pdf((x1, x2), [0, 0], [[1, 0], [0, 1]])
        >>> phi = ContinuousFactor(['x1', 'x2'], normal_pdf)
        >>> phi.assignment(1, 2)
        0.013064233284684921
        """
        return self.distribution.assignment(*args)

    def copy(self):
        """
        Return a copy of the distribution.

        Returns
        -------
        ContinuousFactor object: copy of the distribution

        Examples
        --------
        >>> import numpy as np
        >>> from scipy.special import beta
        >>> from pgmpy.factors.continuous import ContinuousFactor
        # Two variable dirichlet distribution with alpha = (1,2)
        >>> def dirichlet_pdf(x, y):
        ...     return (np.power(x, 1) * np.power(y, 2)) / beta(x, y)
        >>> dirichlet_factor = ContinuousFactor(['x', 'y'], dirichlet_pdf)
        >>> dirichlet_factor.variables
        ['x', 'y']
        >>> copy_factor = dirichlet_factor.copy()
        >>> copy_factor.variables
        ['x', 'y']
        """
        return ContinuousFactor(self.scope(), self.distribution.copy())

    def discretize(self, method, *args, **kwargs):
        """
        Discretizes the continuous distribution into discrete
        probability masses using various methods.

        Parameters
        ----------
        method : A Discretizer Class from pgmpy.discretize

        *args, **kwargs:
            The parameters to be given to the Discretizer Class.

        Returns
        -------
        An n-D array or a DiscreteFactor object according to the discretiztion
        method used.

        Examples
        --------
        >>> import numpy as np
        >>> from scipy.special import beta
        >>> from pgmpy.factors.continuous import ContinuousFactor
        >>> from pgmpy.factors.continuous import RoundingDiscretizer
        >>> def dirichlet_pdf(x, y):
        ...     return (np.power(x, 1) * np.power(y, 2)) / beta(x, y)
        >>> dirichlet_factor = ContinuousFactor(['x', 'y'], dirichlet_pdf)
        >>> dirichlet_factor.discretize(RoundingDiscretizer, low=1, high=2, cardinality=5)
        # TODO: finish this
        """
        return method(self, *args, **kwargs).get_discrete_values()

    def reduce(self, values, inplace=True):
        """
        Reduces the factor to the context of the given variable values.

        Parameters
        ----------
        values: list, array-like
            A list of tuples of the form (variable_name, variable_value).

        inplace: boolean
            If inplace=True it will modify the factor itself, else would return
            a new ContinuousFactor object.

        Returns
        -------
        ContinuousFactor or None: if inplace=True (default) returns None
                                  if inplace=False returns a new ContinuousFactor instance.

        Examples
        --------
        >>> import numpy as np
        >>> from scipy.special import beta
        >>> from pgmpy.factors.continuous import ContinuousFactor
        >>> def custom_pdf(x, y, z):
        ...     return z*(np.power(x, 1) * np.power(y, 2)) / beta(x, y)
        >>> custom_factor = ContinuousFactor(['x', 'y', 'z'], custom_pdf)
        >>> custom_factor.variables
        ['x', 'y', 'z']
        >>> custom_factor.assignment(1, 2, 3)
        24.0

        >>> custom_factor.reduce([('y', 2)])
        >>> custom_factor.variables
        ['x', 'z']
        >>> custom_factor.assignment(1, 3)
        24.0
        """
        phi = self if inplace else self.copy()

        phi.distribution = phi.distribution.reduce(values, inplace=False)
        if not inplace:
            return phi

    def marginalize(self, variables, inplace=True):
        """
        Marginalize the factor with respect to the given variables.

        Parameters
        ----------
        variables: list, array-like
            List of variables with respect to which factor is to be maximized.

        inplace: boolean
            If inplace=True it will modify the factor itself, else would return
            a new ContinuousFactor instance.

        Returns
        -------
        DiscreteFactor or None: if inplace=True (default) returns None
                        if inplace=False returns a new ContinuousFactor instance.

        Examples
        --------
        >>> from pgmpy.factors.continuous import ContinuousFactor
        >>> from scipy.stats import multivariate_normal
        >>> std_normal_pdf = lambda *x: multivariate_normal.pdf(x, [0, 0], [[1, 0], [0, 1]])
        >>> std_normal = ContinuousFactor(['x1', 'x2'], std_normal_pdf)
        >>> std_normal.scope()
        ['x1', 'x2']
        >>> std_normal.assignment([1, 1])
        0.058549831524319168
        >>> std_normal.marginalize(['x2'])
        >>> std_normal.scope()
        ['x1']
        >>> std_normal.assignment(1)

        """
        phi = self if inplace else self.copy()
        phi.distribution = phi.distribution.marginalize(variables, inplace=False)

        if not inplace:
            return phi

    def normalize(self, inplace=True):
        """
        Normalizes the pdf of the continuous factor so that it integrates to
        1 over all the variables.

        Parameters
        ----------
        inplace: boolean
            If inplace=True it will modify the factor itself, else would return
            a new factor.

        Returns
        -------
        ContinuousFactor or None:
             if inplace=True (default) returns None
             if inplace=False returns a new ContinuousFactor instance.

        Examples
        --------
        >>> from pgmpy.factors.continuous import ContinuousFactor
        >>> from scipy.stats import multivariate_normal
        >>> std_normal_pdf = lambda x: 2 * multivariate_normal.pdf(x, [0, 0], [[1, 0], [0, 1]])
        >>> std_normal = ContinuousFactor(['x1', 'x2'], std_normal_pdf)
        >>> std_normal.assignment(1, 1)
        0.117099663049
        >>> std_normal.normalize()
        >>> std_normal.assignment(1, 1)
        0.0585498315243

        """
        phi = self if inplace else self.copy()
        phi.distribution.normalize(inplace=True)

        if not inplace:
            return phi

    def is_valid_cpd(self):
        return self.distribution.is_valid_cpd()

    def _operate(self, other, operation, inplace=True):
        """
        Gives the ContinuousFactor operation (product or divide) with
        the other factor.

        Parameters
        ----------
        other: ContinuousFactor
            The ContinuousFactor to be multiplied.

        operation: String
            'product' for multiplication operation and 'divide' for
            division operation.

        inplace: boolean
            If inplace=True it will modify the factor itself, else would return
            a new factor.

        Returns
        -------
        ContinuousFactor or None:
                        if inplace=True (default) returns None
                        if inplace=False returns a new `DiscreteFactor` instance.

        """
        if not isinstance(other, ContinuousFactor):
            raise TypeError(
                f"ContinuousFactor objects can only be multiplied ",
                f"or divided with another ContinuousFactor object. ",
                f"Got {type(other)}, expected: ContinuousFactor.",
            )

        phi = self if inplace else self.copy()
        phi.distribution = phi.distribution._operate(
            other=other.distribution, operation=operation, inplace=False
        )

        if not inplace:
            return phi

    def product(self, other, inplace=True):
        """
        Gives the ContinuousFactor product with the other factor.

        Parameters
        ----------
        other: ContinuousFactor
            The ContinuousFactor to be multiplied.

        Returns
        -------
        ContinuousFactor or None:
                        if inplace=True (default) returns None
                        if inplace=False returns a new `ContinuousFactor` instance.

        Examples
        --------
        >>> from pgmpy.factors.continuous import ContinuousFactor
        >>> from scipy.stats import multivariate_normal
        >>> sn_pdf1 = lambda x: multivariate_normal.pdf([x], [0], [[1]])
        >>> sn_pdf2 = lambda x1,x2: multivariate_normal.pdf([x1, x2], [0, 0], [[1, 0], [0, 1]])
        >>> sn1 = ContinuousFactor(['x2'], sn_pdf1)
        >>> sn2 = ContinuousFactor(['x1', 'x2'], sn_pdf2)

        >>> sn3 = sn1.product(sn2, inplace=False)
        >>> sn3.assignment(0, 0)
        0.063493635934240983

        >>> sn3 = sn1 * sn2
        >>> sn3.assignment(0, 0)
        0.063493635934240983
        """
        return self._operate(other, "product", inplace)

    def divide(self, other, inplace=True):
        """
        Gives the ContinuousFactor divide with the other factor.

        Parameters
        ----------
        other: ContinuousFactor
            The ContinuousFactor to be divided.

        Returns
        -------
        ContinuousFactor or None:
                        if inplace=True (default) returns None
                        if inplace=False returns a new `ContinuousFactor` instance.

        Examples
        --------
        >>> from pgmpy.factors.continuous import ContinuousFactor
        >>> from scipy.stats import multivariate_normal
        >>> sn_pdf1 = lambda x: multivariate_normal.pdf([x], [0], [[1]])
        >>> sn_pdf2 = lambda x1,x2: multivariate_normal.pdf([x1, x2], [0, 0], [[1, 0], [0, 1]])
        >>> sn1 = ContinuousFactor(['x2'], sn_pdf1)
        >>> sn2 = ContinuousFactor(['x1', 'x2'], sn_pdf2)

        >>> sn4 = sn2.divide(sn1, inplace=False)
        >>> sn4.assignment(0, 0)
        0.3989422804014327

        >>> sn4 = sn2 / sn1
        >>> sn4.assignment(0, 0)
        0.3989422804014327
        """
        if set(other.scope()) - set(self.scope()):
            raise ValueError("Scope of divisor should be a subset of dividend")

        return self._operate(other, "divide", inplace)

    def __mul__(self, other):
        return self.product(other, inplace=False)

    def __rmul__(self, other):
        return self.__mul__(other)

    def __truediv__(self, other):
        return self.divide(other, inplace=False)

    __div__ = __truediv__


# Databricks notebook source
storage_account_name = "saformuladl"
storage_account_key = dbutils.secrets.get('scope4formula1', 'storageAccountName')
configs = {f"fs.azure.account.key.{storage_account_name}.blob.core.windows.net": f"{storage_account_key}"}

# COMMAND ----------

container_name = "raw"
dbutils.fs.mount(
    source = f"wasbs://{container_name}@{storage_account_name}.blob.core.windows.net",
    mount_point = f"/mnt/{storage_account_name}/{container_name}",
    extra_configs = configs)

# COMMAND ----------

dbutils.fs.ls("mnt/saformuladl/raw")

# COMMAND ----------

dbutils.fs.mounts()

# COMMAND ----------

def mount_adls(container_name):
    dbutils.fs.mount(
    source = f"wasbs://{container_name}@{storage_account_name}.blob.core.windows.net",
    mount_point = f"/mnt/{storage_account_name}/{container_name}",
    extra_configs = configs)

# COMMAND ----------

mount_adls("processed")

# COMMAND ----------

dbutils.fs.mounts()

# COMMAND ----------

spark

# COMMAND ----------

# MAGIC %md
# MAGIC #### Data Ingestion Requirements
# MAGIC 1. Ingest all 8 files into the data lake
# MAGIC 2. Ingested data must have the schema applied
# MAGIC 3. Ingested data must have audit columns
# MAGIC 4. Ingested data must be stored in columnar format (i.e., Parquet)
# MAGIC 5. Must be able to analyze the ingested data via SQL
# MAGIC 6. Ingestion Logic must be able to handle incremental load

# COMMAND ----------

# MAGIC %md
# MAGIC #### Data Transformation requirements
# MAGIC 1. Join the key information required for reporting to create a new table.
# MAGIC 2. Join the key information required for analysis to create a new table.
# MAGIC 3. Transformed tables must have audit columns
# MAGIC 4. Must be able to analyze the transformed data via SQL.
# MAGIC 5. Transformed data must be stored in columnar format (i.e., Parquet)
# MAGIC 6. Transformation logic must be able to handle incremental load

# COMMAND ----------

# MAGIC %md
# MAGIC #### Reporting requirements
# MAGIC 1. Driver Standings
# MAGIC 2. Constructor Standings

# COMMAND ----------

# MAGIC %md
# MAGIC #### Analysis Requirements
# MAGIC 1. Dominant drivers
# MAGIC 2. Dominant teams
# MAGIC 3. Visualize the outputs
# MAGIC 4. Create Databricks Dashboards

# COMMAND ----------

# MAGIC %md
# MAGIC #### Scheduling requirements
# MAGIC 1. Scheduled to run every Sunday 10 PM.
# MAGIC 2. Ability to monitor pipelines.
# MAGIC 3. Ability to re -run failed pipelines.
# MAGIC 4. Ability to set-up alerts on failures.

# COMMAND ----------

# MAGIC %md
# MAGIC #### Other Non-functional requirements
# MAGIC 1. Ability to delete individual records
# MAGIC 2. Ability to see history and time travel
# MAGIC 3. Ability to roll back to a previous version


import logging

from community.models import Community
from bot.bin.friendship import create_friendship_members
from bot.onstatus import search_triage
from celery import shared_task

logger = logging.getLogger(__name__)

@shared_task
def handle_follow_member():
    communities = Community.objects.filter(
        active=True,
        twitter_follow_member=True
    )
    for community in communities:
        handle_follow_member_community.apply_async(
            args=(community.name,),
            ignore_result=True
        )

@shared_task
def handle_follow_member_community(community: str):
    try:
        community = Community.objects.get(name=community)
    except Community.DoesNotExist:
        return
    create_friendship_members(community)

@shared_task
def handle_search_triage(community: str):
    try:
        community = Community.objects.get(name=community)
    except Community.DoesNotExist:
        return
    search_triage(community)


# Enter your code here. Read input from STDIN. Print output to STDOUT

test_case = int(input())
for _ in range(test_case):
    no = int(input())
    if no == 2 or no == 3:
        print('Prime')
    elif no % 2 == 0:
        print('Not prime')
    elif no == 1 :
        print('Not prime')

    else:
        global flag
        flag = True
        half = no//2
        l = []
        for i in range(3,half,2):
            l.append(i)
        #print(l)
        for i in l:
            if no % i == 0:
                flag = False
        if flag == True:
            print('Prime')
        else:
            print('Not prime')


from airflow.models import DAG
from airflow.operators.empty import EmptyOperator
from airflow.operators.python import BranchPythonOperator, PythonOperator
import pandas as pd
import os
import pendulum

from great_expectations_provider.operators.great_expectations import GreatExpectationsOperator
from great_expectations.core.batch import BatchRequest
from great_expectations.data_context.types.base import (
    DataContextConfig,
    CheckpointConfig
)

ge_root_dir='/opt/x5/great_expectations'
data_path = '/data'
archive_name = 'retailhero-uplift.zip'

dag = DAG(
    dag_id="x5-data-preparation",
    schedule_interval="@daily",
    start_date=pendulum.datetime(2022, 1, 1, tz="UTC"),
)

def download_zip_archive():
    if not archive_name in os.listdir():
        os.system('wget -P ./ https://storage.yandexcloud.net/datasouls-ods/materials/9c6913e5/retailhero-uplift.zip')

def unzip_data_archive():
    os.system(f'unzip ./{archive_name}')

def join_data():
    df_clients = pd.read_csv(f'{data_path}/clients.csv', index_col='client_id')
    df_train = pd.read_csv(f'{data_path}/uplift_train.csv', index_col='client_id')
    df_test = pd.read_csv(f'{data_path}/uplift_test.csv', index_col='client_id')

    df_clients['first_issue_unixtime'] = pd.to_datetime(df_clients['first_issue_date']).astype(int)/10**9
    df_clients['first_redeem_unixtime'] = pd.to_datetime(df_clients['first_redeem_date']).astype(int)/10**9
    df_features = pd.DataFrame({
        'gender_M': (df_clients['gender'] == 'M').astype(int),
        'gender_F': (df_clients['gender'] == 'F').astype(int),
        'gender_U': (df_clients['gender'] == 'U').astype(int),
        'age': df_clients['age'],
        'first_issue_time': df_clients['first_issue_unixtime'],
        'first_redeem_time': df_clients['first_redeem_unixtime'],
        'issue_redeem_delay': df_clients['first_redeem_unixtime'] - df_clients['first_issue_unixtime'],
    }).fillna(0)
    df_features.to_csv(f'{data_path}/df_features.csv')

download_zip = PythonOperator(
    task_id='download_zip',
    python_callable = download_zip_archive,
    op_kwargs = {},
    dag=dag,
)

unzip_archive = PythonOperator(
    task_id='unzip_archive',
    python_callable = unzip_data_archive,
    op_kwargs = {},
    dag=dag,
)

data_peprocessing = PythonOperator(
    task_id='data_peprocessing',
    python_callable = join_data,
    op_kwargs = {},
    dag=dag,
)

ge_client_data = GreatExpectationsOperator(
    task_id="ge_client_data",
    data_context_root_dir=ge_root_dir,
    checkpoint_name="getting_started",
)

#test

download_zip >> unzip_archive >> ge_client_data  >> data_peprocessing


import os
import pyarrow.parquet as pq
import pandas as pd
import matplotlib.pyplot as plt

from module_package import load_data
from module_package import transformations

import logging
logging.basicConfig(filename="log.txt", format='%(asctime)s %(message)s', \
                    datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.INFO)
logging.info("New execution started")

source_dir = 'dataset'
target_dir = 'output'

# Call json_parquet function to read JSON and to create parquet files
load_data.json_parquet(source_dir, target_dir)
logging.info("Data set loading is completed")

# Get absolute path of parquet directory
dirname = os.path.dirname(__file__)
parquet_directory = os.path.join(dirname, source_dir, target_dir)

# Read parquet dataset
try:
    dataset = pq.ParquetDataset(parquet_directory)
    table = dataset.read()
    source_df = table.to_pandas()
    source_df['ORDERDATE'] = pd.to_datetime(source_df['ORDERDATE'])
except:
    logging.info('Unable to load parquet data')

logging.info('Parquet data is loaded')
# Set status values and calls function to get total value data
values = ['Cancelled','On Hold']
data_df = transformations.total_value(source_df, values)
sales_loss = data_df.plot(kind = 'bar', title = 'Total (Cancelled, On Hold) Sales Per Year',
                          xlabel = 'Year', ylabel = 'Sales', rot = 0, subplots = True)
load_data.plot_diagram(plt)
logging.info("Sales data plot is completed")

# Call function to get products per line data
product_df = transformations.product_per_line(source_df)
product_count = product_df.plot(kind = 'bar', title = 'Products per line',
                                xlabel = 'Product Line', ylabel = 'Number of Products', rot = 0)
load_data.plot_diagram(plt)
logging.info("Product line plot is completed")

# Get the classic car trend data
product_lines = ['Classic Cars']
trend_df = transformations.classic_cars_trend(source_df, product_lines)
trend = trend_df.plot(kind = 'line', title = 'Classic Car Trend', x = 'YEAR_MONTH',
                      xlabel = 'Year_Month', ylabel = 'Quantity Ordered')
load_data.plot_diagram(plt)
logging.info("Classic car plot is completed")

# Call discount function to get the related trend for given product lines
values = ['Classic Cars', 'Vintage Cars', 'Motorcycles', 'Trucks and Buses']
discount_df = transformations.discount(source_df, values)
discount = discount_df.plot(kind = 'bar', title = 'Discount on Products', x = 'PRODUCTLINE',
                            y = 'DISCOUNT', xlabel = 'Product Line', ylabel = 'Discount', rot = 0)
load_data.plot_diagram(plt)
logging.info("Discount plot is completed")

logging.info("Execution completed")


from django.urls import path
from todolist.views import show_homepage, login_user, logout_user, create_task, register, get_json, add_task_json

app_name = 'todolist'

urlpatterns = [
    path('', show_homepage, name='show_homepage'),
    path('register/', register, name='register'),
    path('login/', login_user, name='login'),
    path('logout/', logout_user, name='logout'),
    path('create-task/', create_task, name='create_task'),
    path('json/', get_json, name='get_json'),
    path('add/', add_task_json, name='add_task_json'),
]