import numpy as np
from tqdm import tqdm
import utils
from collections import defaultdict
from qnetwork import DRRN

class StateNode:
    def __init__(self, reward=0, done=False):
        self.ob = None
        self.look = None
        self.inv = None
        self.state = None
        self.prev_action = None
        self.id = None
        self.valid_actions = None

        self.N = 0
        self.children = []
        self.children_probs = []
        self.reward = reward
        self.score = 0
        self.done = done

class ActionNode:
    def __init__(self, action):
        self.action = action
        self.N = 0
        self.Q = 0
        self.Q_hat = 0
        self.Rs = []
        self.children = []
        self.children_text = []

class MCTSAgent:
    def __init__(self, args, env, policy=None, name='MCTS', uct_type='UCT', valid_action_dict=None, actions_info=None, log_dir=None, visited_transitions=None, replay_file=None):
        self.env = env
        self.name = name

        self.uct_type = uct_type
        self.seed = args.seed
        self.round = args.round

        self.exploration_constant = args.exploration_constant
        self.bonus_constant = args.bonus_constant
        self.max_depth = args.max_depth
        self.simulation_per_act = args.simulation_per_act
        self.discount_factor = args.discount_factor
        self.visited_transitions = visited_transitions

        self.action_selection_temp = 0.1 / (self.round + 1)

        self.policy = policy
        self.actions = [] if actions_info is None else actions_info[0]
        self.actions_e = [] if actions_info is None else actions_info[1]

        self.action_values = defaultdict(set)   # Ex: {north: [3.01, 2.00, 5.01]}

        self.maxlen_obs = 150
        self.maxlen_look = 150
        self.maxlen_inv = 50
        self.maxlen_action = 12

        if self.uct_type == 'MC-LAVE':
            self.q_network = DRRN(args)
        else:
            self.q_network = None

        self.valid_action_dict = {} if valid_action_dict is None else valid_action_dict
        self.state_dict = {}
        self.action_embedding = {}
        self.replay_file = replay_file

    def search(self, ob, info, cur_depth):
        '''
        Search the best action with probs
        :return: best action
        '''
        self.root = self.build_state(ob, info)
        for _ in tqdm(range(self.simulation_per_act * len(self.root.children))):
            copy_env = self.env.copy()
            self.simulate(self.root, copy_env, 0)

        # select best action by Q-value
        best_action_node = self.greedy_action_node(self.root, 0, 0)
        # select best action by Count
        # best_action_node = self.max_visit_action_node(self.root)

        return self.root, best_action_node.action, self.visited_transitions

    def build_state(self, ob, info, reward=0, prev_action='<s>'):
        state = StateNode()
        state.ob = ob
        state.look = info['look']
        state.inv = info['inv']
        state.state = ob + info['look'] + info['inv']
        state.reward = reward
        state.score = info['score']
        state.prev_action = prev_action
        state.id = ob + info['look'] + info['inv'] + str(reward) + str(info['score']) + prev_action
        state.valid_actions = info['valid']

        if self.policy is None:
            state.children_probs = np.ones((len(info['valid']),)) / len(info['valid'])

        elif state.id in self.state_dict.keys():
            state.children_probs = self.state_dict[state.id].children_probs

        else:
            obs, look, inv, prev_action, score = utils.state_representation(state.ob, state.look, state.inv,
                                                          state.prev_action, state.score,
                                                          self.maxlen_obs, self.maxlen_look, self.maxlen_inv, self.maxlen_action)
            state.children_probs = self.policy.calculate_probs(obs, look, inv, prev_action, score, info['valid'])[:,0]
            self.state_dict[state.id] = state

        for valid_action in info['valid']:
            state.children.append(ActionNode(valid_action))

        return state

    def write_buffer(self, state_node, best_action_node, ob, reward, done, info):
        # Example of transition strings :
        # [OBS] Outer Court
        # [LOOK] Outer Court High walls surround this court, and a long pathway leads from the gates to the east to the throne room to the west.  Most of the palace is locked securely, but the courtyard is still open, for the very reason of allowing a Dwarven Reclaimer to have access to the Throne Room.
        # [INV] You are carrying: a piece of coal a lantern (providing light) a magical torch (providing light) King's Order
        # [VALID_ACTION] examine west [VALID_ACTION] west [VALID_ACTION] east [VALID_ACTION] put coal down [VALID_ACTION] put magical down [VALID_ACTION] put order down [VALID_ACTION] put lantern down
        # [ACTION] east
        # [PREV_ACTION] east
        # [REWARD] 0000011100

        def clean_string(input_str):
            return " ".join(input_str.split('\n')).strip()

        obs = '[OBS] ' + clean_string(state_node.ob)
        look = '[LOOK] ' + clean_string(state_node.look)
        inven = '[INV] ' + clean_string(state_node.inv)
        sign = '0' if int(state_node.score) >= 0 else '1'
        score_string = '{0:09b}'.format(abs(int(state_node.score)))
        score = '[SCORE] %s%s ' % (sign, score_string)

        prev_action = '[PREV_ACTION] ' + clean_string(state_node.prev_action)
        action = '[ACTION] ' + clean_string(best_action_node.action)
        valid_actions = '[VALID_ACTION] ' + ' [VALID_ACTION] '.join(state_node.valid_actions)

        next_sign = '0' if int(state_node.score + reward) >= 0 else '1'
        next_score_string = '{0:09b}'.format(abs(int(state_node.score  + reward)))

        reward = '[REWARD] %d ' % reward
        next_score = '[NEXT_SCORE] %s%s ' % (next_sign, next_score_string)

        done = '[DONE] %d ' % done
        next_obs = '[NEXT_OBS] ' + clean_string(ob)
        next_look = '[NEXT_LOOK] ' + clean_string(info['look'])
        next_inven = '[NEXT_INV] ' + clean_string(info['inv'])

        transition = [obs, look, inven, score, prev_action, action, valid_actions, reward, done, next_obs, next_look, next_inven, next_score]
        transition_str = " ".join(transition) + '\n'

        if self.replay_file is not None:
            self.replay_file.write(transition_str)

    def simulate(self, state_node, copy_env, depth):
        if state_node.done or depth == self.max_depth or (state_node.look == 'unknown' and state_node.inv == 'unknown'):
            return 0

        best_action_node = self.greedy_action_node(state_node, self.exploration_constant, self.bonus_constant)

        rollout_next = False

        ob, reward, done, info = copy_env.step(best_action_node.action, valid_out=False)
        next_state_text = ob + info['look'] + info['inv']

        if '*** You have won ***' in next_state_text or '*** You have died ***' in next_state_text:
            score = int(next_state_text.split('you scored ')[1].split(' out of')[0])
            reward = score - state_node.score
            info['score'] = score

        self.write_buffer(state_node, best_action_node, ob, reward, done, info)

        if next_state_text in best_action_node.children_text:
            index = best_action_node.children_text.index(next_state_text)
            next_state_node = best_action_node.children[index]

            if next_state_node.N == 0:
                rollout_next = True
            next_state_node.N += 1

        else:
            if next_state_text in self.valid_action_dict.keys():
                info['valid'] = self.valid_action_dict[next_state_text]
            else:
                info['valid'] = copy_env.get_valid(ob)
                self.valid_action_dict[next_state_text] = info['valid']
            next_state_node = self.build_state(ob, info, reward, prev_action=best_action_node.action)
            best_action_node.children.append(next_state_node)
            best_action_node.children_text.append(next_state_node.state)
            rollout_next = True

        if rollout_next:
            R = reward + self.discount_factor * self.rollout(next_state_node, copy_env, depth+1)
        else:
            R = reward + self.discount_factor * self.simulate(next_state_node, copy_env, depth+1)

        state_node.N += 1
        best_action_node.N += 1

        if self.uct_type == 'MC-LAVE':
            if not best_action_node.action in self.action_embedding.keys():
                embed_vector = utils.vectorize(best_action_node.action)
                self.action_embedding[best_action_node.action] = embed_vector

            action_value = self.q_network.get_q_value(ob, info['look'], info['inv'], state_node.prev_action, info['score'], best_action_node.action)
            self.action_values[best_action_node.action].add(action_value)

        best_action_node.Rs.append(R)
        best_action_node.Q = np.sum(np.array(best_action_node.Rs) * utils.softmax(best_action_node.Rs, T=10))

        return R

    def max_visit_action_node(self, state_node):
        children_count = []

        for i in range(len(state_node.children)):
            child = state_node.children[i]
            children_count.append(child.N)

        children_count = children_count / np.max(children_count)
        count_based_probs = children_count ** (1/self.action_selection_temp) / (np.sum(children_count ** (1/self.action_selection_temp)))
        return np.random.choice(state_node.children, p=count_based_probs)

    def greedy_action_node(self, state_node, exploration_constant, bonus_constant):
        best_value = -np.inf
        best_children = []

        for i in range(len(state_node.children)):
            child = state_node.children[i]
            child_prob = state_node.children_probs[i]

            if exploration_constant == 0:
                ucb_value = child.Q
            elif self.uct_type == 'UCT':
                ucb_value = child.Q + exploration_constant * np.sqrt(np.log(state_node.N + 1) / (child.N + 1))
            elif self.uct_type == 'PUCT':
                ucb_value = child.Q + exploration_constant * child_prob * np.sqrt(state_node.N + 1) / (child.N + 1)
            elif self.uct_type == 'MC-LAVE':
                if child.action in self.action_embedding.keys():
                    action_e = self.action_embedding[child.action]
                else:
                    action_e = utils.vectorize(child.action)
                    self.action_embedding[child.action] = action_e

                actions = list(self.action_values.keys())
                if child.action in actions:
                    actions.pop(actions.index(child.action))

                actions_e = []
                for a in actions:
                    actions_e.append(self.action_embedding[a])

                near_act, near_idx = utils.find_near_actions(action_e, actions, np.array(actions_e), threshold=0.8)
                if len(near_idx) == 0:
                    child.Q_hat = 0
                else:
                    near_Qs = set()
                    for a in near_act:
                        near_Qs.add(np.mean(list(self.action_values[a])))
                    near_Qs = list(near_Qs)
                    child.Q_hat = utils.softmax_value(near_Qs)

                ucb_value = child.Q \
                            + exploration_constant * np.sqrt(state_node.N + 1) / (child.N + 1) * child_prob \
                            + bonus_constant * np.sqrt(state_node.N + 1) / (child.N + 1) * child.Q_hat

            else:
                raise NotImplementedError

            if ucb_value == best_value:
                best_children.append(child)
            elif ucb_value > best_value:
                best_value = ucb_value
                best_children = [child]

        return np.random.choice(best_children)

    def rollout(self, state_node, copy_env, depth):
        if state_node.done or depth == self.max_depth or (state_node.look == 'unknown' and state_node.inv == 'unknown'):
            return 0

        action_node = np.random.choice(state_node.children, 1, p=state_node.children_probs)[0]
        action = action_node.action

        ob, reward, done, info = copy_env.step(action, valid_out=False)
        next_state_text = ob + info['look'] + info['inv']

        if '*** You have won ***' in next_state_text or '*** You have died ***' in next_state_text:
            score = int(next_state_text.split('you scored ')[1].split(' out of')[0])
            reward = score - state_node.score
            info['score'] = score

        self.write_buffer(state_node, action_node, ob, reward, done, info)

        if next_state_text in action_node.children_text:
            index = action_node.children_text.index(next_state_text)
            next_state_node = action_node.children[index]
        else:
            if next_state_text in self.valid_action_dict.keys():
                info['valid'] = self.valid_action_dict[next_state_text]
            else:
                info['valid'] = copy_env.get_valid(ob)
                self.valid_action_dict[next_state_text] = info['valid']
            next_state_node = self.build_state(ob, info, reward, prev_action=action)
            action_node.children.append(next_state_node)
            action_node.children_text.append(next_state_node.state)

        return reward + self.discount_factor * self.rollout(next_state_node, copy_env, depth+1)


