import sys
import curses
import argparse
from string import ascii_letters, punctuation
from random import shuffle
from collections import deque

SCREEN = None
ARGS = None

DIGRAPHS = {('a', ':'): 'ä',
            ('o', ':'): 'ö',
            ('u', ':'): 'ü',
            ('s', 's'): 'ß'}
USER_CHARS = ascii_letters+punctuation+' '

def line_from_center(d=0):
    return (curses.LINES//2)+d

class Deck:
    """
    A Deck of flash cards.
    """
    def __init__(self, title):
        self.title = title
        self.cards = []

    def __repr__(self):
        rep = ["\t{}".format(card) for card in self.cards]
        return "\n".join(["==> {}".format(self.title)]+rep)

class Card:
    """
    A flash card.
    """
    def __init__(self, sideA, sideB):
        self.sideA = sideA
        self.sideB = sideB

    def __repr__(self):
        return "{x.sideA} <==> {x.sideB}".format(x=self)

def parse_decks():
    with open(ARGS.flashyfile) as f:
        decks = []
        for line in f.readlines():
            line = line.split("#")[0].strip()
            if not line:
                continue
            if line[0] == "$":
                decks.append(Deck(line[1:]))
            else:
                sideA, sideB = (lang.strip() for lang in line.split("::"))
                decks[-1].cards.append(Card(sideA, sideB))
                if ARGS.all:
                    decks[-1].cards.append(Card(sideB, sideA))
    return decks

def display_question(question):
    left_bound = (curses.COLS-len(question)-1)//2
    SCREEN.addstr(line_from_center(-1), left_bound, question)

def display_answer(answer):
    left_bound = (curses.COLS-len(answer)-1)//2
    SCREEN.addstr(line_from_center(0), left_bound, answer)

def display_opts(opts):
    left_bound = (curses.COLS-len(opts)-1)//2
    SCREEN.addstr(curses.LINES-2, left_bound, opts)

def display_stats(remain, total):
    s = "({}/{})".format(remain, total)
    left_bound = curses.COLS-len(s)-1
    SCREEN.addstr(0, left_bound, s)

def display_title(title):
    s = "Deck: {}".format(title)
    left_bound = (curses.COLS-len(s)-1)//2
    SCREEN.addstr(0, left_bound, s)

def display_guess(s):
    s = "=>"+s
    left_bound = (curses.COLS-1)//2 - 5
    row = line_from_center(2)
    SCREEN.move(row, 0)
    SCREEN.clrtoeol()
    SCREEN.addstr(row, left_bound, s)

def display_correct(correct):
    s = "Correct!" if correct else "Not Correct"
    left_bound = (curses.COLS-len(s)-1)//2
    SCREEN.addstr(line_from_center(3), left_bound, s)

def select_deck(decks):
    SCREEN.clear()
    if len(decks) > 1:
        SCREEN.addstr(0, 0, "Please Select a Deck to Use")
        for i, deck in enumerate(decks):
            SCREEN.addstr(i+1, 0, "{:2d}: {}".format(i+1, deck.title))
        SCREEN.addstr(i+2, 0, " q: Quit")
        SCREEN.move(i+3, 0)
        curses.echo()
        curses.curs_set(2)
        while True:
            selection = SCREEN.getstr().strip().lower()
            if selection == b"q":
                sys.exit(0)
            try:
                selection = int(selection)
                deck = decks[selection-1]
                curses.noecho()
                curses.curs_set(0)
                return deck
            except Exception:
                continue
    else:
        return decks[0]

def get_guess(mimick=None):
    s = ""
    while True:
        display_guess(s)
        key = curses.keyname(SCREEN.getch()).decode()
        if key == '^?':  # BACKSPACE
            s = s[:-1]
        elif key == '^J' and not mimick:  # ENTER
            return s
        elif key == '^W':  # CTRL-W(quit deck)
            return False
        ch = ''
        if key == '^K':  # CTRL-K(Enter digraph)
            dig1 = SCREEN.getkey()
            dig2 = SCREEN.getkey()
            dig = (dig1, dig2)
            if dig in DIGRAPHS:
                ch = DIGRAPHS[dig]
        elif key in USER_CHARS:
            ch = key
        if mimick and not mimick.startswith(s+ch):
            continue
        else:
            s += ch
        if s == mimick:
            return s

def run_deck(deck):
    cards = deque(deck.cards)
    shuffle(cards)
    N = len(cards)
    while cards:
        card = cards.popleft()
        if ARGS.reverse:
            show1, show2 = card.sideA, card.sideB
        else:
            show1, show2 = card.sideB, card.sideA
        SCREEN.clear()
        display_stats(len(cards)+1, N)
        display_title(deck.title)
        display_question(show1)
        if ARGS.spelling:  # Spelling mode
            display_opts('ctrl-W <quit>')
            guess = get_guess()
            if guess is False:
                return
            display_answer(show2)
            if guess.strip() != show2:
                cards.append(card)
                display_correct(False)
                guess = get_guess(show2)
                if guess is False:
                    return
            else:
                display_correct(True)
                SCREEN.getkey()

        else:  # Flash card mode
            SCREEN.getkey()
            display_answer(show2)
            display_opts("r <replace>  d <discard>  q <quit>")

            while True:
                c = SCREEN.getkey().lower()
                if c == 'r':
                    cards.append(card)
                    break
                elif c == 'd':
                    break
                elif c == 'q':
                    return

def main(stdscr):
    global SCREEN
    SCREEN = stdscr

    SCREEN.immedok(True)
    curses.noecho()
    curses.curs_set(0)
    decks = parse_decks()

    while True:
        deck = select_deck(decks)
        run_deck(deck)

if __name__ == "__main__":
    PARSER = argparse.ArgumentParser()
    PARSER.add_argument("flashyfile", help="The card file to use")
    PARSER.add_argument("-r", "--reverse",
                        help="Reverses which side is shown",
                        action="store_true")
    PARSER.add_argument("-a", "--all",
                        help="Creates deck with cards both \
                              flipped and unflipped",
                        action="store_true")
    PARSER.add_argument("-s", "--spelling",
                        help="Enable spelling mode",
                        action="store_true")
    ARGS = PARSER.parse_args()

    curses.wrapper(main)


import pandas as pd

from german_protest_registrations.paths import data

def kiel():
    path = data / "interim/csv/Kiel"
    dfs = []
    for file in path.glob("*.csv"):
        if file.name == "2022_2020.csv":
            continue
        elif file.name == "2022_2021.csv":
            df = pd.read_csv(file, skiprows=1)
        else:
            df = pd.read_csv(file)
        df = df.rename(
            columns={
                "Datum": "event_date",
                "Thema": "topic",
                "Standort": "location",
                "Personenzahl": "participants_registered",
            },
        )
        dfs.append(df)
    df = pd.concat(dfs)
    df = df[["event_date", "topic", "location", "participants_registered"]]
    df["city"] = "Kiel"
    df["region"] = "Schleswig-Holstein"
    df["is_regional_capital"] = True
    return df

if __name__ == "__main__":
    df = kiel()
    print(df.sample(10))


#variabelen
#input()
#print()
#doel: voor- en achternaam invoeren, programma
#geeft volledige naam terug.
getVooraam = input('Vul je voornaam in:\n')
getAchternaam = input('Vul je achternaam in:\n')
getLeeftijd = input('Vul je leeftijd in:\n')

profiel = getVooraam +" " + getAchternaam + " - " + getLeeftijd + "\n"

print('Hallo,',getVooraam,getAchternaam,'!')
print(' Dit is je profiel:\n',profiel)


import numpy as np
from os.path import basename, join, exists
from os import makedirs
from point_extract import process_1_scan,get_lidar
from point_extract import Lidar_to_Max2, Max2_to_Lidar, normalize
from scipy import interpolate
from utils import distortion

''' cutout on object-level pointcloud'''
def cutout(root_path, sample_idx,severity):
    pointcloud = get_lidar(root_path, sample_idx)
    info = process_1_scan(root_path, sample_idx)
    N, _ = pointcloud.shape
    c = [(1,20), (2,20), (3,20), (4,20), (5,20)][severity-1]
    idx_add = np.zeros(pointcloud.shape[0], dtype=bool)
    pts_add = np.zeros((1, pointcloud.shape[1]))
    for i in range(info['num_objs']):
        idx_pts = info['pts_in_gt'][i]
        if sum(idx_pts) > c[0]*c[1]:
            pts_obj = pointcloud[idx_pts]
            # convert to max-2
            pts_obj_max2 = Lidar_to_Max2(pts_obj, info['gt_boxes_lidar'][i])
            points = pts_obj_max2
            ## cutout
            for _ in range(c[0]):
                i_pts = np.random.choice(points.shape[0],1)
                picked = points[i_pts, :3]
                dist = np.sum((points[:, :3] - picked)**2, axis=1, keepdims=True)
                idx = np.argpartition(dist, c[1], axis=0)[:c[1]]
                points = np.delete(points, idx.squeeze(), axis=0)
            pts_obj_max2_crp = points
            # convert to Lidar
            pts_obj_crp = Max2_to_Lidar(pts_obj_max2_crp, info['gt_boxes_lidar'][i])
            idx_add = idx_add | np.array(idx_pts)
            pts_add = np.vstack((pts_add, pts_obj_crp))
        else:
            idx_add = idx_add | np.array(idx_pts)
    pointcloud = np.delete(pointcloud, idx_add, axis=0)
    if pts_add.shape[0]>1: # if pointcloud is indeed processed
        pointcloud =np.vstack((pointcloud, pts_add[1:, :]))
    return pointcloud

''' locally decrease point density on object-level pointcloud'''
def density_dec(root_path, sample_idx,severity):
    pointcloud = get_lidar(root_path, sample_idx)
    info = process_1_scan(root_path, sample_idx)
    N, _ = pointcloud.shape
    c = [(1,30), (2,30), (3,30), (4,30), (5,30)][severity-1]
    idx_add = np.zeros(pointcloud.shape[0], dtype=bool)
    pts_add = np.zeros((1, pointcloud.shape[1]))
    for i in range(info['num_objs']):
        idx_pts = info['pts_in_gt'][i]
        if sum(idx_pts) > c[0]*int((3/4) * c[1]):
            pts_obj = pointcloud[idx_pts]
            # convert to max-2
            pts_obj_max2 = Lidar_to_Max2(pts_obj, info['gt_boxes_lidar'][i])
            points = pts_obj_max2
            ## density decreasing on object
            for _ in range(c[0]):
                i_pts = np.random.choice(points.shape[0],1)
                picked = points[i_pts, :3]
                dist = np.sum((points[:, :3] - picked)**2, axis=1, keepdims=True)
                N_near = min(c[1], points.shape[0]-1)
                idx = np.argpartition(dist, N_near, axis=0)[:N_near]
                idx_2 = np.random.choice(N_near,int((3/4) * c[1]),replace=False)
                idx = idx[idx_2]
                points = np.delete(points, idx.squeeze(), axis=0)
            pts_obj_max2_crp = points
            # convert to Lidar
            pts_obj_crp = Max2_to_Lidar(pts_obj_max2_crp, info['gt_boxes_lidar'][i])
            idx_add = idx_add | np.array(idx_pts)
            pts_add = np.vstack((pts_add, pts_obj_crp))
        else:
            idx_add = idx_add | np.array(idx_pts)
    pointcloud = np.delete(pointcloud, idx_add, axis=0)
    if pts_add.shape[0]>1: # if pointcloud is indeed processed
        pointcloud =np.vstack((pointcloud, pts_add[1:, :]))
    return pointcloud

''' locally increase point density on object-level pointcloud'''
def density_inc(root_path, sample_idx,severity):
    pointcloud = get_lidar(root_path, sample_idx)
    info = process_1_scan(root_path, sample_idx)
    N, _ = pointcloud.shape
    c = [(1,30), (2,30), (3,30), (4,30), (5,30)][severity-1]
    idx_add = np.zeros(pointcloud.shape[0], dtype=bool)
    pts_add = np.zeros((1, pointcloud.shape[1]))
    for i in range(info['num_objs']):
        idx_pts = info['pts_in_gt'][i]
        if sum(idx_pts) > c[1]:
            pts_obj = pointcloud[idx_pts]
            # convert to max-2
            pts_obj_max2 = Lidar_to_Max2(pts_obj, info['gt_boxes_lidar'][i])
            points = pts_obj_max2
            points_add = np.zeros((1, pointcloud.shape[1]))
            ## density increasing on object
            N_opr = min(c[0], (pts_obj_max2.shape[0]-1)//c[1])
            for _ in range(N_opr):
                i_pts = np.random.choice(points.shape[0],1)
                picked = points[i_pts, :3]
                dist = np.sum((points[:, :3] - picked)**2, axis=1, keepdims=True)
                idx = np.argpartition(dist, c[1], axis=0)[:c[1]]
                points_add = np.vstack((points_add, interp_3D(points[idx.squeeze()],2)))
            pts_obj_max2_crp = normalize(np.vstack((points, points_add[1:, :])))
            # convert to Lidar
            pts_obj_crp = Max2_to_Lidar(pts_obj_max2_crp, info['gt_boxes_lidar'][i])
            idx_add = idx_add | np.array(idx_pts)
            pts_add = np.vstack((pts_add, pts_obj_crp))

    if pts_add.shape[0]>1: # if pointcloud is indeed processed
        pointcloud = np.delete(pointcloud, idx_add, axis=0)
        pointcloud =np.vstack((pointcloud, pts_add[1:, :]))
    return pointcloud

''' interpolation by Least-Square '''
def interp_3D(points, inp_rate):
    '''
    Args:
        origin points: N x (3+C)
        inp_rate: float
    Return:
        new points
    '''
    N,_=points.shape
    z_idx = np.argmin( np.max(points[:,:3],axis=0) - np.min(points[:,:3],axis=0))
    if z_idx ==0:
        x_idx, y_idx = 1, 2
    elif z_idx ==1:
        x_idx, y_idx = 2, 0
    else:
        x_idx, y_idx = 0, 1

    X_=np.hstack((np.ones((N,1)), points[:,x_idx].reshape(-1,1), points[:,y_idx].reshape(-1,1)))
    Y_=points[:,z_idx].reshape(-1,1)

    # Least-Square closed-form solution
    W =np.linalg.inv(X_.T @ X_)@X_.T@Y_

    N_new = int(N * inp_rate)
    x_new = np.random.randn(N_new) * np.std(points[:,x_idx]) + np.mean(points[:,x_idx])
    y_new = np.random.randn(N_new) * np.std(points[:,y_idx]) + np.mean(points[:,y_idx])
    r_mean = np.mean(points[:,3])

    X_new = np.hstack((np.ones((N_new,1)), x_new.reshape(-1,1), y_new.reshape(-1,1)))
    z_new = X_new @ W.reshape(-1,1)

    if z_idx ==0:
        points_new = np.hstack((z_new.reshape(-1,1), x_new.reshape(-1,1), y_new.reshape(-1,1)))
    elif z_idx ==1:
        points_new = np.hstack((y_new.reshape(-1,1), z_new.reshape(-1,1), x_new.reshape(-1,1)))
    else:
        points_new = np.hstack((x_new.reshape(-1,1), y_new.reshape(-1,1), z_new.reshape(-1,1)))

    points_new = np.hstack((points_new, np.zeros(N_new).reshape(-1, 1)+r_mean))
    return points_new

MAP = {'cutout_obj': cutout,
       'density_dec_obj': density_dec,
       'density_inc_obj': density_inc,
       'original': None,
}

def opr_pc(root_path, sample_idx, corruption, severity, saving=False):
    pc = get_lidar(root_path, sample_idx)
    pc_crp = MAP[corruption](root_path, sample_idx, severity)
    pc_crp =pc_crp.reshape(-1,)
    pc_crp =pc_crp.astype(np.float32)
    if saving==True:
        dir_save = root_path + '/training/velodyne_' + corruption + '_' + str(severity)
        if not exists(dir_save):
            makedirs(dir_save)
        pc_crp.tofile(join(dir_save,basename(sample_idx+'.bin')))
    return pc, pc_crp


import subprocess

def get_m3u8(url, fname, resolution):

    def get_codes(url):
        nada = subprocess.check_output(['yt-dlp', '-F', url])

        ans = {}
        for line in nada.decode('utf-8').split('\n'):
            if line.find('x') != -1:
                code = line.split()[0]
                res = line.split()[2].split('x')[-1]
                ans[res] = code
        print(ans)
        return ans

    if os.path.exists(fname):
        return

    audio = 'bestaudio'
    # low_audio = 'audio-medium-audio'
    # audio = low_audio

    code = get_codes(url)[str(resolution)]
    cmd = [
        'yt-dlp',
        '-f', f'{code}[ext=mp4]+{audio}[ext=m4a]/{code}+{audio}',
        '--merge-output-format', 'mp4',
        '-o', fname,
        '-N 8',
        url,
    ]
    subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

fout = open('links-daily.txt', 'w')
for link in soup.select('a[class*=episode-link]'):
    video_id = link.get('data-video_id')
    youtube_url = f'https://youtube.com/watch?v={video_id}'
    title = link.select('span[class*=play-title]')[0].text.strip()
    print(title, youtube_url)
    print(title, youtube_url, file=fout)
    try:
        pass
        get_m3u8(youtube_url, f'daily/{title}.mp4', 360)
    except:
        print('FAILED')
fout.close()


import os
import pandas as pd
import numpy as np

from shutil import move, copy2
from PIL import Image

from utils import create_nested_folders
import data.models.yolov5.yolov5_git.train as yolo_train
import data.models.yolov5.yolov5_git.val as yolo_val

class YoloV5:

    def __init__(self):
        self.__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))

    def train(self, dataset, batch_size, weights, img_size, num_epochs, device=0):
        yml = f"{dataset.dataset_id.lower()}.yaml"
        yolo_train.run(data=yml, imgsz=img_size, weights=weights, device=device, batch_size=batch_size,
                       epochs=num_epochs)

    def val(self, dataset, batch_size, weights, img_size, device=0, task='val'):
        yml = f"{self.__location__}/yolov5_git/data/{dataset.dataset_id.lower()}.yaml"
        res = yolo_val.run(data=yml, batch_size=batch_size, imgsz=img_size, device=device, weights=weights, task=task)
        print(res)

    def prepare_dataset(self, dataset, is_data_augmentation=False, data_augmentation_path=None, task='val'):
        dataset_funcs = {
            "GTSRB": self._prepare_gtsrb,
            "GTSDB": self._prepare_gtsdb,
        }
        dataset_funcs.get(dataset.dataset_id)(dataset)
        if is_data_augmentation:
            self.copy_augmented_data(dataset, data_augmentation_path, task)

    def copy_augmented_data(self, dataset, data_augmentation_path, task):
        yolo_folder = f"{dataset.path}/yolo/{task}/images"
        for image in os.listdir(yolo_folder):
            os.remove(f"{yolo_folder}/{image}")

        for image in os.listdir(data_augmentation_path):
            copy2(f"{data_augmentation_path}/{image}", yolo_folder)

    def _prepare_gtsrb(self, dataset):
        # collect gtsrb file paths in txt file, so that yolo can read the dataset
        gtsrb_root = dataset.path
        gtsrb_train = gtsrb_root + "/Train/"
        gtsrb_test = gtsrb_root + "/Test/"

        create_nested_folders(f"{gtsrb_train}yolo/images/")
        for folder in os.listdir(gtsrb_train):
            if folder == "yolo":
                continue
            for image in os.listdir(f"{gtsrb_train}{folder}/"):
                copy2(f"{gtsrb_train}{folder}/{image}", f"{gtsrb_train}yolo/images/")

        create_nested_folders(f"{gtsrb_test}/yolo/images/")
        for image in os.listdir(gtsrb_test):
            if image == "yolo":
                continue
            copy2(f"{gtsrb_test}{image}", f"{gtsrb_test}yolo/images/")

        # convert gtsrb csv Labels to YoloFileFormat
        # YOLO format:
        # one *.txt file per image; The *.txt file specifications are:
        # - one row per object
        # - each row is [class x_center y_center width height] format
        # - Box coordinates must be in normalized xywh format (from 0 - 1). If your boxes are in pixels, divide x_center and width
        #   by image width, and y_center and height by image height
        # - Class numbers are zero-indexed (start from 0)

        create_nested_folders(f"{gtsrb_train}yolo/labels/")
        create_nested_folders(f"{gtsrb_test}yolo/labels/")

        # [train_df, test_df]
        dfs = [pd.read_csv(f"{gtsrb_root}/Train.csv"), pd.read_csv(f"{gtsrb_root}/Test.csv")]
        for subset_df in dfs:
            # Normalize Coordinates
            subset_df["Roi.X1"] /= subset_df["Width"]
            subset_df["Roi.X2"] /= subset_df["Width"]
            subset_df["Roi.Y1"] /= subset_df["Height"]
            subset_df["Roi.Y2"] /= subset_df["Height"]

            for index, row in subset_df.iterrows():
                try:
                    current_subset_id, _, current_image = row.loc["Path"].split("/")
                except ValueError:
                    current_subset_id, current_image = row.loc["Path"].split("/")

                # convert to YoloFormat
                converted = np.array([
                    row.loc["ClassId"],
                    (row.loc["Roi.X1"] + row.loc["Roi.X2"]) / 2.0,
                    (row.loc["Roi.Y1"] + row.loc["Roi.Y2"]) / 2.0,
                    row.loc["Roi.X2"] - row.loc["Roi.X1"] if row.loc["Roi.X2"] - row.loc["Roi.X1"] < 1.0 else 1.0,
                    row.loc["Roi.Y2"] - row.loc["Roi.Y1"] if row.loc["Roi.Y2"] - row.loc["Roi.Y1"] < 1.0 else 1.0
                ])

                # write to label file
                with open(f"{gtsrb_root}/{current_subset_id}/yolo/labels/{current_image[:-4]}.txt", "w+") as f:
                    f.write(f"{int(converted[0])} {' '.join(map(str, converted[1:]))}")

    def _prepare_gtsdb(self, dataset):
        gtsdb_root = dataset.path

        gt_df = pd.read_csv(f"{gtsdb_root}/{dataset.train_ground_truth}",
                            sep=";",
                            names=["Filename", "X1.ROI", "Y1.ROI", "X2.ROI", "Y2.ROI", "classID"]
                            )

        image_size = (1360, 800)  # (width, height)

        # Normalize Coordinates
        gt_df["X1.ROI"] /= image_size[0]
        gt_df["X2.ROI"] /= image_size[0]
        gt_df["Y1.ROI"] /= image_size[1]
        gt_df["Y2.ROI"] /= image_size[1]

        train = dataset.load_train_subset()
        val = dataset.load_validation_subset()
        test = dataset.load_test_subset()

        print("prepared subset: ", val)

        print(len(train))
        print(len(val))
        print(len(test))

        self._prepare_gtsdb_split(train, "train", gt_df, dataset)
        self._prepare_gtsdb_split(val, "val", gt_df, dataset)
        self._prepare_gtsdb_split(test, "test", gt_df, dataset)

    def _prepare_gtsdb_split(self, split_df, split_name, gt_df, dataset):
        gtsdb_root = dataset.path

        create_nested_folders(
            f"{gtsdb_root}/yolo/{split_name}/images",
            f"{gtsdb_root}/yolo/{split_name}/labels",
        )

        # convert gtsdb csv Labels to YoloFileFormat
        # YOLO format:
        # one *.txt file per image; The *.txt file specifications are:
        # - one row per object
        # - each row is [class x_center y_center width height] format
        # - Box coordinates must be in normalized xywh format (from 0 - 1). If your boxes are in pixels, divide x_center and width
        #   by image width, and y_center and height by image height
        # - Class numbers are zero-indexed (start from 0)

        for image in split_df[0]:
            with Image.open(image) as im:  # Yolo can't read images in ppm format
                image_file_name = image.split("/")[-1]
                im.save(
                    f"{gtsdb_root}/yolo/{split_name}/images/{image_file_name[:-4]}.png")  # Therefore instead of moving the image, the image is copied and converted simultaneously
            with open(f"{gtsdb_root}/yolo/{split_name}/labels/{image_file_name[:-4]}.txt", "w+") as f:
                image_df = gt_df.loc[gt_df["Filename"] == image_file_name]
                gt_converted = np.array([
                    [
                        row.loc['classID'],
                        (row.loc["X1.ROI"] + row.loc["X2.ROI"]) / 2.0,
                        (row.loc["Y1.ROI"] + row.loc["Y2.ROI"]) / 2.0,
                        row.loc["X2.ROI"] - row.loc["X1.ROI"],
                        row.loc["Y2.ROI"] - row.loc["Y1.ROI"]
                    ] for index, row in image_df.iterrows()])
                lines = [f"{int(entry[0])} {' '.join(map(str, entry[1:]))}" for entry in gt_converted]
                f.write('\n'.join(lines))
                f.close()