import pytest
from Akeso.config import challenge_mapper

@pytest.mark.parametrize("challenge, expected_ret", [
    ('maze', ('maze', ['mazeAttack'], ['maze'], 31337)),
    ('SQL', ('sqlisimple', ['SQLi'], ['SQLiSimple'], 80)),
    ('shell', ('shell', ['shellAttack'], ['shell'], 4001)),
    ('nginx', ('nginx', ['DirectoryTraversal'], ['ApacheDirectoryTraversal'], 80))
])
def test_challenge_mapper(challenge, expected_ret):
    ret = challenge_mapper(challenge)
    assert ret == expected_ret


# -*- coding: utf-8 -*-
"""
Created on Thu Feb  9 11:45:37 2017

@author: Quentin Courtois
"""
import os
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

#Generate regular watershed
save = 1
plot = 1
name = 'regular_watershed'
X = (np.arange(500))*50
Y = (np.arange(500))*50

coord_o_x = int((len(X)/2)-1)
outlet_x = X[coord_o_x]
outlet_y = 0

Zmax1 = 300
Zmax2 = 50
Zmax3 = 60
Zmin = 0

alpha1 = (Zmax1 - Zmin) / (np.max(Y)-np.min(Y))
beta1 = Zmin
alpha2 = (Zmax1 - Zmax2) / (np.max(Y)-np.min(Y))
beta2 = Zmax2
alpha3 = (Zmax1 - Zmax3) / (np.max(Y)-np.min(Y))
beta3 = Zmax3

Z = np.zeros((len(Y),len(X)))

#Build the 3 main slopes
for j in range(len(Y)):
    Z[j, coord_o_x] = alpha1*Y[j] + beta1
    Z[j, 0] = alpha2*Y[j] + beta2
    Z[j, -1] = alpha3*Y[j] + beta3

for i in range(len(X)):
    Z[-1,:] = Zmax1

alpha_w = np.zeros((len(Y),1))
alpha_e = np.zeros((len(Y),1))
for i in range(len(Y)-1):
    alpha_w[i] = (Z[i, 0] - Z[i, coord_o_x]) / (X[0] - X[coord_o_x])
    alpha_e[i] = (Z[i, -1] - Z[i, coord_o_x]) / (X[-1] - X[coord_o_x])
    for j in range(len(X)):
        if j != coord_o_x and j != 0 and j != len(X)-1:
            if j < coord_o_x:
                Z[i,j] = alpha_w[i]*X[j] + Z[i, 0]
            else:
                Z[i,j] = alpha_e[i]*(X[j]-X[coord_o_x]) + Z[i, coord_o_x]

Elevation = np.zeros((np.size(Z),1))
X_watershed = np.zeros((np.size(Z),1))
Y_watershed = np.zeros((np.size(Z),1))
count = 0

##Set inactives cells
#for i in range(len(Y)):
#    for j in range(len(X)):
#        if i < len(Y)/10 and j < len(X)/10:
#            Z[i,j] = -50
#        elif i < len(Y)/10 and j > 9*len(X)/10:
#            Z[i,j] = -80

for i in range(len(Y)):
    for j in range(len(X)):
        if Z[i,j] > -1:
            X_watershed[count] = X[j]
            Y_watershed[count] = Y[i]
            Elevation[count] = Z[i,j]
            count += 1

if plot > 0:
    fig1 = plt.figure(num=1)
    ax1 = fig1.gca(projection='3d')
    X_new, Y_new = np.meshgrid(X,Y)
    surf = ax1.plot_surface(X_new, Y_new, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
    fig1.colorbar(surf,shrink=0.5, aspect=5)

#save watershed
if save == 1:
   if not os.path.exists(os.getcwd() + "/" + name):
        os.makedirs(os.getcwd() + "/" + name)
   out_folder = os.getcwd() + "/" + name + "/"

   name_file = out_folder + "coord_X_" + name
   with open(name_file, "wb") as f:
       np.savetxt(f, X_watershed, fmt='%1.8e', delimiter="\t", newline='\n')

   name_file = out_folder + "coord_Y_" + name
   with open(name_file, "wb") as f:
       np.savetxt(f, Y_watershed, fmt='%1.8e', delimiter="\t", newline='\n')

   name_file = out_folder + name + "_elevation"
   with open(name_file, "wb") as f:
       np.savetxt(f, Elevation, fmt='%1.8e', delimiter="\t", newline='\n')

   name_file = out_folder + name + "_outlet_coord"
   with open(name_file, "wb") as f:
       np.savetxt(f, [outlet_x, outlet_y], fmt='%1.8e', delimiter="\t", newline='\n')


from django.urls import path

from . import views

app_name = 'emousic'

urlpatterns = [
    path('', views.index, name='index'),
    path('index', views.index, name='index'),
    path('get_moodtags/', views.get_moodtags, name='get_moodtags'),
    path('rdf', views.rdf, name='rdf'),
    path('wildwebmidi.data', views.read_wildwebmidi, name='read_wildwebmidi')
]


"""
SimCamera is a child class of camera, designed to be used for simulator depth/color streams
"""
import os
import sys

parent_dir = os.path.dirname(os.path.abspath(__file__))
gparent_dir = os.path.dirname(parent_dir)
ggparent_dir = os.path.dirname(gparent_dir)
sys.path += [parent_dir, gparent_dir, ggparent_dir]

import cv2
import numpy as np
import airsim
try:
    from vision.camera.template import Camera
except ImportError:
    from template import Camera

class SimCamera(Camera):
    """
    Creates an airsim camera object
    """
    def __init__(self, **kwargs):
        super().__init__(-1, -1, -1)  # for screen_width, screen_height, and framerate, unnecessary
        self.client = airsim.MultirotorClient()

    def __iter__(self):
        """
        Iterate through each frame in the airsim cameras
        NOTE: The airsim must be running currently for __iter__ to work

        Returns
        -------
        depth image[1 channel]: numpy array
        color image[3 channel]: numpy array
            in RGB format
        """
        while True:
            depth_responses = self.client.simGetImages([airsim.ImageRequest("0", airsim.ImageType.DepthVis, False, False)])
            depth_response = depth_responses[0]

            scene_responses = self.client.simGetImages([airsim.ImageRequest("0", airsim.ImageType.Scene, False, False)])
            scene_response = scene_responses[0]

            depth_np_1d = np.frombuffer(depth_response.image_data_uint8, dtype=np.uint8)
            color_np_1d = np.frombuffer(scene_response.image_data_uint8, dtype=np.uint8)

            depth_np = depth_np_1d.reshape(depth_response.height, depth_response.width, 3)
            color_np = color_np_1d.reshape(scene_response.height, scene_response.width, 3)

            yield depth_np, color_np

    def display_in_window(self):
        """
        Displays the depth/color image streams, separately, in one window
        """
        for depth_image, color_image in self:
            # Render images
            depth_colormap = cv2.applyColorMap(
                cv2.convertScaleAbs(depth_image, alpha=0.03),
                cv2.COLORMAP_JET)

            images = np.hstack((color_image, depth_colormap))

            cv2.namedWindow('Depth/Color Stream', cv2.WINDOW_AUTOSIZE)
            cv2.imshow('Depth/Color Stream', images)

            key = cv2.waitKey(0)

            # Press esc or 'q' to close the image window
            if key == ord('q') or key == 27 or cv2.getWindowProperty('Depth/Color Stream', 0) == -1:
                cv2.destroyAllWindows()
                break

if __name__ == '__main__':
    ## Display algorithm output on simulator
    import json
    from vision.obstacle.obstacle_finder import ObstacleFinder
    from vision.common.import_params import import_params

    camera = SimCamera()

    prefix = 'vision' if os.path.isdir("vision") else ''
    config_filename = os.path.join(prefix, 'obstacle', 'config.json')

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

    obstacle_finder = ObstacleFinder(params=import_params(config))

    for depth_image, color_image in camera:
        bboxes = []

        bboxes = obstacle_finder.find(color_image, depth_image)

        from vision.common.blob_plotter import plot_blobs
        plot_blobs(obstacle_finder.keypoints, color_image)


import cv2
import os
import numpy as np
import datetime
import tkinter as tk
from tkinter import filedialog
from tkinter import *
from tkinter import messagebox
from PIL import ImageTk, Image
from tkmacosx import Button
import matplotlib.pyplot as plt
from tkinter.font import Font

def upload():
    try:
        global filePath
        filePath = filedialog.askopenfilename()
        upload = Image.open(filePath)
        upload = upload.resize((300, 300),Image.ANTIALIAS)
        #print("Uploaded")
        img = ImageTk.PhotoImage(upload)
        #cv2.imshow(img)
        picture.configure(image=img)
        picture.image=img
        picture.pack(side=TOP,expand=True)
        #plt.imshow(picture)

        #label.configure(text="",fg="red",font=('montserrat',20, "bold"))

    except:
        pass

def cartoonify(filePath):

    global dtmy,cartoon

    x = datetime.datetime.now()
    dtmy = x.strftime("%d-%b-%y")

    img = Image.open(filePath)
    img = img.resize((600,400))
    img = np.array(img)

    label.configure(foreground = "#ad3e72", text = "Cartooned Image",font=('montserrat',20))

    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

    gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
    gray = cv2.medianBlur(gray,5)
    edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9)
    #plt.imshow(edges,cmap= "gray")

    ctn = cv2.bilateralFilter(img,9,250,250)
    cartoon = cv2.bitwise_and(ctn,ctn,mask = edges)
    #plt.imshow(cartoon)
    cv2.imshow("Cartoon Art",cartoon)

    return cartoon

def lineEdge(filePath):

    global dtmy,edges

    x = datetime.datetime.now()
    dtmy = x.strftime("%d-%b-%y")

    img = Image.open(filePath)
    img = img.resize((600,400))
    img = np.array(img)

    label.configure(foreground = "#ad3e72", text = "Edge Image",font=('montserrat',20))

    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

    gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
    gray = cv2.medianBlur(gray,5)
    edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9)
    cv2.imshow("Line Art",edges)

    return edges

#filePath = "../Cartoonify/Data/"

def saveCartoon(res):
    global result
    path = '../Cartoonify/CartoonImag/Cartooned/'
    cv2.imwrite(os.path.join(path , 'Cartoonify_'+dtmy+'.jpg'), res)

def saveEdgeLine(edge):
    path = '../Cartoonify/CartoonImag/Edges/'
    cv2.imwrite(os.path.join(path , 'EdgesImage_'+dtmy+'.jpg'),edge)

#I = "Image saved at "+ path
#tk.messagebox.showinfo(title=None, message=I)

top=tk.Tk()
top.geometry('1200x800')
top.title('Cartoonify Image')
top.configure(background='white')
label = tk.Label(top, background = "white", font = ("montserrat",15,"bold"))

picture = tk.Label(top)

## hex - #293861

## IMAGE CARTOONIFIER--Image Cartoonifier
heading = Label(top, text="IMAGE CARTOONIFIER",pady=10, font=('montserrat',21,"bold"))
heading.configure(background='white',foreground='#434f70')
heading.pack(side=TOP,pady=20)
#heading.grid(row=10,column=5)

Cartoonify_button = Button(top,text="Cartoonified Image", command = lambda : cartoonify(filePath), borderless=1, padx=15,pady=10)
Cartoonify_button.configure(background="#ffcbc4", foreground="#383838",font=("montserrat",15))
#Cartoonify_button.configure(background="white", foreground="#447f80",font=("montserrat",15),highlightbackground="#447f80",highlightthickness=1)
Cartoonify_button.pack(side=LEFT,padx=10)
#Cartoonify_button.grid(row=3,column=3)

LineEdge_button = Button(top,text="Line Edge Image", command = lambda : lineEdge(filePath), borderless=1, padx=15,pady=10)
LineEdge_button.configure(background="#ffcbc4", foreground="#383838",font=("montserrat",15))
LineEdge_button.pack(side=RIGHT,padx=10)
#LineEdge_button.grid(row=3,column=6)

saveC = Button(top,text="Save Cartoon Image",command=lambda: saveCartoon(cartoon),padx=30,pady=5)
saveC.configure(background="#ffcbc4", foreground="#383838",font=("montserrat",15))
saveC.pack(side=BOTTOM,padx=10,pady=5)
#saveC.grid(row=3,column=9)

saveE = Button(top,text="Save LineEdge Image",command=lambda: saveEdgeLine(edges),padx=30,pady=5)
saveE.configure(background="#ffcbc4", foreground="#383838",font=("montserrat",15))
saveE.pack(side=BOTTOM,padx=10,pady=5)
#saveE.grid(row=3,column=12)

upload = Button(top,text="Upload Image",command=upload,padx=10,pady=5)
upload.configure(background='#434f70', foreground='white',font=('montserrat',20))
upload.pack(side=TOP,pady=30)
#upload.grid(row=3,column=1)

label.pack(side=TOP,expand=True)
#label.grid(row=3,column=3)

top.mainloop()

#cv2.waitKey(0)
#cv2.destroyAllWindows()


import argparse

from abc import abstractmethod

from git_fzf.lib.utils.shell import run

from .InteractiveCommand import InteractiveCommand

class InteractiveDiffLikeCommand(InteractiveCommand):
    def __init__(self):
        super().__init__(
            no_candidates_message="you do not have any files to diff",
            enable_multi_select=True,
        )

        self.parser = argparse.ArgumentParser()
        self.parser.add_argument("--staged", "--cached", action="store_true")
        self.parser.set_defaults(staged=False)
        self.args = self.parser.parse_args()

        self.flags = {
            "get_candidates": [
                "--name-only",
                "--relative",
            ],
            "affect_selected": [],
        }

        if self.args.staged:
            self.flags.get("get_candidates").append("--staged")
            self.flags.get("affect_selected").append("--staged")

    def get_candidates(self):
        return run(
            f"git diff {' '.join(self.flags.get('get_candidates'))}",
            capture_output=True,
        ).splitlines()

    @abstractmethod
    def affect_selected(self):
        raise NotImplementedError


from flask import Flask, render_template, request, json
import pymongo
from pymongo import MongoClient
import json
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
from textblob import TextBlob
import tweepy
import re

app = Flask(__name__)

consumer_key = ''
consumer_secret = ''
access_token = ''
access_token_secret = ''

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

collection = '-1'
ptweet = 0
netweet = 0
ntweet = 0

#try:
MONGODB_URI = ""
client = MongoClient(MONGODB_URI, connectTimeoutMS=30000)
db = client.get_database("") # .
collection = ''
    #results = collection.find()
    #data = str(results.count())

    #return results
#except Exception as e:
#   print(e)

def streamTweet(tag):
    data = []
    for tweet in tweepy.Cursor(api.search, q="#"+tag, count=100, lang="en").items():
        data.append(tweet)

    return data

def getTweet(searchterm):
    global collection
    global ptweet
    global netweet
    global ntweet

    #results = collection.find()
    results = streamTweet(searchterm)
    data = ''
    #data = str(results.count())
    for emp in results:
        #dt = json.loads(emp)
        #txt = emp['text']
        txt = emp.text

        sentiment = get_tweet_sentiment(txt);

        #print(txt + " -- " + sentiment + " --- " + id_str + " --- " + name)
        if sentiment == 'positive':
            ptweet += 1
        elif sentiment == 'neutral':
            netweet += 1
        else:
            ntweet += 1
    myl = [ptweet, netweet, ntweet]
    total = sum(myl)
    pcent = round((ptweet / total) * 100, 2)
    necent = round((netweet / total) * 100, 2)
    ncent = round((ntweet / total) * 100, 2)
    mylist = [pcent, necent, ncent, total]
    return mylist
    #return str(results[0]['text'])

    return
    #return results

def clean_tweet(tweet):

    #clean tweet text by removing links, special characters using simple regex statements.
    return ' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)", " ", tweet).split())

def get_tweet_sentiment(tweet):

    #classify sentiment of passed tweet using textblob's sentiment method
    analysis = TextBlob(clean_tweet(tweet))
    if analysis.sentiment.polarity > 0:
        return 'positive'
    elif analysis.sentiment.polarity == 0:
        return 'neutral'
    else:
        return 'negative'

@app.route('/')
def homepage():

    title = "Epic Tutorials"
    paragraph = ["wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!","wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!wow I am learning so much great stuff!"]
    #mylist = getTweet()

    try:
        return render_template("index.html", title = title, paragraph=paragraph)
    except Exception:
        return str(e)

@app.route('/about')
def aboutpage():

    title = "About this site"
    paragraph = ["blah blah blah memememememmeme blah blah memememe"]

    pageType = 'about'

    return render_template("index.html", title=title, paragraph=paragraph, pageType=pageType)

@app.route('/contact')
def contactPage():

    title = "About this site"
    paragraph = ["blah blah blah memememememmeme blah blah memememe"]

    pageType = 'about'

    return render_template("index.html", title=title, paragraph=paragraph, pageType=pageType)

@app.route('/searchHashTag', methods=['POST'])
def searchHashTag(chartID = 'chart_ID', chart_type = 'pie', chart_height = 600):
    term =  request.form['searchterm'];
    mylist = getTweet(term)
    #return json.dumps({'status':'OK','title_text':term});
    pageType = 'graph'
    title = term
    total_tweets = mylist[3]

    series = [{
                "name": 'Brands',
                "colorByPoint": "true",
                "data": [
                    {
                        "name": 'Positive '+str(mylist[0])+'%',
                        "y": mylist[0],
                        "sliced": "true",
                    },
                    {
                        "name": 'Negative '+str(mylist[2])+'%',
                        "y": mylist[2],
                    },
                    {
                        "name": 'Neutral '+str(mylist[1])+'%',
                        "y": mylist[1],
                    }
                ]
            }]

    return json.dumps(series)
    #return render_template('index.html', chartID=chartID, chart=chart, series=series, title=title, credits=credits)

@app.route('/graph')
def graph(chartID = 'chart_ID', chart_type = 'pie', chart_height = 600):
    #chart = {"renderTo": chartID, "type": chart_type, "height": chart_height,}
    chart = {
                "renderTo": chartID,
                "plotBackgroundColor": "#fff",
                "plotBorderWidth": "null",
                "plotShadow": "false",
                "type": chart_type
            }
    series = [{
                "name": 'Brands',
                "colorByPoint": "true",
                "data": [{
                    "name": 'Chrome',
                    "y": 61.41,
                    "sliced": "true",
                    "selected": "true"
                }, {
                    "name": 'Internet Explorer',
                    "y": 11.84
                }, {
                    "name": 'Firefox',
                    "y": 10.85
                }, {
                    "name": 'Edge',
                    "y": 4.67
                }, {
                    "name": 'Safari',
                    "y": 4.18
                }, {
                    "name": 'Other',
                    "y": 7.05
                }]
            }]
    title = {"text": 'My Title'}
    credits = {"text":"Junior Peter"}
    tooltip: { "pointFormat": '{series.name}: <b>{point.percentage:.1f}%</b>'}
    plotOptions: {
                    "pie": {
                        "allowPointSelect": "true",
                        "cursor": 'pointer',
                        "dataLabels": {
                            "enabled": "true"
                        },
                        "showInLegend": "true"
                    }
                }
    title: {
                "text": "title_text"
            }
    return render_template('index.html', chartID=chartID, chart=chart, series=series, title=title, credits=credits)

if __name__ == "__main__":
    app.run()


import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegressionCV
from sklearn.svm import SVC
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier, VotingClassifier
from sklearn.metrics import accuracy_score, log_loss

all_games_df = pd.read_csv("Training_Data_2003_2019.csv")
test_df = all_games_df[all_games_df["Season"] > 2014]
train_df = all_games_df[all_games_df["Season"] < 2015]

x_train = train_df.iloc[:, 4:-1]
y_train = train_df.iloc[:, -1]
x_test = test_df.iloc[:, 4:-1]
y_test = test_df.iloc[:, -1]

lr_model = LogisticRegressionCV(cv=10, max_iter=1000)
# lr_model.fit(x_train, y_train)

svc_model = SVC(probability=True)
# svc_model.fit(x_train, y_train)

gb_model = GradientBoostingClassifier(n_estimators=1000, learning_rate=0.3, max_depth=3, random_state=0)
# gb_model.fit(x_train, y_train)

rf_model = RandomForestClassifier(n_estimators=100)
# rf_model.fit(x_train, y_train)

vc_model = VotingClassifier(estimators=[('lr', lr_model), ('rf', rf_model)],
                            voting='soft')
vc_model.fit(x_train, y_train)
y_pred = vc_model.predict_proba(x_test)
# y_pred[234, 1] = 0.5
print(log_loss(y_test, y_pred))

test_games_df = pd.read_csv("Test_Games.csv")
x_new_test = test_games_df.iloc[:, 4:-1]
y_new_pred = vc_model.predict_proba(x_new_test)