#Program asks the user for a number and the prints out a list
#of all the divisors of that number.

num = raw_input('Please Enter a number: ')
num = int(num)

x = range(1, num+1)
divList = []

for element in x:
	if num % element == 0:
		divList.append(element)

print (divList)


import numpy
import copy

class HomogeneousData():

    def __init__(self, data, batch_size=128, maxlen=None):
        self.data = data
        self.batch_size = batch_size
        self.maxlen = maxlen

        self.prepare()
        self.reset()

    def prepare(self):
        self.caps = self.data[0]
        self.feats = self.data[1]
        self.feats2 = self.data[2]

        # find the unique lengths
        self.lengths = [len(cc.split()) for cc in self.caps]
        self.len_unique = numpy.unique(self.lengths)
        # remove any overly long sentences
        if self.maxlen:
            self.len_unique = [ll for ll in self.len_unique if ll <= self.maxlen]

        # indices of unique lengths
        self.len_indices = dict()
        self.len_counts = dict()
        for ll in self.len_unique:
            self.len_indices[ll] = numpy.where(self.lengths == ll)[0]
            self.len_counts[ll] = len(self.len_indices[ll])

        # current counter
        self.len_curr_counts = copy.copy(self.len_counts)

    def reset(self):
        self.len_curr_counts = copy.copy(self.len_counts)
        self.len_unique = numpy.random.permutation(self.len_unique)
        self.len_indices_pos = dict()
        for ll in self.len_unique:
            self.len_indices_pos[ll] = 0
            self.len_indices[ll] = numpy.random.permutation(self.len_indices[ll])
        self.len_idx = -1

    def __next__(self):
        count = 0
        while True:
            self.len_idx = numpy.mod(self.len_idx+1, len(self.len_unique))
            if self.len_curr_counts[self.len_unique[self.len_idx]] > 0:
                break
            count += 1
            if count >= len(self.len_unique):
                break
        if count >= len(self.len_unique):
            self.reset()
            raise StopIteration()

        # get the batch size
        curr_batch_size = numpy.minimum(self.batch_size, self.len_curr_counts[self.len_unique[self.len_idx]])
        curr_pos = self.len_indices_pos[self.len_unique[self.len_idx]]
        # get the indices for the current batch
        curr_indices = self.len_indices[self.len_unique[self.len_idx]][curr_pos:curr_pos+curr_batch_size]
        self.len_indices_pos[self.len_unique[self.len_idx]] += curr_batch_size
        self.len_curr_counts[self.len_unique[self.len_idx]] -= curr_batch_size

        # 'feats' corresponds to the after and before sentences
        caps = [self.caps[ii] for ii in curr_indices]
        feats = [self.feats[ii] for ii in curr_indices]
        feats2 = [self.feats2[ii] for ii in curr_indices]

        return caps, feats, feats2

    def __iter__(self):
        return self