submission_df = pd.DataFrame(data=0, index=range(test_games_df.shape[0]), columns=["ID", "Pred"])
for i in range(submission_df.shape[0]):
    submission_df.iloc[i, 0] = test_games_df.iloc[i, 1].astype(str) + "_" + test_games_df.iloc[i, 2].astype(str) + "_" + \
                               test_games_df.iloc[i, 3].astype(str)
    submission_df.iloc[i, 1] = y_new_pred[i, 1]

submission_df.to_csv("Test_Submission.csv", index=False)


#!/usr/local/bin/python
# -*- coding: utf-8 -*-

""" Handler of result view

"""

from lib.record import recordFactory

IMP_MOD = "from %s.%s import %s"

class Handler(object):

    def __init__(self, judge_no):
        self.judge_no = judge_no
        self.conn = recordFactory.init().get_connection()

    def arrange(self, result):
        result = {}
        contest_no = result["contest_no"]
        cls_name = self.__extract_contest_cls(contest_no)
        mods = self.__make_imp_string(cls_name)
        for mod in mods:
            exec(mod)
        loader = Loader(contest_no)
        targets = loader.load()
        calc = Calculation(contest_no)
        rank = calc.calculate(targets)
        result["rank"] = rank
        viewer = Viewer(contest_no)
        result["template"] = viewer.template
        return result

    def __extract_contest_cls(contest_no):
        """ must fix to load from database """
        return "OBO"

    def __make_imp_string(cls_name):
        mods = []
        cls_list = ["Calculation", "Loader", "Viewer"]
        for cls in cls_list:
            cls = IMP_MOD % (cls_name.upper(), cls.lower(), cls)
            mods.append(cls)
        return mods


from dllist import DoubleLinkedList

class Dictionary(object):
    def __init__(self, num_buckets=256):
        """Initializes a Map with the given number of buckets."""
        # save to init List
        # make buckets which has  List

        self.num_buckets = num_buckets
        self.map = DoubleLinkedList()
        for i in range(num_buckets):
            self.map.push(DoubleLinkedList())

    def hash_key(self, key):
        """Given a key this will create a number and then convert it to
        an index for the aMap's buckets."""
        # return HASH value that was made by key
        return hash(key) % self.num_buckets

    def get_bucket(self, key):
        """Given a key, find the bucket where it would go."""

        # return bucket index
        # using HASH

        idx = self.hash_key(key)
        bucket = self.map.get(idx)
        return bucket

    def get_slot(self, key, default=None):
        """
        Returns either the bucket and node for a slot, or None, None
        """
        #point out the bucket
         # bucket ok ?
         #  search bucket
         #   if find  return ( bucket, node)
         #  not found  return ( bucket, next-node)
         #
         # bucket not Ok
         #
        slot = self.get_bucket(key)

        s_num = slot.count()
        for i in range(s_num):

            val = slot.get(i)
            if (val[0] == key):
                return slot, val
                break;

        return slot, None

    def get(self, key, default=None):
        """Gets the value in a bucket for the given key, or the default."""
        # get node
        # return value  or   node ( node == None)
        slot, node = self.get_slot(key)
        if (node):
            print("__Get_Val=", node[1])
            return node[1]
        else:
            return default

    def set(self, key, value):
        """Sets the key to the value, replacing any existing value."""

        # get bucket, node
        #  if node ?   ( key was found)
        #   change value

        #  node == None ( do not have key)

        slot, node = self.get_slot(key)
        if (node):
            node[1] = value
        else:
            slot.push([key, value])

    def delete(self, key):
        """Deletes the given key from the Map."""
        # get bucket
        # search node
        # detach from List

        #slot, val = self.get_slot(key)
        slot = self.get_bucket(key)
        if (slot):

            bfound = False
            node = slot.begin
            while (node):
                if (node.value[0] == key):
                    print("will be Deleted ", node.value[0], node.value[1])
                    bfound = True
                    break
                node = node.next

            if bfound:
                slot.detach_node(node)

    def list(self):
        """Prints out what's in the Map."""

        print("__________list of dictionary______")

        for i in range(self.num_buckets):
            bucket = self.map.get(i)

            cnt = bucket.count()
            for j in range(cnt):

                node = bucket.get(j)
                print("KEY=", node[0], "VALUE=", node[1])


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 27 22:38:22 2023

@author: micahborrero
"""
# Import needed modules
# NOTE: For testing purposes qgis packages are commented out
# from qgis.core import *
# import qgis.utils
# from qgis.PyQt import QtGui
# from console.console import _console

import os
import sys

import numpy as np
import pandas as pd

# Random efficiency modules
# from dask import delayed
# import multiprocessing
# from numba import jit, cuda
# import dask.dataframe as dd

import geopandas as gpd
import geopy
from tqdm import tqdm, trange
import LCATools as LCAT
from CommonTools import get_top_dir
import argparse

top_dir = get_top_dir()

def geocode(loc):
    locator = geopy.Nominatim(user_agent = "MyGeocoder")
    location = locator.geocode(loc)
    print(location.longitude, location.latitude)

def readMeta():
    '''
    Reads in the metadata file (functionally keys) for the FAF5 data

    Parameters
    ----------
    None

    Returns
    -------
    dest (pd.DataFrame): A pandas dataframe containing (currently) all domestic regions from the FAF5_metadata
    mode (pd.DataFrame): A pandas dataframe containing (currently) all modes of transit used in the FAF5_metadata

    NOTE: None.

    '''

    # Read in Meta Data
    metaPath = f'{top_dir}/data/FAF5_regional_flows_origin_destination/FAF5_metadata.xlsx'
    meta = pd.ExcelFile(metaPath)

    tradeType = pd.read_excel(meta, 'Trade Type')
    # Only include truck rail and water
    mode = pd.read_excel(meta, "Mode")[0:3]
    dest = pd.read_excel(meta, 'FAF Zone (Domestic)')
    comms = pd.read_excel(meta, 'Commodity (SCTG2)')
    # dest.head()
    # print(origin)
    # geocode(origin.iloc[1, 1])

    # print('Meta read succesfully')

    return dest, mode, comms

def readData(cols=None):
    '''
    Reads in FAF5 origin-destination data

    Parameters
    ----------
    cols (list): List of columns to filter the data by

    Returns
    -------
    None

    NOTE: dms_dest -> index 2; dms_orig -> index 1; tons_2020 -> index 12

    '''
    dataPath = f'{top_dir}/data/FAF5_regional_flows_origin_destination/FAF5.4.1_2018-2020.csv'
    data = pd.read_csv(dataPath)
    #data = pd.read_csv(dataPath, nrows=1000)  # DMM: This line is just for testing/development, to reduce processing time

    if cols is not None: data = data[cols]

    return data

def filterLCA(item='CO2 (w/ C in VOC & CO)', comm='all'):
    '''
    The purpose of this method is to import the LCA data and filter it in a
        manner that is easily readable for processing

    Parameters
    ----------
    item : String, optional
        The pollutant modifier in which things will be filtered by.
            The default is 'CO2 (w/ C in VOC & CO)'.
    comm : String, optional
        The commodity in which all things will be filtered by. In the event
            that the input is None, it will include all commodities.
            The default is 'all'.

    Returns
    -------
    lca_filt : DataFrame
        DataFrame based on the LCA data containing the relevant rows based on
            the filters.

    '''
    emit = LCAT.df_lca_dict
    lca_filt = pd.DataFrame()
    commodities = []
    modes = []

    # It is a two layer dictionary with the first being modes
    # The second layer is commodities
    for key, mode in emit.items():
        # This only goes through a specific commodity for all modes given the input
        # The default value is 'all' for the sake of ease
        if comm != None:
            new_row = mode[comm].loc[mode[comm]['Item'] == item]
            lca_filt = pd.concat([lca_filt.loc[:], new_row]).reset_index(drop=True)
            commodities.append(comm)
            modes.append(key)

        else:
            for cKey, commodity in mode.items():
                # This loop goes through all possible commodities given that the input is none
                if cKey != 'all':
                    new_row = commodity.loc[commodity['Item'] == item]
                    lca_filt = pd.concat([lca_filt.loc[:], new_row]).reset_index(drop=True)
                    commodities.append(cKey)
                    modes.append(key)

    lca_filt['Commodity'] = commodities
    lca_filt['Modes'] = modes

    return lca_filt

# No longer used
# =============================================================================
# # The method will be modified to incorporate the below calculation of emissions in
# #   completeOD() for simplification purposes
# def emissions_OD(dest, mode, comm=None):
#     '''
#     Assigns a net ton (either import or export) to each FAF5 region
#
#     Parameters
#     ----------
#     dest (pd.DataFrame): A pandas dataframe containing (currently) all domestic regions from the FAF5_metadata
#
#     Returns
#     -------
#     None
#
#     NOTE: dms_dest -> index 2; dms_orig -> index 1; tons_2020 -> index 12
#
#     '''
#     data = readData(["dms_orig", "dms_dest", "tons_2020", "dms_mode", 'tmiles_2020', 'sctg2'])
#
#     # This is dest*mode based on the idea that we account for all possible
#     #   values (excluding the finer commodity ones)
#     tot_len = len(dest)*len(mode)
#
#     tons_in = np.zeros(tot_len)
#     tons_out = np.zeros(tot_len)
#     ton_miles = np.zeros(tot_len)
#
#     emissions = np.zeros(tot_len)
#
#     emissions_data = filterLCA()
#
#     # Currently the algorithm works by iterating through the values in the meta
#     #   data follows by iterating over the entirety of the data
#     # The new goal is to break things down by mode utilizing the "dms_mode" key
#     i = 0
#     for row in tqdm(dest.values):
#         # 0 will be truck, 1 will be rail, 2 will be water
#         #   for momo in mode.values:
#         for line in data.values:
#             if line[3] == mode['Numeric Label'][0]:
#                 j = i
#                 eMult = emissions_data['WTW'][0]
#             elif line[3] == mode['Numeric Label'][1]:
#                 j = i+1
#                 eMult = emissions_data['WTW'][1]
#             elif line[3] == mode['Numeric Label'][2]:
#                 j = i+2
#                 eMult = emissions_data['WTH'][2]
#             else:
#                 # This continue exists as we only want to consider truck, rail,
#                 #   or water
#                 continue
#
#             if line[1] == row[0]:
#                 tons_in[j] += line[2]
#                 ton_miles[j] += line[4]
#                 emissions[j] += line[4] * eMult
#
#             if line[0] == row[0]:
#                 tons_out[j] += line[2]
#
#         i+=1
#
#     dest['Total Import'] = tons_in
#     dest['Total Export'] = tons_out
#     dest['FAF_Zone'] = dest['Numeric Label'].apply(str).apply(lambda x: x.zfill(3))
#     dest['Mode'] = pd.concat([mode['Description']]*tot_len, ignore_index=True)
#     dest['Ton-Miles'] = ton_miles
#     dest['Emissions'] = emissions
#
#     return dest
# =============================================================================

def completeOD(mode, commodity, selected_mode=None, selected_commodity=None, selected_origin=None, selected_destination=None):
    '''
    The idea behind this method is that since modifying the origin destination
        pairs by commodity and then mode is the same as going over the entire
        data set, we simply calculate the emissions for the entire dataset and
        then use that new dataset to be summed over (it's less math/operations
        overall)

    Parameters
    ----------
    mode : DataFrame
        Is a DataFrame from the meta data containing the associated keys for
            the various FAF5 modes. Note we only are considering truck, rail,
            and ship.
    commodity : DataFrame
        DESCRIPTION.

    Returns
    -------
    data : DataFrame
        DESCRIPTION.

    '''
    data = readData(["dms_orig", "dms_dest", "tons_2020", "dms_mode", 'tmiles_2020', 'sctg2'])
    emissions_data = filterLCA(comm=None)

    # Remove rows with dms_mode > 3
    if (not selected_origin is None) and (not selected_origin=='all'):
        data = data.drop(data[data.dms_orig != int(selected_origin)].index)
    if (not selected_destination is None) and (not selected_destination=='all'):
        data = data.drop(data[data.dms_dest != int(selected_destination)].index)

    data = data.drop(data[data.dms_mode > 3].index)
    data['emissions'] = data['sctg2']
    data['commodity'] = data['sctg2']
    data['mode'] = data['sctg2']

    for this_mode in mode['Numeric Label']:
        for this_commodity in commodity['Numeric Label']:
            cCommodity_mode = (data['dms_mode'] == this_mode) & (data['sctg2'] == this_commodity)

            commodity_sp = commodity.loc[commodity['Numeric Label'] == this_commodity].values[0][1]
            data['commodity'][cCommodity_mode] = commodity_sp

            mode_sp = mode.loc[mode['Numeric Label'] == this_mode].values[0][1].lower()
            if mode_sp == 'water':
                w2 = 'WTH'
                mode_sp = 'ship'
            else:
                w2 = 'WTW'

            data['mode'][cCommodity_mode] = mode_sp
            emissions_modifier = emissions_data.loc[(emissions_data['Modes'] == mode_sp) & (emissions_data['Commodity'] == commodity_sp)][w2].values[0]
            data['emissions'][cCommodity_mode] = data['tmiles_2020'][cCommodity_mode] * emissions_modifier

    return data

def getCompleteOD():
    '''
    Method gets the saved csv of the completeOD() data and returns as a DF

    Returns
    -------
    data : DataFrame
        DataFrame of the complete emissions data.

    '''
    savePath = f'{top_dir}/data/'

    dataPath = savePath + 'completeOD.csv'
    data = pd.read_csv(dataPath)

    return data

def filterDataMC(data, mode, commodity):
    '''
    This method filters the data based on a given array of modes and commodities.

    Parameters
    ----------
    data : DataFrame
        DataFrame of the entire dataset produced in completeOD().
    mode : Array
        Array of the modes that are being filtered.
    commodity : Array
        Array of the commodities that are being filtered.

    Returns
    -------
    data_filtered : DataFrame
        DataFrame of the filtered and summed data based on the input modes and
            commodities.

    '''
    data_filtered = pd.DataFrame()
    data_length = len(mode) * len(commodity)

    data_filtered['Mode'] = pd.concat([mode]*len(commodity), ignore_index=True)
    data_filtered['Commodity'] = pd.concat([commodity]*len(mode), ignore_index=True)

    emissions = np.zeros(data_length)

    i = 0
    for row in tqdm(data_filtered.values):
        for line in data.values:
            if line[-1] == row[0]:
                if line[-2] == row[1]:
                    emissions[i] += line[-3]

        i += 1

    data_filtered['Emissions'] = emissions()

    return data_filtered

def filterOD(dest, data, direction=True):
    data_filtered = pd.DataFrame()

    tot_len = len(dest)

    tons_in = np.zeros(tot_len)
    tons_out = np.zeros(tot_len)
    tons_tot = np.zeros(tot_len)

    ton_miles_in = np.zeros(tot_len)
    ton_miles_out = np.zeros(tot_len)
    ton_miles_tot = np.zeros(tot_len)

    emissions_in = np.zeros(tot_len)
    emissions_out = np.zeros(tot_len)
    emissions_tot = np.zeros(tot_len)

    i = 0
    for row in tqdm(dest.values):
        for line in data.values:
            if line[1] == row[0] or line[0] == row[0]:
                tons_tot[i] += line[2]
                ton_miles_tot[i] += line[4]
                emissions_tot[i] += line[-3]
            if line[1] == row[0]: # Import
                tons_in[i] += line[2]
                ton_miles_in[i] += line[4]
                emissions_in[i] += line[-3]
#                    if direction:
#                        ton_miles[i] += line[3]
#                        emissions[i] += line[-3]

            if line[0] == row[0]: # Export
                tons_out[i] += line[2]
                ton_miles_out[i] += line[4]
                emissions_out[i] += line[-3]

#                    if not direction:
#                        ton_miles[i] += line[3]
#                        emissions[i] += line[-3]

        i+=1

    data_filtered['FAF_Zone'] = dest['Numeric Label'].apply(str).apply(lambda x: x.zfill(3))
    data_filtered['Tons Import'] = tons_in
    data_filtered['Tons Export'] = tons_out
    data_filtered['Tons Total'] = tons_tot

    data_filtered['Tmiles Import'] = ton_miles_in
    data_filtered['Tmiles Export'] = ton_miles_out
    data_filtered['Tmiles Total'] = ton_miles_tot

    data_filtered['E Import'] = emissions_in
    data_filtered['E Export'] = emissions_out
    data_filtered['E Total'] = emissions_tot

    return data_filtered

def mergeShapefile(dest, shapefile_path):
    '''
    Merges the shapefile containing FAF5 region borders with the csv file containing total tonnage
    calculated in processData()

    Parameters
    ----------
    dest (pd.DataFrame): A pandas dataframe containing (currently) all domestic regions from the FAF5_metadata, along
    with total tonnages calculated in processData()

    shapefile_path (string): Path to the shapefile to be joined with the dataframe

    Returns
    -------
    merged_Dataframe (pd.DataFrame): Joined dataframe
    '''
    shapefile = gpd.read_file(shapefile_path)

    # Select columns of interest
    shapefile_filtered = shapefile.filter(['Short Description', 'FAF_Zone', 'FAF_Zone_D', 'ShapeSTAre', 'ShapeSTLen', 'geometry'], axis=1)
    dest_filtered = dest.filter(['FAF_Zone', 'Tons Import', 'Tons Export', 'Tons Total', 'Tmiles Import', 'Tmiles Export', 'Tmiles Total', 'E Import', 'E Export', 'E Total'], axis=1)

    merged_dataframe = shapefile_filtered.merge(dest_filtered, on='FAF_Zone', how='left')

    # Add columns with imports and exports per unit area (km^2)
    meters_per_mile = 1609.34
    merged_dataframe['Tons Imp Den'] = merged_dataframe['Tons Import'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )
    merged_dataframe['Tons Exp Den'] = merged_dataframe['Tons Export'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )
    merged_dataframe['Tons Tot Den'] = merged_dataframe['Tons Total'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )
    merged_dataframe['Tmil Imp Den'] = merged_dataframe['Tmiles Import'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )
    merged_dataframe['Tmil Exp Den'] = merged_dataframe['Tmiles Export'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )
    merged_dataframe['Tmil Tot Den'] = merged_dataframe['Tmiles Total'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )
    merged_dataframe['E Imp Den'] = merged_dataframe['E Import'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )
    merged_dataframe['E Exp Den'] = merged_dataframe['E Export'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )
    merged_dataframe['E Tot Den'] = merged_dataframe['E Total'] / ( merged_dataframe['ShapeSTAre'] * (1./meters_per_mile)**2 )

    dest_filtered = merged_dataframe.filter(['FAF_Zone', 'Tons Import', 'Tons Export', 'Tons Total', 'Tmiles Import', 'Tmiles Export', 'Tmiles Total', 'E Import', 'E Export', 'E Total', 'Tons Imp Den', 'Tons Exp Den', 'Tons Tot Den', 'Tmil Imp Den', 'Tmil Exp Den', 'Tmil Tot Den', 'E Imp Den', 'E Exp Den', 'E Tot Den'], axis=1)

    return merged_dataframe, dest_filtered

def saveFile(file, name):
    savePath = f'{top_dir}/data/Point2Point_outputs/'
    if not os.path.exists(savePath):
        os.makedirs(savePath)

    file.to_csv(savePath + f'{name}.csv', index=False)
    print(f'file has been saved as a csv')

def saveShapefile(file, name):
    '''
    Saves a pandas dataframe as a shapefile

    Parameters
    ----------
    file (pd.DataFrame): Dataframe to be saved as a shapefile

    name (string): Filename to the shapefile save to (must end in .shp)

    Returns
    -------
    None
    '''
    # Make sure the filename ends in .shp
    if not name.endswith('.shp'):
        print("ERROR: Filename for shapefile must end in '.shp'. File will not be saved.")
        exit()
    # Make sure the full directory path to save to exists, otherwise create it
    dir = os.path.dirname(name)
    if not os.path.exists(dir):
        os.makedirs(dir)
    file.to_file(name)

parser = argparse.ArgumentParser()
parser.add_argument('-m', '--mode', default='truck')
parser.add_argument('-c', '--commodity', default='all')
parser.add_argument('-o', '--origin', default='all')
parser.add_argument('-d', '--dest', default='all')

def main ():
    args = parser.parse_args()

    # filterLCA()

    # Load FAF5 Regional Metadata
    dest, mode, comm = readMeta()
    #print(dest, mode, comms)

    dataOD = completeOD(mode, comm, selected_origin=args.origin, selected_destination=args.dest)#, selected_modes, selected_commodities, origin_region=11, dest_region='all')#, origin_region='all', dest_region='all')

    # Apply selections
    cBaseline = (dataOD['dms_orig'] > -9999)
    if args.mode == 'all':
        cMode = True
    else:
        cMode = (dataOD['mode'] == args.mode)

    if args.commodity == 'all':
        cCommodity = True
    else:
        cCommodity = (dataOD['commodity'] == args.commodity)

    if args.origin == 'all':
        cOrigin = True
    else:
        cOrigin = (dataOD['dms_orig'] == int(args.origin))

    if args.dest == 'all':
        cDest = True
    else:
        cDest = (dataOD['dms_dest'] == int(args.dest))

    dataOD_selected = dataOD[cBaseline&cMode&cCommodity&cOrigin&cDest]

    # Sum emissions and ton-miles over all trips
    data_filtered = filterOD(dest, dataOD_selected, direction=True)

    commodity_save = args.commodity.replace(' ', '_').replace('/', '_')

#    with pd.option_context('display.max_rows', None,):
#        print(data_filtered)

    # print(comms.loc[comms['Numeric Label'] == 1].values[0][1])
    # print(mode.loc[mode['Numeric Label'] == 1].values[0][1])
    # print(mode[mode.Numeric_Label=='1'].Description.item())
    # print(dataOD)

    #print(mode.loc[mode['Description']=='Truck'])
    #datfil1 = filterDataMC(dataOD, mode, comms)
    #print(datafil1)

    #saveFile(dataOD, 'completeOD')

    # dest_with_tonnage = emissions_OD(dest, mode)
    # saveFile(dest_with_tonnage, 'total_tons_short')

    # DMM: To save time for testing and development, can read in saved csv with the following three lines
    # and comment out above two lines
    #dest = pd.read_csv(f'{top_dir}/data/total_tons.csv', dtype=object)
    #dest['Total Import'] = dest['Total Import'].astype('float')
    #dest['Total Export'] = dest['Total Export'].astype('float')

    merged_dataframe, data_filtered = mergeShapefile(data_filtered, f'{top_dir}/data/FAF5_regions/Freight_Analysis_Framework_(FAF5)_Regions.shp')
    saveFile(data_filtered, f'mode_{args.mode}_commodity_{commodity_save}_origin_{args.origin}_dest_{args.dest}')
    saveShapefile(merged_dataframe, f'{top_dir}/data/Point2Point_outputs/mode_{args.mode}_commodity_{commodity_save}_origin_{args.origin}_dest_{args.dest}.shp')

main()


import asyncio
import logging
import random
from datetime import timedelta
from json.decoder import JSONDecodeError

import async_timeout
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from h11 import Data
from homeassistant import core
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.exceptions import IntegrationError
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.discovery import async_load_platform
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import (DataUpdateCoordinator,
                                                      UpdateFailed)

from .const import DOMAIN, GW_ID, GW_IP, NAME, PLATFORMS, TAP_ID
from .linktap_local import LinktapLocal

_LOGGER = logging.getLogger(__name__)

async def async_setup(_hass, _config):
    return True

async def async_setup_entry(hass: core.HomeAssistant, entry: ConfigEntry)-> bool:
    """Set up the platform."""

    gw_ip = entry.data.get(GW_IP)

    linker = LinktapLocal()
    linker.set_ip(gw_ip)
    try:
        gw_id = await linker.get_gw_id()
    except JSONDecodeError:
        try:
            await asyncio.sleep(random.randint(1,3))
            gw_id = await linker.get_gw_id()
        except JSONDecodeError:
            await asyncio.sleep(random.randint(1,3))
            gw_id = await linker.get_gw_id()

    _LOGGER.debug(f"Found GW_ID: {gw_id}")

    gateway_config = await linker.get_gw_config(gw_id)
    if "end_dev" not in gateway_config:
        raise IntegrationError("Linktap Gateway needs to be updated")

    devices = {
        "devs": gateway_config["end_dev"],
        "names": gateway_config["dev_name"],
    }
    _LOGGER.debug(f"Found devices: {devices}")

    coordinator_conf = {
        GW_IP: gw_ip,
        GW_ID: gw_id,
    }
    counter = 0
    tap_list = []
    for tap_id in devices["devs"]:
        coordinator = LinktapCoordinator(hass, linker, coordinator_conf, tap_id)
        device_name = devices["names"][counter]
        tap_list.append({
            NAME: device_name,
            TAP_ID: tap_id,
            GW_IP: gw_ip,
            "coordinator": coordinator
        })
        counter = counter + 1
        await coordinator.async_config_entry_first_refresh()
        _LOGGER.debug(f"Coordinator has synced for {tap_id}")
    _LOGGER.debug(f"List of Taps: {tap_list}")

    vol_unit = gateway_config["vol_unit"]
    _LOGGER.debug(f"Setting volume unit to {vol_unit}")

    conf = {
        GW_IP: gw_ip,
        GW_ID: gw_id,
        "taps": tap_list,
        "vol_unit": vol_unit,
    }

    hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {"conf": conf}
    _LOGGER.debug(hass.data[DOMAIN])
    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
    # Reload entry when its updated.
    entry.async_on_unload(entry.add_update_listener(async_reload_entry))

    return True

async def async_unload_entry(hass: core.HomeAssistant, entry: ConfigEntry) -> bool:
    """Unload a component config entry."""
    unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
    if unload_ok:
        hass.data[DOMAIN].pop(entry.entry_id)
    return unload_ok

async def async_remove_config_entry_device(hass: core.HomeAssistant, entry: ConfigEntry, device) -> bool:
    device_registry(hass).async_remove_device(device.id)
    return True

class LinktapCoordinator(DataUpdateCoordinator):
    def __init__(self, hass, linker, conf, tap_id):
        super().__init__(
            hass,
            _LOGGER,
            name=DOMAIN,
            update_interval=timedelta(seconds=13),
        )
        self.tap_api = linker
        self.conf = conf
        self.hass = hass
        self.tap_id = tap_id

    def get_gw_id(self):
        return self.conf[GW_ID]

    #def get_vol_unit(self):
    #    return self.conf["vol_unit"]

    async def _async_update_data(self):
        """Fetch data from API endpoint.

        This is the place to pre-process the data to lookup tables
        so entities can quickly look up their data.
        """

        #tap_id = self.conf["taps"][TAP_ID]
        gw_id = self.conf[GW_ID]

        try:
            # Note: asyncio.TimeoutError and aiohttp.ClientError are already
            # handled by the data update coordinator.
            async with async_timeout.timeout(10):
                return await self.tap_api.fetch_data(gw_id, self.tap_id)
        except:# ApiAuthError as err:
            await asyncio.sleep(random.randint(1,3))
            async with async_timeout.timeout(10):
                return await self.tap_api.fetch_data(gw_id, self.tap_id)
            # Raising ConfigEntryAuthFailed will cancel future updates
            # and start a config flow with SOURCE_REAUTH (async_step_reauth)
        #    raise ConfigEntryAuthFailed from err
        #except ApiError as err:
        #    raise UpdateFailed(f"Error communicating with API: {err}")

async def async_reload_entry(hass: core.HomeAssistant, entry: ConfigEntry) -> None:
    """Reload the config entry when it changed."""
    await hass.config_entries.async_reload(entry.entry_id)


from rle.explainers.logistic_regression_explainer import LogisticRegressionExplainer
from rle.samplers.gaussian_exponential_sampler import GaussianExponentialSampler
from rle.depicters.depicter_bar_weights import DepicterBarWeights
from sklearn.model_selection import train_test_split
from rle.explanation.robust_explanation import RobustExplanation
from sklearn.ensemble import RandomForestClassifier
import sklearn.datasets as datasets
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

sns.set_style("whitegrid")
plt.rc('text', usetex=True)
plt.rc('font', family='serif')

def same_side(p1, p2, a, b):
    cp1 = np.cross(b - a, p1 - a)
    cp2 = np.cross(b - a, p2 - a)
    if np.inner(cp1, cp2) >= 0:
        return True
    else:
        return False

def inside_triangle(p, a, b, c):
    if same_side(p, a, b, c) and same_side(p, b, a, c) and same_side(p, c, a, b):
        return True
    else:
        return False

# Initializes double triangle dataset
X = np.random.rand(5000, 2)
triangle = np.array([[0.4, 0.4], [0.6, 0.6], [0.01, 0.99]])
decision = np.array([0.27, 0.64])
y = np.array(list(map(lambda x: int(x[1] < x[0] or inside_triangle(x, triangle[0], triangle[1], triangle[2])), X)))

# Plots classified data (Random Forest)
X_train, X_test, y_train, y_test = train_test_split(X, y)
rf = RandomForestClassifier(n_estimators=100)
rf.fit(X_train, y_train)

dest = "./imgs/test_logistic_regression_robust_explanation_3.pdf"
# Initializes explainer
exp = RobustExplanation(X_train, ["F1", "F2"], None,
                        y_train, "Label", None,
                        model=RandomForestClassifier(n_estimators=100),
                        explainer=LogisticRegressionExplainer,
                        sampler=GaussianExponentialSampler,
                        depicter=DepicterBarWeights)

exp.sample_explain_depict(decision, 5, num_samples=5000, measure_min=0.005, measure_max=0.5, number_eval=500, dest=dest)


import uuid
from unittest.mock import MagicMock

from django.urls import reverse_lazy

from rest_framework.test import APIClient

from libs.testing.constants import OK

def get_url():
    """Get url for `getting setup intent`."""
    return reverse_lazy('v1:subscribe-get-setup-intent')

def test_get_setup_intent(api_client: APIClient, mocker):
    """Test `get_setup_intent` API method."""
    expected_secret = str(uuid.uuid4())
    mocker.patch(
        'djstripe.models.SetupIntent._api_create',
        return_value=MagicMock(client_secret=expected_secret)
    )

    url = get_url()
    response = api_client.get(url)

    assert response.status_code == OK
    assert response.data['client_secret'] == expected_secret


import pandas as pd
import time
from selenium.webdriver import Chrome
from selenium import webdriver
import json
driver = webdriver.Chrome("/usr/lib/chromium-browser/chromedriver")
browser = Chrome()
url = "https://www.instagram.com/"

def recent_posts(username):
    """With the input of an account page, scrape the 25 most recent posts urls"""
    url = "https://www.instagram.com/" + username + "/"
    browser = Chrome()
    browser.get(url)
    post = 'https://www.instagram.com/p/'
    post_links = []
    #xpath_comment = '//*[@id="react-root"]/section/main/div/header/section/ul/li[1]/a/span'
    #comment = browser.find_element_by_xpath(xpath_comment)
    #comment = comment.text
    #num_of_posts = int(comment)
    while len(post_links) < 150:
        links = [a.get_attribute('href') for a in browser.find_elements_by_tag_name('a')]
        for link in links:
            if post in link and link not in post_links:
                post_links.append(link)
        scroll_down = "window.scrollTo(0, document.body.scrollHeight);"
        browser.execute_script(scroll_down)
        time.sleep(10)
    else:
        return post_links

def insta_details(urls):
    """Take a post url and return post details"""
    browser = Chrome()
    post_details = []
    for link in urls:
        browser.get(link)
        xpath_comment = '//*[@id="react-root"]/section/main/div/div[1]/article/div[2]/div[1]/ul/div/li/div/div/div[2]/span'
        try:
            comment = browser.find_element_by_xpath(xpath_comment)
            comment = comment.text
            post_details.append(comment)
        except:
            continue

        time.sleep(10)
    return post_details

posts = insta_details(recent_posts('username'))
print(posts)
with open("username.json", "w") as write_file:
    json.dump(posts, write_file)


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

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('store', '0005_items_cloud_d_it_id'),
    ]

    operations = [
        migrations.RenameField(
            model_name='cloud_users',
            old_name='cloud_users',
            new_name='cloud_user',
        ),
        migrations.AddField(
            model_name='cloud_users',
            name='pk_cu',
            field=models.IntegerField(default=0, max_length=11),
            preserve_default=False,
        ),
    ]


import webbrowser, sys, pyperclip

sys.argv # ['mapit.py','Rua do Conde de Redondo','91B', '1150-103 Lisboa', 'Portugal']

# Check if command Line argurments were passed
if len(sys.argv) > 1:
    # ['mapit.py','Rua do Conde de Redondo','91B', '1150-103 Lisboa', 'Portugal']
    address = ' '.join(sys.argv[1:])
else:
    address = pyperclip.paste()

# https://www.google.fr/maps/place/Le+Wagon+Lisbon+Coding+Bootcamp/@38.7260907,-9.1476757,17z/data=!3m1!4b1!4m5!3m4!1s0xd19351a74f8e2a3:0x779f5b9fe8faf6a7!8m2!3d38.7260865!4d-9.145487
webbrowser.open('https://www.google.fr/maps/place/' + address)

Automate The Boring Stuff/section12/mapit.py


from django.contrib.auth.models import User
from django import forms

from torch.idea.models import Idea

def make_IdeaForm(user):

    class IdeaForm(forms.ModelForm):
        title = forms.CharField(
            label='What do you want to call your idea?',
            required=True,
            max_length=200,
            widget=forms.TextInput(attrs={
                'placeholder': 'I think it would be a good idea if Elkhart...',
                'class': 'input-xxlarge title-input',
                'type': 'text',
            }),
        )
        description = forms.CharField(
            required=True,
            label='Why should people like your idea?',
            widget=forms.Textarea(attrs={
                'placeholder': 'The reason we should do this is...',
                'class': 'input-xxlarge description-input',
                'type': 'text',
                'rows': '2',
            }),
        )

        def clean(self, *args, **kwargs):
            result = super(IdeaForm, self).clean(*args, **kwargs)
            if not isinstance(user, User):
                raise forms.ValidationError('This field is required.')
            return result

        def save(self, *args, **kwargs):
            self.instance.author = user
            return super(IdeaForm, self).save(*args, **kwargs)

        class Meta:
            model = Idea
            exclude = ('author')
    return IdeaForm


import rdflib
import urllib.request
import ssl
from SPARQLWrapper import SPARQLWrapper, JSON

sparql = SPARQLWrapper("http://192.168.31.230:7200/repositories/0531-0610")

query = """
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX yourNamespace: <yourNamespaceURI>