def prepare_data(seqs_x, seqs_y, seqs_z, worddict, maxlen=None, n_words=20000):
    """
    Put the data into format useable by the model
    """
    seqs_x, seqs_y, seqs_z = fill_seqs(seqs_x, seqs_y, seqs_z, worddict, n_words)

    lengths_x = [len(s) for s in seqs_x]
    lengths_y = [len(s) for s in seqs_y]
    lengths_z = [len(s) for s in seqs_z]

    if maxlen != None:
        new_seqs_x = []
        new_seqs_y = []
        new_seqs_z = []
        new_lengths_x = []
        new_lengths_y = []
        new_lengths_z = []
        for l_x, s_x, l_y, s_y, l_z, s_z in zip(lengths_x, seqs_x, lengths_y, seqs_y, lengths_z, seqs_z):
            if l_x < maxlen and l_y < maxlen and l_z < maxlen:
                new_seqs_x.append(s_x)
                new_lengths_x.append(l_x)
                new_seqs_y.append(s_y)
                new_lengths_y.append(l_y)
                new_seqs_z.append(s_z)
                new_lengths_z.append(l_z)
        lengths_x = new_lengths_x
        seqs_x = new_seqs_x
        lengths_y = new_lengths_y
        seqs_y = new_seqs_y
        lengths_z = new_lengths_z
        seqs_z = new_seqs_z

        if len(lengths_x) < 1 or len(lengths_y) < 1 or len(lengths_z) < 1:
            return None, None, None, None, None, None

    n_samples = len(seqs_x)
    maxlen_x = numpy.max(lengths_x) + 1
    maxlen_y = numpy.max(lengths_y) + 1
    maxlen_z = numpy.max(lengths_z) + 1

    x = numpy.zeros((maxlen_x, n_samples)).astype('int64')
    y = numpy.zeros((maxlen_y, n_samples)).astype('int64')
    z = numpy.zeros((maxlen_z, n_samples)).astype('int64')
    x_mask = numpy.zeros((maxlen_x, n_samples)).astype('float32')
    y_mask = numpy.zeros((maxlen_y, n_samples)).astype('float32')
    z_mask = numpy.zeros((maxlen_z, n_samples)).astype('float32')
    for idx, [s_x, s_y, s_z] in enumerate(zip(seqs_x,seqs_y,seqs_z)):
        x[:lengths_x[idx],idx] = s_x
        x_mask[:lengths_x[idx]+1,idx] = 1.
        y[:lengths_y[idx],idx] = s_y
        y_mask[:lengths_y[idx]+1,idx] = 1.
        z[:lengths_z[idx],idx] = s_z
        z_mask[:lengths_z[idx]+1,idx] = 1.

    return x, x_mask, y, y_mask, z, z_mask

def grouper(text):
    """
    Group text into triplets
    """
    source = text[1:][:-1]
    forward = text[2:]
    backward = text[:-2]
    X = (source, forward, backward)
    return X

def fill_seqs(seqs_x, seqs_y, seqs_z, worddict, n_words):

    seqsx = []
    seqsy = []
    seqsz = []
    for cc in seqs_x:
        seqsx.append([worddict[w] if worddict[w] < n_words else 1 for w in cc.split()])
    for cc in seqs_y:
        seqsy.append([worddict[w] if worddict[w] < n_words else 1 for w in cc.split()])
    for cc in seqs_z:
        seqsz.append([worddict[w] if worddict[w] < n_words else 1 for w in cc.split()])
    seqs_x = seqsx
    seqs_y = seqsy
    seqs_z = seqsz
    return seqs_x, seqs_y, seqs_z


import os
import sys
from functools import partial

import numpy as np
import pandas as pd
from PyQt5 import QtWidgets as widgets
from PyQt5.QtCore import Qt, QObjectCleanupHandler, pyqtSignal
from PyQt5 import QtGui as gui
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib import ticker

from suss.analysis import align
from suss.gui.utils import clear_axes, get_changed_labels
from suss.gui.tags import ClusterTag, UserTag

import suss.gui.config as config

class HoverButton(widgets.QPushButton):
    hover = pyqtSignal(bool)

    def __init__(self, text, parent=None):
        super().__init__(text, parent)
        self.setMouseTracking(True)

    def enterEvent(self, QEvent):
        self.hover.emit(True)

    def leaveEvent(self, QEvent):
        self.hover.emit(False)

def create_check_button(text):
    button = HoverButton(text)
    button.setCheckable(True)
    button.setDefault(False)
    button.setAutoDefault(False)

    def flip_text(selected):
        if selected:
            button.setText("X")
        else:
            button.setText(" ")

    button.clicked[bool].connect(flip_text)
    color = "white"
    button.setStyleSheet("""
        QPushButton:checked
        {{
            border: 4px solid #444444;
            border-style: inset;
        }}
        QPushButton {{
            background-color: {};

        }}
    """.format(color))
    button.setFixedSize(20, 20)

    return button

class ClusterSelector(widgets.QScrollArea):

    CARD_HEIGHT = 160 if sys.platform == "darwin" else 130

    def __init__(self, parent=None):
        super().__init__(parent)
        self.allow_scroll_to = True
        self._cached_cluster_info = {}
        self.show_auditory_responses = False

        # TOOD (kevin): make this configurable
        vocal_period_file = os.path.join(
                os.path.dirname(os.path.dirname(self.window().current_file)),
                "vocal_periods.npy")
        playback_periods_csv = os.path.join(
                os.path.dirname(os.path.dirname(self.window().current_file)),
                "playback_segments.csv")
        if os.path.exists(vocal_period_file):
            vocal_periods = np.load(vocal_period_file, allow_pickle=True)[()]
            self._stimuli = {
                "playback": [period["start_time"].item() for period in vocal_periods["playback"]],
                "live": [period["start_time"].item() for period in vocal_periods["live"]]
            }
        elif os.path.exists(playback_periods_csv):
            vocal_periods = pd.read_csv(playback_periods_csv)
            self._stimuli = {
                "playback": list(vocal_periods["start_time"]),
                "live": []
            }
        else:
            self._stimuli = None

        self.setup_data()
        self.init_ui()

        self.parent().UPDATED_CLUSTERS.connect(self.reset)
        self.parent().CLUSTER_SELECT.connect(self.update_checks)
        self.parent().CLUSTER_HIGHLIGHT.connect(self.on_cluster_highlight)
        self.parent().AUDITORY_RESPONSES.connect(self.on_auditory_responses)

    def stimuli(self, key):
        if not self.has_stimuli:
            return []
        return [period for period in self._stimuli[key]]

    @property
    def has_stimuli(self):
        return self._stimuli is not None

    def reset(self, new_dataset, old_dataset):
        old_scroll = self.verticalScrollBar().value()
        for label in get_changed_labels(new_dataset, old_dataset):
            if label in self._cached_cluster_info:
                del self._cached_cluster_info[label]
        self.setup_data()
        self.init_ui()
        for label, info in self._cached_cluster_info.items():
            info.update_color(self.colors[label])
        for label in self.dataset.labels:
            self.pixmaps[label].fill(gui.QColor(*[
                255 * c
                for c in self.colors[label]
            ]))

        self.verticalScrollBar().setValue(old_scroll)

    @property
    def dataset(self):
        return self.parent().dataset

    @property
    def colors(self):
        return self.parent().colors

    def toggle(self, label, selected):
        self.parent().toggle_selected(label, selected)

    def update_checks(self, selected):
        for label, button in self.buttons.items():
            if button.isChecked() != (label in selected):
                button.clicked.emit(label in selected)
                button.setChecked(label in selected)

    def on_auditory_responses(self, category, state):
        if not self.show_auditory_responses and not state:
            return
        elif self.show_auditory_responses == category and state:
            return

        if not state:
            self.show_auditory_responses = False
        else:
            self.show_auditory_responses = category

        for label in list(self._cached_cluster_info.keys()):
            del self._cached_cluster_info[label]
        self.setup_data()
        self.init_ui()

    def on_cluster_highlight(self, new_highlight, old_highlight, temporary):
        if old_highlight is not None and old_highlight in self.panels:
            self.panels[old_highlight].setFrameShape(widgets.QFrame.NoFrame)

        if new_highlight is None:
            return
        new_panel = self.panels[new_highlight]
        self.panels[new_highlight].setFrameShape(widgets.QFrame.Box)
        if self.allow_scroll_to and not temporary:
            self.verticalScrollBar().setValue(new_panel.y())

    def set_highlight(self, cluster_label, selected):
        # Hacky flag to prevent jumping the scroll bar
        # when highlighted through the cluster select menu
        self.allow_scroll_to = not selected
        self.parent().set_highlight(cluster_label if selected else None)

    def setup_data(self):
        self.buttons = {}
        self.panels = {}

        ordered_idx = reversed(np.argsort(self.dataset.labels))

        self.layout = widgets.QVBoxLayout(self)
        self.pixmaps = {}

        if not len(self.dataset):
            return

        wf_ylims = (np.min(self.dataset.waveforms), np.max(self.dataset.waveforms))

        progress = widgets.QProgressDialog(
                "Loading {} clusters".format(
                    len(self.dataset.nodes)
                ),
                None,
                0,
                len(self.dataset.nodes) + 1,
                self)
        progress.setMinimumDuration(2000)
        progress.open()

        for _progress, label_idx in enumerate(ordered_idx):
            cluster_label = self.dataset.labels[label_idx]
            cluster = self.dataset.nodes[label_idx]

            header = widgets.QHBoxLayout()
            header_label = widgets.QLabel(
                "<b>{}</b> (n={}) {} clusters".format(
                    cluster_label,
                    cluster.count,
                    "No cluster data" if not "nodes" in cluster._data.dtype.names else len(cluster.nodes)
                )
            )
            header_label.setFixedHeight(14)
            check_button = create_check_button(" ")
            check_button.clicked[bool].connect(partial(self.toggle, cluster_label))
            check_button.hover.connect(partial(self.set_highlight, cluster_label))
            self.buttons[cluster_label] = check_button
            header.addWidget(check_button)
            header.addWidget(header_label)
            header_label.setStyleSheet("""
                QLabel {
                    border:none;
                    padding:0;
                    margin:0;
                    font-size: 12px;
                }
            """)

            header.setAlignment(Qt.AlignTop)

            pixmap = gui.QPixmap(10, self.CARD_HEIGHT)
            pixmap.fill(gui.QColor(*[
                255 * c
                for c in self.colors[cluster_label]
            ]))
            self.pixmaps[cluster_label] = pixmap
            color_banner = widgets.QLabel()
            color_banner.setPixmap(pixmap)
            # color_banner.setScaledContents(True)

            container = widgets.QFrame(self) # ClusterClickFilter(self, label=cluster_label)
            # container.setStyleSheet("QWidget#highlighted {border: 2px dotted black;}")
            cluster_layout = widgets.QGridLayout()
            # cluster_layout.setColumnStretch(0, 1)
            cluster_layout.setColumnStretch(1, 6)

            cluster_layout.addWidget(color_banner, 0, 0, 2, 1)
            cluster_layout.addLayout(header, 0, 1)

            # Try to access a cached version of the cluster info plots
            plots_loaded = False
            if cluster_label in self._cached_cluster_info:
                plots_widget = self._cached_cluster_info[cluster_label]
                try:
                    cluster_layout.addWidget(plots_widget, 1, 1)
                except:
                    del self._cached_cluster_info[cluster_label]
                else:
                    plots_loaded = True
                plots_widget.set_ylim(wf_ylims)
            if not plots_loaded:
                plots_widget = ClusterInfo(
                        cluster,
                        self.colors[cluster_label],
                        ylim=wf_ylims,
                        parent=self)
                self._cached_cluster_info[cluster_label] = plots_widget
                cluster_layout.addWidget(plots_widget, 1, 1)

            container.setLayout(cluster_layout)

            container.setContextMenuPolicy(Qt.CustomContextMenu)
            container.customContextMenuRequested.connect(
                partial(self.on_click, container, cluster, cluster_label)
            )
            container.setFixedHeight(self.CARD_HEIGHT)

            self.layout.addWidget(container)
            self.panels[cluster_label] = container
            progress.setValue(_progress)

        progress.setValue(len(self.dataset.nodes) + 1)
        progress.hide()

    def create_tags_menu(self, cluster):
        menu = widgets.QMenu("Tags")

        for _tag in ClusterTag:
            _checkbox = widgets.QCheckBox(_tag.name, menu)
            _act = widgets.QWidgetAction(menu)
            _act.setDefaultWidget(_checkbox)
            # _act.setCheckable(True)
            _checkbox.setChecked(_tag in cluster.tags)
            _checkbox.toggled.connect(partial(self._update_tag, cluster, _tag))
            menu.addAction(_act)

        for _tag in UserTag:
            _checkbox = widgets.QCheckBox(_tag.name, menu)
            _act = widgets.QWidgetAction(menu)
            _act.setDefaultWidget(_checkbox)
            # _act.setCheckable(True)
            _checkbox.setChecked(_tag in cluster.tags)
            _checkbox.toggled.connect(partial(self._update_tag, cluster, _tag))
            menu.addAction(_act)

        return menu

    def _update_tag(self, cluster, _tag, state):
        if state and _tag not in cluster.tags:
            cluster.add_tag(_tag)
        elif not state and _tag in cluster.tags:
            cluster.remove_tag(_tag)

    def on_click(self, obj, cluster, label, pos):
        self.parent().show_right_click_menu(
                label,
                obj.mapToGlobal(pos),
                [self.create_tags_menu(cluster)]
        )

    def init_ui(self):
        self.frame = widgets.QGroupBox()
        self.frame.setLayout(self.layout)
        self.setWidget(self.frame)
        self.setWidgetResizable(True)
        self.setFixedWidth(360)