SELECT ?property ?value
WHERE {
  ?subject ?property ?value .
}
"""

# Set the SPARQL query and return format
sparql.setQuery(query)
sparql.setReturnFormat(JSON)

# Execute the SPARQL query
results = sparql.query().convert()

# Process the query results
for result in results["results"]["bindings"]:
    property_name = result["property"]["value"]
    value = result["value"]["value"]
    print(f"Property: {property_name} | Value: {value}")


# Calculates the smallest integer that can be the length of a cathetus of exactly 47,547 different integer sided right-angled triangles

from functools import reduce
import operator

def prime_factors(n):
	i = 2
	factors = []
	while i * i <= n:
		if n % i:
			i += 1
		else:
			n //= i
			factors.append(i)
	if n > 1:
		factors.append(n)
	return factors

max = 50
primes = []
sieve = [True] * max
for i in range(2, max):
	if sieve[i]:
		primes.append(i)
		for j in range(i * i, max, i):
			sieve[j] = False

n = 47547
P = prime_factors(2*n+1)[::-1]
print(reduce(operator.mul,[primes[P.index(p)]**((p-1)//2) for p in P[1:]],2**((P[0]+1)//2)))


import os

import numpy as np
from matplotlib import pyplot as plt
from scipy.stats import pearsonr

from decoders import get_R2
from main import Evaluation

result_path = './results/'
kin_file = 'indy_20170124_01_kin_test.npy'
kin_pred_file = 'indy_20170124_01_kin_pred.npy'
decoder = ['Linear', 'KF', 'DNN', 'LSTM']

n_motion = 6

kin = []
kin_pred = []

kin.append(np.load(result_path + decoder[0] + '/' + kin_file))
kin.append(np.load(result_path + decoder[1] + '/' + kin_file))
kin.append(np.load(result_path + decoder[2] + '/' + kin_file))
kin.append(np.load(result_path + decoder[3] + '/' + kin_file))

kin_pred.append(np.load(result_path + 'Linear/' + kin_pred_file))
kin_pred.append(np.load(result_path + 'KF/' + kin_pred_file))
kin_pred.append(np.load(result_path + 'DNN/' + kin_pred_file))
kin_pred.append(np.load(result_path + 'LSTM/' + kin_pred_file))

all_cc = np.zeros((len(kin), n_motion))
all_r2 = np.zeros(all_cc.shape)

for i in range(len(kin)):
    r2 = get_R2(kin[i], kin_pred[i])
    for MoBin in range(n_motion):
        all_r2[i, MoBin] = r2[MoBin]

        r, p = pearsonr(kin[i][:, MoBin], kin_pred[i][:, MoBin])
        all_cc[i, MoBin] = r

# # Plot all cc
# Evaluation(result_path, all_cc, decoder)
# np.save(os.path.join(result_path, 'all_cc.npy'), all_cc)

# Plot all r2
a = 0.7
colors = ['C' + str(i) for i in range(len(kin))]
x = range(len(kin))

plt.figure(figsize=(12, 8))
plt.subplot(2, 3, 1)
plt.bar(x, all_r2[:, 0], alpha=a, color=colors)
plt.xlabel('x_pos')
plt.ylabel('R^2')

plt.subplot(2, 3, 2)
plt.bar(x, all_r2[:, 2], alpha=a, color=colors)
# for i in range(len(kin)):
#     plt.bar(x[i], all_r2[i, 2], alpha=a, color=colors[i], label=decoder[i])
plt.xlabel('x_vel')

plt.subplot(2, 3, 3)
# plt.bar(x, all_r2[:, 4], alpha=a, color=colors)
for i in range(len(kin)):
    plt.bar(x[i], all_r2[i, 4], alpha=a, color=colors[i], label=decoder[i])
plt.xlabel('x_acc')
plt.legend()

plt.subplot(2, 3, 4)
plt.bar(x, all_r2[:, 1], alpha=a, color=colors)
plt.xlabel('y_pos')

plt.subplot(2, 3, 5)
plt.bar(x, all_r2[:, 3], alpha=a, color=colors)
plt.xlabel('y_vel')

plt.subplot(2, 3, 6)
plt.bar(x, all_r2[:, 5], alpha=a, color=colors)
plt.xlabel('y_acc')

plt.savefig(result_path + '/all_r2.png', dpi=600)
plt.show()
np.save(os.path.join(result_path, 'all_r2.npy'), all_r2)


import torch
import torch.nn as nn
import torch.nn.functional as F
from einops import rearrange
import pdb

__all__ = [
    'Mlp',
    'Attention',
    'TransformerBlock',
    'LayerNorm',
]

class Mlp(nn.Module):
    def __init__(self, in_dim, hid_dim=None, out_dim=None, act=nn.GELU, drop=0.):
        super().__init__()
        out_dim = out_dim or in_dim
        hid_dim = hid_dim or in_dim
        self.fc1 = nn.Linear(in_dim, hid_dim)
        self.act = act()
        self.fc2 = nn.Linear(hid_dim, out_dim)
        self.drop = nn.Dropout(drop)

    def forward(self, x):
        x = self.fc1(x)
        x = self.act(x)
        x = self.drop(x)
        x = self.fc2(x)
        x = self.drop(x)

        return x

class PreNorm(nn.Module):
    def __init__(self, dim, fn):
        super().__init__()
        self.norm = nn.LayerNorm(dim)
        self.fn = fn
    def forward(self, x, **kwargs):
        return self.fn(self.norm(x), **kwargs)

class Attention(nn.Module):
    def __init__(self, dim, heads, dim_head, attn_drop=0., proj_drop=0.):
        super().__init__()

        inner_dim = dim_head * heads

        self.heads = heads
        self.scale = dim_head ** -0.5

        self.to_qkv = nn.Linear(dim, inner_dim*3, bias=False)

        self.to_out = nn.Linear(inner_dim, dim)

        self.proj_drop = nn.Dropout(proj_drop)

    def rearrange1(self, x, heads):
        # rearrange is not supported by pytorch2.0 torch.compile
        # 'b l (heads dim_head) -> b heads l dim_head'
        b, l, n = x.shape
        dim_head = int(n / heads)
        x = x.view(b, l, heads, dim_head).contiguous()
        x = x.permute(0, 2, 1, 3).contiguous()

        return x

    def rearrange2(self, x):
         # 'b heads l dim_head -> b l (dim_head heads)')
         b, heads, l, dim_head = x.shape
         x = x.permute(0, 2, 1, 3).contiguous()
         x = x.view(b, l, -1).contiguous()

         return x

    def forward(self, x):
        # x: B, L, C.   Batch, sequence length, dim
        # 'b l (heads dim_head) -> b heads l dim_head',
        q, k, v = self.to_qkv(x).chunk(3, dim=-1)

        #q, k, v = map(lambda t: rearrange(t, 'b l (heads dim_head) -> b heads l dim_head', heads=self.heads), [q, k, v])
        q, k, v = map(lambda t: self.rearrange1(t, heads=self.heads), [q, k, v])

        attn = torch.einsum('bhid,bhjd->bhij', q, k) * self.scale

        attn = F.softmax(attn, dim=-1)

        attned = torch.einsum('bhij,bhjd->bhid', attn, v)
        #attned = rearrange(attned, 'b heads l dim_head -> b l (dim_head heads)')
        attned = self.rearrange2(attned)

        attned = self.to_out(attned)

        return attned

class TransformerBlock(nn.Module):
    def __init__(self, dim, depth, heads, dim_head, mlp_dim, attn_drop=0., proj_drop=0.):
        super().__init__()

        self.layers = nn.ModuleList([])

        for i in range(depth):
            self.layers.append(nn.ModuleList([
                PreNorm(dim, Attention(dim, heads, dim_head, attn_drop, proj_drop)),
                PreNorm(dim, Mlp(dim, mlp_dim, dim, drop=proj_drop))
                ]))
    def forward(self, x):

        for attn, ffn in self.layers:
            x = attn(x) + x
            x = ffn(x) + x

        return x

class LayerNorm(nn.Module):
    r""" LayerNorm that supports two data formats: channels_last (default) or channels_first.
    The ordering of the dimensions in the inputs. channels_last corresponds to inputs with
    shape (batch_size, height, width, channels) while channels_first corresponds to inputs
    with shape (batch_size, channels, height, width).
    """

    def __init__(self, normalized_shape, eps=1e-5, data_format="channels_first"):
        super().__init__()

        self.weight = nn.Parameter(torch.ones(normalized_shape))
        self.bias = nn.Parameter(torch.zeros(normalized_shape))
        self.eps = eps
        self.data_format = data_format

        if self.data_format not in ["channels_last", "channels_first"]:
            raise NotImplementedError
        self.normalized_shape = (normalized_shape, )

    def forward(self, x):

        if self.data_format == "channels_last":
            return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)

        elif self.data_format == "channels_first":
            u = x.mean(1, keepdim=True)
            s = (x - u).pow(2).mean(1, keepdim=True)
            x = (x - u) / torch.sqrt(s + self.eps)
            x = self.weight[None, :, None, None, None] * x + self.bias[None, :, None, None, None]
            return x


import asyncio
import os

import discord
import youtube_dl
from discord.ext import commands
from pathlib import Path

from bot.music import Queue, Song

# 20 minutes, in seconds
DURATION_CEILING = 20 * 60

DURATION_CEILING_STRING = '20mins'

SONGS_PER_PAGE = 10

def set_str_len(s: str, length: int):
    '''Adds whitespace or trims string to enforce a specific size'''

    return s.ljust(length)[:length]

class Music(commands.Cog):

    def __init__(self, bot):
        self.bot = bot
        self.music_queues = {}
        self.voice_clients = {}

    @commands.command()
    async def play(self, ctx: commands.Context, url: str, *args: str):
        '''Adds a song to the queue either by YouTube URL or YouTube Search.'''

        music_queue = self.music_queues.get(ctx.guild, None)
        voice = self.voice_clients.get(ctx.guild)

        if music_queue is None:
            music_queue = Queue()
            self.music_queues[ctx.guild] = music_queue

        try:
            channel = ctx.message.author.voice.channel
        except:
            await ctx.send("You're not connected to a voice channel.")
            return

        if voice is not None and not self.client_in_same_channel(ctx.message.author, ctx.guild):
            await ctx.send("You're not in my voice channel.")
            return

        if not url.startswith('https://'):
            url = f'ytsearch1:{url} {" ".join(args)}'

        song = Song(url, ctx.author)
        valid_song, song_err = self.song_error_check(song)

        if not valid_song:
            await ctx.send(song_err)
            return

        if voice is None or not voice.is_connected():
            self.voice_clients[ctx.guild] = await channel.connect()

        music_queue.append(song)
        await ctx.send(f'Queued song: {song.title}')

        await self.play_all_songs(ctx.guild)

    @commands.command()
    @commands.has_permissions(ban_members=True)
    async def stop(self, ctx: commands.Context):
        '''Admin command that stops playback of music and clears out the music queue.'''

        voice = self.voice_clients.get(ctx.guild)
        queue = self.music_queues.get(ctx.guild)

        if self.client_in_same_channel(ctx.message.author, ctx.guild):
            voice.stop()
            queue.clear()
            self.voice_clients[ctx.guild] = None
            await ctx.send("Stopping playback")
            await voice.disconnect()
        else:
            await ctx.send("You're not in a voice channel with me.")

    @commands.command()
    async def skip(self, ctx: commands.Context):
        '''Puts in your vote to skip the currently played song.'''
        voice = self.voice_clients.get(ctx.guild)

        if not self.client_in_same_channel(ctx.message.author, ctx.guild):
            await ctx.send("You're not in a voice channel with me.")
        elif voice is None or not voice.is_playing():
            await ctx.send("I'm not playing a song right now.")
        else:
            voice.stop()

    @commands.command()
    @commands.has_permissions(ban_members=True)
    async def fskip(self, ctx: commands.Context):
        '''Admin command that forces skipping of the currently playing song.'''

        voice = self.voice_clients.get(ctx.guild)

        if not self.client_in_same_channel(ctx.message.author, ctx.guild):
            await ctx.send("You're not in a voice channel with me.")
        elif voice is None or not voice.is_playing():
            await ctx.send("I'm not playing a song right now.")
        else:
            voice.stop()

    @commands.command()
    async def songinfo(self, ctx: commands.Context, song_index: int = 0):
        '''Print out more information on the song currently playing.'''

        queue = self.music_queues.get(ctx.guild)

        if song_index not in range(len(queue)+1):
            await ctx.send("A song does not exist at that index in the queue.")
            return

        embed = queue.get_embed(song_index)
        await ctx.send(embed=embed)

    @commands.command()
    async def remove(self, ctx: commands.Context, song_id: int = None):
        '''Removes the last song you requested from the queue, or a specific song if queue position specified.'''

        if not self.client_in_same_channel(ctx.message.author, ctx.guild):
            await ctx.send("You're not in a voice channel with me.")
            return

        if song_id is None:
            queue = self.music_queues.get(ctx.guild)

            for index, song in reversed(list(enumerate(queue))):
                if ctx.author.id == song.requested_by_id:
                    queue.pop(index)
                    await ctx.send(f'Song "{song.title}" removed from queue.')
                    return
        else:
            queue = self.music_queues.get(ctx.guild)

            try:
                song = queue[song_id-1]
            except IndexError:
                await ctx.send('An invalid index was provided.')
                return

            if ctx.author.id == song.requested_by_id:
                queue.pop(song_id-1)
                await ctx.send(f'Song {song.title} removed from queue.')
            else:
                await ctx.send('You cannot remove a song requested by someone else.')

    @commands.command()
    @commands.has_permissions(ban_members=True)
    async def fremove(self, ctx: commands.Context, song_id: int = None):
        '''Admin command to forcibly remove a song from the queue by it's position.'''

        queue = self.music_queues.get(ctx.guild)

        if not self.client_in_same_channel(ctx.message.author, ctx.guild):
            await ctx.send('You\'re not in a voice channel with me.')
            return

        if song_id is None or 0:
            await ctx.send('You need to specify a song by it\'s queue index.')
            return

        try:
            song = queue[song_id-1]
        except IndexError:
            await ctx.send('A song does not exist at this queue index.')
            return

        queue.pop(song_id-1)
        await ctx.send(f'Removed {song.title} from the queue.')
        return

    @commands.command()
    async def queue(self, ctx: commands.Context, page: int = 1):
        '''Prints out a specified page of the music queue, defaults to first page.'''

        queue = self.music_queues.get(ctx.guild)

        if not self.client_in_same_channel(ctx.message.author, ctx.guild):
            await ctx.send('You\'re not in a voice channel with me.')
            return

        if not len(queue):
            await ctx.send('I don\'t have anything in my queue right now.')
            return

        if len(queue) < SONGS_PER_PAGE*(page-1):
            await ctx.send('I don\'t have that many pages in my queue.')
            return

        to_send = f'```\n    {set_str_len("Song", 66)}{set_str_len("Uploader", 36)}Requested By\n'

        for pos, song in enumerate(queue[:SONGS_PER_PAGE*page], start=SONGS_PER_PAGE*(page-1)):
            title = set_str_len(song.title, 65)
            uploader = set_str_len(song.uploader, 35)
            requested_by = song.requested_by_username
            to_send += f'{set_str_len(f"{pos+1})",4)}{title}|{uploader}|{requested_by}\n'

        await ctx.send(to_send + '```')

    async def play_all_songs(self, guild: discord.Guild):
        queue = self.music_queues.get(guild)

        # Play next song until queue is empty
        while len(queue) > 0:
            await self.wait_for_end_of_song(guild)

            song = queue.next_song()

            await self.play_song(guild, song)

        # Disconnect after song queue is empty
        await self.inactivity_disconnect(guild)

    async def play_song(self, guild: discord.Guild, song: Song):
        '''Downloads and starts playing a YouTube video's audio.'''

        audio_dir = os.path.join('.', 'audio')
        audio_path = os.path.join(audio_dir, f'{guild.id}.mp3')
        voice = self.voice_clients.get(guild)

        queue = self.music_queues.get(guild)
        ydl_opts = {
            'format': 'bestaudio/best',
            'noplaylist': True,
            'postprocessors': [{
                'key': 'FFmpegExtractAudio',
                'preferredcodec': 'mp3',
                'preferredquality': '192',
            }],
            'outtmpl': audio_path
        }

        Path(audio_dir).mkdir(parents=True, exist_ok=True)

        try:
            os.remove(audio_path)
        except OSError:
            pass

        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
            try:
                ydl.download([f'{song.url}'])
            except:
                await self.play_all_songs(guild)
                print('Error downloading song. Skipping.')
                return

        voice.play(discord.FFmpegPCMAudio(audio_path))
        queue.clear_skip_votes()

    async def wait_for_end_of_song(self, guild: discord.Guild):
        voice = self.voice_clients.get(guild)
        while voice.is_playing():
            await asyncio.sleep(1)

    async def inactivity_disconnect(self, guild: discord.Guild):
        '''If a song is not played for 5 minutes, automatically disconnects bot from server.'''

        voice = self.voice_clients.get(guild)
        queue = self.music_queues.get(guild)
        last_song = queue.current_song

        await asyncio.sleep(300)
        if queue.current_song == last_song:
            await voice.disconnect()

    def client_in_same_channel(self, author: discord.Member, guild: discord.Guild):
        '''Checks to see if a client is in the same channel as the bot.'''

        voice = self.voice_clients.get(guild)

        try:
            channel = author.voice.channel
        except AttributeError:
            return False

        return voice is not None and voice.is_connected() and channel == voice.channel

    @staticmethod
    def song_error_check(song: Song):
        ''' Checks song properties to ensure that the song is both valid and doesn't match any filtered properties'''

        if song.url is None:
            return False, 'Invalid URL provided or no video found.'

        if song.get('is_live', True):
            return False, 'Invalid video - either live stream or unsupported website.'

        if song.duration_raw > DURATION_CEILING:
            return False, f'Video is too long. Keep it under {DURATION_CEILING_STRING}.'

        return True, None

def setup(bot):
    bot.add_cog(Music(bot))


import numpy as np
import cv2
import glob
import matplotlib.pyplot as plt

# %matplotlib qt
# %matplotlib inline

# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*9,3), np.float32)
objp[:,:2] = np.mgrid[0:9,0:6].T.reshape(-1,2)

# Arrays to store object points and image points from all the images.
objpoints = [] # 3d points in real world space
imgpoints = [] # 2d points in image plane.

# Make a list of calibration images
images = glob.glob('../camera_cal/calibration*.jpg')

# Step through the list and search for chessboard corners
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    # Find the chessboard corners
    ret, corners = cv2.findChessboardCorners(gray, (9,6),None)

    # If found, add object points, image points
    if ret == True:
        objpoints.append(objp)
        imgpoints.append(corners)

        # Draw and display the corners
        # img = cv2.drawChessboardCorners(img, (9,6), corners, ret)
        # cv2.imshow('img',img)
        # cv2.waitKey(500)

cv2.destroyAllWindows()

import matplotlib.image as mpimg
def show_comparison(img_before, img_after, title_before='', title_after=''):
    f, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))
    f.tight_layout()
    ax1.imshow(img_before)
    ax1.set_title(title_before, fontsize=50)
    ax2.imshow(img_after)
    ax2.set_title(title_after, fontsize=50)
    plt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)
    return ax1, ax2

def cal_undistort(img):
    # Use cv2.calibrateCamera() and cv2.undistort()
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, (img.shape[1], img.shape[0]),None,None)
    undist = cv2.undistort(img, mtx, dist, None, mtx)
    # undist = np.copy(img)  # Delete this line
    return undist

test_img = mpimg.imread("../test_images/test6.jpg")
undist_img = cal_undistort(test_img)
show_comparison(test_img, undist_img, 'Original image', 'Undistorted image')