class ClusterInfo(widgets.QWidget):

    def __init__(self, cluster, color, size=(265, 75), ylim=None, parent=None):
        super().__init__(parent)
        self.cluster = cluster
        self.color = color
        self.size = size
        self.ylim = ylim

        self.setup_plots()
        self.setup_data()
        self.init_ui()

    def update_color(self, color):
        self.color = color
        self.wf_plot.set_color(self.color)
        self.canvas.draw_idle()

    def setup_plots(self):
        fig = Figure()
        fig.patch.set_alpha(0.0)
        self.canvas = FigureCanvas(fig)
        self.canvas.setFixedSize(*self.size)
        self.canvas.setStyleSheet("background-color:transparent;")
        self.ax_wf = fig.add_axes([0.0, 0, 0.33, 1])
        self.ax_wf.patch.set_alpha(0.0)
        self.ax_isi = fig.add_axes([0.33, 0, 0.33, 1])
        self.ax_isi.patch.set_alpha(0.0)
        self.ax_psth = fig.add_axes([0.66, 0, 0.34, 1])
        self.ax_psth.patch.set_alpha(0.0)
        self.fr_label = self.ax_wf.text(0, self.ax_wf.get_ylim()[0], "",
                horizontalalignment="left", verticalalignment="bottom", fontsize=6)
        self.snr_label = None
        clear_axes(self.ax_isi, self.ax_psth)

    def set_ylim(self, ylim):
        self.ylim = ylim
        self.ax_wf.set_ylim(*self.ylim)
        self.fr_label.set_y(self.ylim[0])
        if self.snr_label:
            self.snr_label.set_y(self.ylim[0])

    def setup_data(self):
        cluster = self.cluster.flatten()

        mean = np.mean(self.cluster.waveforms, axis=0)
        std = np.std(cluster.waveforms, axis=0)
        self.ax_wf.fill_between(
                np.arange(len(mean)),
                mean - std,
                mean + std,
                color="Black",
                alpha=0.25)
        self.wf_plot = self.ax_wf.plot(
                mean,
                color=self.color,
                alpha=1.0,
                linewidth=2)[0]

        fr = len(cluster) / (np.max(cluster.times) - np.min(cluster.times))

        snr = (np.max(mean) - np.min(mean)) / np.mean(std)
        # snr = np.abs(mean)[len(mean) // 2] / std[len(mean) // 2]
        if not self.snr_label:
            self.snr_label = self.ax_wf.text(self.ax_wf.get_xlim()[1], self.ax_wf.get_ylim()[0], "",
                    horizontalalignment="right", verticalalignment="bottom", fontsize=6)
        self.snr_label.set_text("SNR: {:.1f}".format(snr))
        self.ax_wf.yaxis.set_major_locator(ticker.MultipleLocator(base=100))
        self.ax_wf.xaxis.set_major_locator(ticker.MultipleLocator(base=10))
        self.ax_wf.grid(True)

        if self.ylim is None:
            self.set_ylim(self.ax_wf.get_ylim())
        else:
            self.set_ylim(self.ylim)

        self.fr_label.set_text("{:.1f} uV\n{:.1f} Hz".format(mean[len(mean) // 2], fr))

        isi = np.diff(cluster.times)
        isi_violations = np.sum(isi < 0.001) / len(isi)
        n_bins = config.ISI_BINS
        t_max = config.ISI_MAX
        hist, bin_edges = np.histogram(isi, bins=n_bins, density=True, range=(0, t_max))
        self.ax_isi.bar(
                (bin_edges[:-1] + bin_edges[1:]) / 2,
                hist,
                width=t_max / n_bins,
                color="Black")
        self.ax_isi.text(
                self.ax_isi.get_xlim()[1] * 0.9,
                self.ax_isi.get_ylim()[1] * 0.9,
                "{:.1f}% < 1ms".format(100.0 * isi_violations),
                fontsize=6,
                horizontalalignment="right",
                verticalalignment="top")
        self.ax_isi.vlines(
                0.001,
                *self.ax_isi.get_ylim(),
                color="Red",
                linestyle="--",
                linewidth=0.2)
        self.ax_isi.set_xlim(0, t_max)

        if self.parent().show_auditory_responses and self.parent().has_stimuli:
            stimuli_times = [
                start_time for start_time in self.parent().stimuli(
                    self.parent().show_auditory_responses
                )
                if cluster.times[0] <= start_time < cluster.times[-1]
            ]
            psth, _ = align(cluster.flatten(), stimuli_times, -1, 1)
            if len(psth):
                hist, bin_edges = np.histogram(
                        np.concatenate(psth),
                        bins=20,
                        density=False,
                        range=(0, 1))
                self.ax_psth.bar(
                        (bin_edges[:-1] + bin_edges[1:]) / 2,
                        hist / len(psth),
                        width=1 / 20.0,
                        color="Black")
                self.ax_psth.vlines(
                        [0.5],
                        *self.ax_psth.get_ylim(),
                        color="Red",
                        linestyle="--",
                        linewidth=0.5,
                )

        self.canvas.draw_idle()

    def init_ui(self):
        layout = widgets.QVBoxLayout()
        layout.addWidget(self.canvas)
        self.setLayout(layout)


import argparse

def SolveEqt(eqt:str, verbose: bool=False) -> float:
	""" The main controller, it takes the eqation string
	    and returns the outcome.

	Args:
		eqt(str): The equation string. It is a string
			  containing an equation (ex:
			  1 + 2 / (2 * 4) )
		verbose(bool): Whether or not an output should be
				generated.
	Returns:
		The outcome of the passed equation
	"""

	eqt = equationify(eqt)  #: Get back a list of each valid element for the equation
	outcome = bedmasify(eqt, verbose)  #: Get the outcome of the equation
	return outcome  #: Return the outcome.

def bedmasify(eqt: list, verbose:bool, nested_level: int=0) -> list:
	""" Evaluates the equation based on bedmas/pedmas rules.

	Args:
		eqt(list): A list containing all of the operations and numbers of
			   the equation. (ex ['1', '+', '1', '*', '2'])
		vebose(bool): Whether or not an output should be generated.
	Returns:
		The outcome of the passed equation list.
	"""

	#: Evaluate all equations within curly braces as if they are their
	#: own seperate equations.
	while '{' in eqt:
		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print_eqt(eqt)

		#: Get the indices of the first opening and closing curl braces.
		open_cur = eqt.index('{')
		close_cur = eqt.index('}')
		if verbose:
			print()
			for i in range(nested_level):
				print("\t", end='')
			print('{')

		#: If nested parenthesis exist, find the outermost closing curly brace..
		i = 0
		while '(' in eqt[open_par + 1: close_par] and ')' not in eqt[open_par + 1: close_par]:
			i += 1
			close_par = eqt.index(')', i)

		#: Black magic of recursion.
		#: Replace the chunk of the list containing the bracketed section
		#: With the outcome of the chunk within brackets by recursively
		#: Evaluating the inside of the brackets.
		#: Example:
		#:	['1', '+', '{', '3', '*', '2', '}']
		#: 	the inside of the brackets (3 * 2) are evaluated recursively
		#:	 so the list becomes:
		#:		['3', '*', '2']
		#:	which is evaluated to [6] by upcoming devices, and then the
		#:	original list becomes:
		#:	['1', '+', '6']
		#: 	which is finally resolved to [7]
		eqt[open_cur: close_cur + 1] = [bedmasify(eqt[open_cur + 1: close_cur], verbose, nested_level + 1)]

		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print('}\n')

	#: Evalulate all equations within square braces as if they are their own
	#: Seperate equations.
	while '[' in eqt:
		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print_eqt(eqt)

		#: Get the indices of the first appearing set of opening and
		#: Square Braces.
		open_sq = eqt.index('[')
		close_sq = eqt.index(']')

		if verbose:
			print()
			for i in range(nested_level):
				print("\t", end='')
			print('[')

		#: If nested square brackets exist, find the outermost closing square bracket.
		i = 0
		while '[' in eqt[open_sq + 1: close_sq] and ']' not in eqt[open_sq + 1: close_sq]:
			i += 1
			close_sq = eqt.index(']', i)

		#: Black magic of recursion. PLEASE NOTE, THIS USES THE SAME
		#: FUNCTIONALTY AS THE CURLY BRACES SECTION
		#: Replace the chunk of the list containing the bracketed section
		#: With the outcome of the chunk within brackets by recursively
		#: Evaluating the inside of the brackets.
		#: Example:
		#:	['1', '+', '[', '3', '*', '2', ']']
		#: 	the inside of the brackets (3 * 2) are evaluated recursively
		#:	 so the list becomes:
		#:		['3', '*', '2']
		#:	which is evaluated to [6] by upcoming devices, and then the
		#:	original list becomes:
		#:	['1', '+', '6']
		#: 	which is finally resolved to [7]
		eqt[open_sq: close_sq + 1] = [bedmasify(eqt[open_sq + 1: close_sq], verbose, nested_level + 1)]
		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print(']\n')

	#: Evaluate all equations within paranthesis as if they are their
	#: own seperate equations.
	while '(' in eqt:
		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print_eqt(eqt)

		#: Find the first appearance of an opening and closing parenthesis.
		open_par = eqt.index('(')
		close_par = eqt.index(')')

		if verbose:
			print()
			for i in range(nested_level):
				print("\t", end='')
			print('(')

		#: If nested parenthesis exist, find the outermost closing parenthesis.
		i = 0
		while '(' in eqt[open_par + 1: close_par] and ')' not in eqt[open_par + 1: close_par]:
			i += 1
			close_par = eqt.index(')', i)

		#: Black magic of recursion. PLEASE NOTE, THIS USES THE SAME
		#: FUNCTIONALTY AS THE CURLY BRACES SECTION
		#: Replace the chunk of the list containing the bracketed section
		#: With the outcome of the chunk within brackets by recursively
		#: Evaluating the inside of the brackets.
		#: Example:
		#:	['1', '+', '[', '3', '*', '2', ']']
		#: 	the inside of the brackets (3 * 2) are evaluated recursively
		#:	 so the list becomes:
		#:		['3', '*', '2']
		#:	which is evaluated to [6] by upcoming devices, and then the
		#:	original list becomes:
		#:	['1', '+', '6']
		#: 	which is finally resolved to [7]
		eqt[open_par: close_par + 1] = [bedmasify(eqt[open_par + 1: close_par], verbose, nested_level + 1)]
		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print(")\n")

	#: Evaluate all powers as this comes after brackets/parenthesis in bedmas/pedmas.
	while '^' in eqt:
		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print_eqt(eqt)

		#: Find the index of the first appearance of the power symbol.
		hat = eqt.index('^')

		base_pos = hat - 1  #: Get the index for the base of the found symbol.
		exp_pos = hat + 1  #: Get the index for the exponent of the found symbol.
		base = float(eqt[base_pos])  #: Gets the value of the base.
		exponent = float(eqt[exp_pos])  #: Gets the value of the exponent.
		eval = float(base) ** float(exponent)  #: Evaluates the exponential expression.

		#: Replace the 'X', '^', 'Y' portion of the list with the
		#: outcome of the exponential expression.
		eqt[base_pos: exp_pos + 1] = [eval]

	#: Evaluate all multiplication and division expressions from left to right
	#: as this comes after exponentials in bedmas/pedmas.
	while '*' in eqt or '/' in eqt:
		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print_eqt(eqt)
		#: Try to find an index for the multiplication symbol. If it isnt found
		#: Set its position to 1 + the length of the list so that it will be ignored.
		#: PLEASE NOTE:
		#: 	this block of code will never be reached unless either the division
		#: 	or multiplication symbols exist, so setting one of the symbols to
		#:	1 + the length of the list is NOT an issue
		try:
			mul = eqt.index('*')
		except ValueError:
			mul = len(eqt) + 1

		#: Try to find an index  for the division symbol. If it isnt found
		#: set its position to 1 + the length of the list so that it will be ignored.
		#: PLEASE NOTE:
		#: 	this block of code will never be reached unless either the division
		#: 	or multiplication symbols exist, so setting one of the symbols to
		#:	1 + the length of the list is NOT an issue
		try:
			div = eqt.index('/')
		except ValueError:
			div = len(eqt) + 1

		#: Multiply the two values if a multiplication symbol is found before a
		#: Division symbol, otherwise divide.
		multiply = False  #: Default
		if mul < div:  #: If the multiply index is lower than the division index,
			multiply = True  #: Set multiply to true.

		#: Find the index of the first type of appearing symbol.
		sym_position = min([mul, div])

		first_pos = sym_position - 1  #: Get the operator's index
		second_pos = sym_position + 1  #: Get the operand's index

		first = float(eqt[first_pos])  #: Get the value for the operator
		second = float(eqt[second_pos])  #: Get the value for the operand

		#: If multply is true, then set eval equal to the operator times the operand.
		#: Otherwise, set eval to the operator divided by the operand.
		if multiply:
			eval = first * second
		else:
			eval = first / second

		#: Replace the 'X', '*', 'Y' or 'X', '/', 'Y'  portion of the list with the
		#: outcome of the multiplication/division expression.
		eqt[first_pos:second_pos + 1] = [eval]

	#: Evaluate all addition and subtractions expressions from left to right
	#: as this comes after division and multiplication in bedmas/pedmas.
	while '+' in eqt or '-' in eqt:
		if verbose:
			for i in range(nested_level):
				print("\t", end='')
			print_eqt(eqt)

		#: Try to find an index for the addition symbol. If it isnt found
		#: Set its position to 1 + the length of the list so that it will be ignored.
		#: PLEASE NOTE:
		#: 	this block of code will never be reached unless either the subtraction
		#: 	or addtion symbols exist, so setting one of the symbols to
		#:	1 + the length of the list is NOT an issue
		try:
			add = eqt.index('+')
		except ValueError:
			add = len(eqt) + 1

		#: Try to find an index for the subtraction symbol. If it isnt found
		#: Set its position to 1 + the length of the list so that it will be ignored.
		#: PLEASE NOTE:
		#: 	this block of code will never be reached unless either the subtraction
		#: 	or addtion symbols exist, so setting one of the symbols to
		#:	1 + the length of the list is NOT an issue
		try:
			sub = eqt.index('-')
		except ValueError:
			sub = len(eqt) + 1

		#: add the two values if an addition symbol is found before a
		#: subtraction symbol, otherwise subtract.
		add = False
		if add < sub:
			add = True

		#: Find the index of the first type of appearing symbol.
		sym_position = min([add, sub])
		first_pos = sym_position - 1  #: The index of the operatior.
		second_pos = sym_position + 1  #: The index of the operand.

		first = float(eqt[first_pos])  #: Get the value of the operator
		second = float(eqt[second_pos])  #: Get the value of the operand.

		#: If addition is true, then set eval equal to the operator plus the operand.
		#: Otherwise, set eval to the operator subtract by the operand.
		if add:
			eval = first + second
		else:
			eval = first - second
		#: Replace the 'X', '+', 'Y' or 'X', '-', 'Y'  portion of the list with the
		#: outcome of the addition/subtraction expression.
		eqt[first_pos:second_pos + 1] = [eval]

	if verbose:
		for i in range(nested_level):
			print('\t', end='')
		print(eqt[0])
	return eqt[0]  #: Return the outcome of the equation.

def equationify(eqt: str):
	""" Takes in a string (preferably without garbage characters, though it
	    does handle those) and converts it into a list of operators, operands and
	    operations.

	    PLEASE NOTE:
			All comments marked with (GR) are used to remove garbage from the
			equation string.

	Args:
		eqt(str): The equation string to convert.
	Returns:
		A list with the operators operands, and operations
		of the passed strings.
	"""

	proper = ''  #: Initialize the "proper" string.
	symbol = True  #: Used to determine whether the last encountered item was a symbol (GR)
	eqt = "".join(eqt.split())  #: Removes all whitespace from the string (GR)
	brackets = ['(', ')', '[', ']', '{', '}']  #: A list of the types of brackes that may be used.
	operations = ['+', '-', '*', 'x', 'X', '/', '^']  #: A list of valid operators.

	#: Append each bracket type to the operators list.
	for type in brackets:
		operations.append(type)

	#: Sanatize the string so that it only contains valid operands and operators.
	#: This will remove any doubled up operators (excluding a symbol followed by a -
	#: for negative numbers, and a symbol following a brackets or a bracket following
	#: a symbol.
	#: Example sanitized string:
	#:		"1asjdfie+dlfdk2*kkkkkkkkkkkk3"
	#:		becomes: "1+2*3"
	#: 		---- OR ----
	#:		"1 ++* 2 /@R #3"
	#:		becomes: "1+2/3"
	#:
	for index, character in enumerate(eqt):

		if character.isdigit() or character == '.':  #: If this character is a digit or a decimal point for a number.
			if symbol:  #: then, if the previous character was a symbol
				symbol = False #: then set symbol to false.
			proper += character  #: And finally append the character to proper.

		elif character in operations:  #: Otherwise, if the character is an operation (GR)
			if not symbol:  #: If the previous character wasn't a symbol

				#: Then if the character is not a closing bracket, set
				#: symbol to true, and...
				if character != ')' and character != ']' and character != '}':
					symbol = True

				#: If the character is an x or X, append a multiplication symbol.
				if 'x' == character.lower():
					proper += "*"

				#: Otherwise, append the operation's character to the proper string.
				else:
					proper += character

			#: If the last character WAS a symbol
			#: Then check the special cases, and append
			#: characters if this is a special case.

			elif character == '-':  #: Special case: Number is negative
				proper += ':' #: ':' is being used to signify a negative value.

			elif character in brackets:  #: Special case: This is a bracket
				proper += character  #: Append the characer.

	eqt = []  #: Initialize a list to hold the equation.
	builder = ""  #: Initialize a string to build numbers with.

	#: For each chatacter in the string that has been sanitized,
	#: Add each character to the builder string until an operator
	#: is reached, then append the builder string (which will be a number)
	#: then append the symbol.
	for character in proper:
		if  character in operations:  #: If the character is in operations,
			if builder != "":  #: If the builder string is not empty
				eqt.append(builder)  #: Append the string
			eqt.append(character)  #: Then append the operator.
			builder = ""  #: And finally reset the builder string for a new number.

		#: If the character is a colon, then this is leftovers from sanitation, and
		#: the colon means that this number is negative.
		elif character == ':':
			builder += '-'

		#: After all special cases are accounted for, append the character to the builder
		#: string as the character is guarenteed to be a number.
		else:
			builder += character

	#: Catch the last number.
	if builder != "":  #: If the builder string is not empty
		eqt.append(builder)  #: Append that string to the equation list.

	return eqt #: Return the equation list.

def print_eqt(eqt: list):
	""" Used to print out the equation lists without
	    the square brackets, commas, or quotes that come
	    with printing a list.
	    For example, printing the list ['5', '5'] you would get:
		"['5', '5']"
	    When using this function, you would get:
	    "5 5"

	Args:
		eqt(list): The equation to be printed

	"""

	#: Print each item of the list seperately followed by a space.
	for item in eqt:
		print(item, end=' ')

	print()  #: Print a newline after for readablity.

if __name__ == "__main__":  #: Allow this code to be used outside of just the command line.

	#: Create an arugment parser to be used when this is called from the command line.
	parser = argparse.ArgumentParser(description="Command line equation solver")

	#: Create the equation argument.
	parser.add_argument("Equation", type=str, help="The equation that should be solved. Type = str")

	#: Create the verbose argument.
	parser.add_argument('-v', "--verbose", action="store_true",
			    help="Output each step of the equation solver.")

	#: Parse the arguments.
	args = parser.parse_args()

	#: Print the result of the passed equation. If the verbose argument was given,
	#: output each step of the computing process.
	if args.verbose:
		SolveEqt(args.Equation, args.verbose)
	else:
		print(SolveEqt(args.Equation))


from django import forms
from .models import Calculator
from prices.models import SolarModulePreise, WallBoxPreise
from django.core.exceptions import ValidationError
import decimal

def validate_two_decimal_places(value):
    decimal_value = decimal.Decimal(value)
    if decimal_value.as_tuple().exponent < -2:  # type: ignore
        raise ValidationError(
            "Achten Sie darauf, dass dieser Wert nicht mehr als zwei Dezimalstellen hat."
        )

def validate_floats(value):
    if not isinstance(value, float) or value < 0:
        raise ValidationError(
            (
                "Ungültige Eingabe: %(value)s. Eine gültige Gleitkommazahl größer oder gleich Null ist erforderlich."
            ),
            params={"value": value},
        )

def validate_integers(value):
    if not isinstance(value, int) or value < 0:
        raise ValidationError(
            (
                "Ungültige Eingabe: %(value)s. Eine gültige ganze Zahl größer oder gleich Null ist erforderlich."
            ),
            params={"value": value},
        )

def validate_integers_ticket(value):
    if not isinstance(value, int):
        raise ValidationError(
            ("Ungültige Eingabe: %(value)s. Die Menge muss ganzzahlig sein."),
            params={"value": value},
        )

def validate_solar_module_anzahl(value):
    if value < 6 and value != 0:
        raise ValidationError(
            (
                "Ungültige Eingabe: %(value)s. Die Anzahl der Solarmodule sollte 6 oder mehr betragen."
            ),
            params={"value": value},
        )

def validate_solar_module_ticket_anzahl(value):
    if value > 4:
        raise ValidationError(
            (
                "Ungültige Eingabe: %(value)s. Die Anzahl der Solarmodule sollte 4 oder weniger betragen."
            ),
            params={"value": value},
        )

def validate_optimizer_ticket_anzahl(value):
    if value > 4:
        raise ValidationError(
            (
                "Ungültige Eingabe: %(value)s. Die Anzahl der Optimierer sollte 4 oder weniger betragen."
            ),
            params={"value": value},
        )

def validate_range(value):
    if not isinstance(value, int):
        if value < 0 or value > 6:
            raise ValidationError(
                ("Ungültige Eingabe: %(value)s. Der gültige Bereich ist 0-6."),
                params={"value": value},
            )

def validate_empty(value):
    if value is None or value == "":
        raise ValidationError(
            ("Ungültige Eingabe: %(value)s. Etwas hinzufügen"),
            params={"value": value},
        )

class CalculatorForm(forms.ModelForm):
    solar_module = forms.ChoiceField(
        label="Solar Module",
        widget=forms.Select(attrs={"class": "form-select", "id": "solar_module"}),
    )

    modulanzahl = forms.IntegerField(
        label="Module Anzahl",
        initial=0,
        validators=[validate_solar_module_anzahl],
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "id": "id_modulanzahl",
            }
        ),
    )
    wallboxtyp = forms.ChoiceField(
        required=False,
        widget=forms.Select(
            attrs={
                "class": "form-select",
                "id": "wallboxtyp",
            }
        ),
    )
    wallbox_anzahl = forms.IntegerField(
        initial=0,
        label="Anzahl",
        required=False,
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "id": "id_wallbox_anzahl",
            }
        ),
    )
    optimizer = forms.BooleanField(
        label="Optimizer",
        required=False,
        widget=forms.CheckboxInput(
            attrs={"class": "form-check-input form-check-input mb-3", "id": "optimizer"}
        ),
    )
    notstrom = forms.BooleanField(
        label="Notstrom",
        required=False,
        widget=forms.CheckboxInput(
            attrs={"class": "form-check-input form-check-input mb-3", "id": "notstrom"}
        ),
    )
    elwa = forms.BooleanField(
        label="AC-ELWA 2",
        required=False,
        widget=forms.CheckboxInput(
            attrs={
                "class": "form-check-input",
                "id": "elwa",
                "style": "max-width: 70px",
            }
        ),
    )
    thor = forms.BooleanField(
        label="AC-THOR",
        required=False,
        widget=forms.CheckboxInput(attrs={"class": "form-check-input", "id": "thor"}),
    )
    heizstab = forms.BooleanField(
        label="Heizstab inklusive",
        required=False,
        widget=forms.CheckboxInput(
            attrs={
                "class": "form-check-input",
                "id": "heizstab-checkbox",
                "style": "max-width: 300px",
            }
        ),
    )
    anzOptimizer = forms.IntegerField(
        label="Optimizer",
        required=True,
        validators=[validate_integers],
        widget=forms.NumberInput(
            attrs={"class": "form-control form-control mb-3", "id": "id_anzOptimizer"}
        ),
    )
    anz_speicher = forms.IntegerField(
        label="Anzahl Speichermodule (kann sein 0)",
        required=False,
        initial=0,
        validators=[validate_range],
        widget=forms.NumberInput(
            attrs={
                "class": "form-control form-control mb-3",
                "id": "id_anz_speicher",
            }
        ),
    )
    speicher = forms.BooleanField(
        label="Speichermodule",
        required=False,
        widget=forms.CheckboxInput(
            attrs={
                "class": "form-check-input form-check-input mb-3",
                "id": "speicher",
            }
        ),
    )
    angebotsumme = forms.FloatField(
        label="Angebotsumme: ",
        required=False,
        widget=forms.NumberInput(
            attrs={"class": "badge badge-info-lighten", "id": "id_angebotsumme"}
        ),
    )

    def __init__(self, *args, user, **kwargs):
        super(CalculatorForm, self).__init__(*args, **kwargs)

        self.fields["solar_module"].choices = [
            (module.name, module.name)
            for module in SolarModulePreise.objects.filter(in_stock=True)
        ]
        self.fields["wallboxtyp"].choices = [
            (module.name, module.name)
            for module in WallBoxPreise.objects.filter(in_stock=True)
        ]
        self.fields["wallbox_anzahl"].widget.attrs.update({"id": "wallbox_anzahl"})
        self.fields["modulanzahl"].widget.attrs.update({"id": "modulanzahl"})
        self.fields["anzOptimizer"].widget.attrs.update({"id": "anzOptimizer"})
        self.fields["anz_speicher"].widget.attrs.update({"id": "anz_speicher"})
        self.fields["angebotsumme"].widget.attrs.update({"id": "angebotsumme"})

        for field in self.fields:
            if self.initial.get(field):
                self.fields[field].widget.attrs.update(
                    {"placeholder": self.initial[field]}
                )

    def save(self, commit=True):
        calculator_form = super(CalculatorForm, self).save(commit=False)

        if commit:
            calculator_form.save()

        return calculator_form

    class Meta:
        model = Calculator
        fields = [
            "solar_module",
            "modulanzahl",
            "notstrom",
            "elwa",
            "thor",
            "heizstab",
            "optimizer",
            "anzOptimizer",
            "wallboxtyp",
            "wallbox_anzahl",
            "speicher",
            "anz_speicher",
            "angebotsumme",
        ]


import datetime as dt
from typing import Optional, List
import uuid

from fastapi import APIRouter, Depends
from pydantic import BaseModel
from sqlalchemy import func
from sqlalchemy.orm import Session
from app.db.deps import get_db
from app.db.utils import NOT_FOUND_EXCEPTION, save_model
from app.dependencies.auth import TokenUser, credential_check
# from app.db.utils import save_model

from app.models.task import Task, TaskOut
from app.models.task_activity import TaskActivity, TaskActivityOut
from app.models.task_completion import TaskCompletion, TaskCompletionOut
from app.models.user import User

router = APIRouter()

@router.get("/", response_model=List[TaskOut])
async def get_tasks(
    limit: Optional[int] = 100,
    skip: Optional[int] = 0,
    db: Session = Depends(get_db),
):
    return db.query(Task).limit(limit).offset(skip).all()

@router.get("/active", response_model=List[TaskActivityOut])
async def get_active_tasks(
    limit: Optional[int] = 100,
    skip: Optional[int] = 0,
    db: Session = Depends(get_db),
    user: TokenUser = Depends(credential_check)
):
    query = (
        db.query(TaskActivity).
        filter(
            TaskActivity.id.not_in(
                db.query(TaskCompletion.task_activity_id)
                    .filter(TaskCompletion.user_id == user.id)
            ),
            func.date(TaskActivity.ends_at) >= dt.date.today()
        ).
        order_by(TaskActivity.ends_at)
    )

    return (
        query.limit(limit).offset(skip).all()
    )

@router.post("/complete/{task_activity_id}", response_model=TaskCompletionOut)
async def post_complete_task(
    task_activity_id : uuid.UUID,
    db : Session = Depends(get_db),
    user : TokenUser = Depends(credential_check)
):
    # TODO TEST
    task_activity = db.query(TaskActivity).filter(TaskActivity.id == task_activity_id).one_or_none()
    if task_activity == None:
        raise NOT_FOUND_EXCEPTION

    tc = TaskCompletion(
        task_activity_id = task_activity_id,
        task_id = task_activity.task.id,
        user_id = user.id
    )
    usr = db.query(User).filter(User.id == user.id).one_or_none()

    if user == None:
        raise NOT_FOUND_EXCEPTION

    usr.emissions_saved += task_activity.emissions_saved
    usr.money_saved += task_activity.money_saved
    db.add(usr)

    usr = db.query(User).filter(User.id == user.id).one_or_none()

    if user == None:
        raise NOT_FOUND_EXCEPTION

    usr.emissions_saved += task_activity.emissions_saved
    usr.money_saved += task_activity.money_saved
    db.add(usr)

    return save_model(db,tc)

@router.get("/user/completed", response_model=List[TaskActivityOut])
async def get_active_tasks(
    limit: Optional[int] = 100,
    skip: Optional[int] = 0,
    db: Session = Depends(get_db),
    user: TokenUser = Depends(credential_check)
):
    return (
        db.query(TaskCompletion).
        filter(TaskCompletion.user_id == user.id).
        limit(limit).offset(skip).all()
    )

class EmissionAnalytics(BaseModel):
    emissions_saved: float
    date: dt.datetime

class MoneyAnalytics(BaseModel):
    money_saved: float
    date: dt.datetime

@router.get("/emission/analytics", response_model=List[EmissionAnalytics])
async def get_active_tasks(
    days: Optional[int] = 6,
    db: Session = Depends(get_db),
    user: TokenUser = Depends(credential_check)
):
    query = (
        db.query(
            func.sum(TaskActivity.emissions_saved).label(
                "emissions_saved"
            ),
            func.date_trunc('day', TaskCompletion.completed_at).label("date")
        ).
        outerjoin(TaskActivity, TaskActivity.id == TaskCompletion.task_activity_id).
        filter(
            TaskCompletion.user_id == user.id,
            func.date(TaskCompletion.completed_at) >= dt.date.today() - dt.timedelta(days=days)
        ).group_by(
            func.date_trunc('day', TaskCompletion.completed_at)
        )
    )

    return query.all()

@router.get("/money/analytics", response_model=List[MoneyAnalytics])
async def get_active_tasks(
    days: Optional[int] = 6,
    db: Session = Depends(get_db),
    user: TokenUser = Depends(credential_check)
):
    query = (
        db.query(
            func.sum(TaskActivity.money_saved).label(
                "money_saved"
            ),
            func.date_trunc('day', TaskCompletion.completed_at).label("date")
        ).
        outerjoin(TaskActivity, TaskActivity.id == TaskCompletion.task_activity_id).
        filter(
            TaskCompletion.user_id == user.id,
            func.date(TaskCompletion.completed_at) >= dt.date.today() - dt.timedelta(days=days)
        ).group_by(
            func.date_trunc('day', TaskCompletion.completed_at)
        )
    )

    return query.all()


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

import pyvirtualdisplay.smartdisplay as smartdisplay
import selenium.webdriver
import contextlib
import time
import csv
import bs4
import psycopg2

import settings

def download_html(site_url, output_file):
    with smartdisplay.SmartDisplay(visible=0, bgcolor='black'):
        with contextlib.closing(selenium.webdriver.Chrome()) as browser:
            browser.get(site_url)

            time.sleep(settings.BROWSER_JS_EXEC_PAUSE)

            browser.execute_script("window.scrollTo "
                                   "(0, document.body.scrollHeight);")

            with open(output_file, "w") as fp:
                fp.write(browser.page_source.encode(settings.DEFAULT_ENCODING))

def extract_into_csv(input_html, output_csv):
    with open(input_html, "r") as fp:
        soup = bs4.BeautifulSoup(fp, "lxml")

    with open(output_csv, "w") as fp:
        csv_writer = csv.writer(fp)

        csv_writer.writerow(settings.CSV_HEADER)

        for row in soup.find_all('tr'):
            row_to_write = tuple(
                (r.encode(settings.DEFAULT_ENCODING)
                    for r in row.stripped_strings)
            )
            csv_writer.writerow(row_to_write)

def download_to_bd(input_csv):
    try:
        with psycopg2.connect(**(settings.DATABASE_SETTINGS)) as db:
            cur = db.cursor()

            query = """INSERT into snap_jobs."Jobs"
                    (job_title, category, status, location)
                    VALUES ('{}', '{}', '{}', '{}')"""

            with open(input_csv) as fp:
                csv_reader = csv.reader(fp)

                csv_reader.next()

                for row in csv_reader:
                    cur.execute(query.format(*row))

            db.commit()

    except psycopg2.IntegrityError as error:
        print(error)


from django.urls import path,include
from . import views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('post', views.PostViewSet)

app_name = 'api'
urlpatterns = [
    #Authentication
    path('login/', views.MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('register/', views.RegisterView.as_view(), name='auth_register'),

    #Profile
    path('profile/', views.getProfile, name='profile'),
    path('profile/update/', views.updateProfile, name='update-profile'),
    path('follow/<int:pk>/', views.FollowUserView.as_view(), name='follow'),
    path('unfollow/<int:pk>/', views.UnfollowUserView.as_view(), name='unfollow'),
    path('logout/', views.LogoutView.as_view(), name='logout'),
    path('', include(router.urls)),
]


# I use last.fm to scrobble all of the music I listen to.
# Each month I have an average listen count
# I wanted to be able to work out how many tracks a day I needed to listen to,
# To allow me to achieve a particular play count average.

import math
import calendar
from datetime import date

today = date.today()
d1 = today.strftime("%d/%m/%Y")
d2 = today.strftime("%d")
d3 = today.strftime("%m")
d4 = today.strftime("%Y")

print("Today's date =", d1)
print("The current day =", d2)
print("the current month =", d3)
print("The current year is", d4)

today = d2
today = int(today)

monthNow = d3
monthNow = str(monthNow)

if monthNow != "10" or monthNow != "11" or monthNow != "12":
    monthNow = str(monthNow[1])
else:
    monthNow = str(monthNow)
#print(monthNow)

yearNow = d4
yearNow = int(yearNow)
#print(calendar.isleap(yearNow))

if calendar.isleap(yearNow):
    print("This is a leap year.")
else:
    print("This year is not a leap year")

days1 = 31
days2 = 30
days3 = 28
days4 = 29
monthLength = 0

# stage 1 - work out the length of the month
if monthNow == str(2) and calendar.isleap(yearNow):
    monthLength = days4
elif monthNow == str(2) and False == calendar.isleap(yearNow):
    monthLength = days3

elif monthNow == str(1) or monthNow == str(3) or monthNow == str(5) or monthNow == str(7) or monthNow == str(8) \
        or monthNow == str(10) or monthNow == str(12):
    monthLength = days1
# elif monthNow == str(4) or monthNow == str(6) or monthNow == str(9) or monthNow == str(11):
else:
    monthLength = days2
print("This month is", monthLength, "days long.")

scrobbles = int(input("How many scrobbles have you listened to so far this month? "))
average = scrobbles / today
rounded = math.floor(average)
print("Your current play average is: ", rounded)

# #Uses the data from the current average to ask what the target is and
# #works out how many tracks need to be listened to
target = int(input("What is your target average? "))
scrobblesNeeded = target * monthLength
print("To achieve that you have to listen to", scrobblesNeeded, "tracks")
scrobblesToGet = scrobblesNeeded - scrobbles
print("You need to listen to another", scrobblesToGet, "tracks")

# if daysLeft is 0, this prevents a ZeroDivisionError
daysLeft = monthLength - today
print("There are", daysLeft, "days left this month.")

if daysLeft != 0:
    daily = scrobblesToGet / daysLeft
    daily = math.floor(daily)
    print("You need to listen to about", daily, "tracks a day.")
    print("Thank you for using the Average Scrobble calculator.")
else:
    print("Thank you for using the Average Scrobble calculator.")
print("End")


import os

from .paintingDB import PaintingDatabaseHandler
from .modelDB import ModelDatabaseHandler

__all__ = ["PaintingDatabaseHandler", "ModelDatabaseHandler",
           "paintings_dir", "faces_dir", "temp_dir",
           "models_dir", "predictor_path", "style_path",
           "svm_path", "dataset_dir", "emotions", "emotions_dir"]

resource_dir   = "/Users/lun/Desktop/ProjectX"
paintings_dir  = os.path.join(resource_dir, "paintings")
faces_dir      = os.path.join(resource_dir, "faces")
temp_dir       = os.path.join(resource_dir, "temp")
models_dir     = os.path.join(resource_dir, "models")
predictor_path = os.path.join(models_dir, "predictor.dat")
style_path     = os.path.join(models_dir, "style150.h5")
svm_path       = os.path.join(models_dir, "svm.pkl")
dataset_dir    = os.path.join(models_dir, "dataset")
emotions       = ["angry", "disgust", "fear", "happy", "neutral", "sad", "surprise"]
emotions_dir   = [os.path.join(dataset_dir, emotion) for emotion in emotions]


import pint
import time
import datetime

from . import ureg
from .constants import std_temperature, std_pressure
from .error import OpgeeException, AbstractMethodError
from .log import getLogger
from .utils import coercible, getBooleanXML

_logger = getLogger(__name__)

def magnitude(value, units=None):
    """
    Return the magnitude of ``value``. If ``value`` is a ``pint.Quantity`` and
    ``units`` is not None, check that ``value`` has the expected units and
    return the magnitude of ``value``. If ``value`` is not a ``pint.Quantity``,
    just return it.

    :param value: (float or pint.Quantity) the value for which we return the magnitude.
    :param units: (None or pint.Unit) the expected units
    :return: the magnitude of `value`
    """
    if isinstance(value, ureg.Quantity):
        # if optional units are provided, validate them
        if units:
            if not isinstance(units, pint.Unit):
                units = ureg.Unit(units)
            if value.units != units:
                raise OpgeeException(f"magnitude: value {value} units are not {units}")

        return value.m
    else:
        return value

def name_of(obj):
    return obj.name

def elt_name(elt):
    return elt.attrib.get('name')

def instantiate_subelts(elt, cls, parent=None, as_dict=False, include_names=None):
    """
    Return a list of instances of ``cls`` (or of its indicated subclass of ``Process``).

    :param elt: (lxml.etree.Element) the parent element
    :param cls: (type) the class to instantiate. If cls is Process, the class will
        be that indicated instead in the element's "class" attribute.
    :param parent: (XmlInstantiable) the parent to record in each object instantiated
    :param as_dict: (bool) if True, return a dictionary of subelements, keyed by name
    :param include_names: (list of str) Names of elements to include (i.e., the element's
       attrib dict must have a "name" item, whose value is compared to the list). If
       ``include_names`` is not None, then elements with names not in the list are
       ignored.
    :return: (list) instantiated objects
    """
    tag = cls.__name__  # class name matches element name

    include = None if include_names is None else set(include_names)
    objs = [cls.from_xml(e, parent=parent) for e in elt.findall(tag) if include is None or e.attrib.get('name') in include]

    if as_dict:
        d = {obj.name: obj for obj in objs}
        return d
    else:
        return objs

def dict_from_list(objs):
    """
    Create a dictionary of ``XMLInstantiable`` objects by their name attribute, but
    raise an error if any name is repeated.

    :param objs: (list of XMLInstantiable instances) the object to create dict from.
    :return: (dict) objects keyed by name
    :raises: OpgeeException if a any name is repeated
    """
    d = dict()
    for obj in objs:
        name = obj.name
        if d.get(name):
            classname = obj.__class__.__name__
            raise OpgeeException(f"{classname} instances must have unique names: {name} is not unique.")

        d[name] = obj

    return d

CLASS_DELIMITER = '.'

def split_attr_name(attr_name):
    splits = attr_name.split(CLASS_DELIMITER)
    count = len(splits)

    if count == 0:
        raise OpgeeException(f"Attribute name is empty")

    if count == 1:
        class_name, attr_name = None, splits[0]

    elif count == 2:
        class_name, attr_name = splits

    else:
        raise OpgeeException(f"Attribute name '{attr_name}' has more than 2 dot-delimited parts")

    return class_name, attr_name

# Top of hierarchy, because it's useful to know which classes are "ours"
class OpgeeObject():
    @classmethod
    def clear(cls):
        # Clear state stored in class variables
        pass

class XmlInstantiable(OpgeeObject):
    """
    This is the superclass for all classes that are instantiable from XML. The requirements of
    such classes are:

    1. They subclass from XmlInstantiable or its subclasses
    2. They define ``__init__(self, name, **kwargs)`` and call ``super().__init__(name)``
    3. They define ``@classmethod from_xml(cls, element, parent=None)`` to create an instance from XML.
    4. Subclasses of Container and Process implement ``run(self)`` to perform any required operations.

    """
    def __init__(self, name, parent=None):
        super().__init__()
        self.name = name
        self.parent = parent
        self.enabled = True

    def set_parent(self, parent):
        self.parent = parent

    @classmethod
    def from_xml(cls, elt, parent=None):
        raise AbstractMethodError(cls, 'XmlInstantiable.from_xml')

    def __str__(self):
        type_str = type(self).__name__
        name_str = f' name="{self.name}"' if self.name else ''
        return f'<{type_str}{name_str} enabled={self.enabled}>'

    def is_enabled(self):
        return self.enabled

    def set_enabled(self, value):
        self.enabled = getBooleanXML(value)

    def adopt(self, objs, asDict=False):
        """
        Set the `parent` of each object to self. This is used to create back pointers
        up the hieararchy so Processes and Streams can find their Field and Analysis
        containers. Return the objects either as a list or dict.

        :param objs: (None or list of XmlInstantiable)
        :param asDict: (bool) if True, return a dict of objects keyed by their name,
            otherwise return a list of the objects.
        :return: (list) If objs is None, return an empty list or dict (per `asDict`),
            otherwise return the objs either in a list or dict.
        """
        objs = [] if objs is None else objs

        for obj in objs:
            obj.set_parent(self)

        return {obj.name: obj for obj in objs} if asDict else objs

    def find_container(self, cls):
        """
        Ascend the parent links in the object hierarchy until an object of class `cls`
        is found, or an object with a parent that is None.

        :param cls: (type or str name of type) the class of the parent sought
        :return: (XmlInstantiable or None) the desired parent instance or None
        """
        if type(self) == cls or self.__class__.__name__ == cls:
            return self

        if self.parent is None:
            return None

        return self.parent.find_container(cls)  # recursively ascend the graph

# to avoid redundantly reporting bad units
_undefined_units = {}

def validate_unit(unit):
    """
    Return the ``pint.Unit`` associated with the string ``unit``, or ``None``
    if ``unit`` is ``None`` or not in the unit registry.

    :param unit: (str) a string representation of a ``pint.Unit``

    :return: (pint.Unit or None)
    """
    if not unit:
        return None

    if unit in ureg:
        return ureg.Unit(unit)

    if unit not in _undefined_units:
        _logger.warning(f"Unit '{unit}' is not in the UnitRegistry")
        _undefined_units[unit] = 1

    return None

class A(OpgeeObject):
    """
    The ``<A>`` element represents the value of an attribute previously defined in
    `attributes.xml` or a user-provided file. Note that this class is not instantiated
    using ``from_xml()`` approach since values are merged with metadata from `attributes.xml`.
    """

    def __init__(self, name, value=None, pytype=None, unit=None, explicit=False):
        """
        Creates an attribute instance.

        :param name: (str) the attribute name
        :param value: (str) string representation of attribute value
        :param pytype: (type) the type the value should be coerced to (plus unit)
        :param unit: (str) the attributes units
        :param explicit: (bool) whether the value was explicit in the file; if not,
          it implies the value was set from the default in the attribute definition.
        """
        super().__init__()
        self.name = name
        self.unit = unit
        self.pytype = pytype
        self.explicit = explicit
        self.value = self.set_value(value)

    def set_value(self, value):
        """
        Sets the instances' value to the value given, using the stored ``pytype`` for type
        conversion and ``unit`` to define a ``pint.Quantity``, if given.

        :param value: (str, numerical, or pint.Quantity) the value to possibly convert
        :return: the value, converted to ``pytype``, and with ``unit``, if specified.
        """
        if value is None:
            return None

        unit_obj = validate_unit(self.unit)

        if isinstance(value, pint.Quantity):
            if value.units == unit_obj:
                self.value = value
                return value
            else:
                value = value.magnitude

        if self.pytype:
            value = coercible(value, self.pytype)

        if unit_obj is not None:
            value = ureg.Quantity(value, unit_obj)

        self.value = value
        return value

    def str_value(self):
        """
        Return the value of an attribute as a string.

        :return: (str) string representation of the attribute value
        """
        return str(self.value)

    def __str__(self):
        type_str = type(self).__name__
        attrs = f"name='{self.name}' type='{self.pytype}' value='{self.value}'"

        return f"<{type_str} {attrs}>"

class TemperaturePressure(OpgeeObject):
    """
    Stores temperature and pressure together for convenience.
    """
    __slots__ = ('T', 'P')      # keeps instances small and fast

    def __init__(self, T, P):
        self.T = None
        self.P = None
        self.set(T=T, P=P)

    def __str__(self):
        return f"<T={self.T} P={self.P}>"

    def set(self, T=None, P=None):
        if T is None and P is None:
            #_logger.warning("Tried to set TemperaturePressure with both values None")
            return

        if T is not None:
            self.T = T if isinstance(T, pint.Quantity) else ureg.Quantity(float(T), "degF")

        if P is not None:
            self.P = P if isinstance(P, pint.Quantity) else ureg.Quantity(float(P), "psia")

    def get(self):
        return (self.T, self.P)

    def copy_from(self, tp):
        self.set(T=tp.T, P=tp.P)

# Standard temperature and pressure
STP = TemperaturePressure(std_temperature, std_pressure)

class Timer:
    def __init__(self, feature_name):
        self.feature_name = feature_name
        self.start_time = None
        self.stop_time  = None

    def start(self):
        self.start_time = time.time()
        return self

    def stop(self):
        self.stop_time = time.time()
        return self

    def duration(self):
        seconds = self.stop_time - self.start_time
        return datetime.timedelta(seconds=int(seconds))

    def __str__(self):
        if self.start_time is None:
            status = "is uninitialized"
        elif self.stop_time is None:
            status = "is running"
        else:
            d = self.duration()
            status = f"completed in {d}"

        return f"<Timer '{self.feature_name}' {status}>"


import unittest

import ui
from ui import UI
from ui.low.file import File
import tool.utilities as utils

__author__ = 'John Underwood'

class TestSuiteFileGeneral(unittest.TestCase):
    ui.log.info(">>> Inside TestSuiteFileGeneral class")
    debug = False
    process = UI()
    user_name = utils.get_configurations("USER", "name")

    def setUp(self):
        File()

    def tearDown(self):
        pass

    @classmethod
    def tearDownClass(cls):
        UI().teardown()

    # ^*^*^*^*^*^*^*^*^*^*^*^*^*^*^* TEST CASES ^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*
    @unittest.skipIf(debug, "debugging a single test")
    def test_generic_files(self):
        ui.log.info(">>> Inside function test_generic_files()")
        runtime = {
            'generic': ('Click', '//*[@id="vsubnav"]/div/div[6]/a[1]', )
        }
        expected = "System Files"  # can also use 'System Documents'
        self.process.update(runtime)
        self.process.execute(('generic', ))
        result = self.process.results(expected)
        self.assertTrue(result, msg=expected)

    @unittest.skipIf(debug, "debugging a single test")
    def test_my_files(self):
        ui.log.info(">>> Inside function test_my_files()")
        runtime = {
            'myfile': ('Click', '//*[@id="vsubnav"]/div/div[6]/a[2]', )
        }
        expected = "{}'s Files".format(self.user_name)
        self.process.update(runtime)
        self.process.execute(('myfile', ))
        result = self.process.results(expected)
        self.assertTrue(result, msg=expected)


import sqlite3

def get_id(coal_engine_db, game_ID):
    query = "SELECT game_ID FROM Game WHERE id=?;"
    connection = sqlite3.connect(coal_engine_db)
    cursor = connection.cursor()
    cursor.execute(query,[game_ID])
    results = cursor.fetchall()
    cursor.close()
    connection.close()
    return results
    print("Your Game ID is: ", game_ID('coal_engine_db'))

def get_games(coal_engine_db, game_Name):
    query = "SELECT game_Name FROM Game"
    connection = sqlite3.connect(coal_engine_db)
    cursor = connection.cursor()
    cursor.execute(query,[game_Name])
    results = cursor.fetchall()
    cursor.close()
    connection.close()
    return results
    print("Welcome To : ", game_Name('coal_engine_db'))

def get_description(coal_engine_db, game_Description):
    query = "SELECT game_Description FROM Game"
    connection = sqlite3.connect(coal_engine_db)
    cursor = connection.cursor()
    cursor.execute(query,[game_Description])
    results = cursor.fetchall()
    cursor.close()
    connection.close()
    return results
    print("General Description : ", game_Description('coal_engine_db'))


from __future__ import unicode_literals, print_function, division
import torch.nn as nn
from torch.nn import ModuleList
import torch.nn.functional as F
from torch_geometric.nn import BatchNorm
from torch_geometric.nn import GeneralConv
from model.datautil import (flat_gather)
from model.gnn_datatransform import GNNDataTransform, DependencyIndexer

class SubwordNet(nn.Module):
    def __init__(self, options):
        super().__init__()
        self.subword_edge_feature_emb = nn.Embedding(options["depth_size"],
                                                    options["depth_dim"],
                                                    padding_idx=options["depth_emb_pad"])
        self.convs = ModuleList()
        self.batch_norms = ModuleList()
        for _ in range(options["n_layers"]):
            conv = GeneralConv(in_channels=options["dims"][0],
                                    out_channels=options["dims"][1],
                                    in_edge_channels=options["depth_dim"],
                                    aggr=options["aggregation"],
                                    skip_linear=options["linearity"],
                                    directed_msg=True,
                                    attention=False,
                                    l2_normalize=False,
                                    bias=True,
                                    flow="target_to_source")
            self.convs.append(conv)
            self.batch_norms.append(BatchNorm(options["dims"][1]))

        self.transform = GNNDataTransform()
        self.dep_indexer = DependencyIndexer()

    def forward(self, inputs):
        '''
            Compute graph representation of sequence dependency structure.

            transform:              Data transformation object.
            dep_indexer:            Dependency data indexing object.
            data:                   Latent data.
            token_arc_head:         Sparsified dependency head of syntactic arc.
            token_arc_type:         Sparsified dependency type of syntactic arc.
            attention_mask:         Inlucde special tokens such as BOS and EOS.
                                    It is created by a tokenizer.
            token_dense_mask:       Mask out the special tokens from attention_mask.
            token_sparse_mask:      Sparse mask that mask the first token of word segmentation.
                                    It may include the special tokens.
        '''
        data = inputs["data"]
        attention_mask = inputs["attention_mask"]
        token_head = inputs["token_head"]
        token_depth = inputs["token_depth"]
        token_dense_mask = inputs["token_dense_mask"]
        token_sparse_mask = inputs["token_sparse_mask"]

        sparse_mask = token_sparse_mask*token_dense_mask
        results = self.dep_indexer(mask=attention_mask,
                                sparse_mask=sparse_mask)
        indexer = results["indexer"]
        cumsum = results["cumsum"]
        edges = self.transform.make_edges(token_head, indexer, cumsum)
        edge_features = self.subword_edge_feature_emb(token_depth)
        edge_features = flat_gather(edge_features, sparse_mask)
        data_g = self.transform.debatch(data, indexer=None)
        repr = self.subword_net(x=data_g,
                                edge_index=edges,
                                edge_attr=edge_features)

        repr = repr.reshape(data.shape)
        return repr

    def subword_net(self, x, edge_index, edge_attr):
        for conv, batch_norm in zip(self.convs, self.batch_norms):
            x = F.relu(batch_norm(conv(x, edge_index, edge_attr)))
        return x