import numpy as np
from sklearn.metrics import precision_recall_curve, average_precision_score

def calc_tp_tn_fp_fn(label, cmat, cmat_labels):
    """
    Return the number of true positives (TPs), true negatives (TNs),
    false positives (FPs) and false negatives (FNs) for a given class label.

    Args:
        label: The class label for which to calculate the TPs, TNs, FPs and FNs.
        cmat: The confusion matrix. The rows should correspond to the true labels,
            the columns should correspond to the predicted labels.
        cmat_labels: The class labels in the confusion matrix.
    """
    label_idx = get_label_idx(label, cmat_labels)

    tps = cmat[label_idx, label_idx]
    fps = np.sum(cmat[:, label_idx]) - tps
    fns = np.sum(cmat[label_idx, :]) - tps
    tns = np.sum(cmat) - fps - fns - tps

    return tps, tns, fps, fns

def calc_precision(label, cmat, cmat_labels):
    """
    Return the precision for a given class label.

    Args:
        label: The class label for which to calculate the precision.
        cmat: The confusion matrix. The rows should correspond to the true labels,
            the columns should correspond to the predicted labels.
        cmat_labels: The class labels in the confusion matrix.
    """
    label_idx = get_label_idx(label, cmat_labels)

    tps = cmat[label_idx, label_idx]
    all_positives = np.sum(cmat[:, label_idx])

    return tps / all_positives

def calc_recall(label, cmat, cmat_labels):
    """
    Return the recall for a given class label.

    Args:
        label: The class label for which to calculate the recall.
        cmat: The confusion matrix. The rows should correspond to the true labels,
            the columns should correspond to the predicted labels.
        cmat_labels: The class labels in the confusion matrix.
    """
    label_idx = get_label_idx(label, cmat_labels)

    tps = cmat[label_idx, label_idx]
    all_true = np.sum(cmat[label_idx, :])

    return tps / all_true

def calc_pr_curve(label, sim_mat, gallery_labels, query_labels):
    """
    Return the precision-recall curve for a given class label. The PR-curve is returned
    as three arrays: precision, recall, thresholds. Doing this correctly, however, is not
    trivial when we have multiple classes. The following text goes through it step by step.

    Each query will be classified as the label with which it has the highest similarity. For
    a certain class, queries that are classified as that class are (true or false) positives
    and queries that are classified as another class are (true or false) negatives. As such,
    we can compute the precision and recall for each class.

    Since each classification also has a similarity score, we can choose to put a *threshold*
    on the similarity scores. Setting a threshold value for a certain class means that we
    classify all queries with a score lower than the threshold as *negative* and those with a
    score higher than or equal to the threshold as *positive*. The lowest (resp. highest)
    possible threshold is thus the lowest (resp. highest) similarity score.

    By increasing the threshold value for a certain class from the lowest to the highest
    possible value, we will get less and less queries that are classified as that class. Hence,
    the recall of the classifier will decrease (or stay the same, but never increase). However,
    meanwhile, the precision might increase since we are raising the bar on which scores we
    consider high enough. A PR-curve visualizes this trade-off between precision and recall for
    all possible thresholds.

    The PR-curve that evaluates the classification of a certain class is drawn based on a list
    of scores (`y_score`) and a binary list (`y_true`) that indicates which of the queries truly
    belonged to the chosen class. The scores are sorted from high to low and at each rank the
    precision and recall are evaluated by classifying the samples up until the rank as *positive*
    and those after the rank as *negative*. This is equivalent to choosing thresholds and
    classifying the queries under the threshold as negative and those equal to or above the
    threshold as positive.

    An important issue is how to compose `y_score` and `y_true` correctly for the evaluation of
    the classification of a certain class label, given the similarity matrix. As described above,
    the scores in `y_score` will be sorted and will be considered as a predicted positive
    classification at certain ranks. There are scores in the similarity matrix, however, that will
    *never* lead to a positive classification for the chosen class. First, the similarity scores
    with other classes will obviously never lead to a classification as the chosen class. Therefore,
    these scores should be excluded from `y_score`. Second, the similarity scores with the chosen
    class that are *not* the maximum similarity score of the query, will also *never* lead to a
    positive classification for the chosen class. This is because, when classifying a query, we
    only take the class with maximum similarity score into consideration.

    From the above reasoning, it follows that `y_score` should only consist of scores that have
    a maximum value for the class label that we are evaluating. `y_true` then indicates which of
    the queries corresponding to the scores in `y_scores` truely belong to that class.

    The problem with this is, however, that **we will miss a constant number of false negatives**.
    This is because the queries that *do* belong to the chosen class but that will never be classified
    *as* the chosen class (because their score is not the maximum similarity), will also not
    show up in `y_scores` and `y_true`. Hence, the denominator of the recall will be too small and
    the recall will be overestimated. Luckily, the denominator of the recall is constant as it is
    equal to the number of queries that truely have the chosen label. Hence, we can easily correct
    the recalls by multiplying away the wrong denominator and dividing it again with the correct
    denominator.

    One might suggest to add the non-maximum queries that do belong to the chosen class to `y_scores`
    and `y_true` as well. This, however, will lead to erroneous results, since those scores are not
    guaranteed to be lower than the other scores in `y_scores`, while they *should* be. A more valid
    suggestion would be to assign a score of $-\infty$ to these queries, which illustrates the fact
    that these queries will never be classified as positive. Similarity scores of infinite value
    might not be supported, however (e.g. in `sklearn`).

    Args:
        label: The class label for which to calculate the precision-recall curve.
        sim_mat: The similarity matrix. It should have the same amount of rows as
            the number of queries and the same amount of columns as the number of
            class labels in the gallery.
        gallery_labels: The labels that correspond to the columns in `sim_mat`,
            i.e. the labels in the gallery.
        query_labels: The labels that correspond to the rows in `sim_mat`, i.e.
            the true label of each query.
    """
    # y_score should only contain scores that have a maximum value
    # for `label`
    match_idxs = sim_mat.argmax(axis=1)
    label_idx = get_label_idx(label, gallery_labels)
    row_idxs, = np.where(match_idxs == label_idx)
    y_score = sim_mat[row_idxs, match_idxs[row_idxs]]

    # y_score tells which of these truely correspond to `label`
    y_true = query_labels[row_idxs] == label

    # If no queries has a betch match for the given label,
    # return a PR-curve with a single point at p = 1., r = 0.
    if len(y_true) == 0:
        return (np.array([0.]),
                np.array([1.]),
                np.array([0.]))

    # Calculate the PR-curve from y_true and y_score
    p, r, t = precision_recall_curve(y_true, y_score)

    # Compensate for the underestimation of false negatives
    true_num_tp_fn = (query_labels == label).sum()
    selected_num_tp_fn = y_true.sum()
    r *= selected_num_tp_fn / true_num_tp_fn

    return p, r, t

def calc_ap(label, sim_mat, gallery_labels, query_labels):
    """
    Return the average precision for a given class label.

    Args:
        label: The class label for which to calculate the precision-recall curve.
        sim_mat: The similarity matrix. It should have the same amount of rows as
            the number of queries and the same amount of columns as the number of
            class labels in the gallery.
        gallery_labels: The labels that correspond to the columns in `sim_mat`,
            i.e. the labels in the gallery.
        query_labels: The labels that correspond to the rows in `sim_mat`, i.e.
            the true label of each query.
    """
    precision, recall, _ = calc_pr_curve(label, sim_mat, gallery_labels,
                                         query_labels)
    return -np.sum(np.diff(recall) * np.array(precision)[:-1])

def get_label_idx(label, cmat_labels):
    if label not in cmat_labels:
        raise ValueError(f'Label {label} not found')

    idxs = np.where(cmat_labels == label)[0]

    if len(idxs) > 1:
        raise ValueError(f'Label {label} should only occur once')

    return idxs[0]


import numpy as np
import cv2
import os
import time

class Model:

    def __init__(self,WEIGHTS_PATH,CONFIG_PATH,LABELS_PATH):
        self.WEIGHTS_PATH = WEIGHTS_PATH
        self.CONFIG_PATH = CONFIG_PATH
        self.LABELS_PATH = LABELS_PATH

        self.LABELS = []
        self.USE_GPU = True

        try:
            with open(self.LABELS_PATH, "r") as f:
                for line in f.readlines():
                    self.LABELS.append(line.strip("\n"))  # her bir class adından '\n' i sildik
            print("LABELS :",self.LABELS)
            self.__colors = np.random.randint(0, 255, size=(len(self.LABELS), 3), dtype='uint8')
        except:
            print("[LOAD LABELS ERROR]")
            exit(1)

    def load_yolo(self):

        self.net = cv2.dnn.readNet(self.WEIGHTS_PATH, self.CONFIG_PATH)  # load YOLO algorithm.

        if self.USE_GPU:
            self.net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
            self.net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
            print('Using GPU')
        else:
            self.net.setPreferableBackend(cv2.dnn.DNN_BACKEND_DEFAULT)
            self.net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
            print('Using CPU')

        self.layer_names = self.net.getLayerNames()

        print(f"Layers Names [{len(self.layer_names)}] :", self.layer_names)  # CNN modelinin katmanları

        self.output_layers = []  # Output layerlarin isimleri
        for i in range(len(self.layer_names)):
            if i + 1 in self.net.getUnconnectedOutLayers():  # Output layerlarin indisini doner
                self.output_layers.append(self.layer_names[i])

        print("Output Layers : ", self.output_layers)

        print("[WAIT] Model is loading...")

    def __extract_boxes_confidences_classids(self,outputs, confidence, width, height):
        boxes = []
        confidences = []
        classIDs = []

        for output in outputs:
            for detection in output:
                # Extract the scores, classid, and the confidence of the prediction
                scores = detection[5:]
                classID = np.argmax(scores)
                conf = scores[classID]

                # Consider only the predictions that are above the confidence threshold
                if conf > confidence:
                    # Scale the bounding box back to the size of the image
                    box = detection[0:4] * np.array([width, height, width, height])
                    centerX, centerY, w, h = box.astype('int')

                    # Use the center coordinates, width and height to get the coordinates of the top left corner
                    x = int(centerX - (w / 2))
                    y = int(centerY - (h / 2))

                    boxes.append([x, y, int(w), int(h)])
                    confidences.append(float(conf))
                    classIDs.append(classID)

        return boxes, confidences, classIDs

    def make_prediction(self, image, confidence=0.5, threshold=0.3):
        height, width = image.shape[:2]

        # Create a blob and pass it through the model
        blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (416, 416), swapRB=True, crop=False)
        self.net.setInput(blob)
        outputs = self.net.forward(self.output_layers)

        # Extract bounding boxes, confidences and classIDs
        boxes, confidences, classIDs = self.__extract_boxes_confidences_classids(outputs, confidence, width, height)

        # Apply Non-Max Suppression
        idxs = cv2.dnn.NMSBoxes(boxes, confidences, confidence, threshold)

        return boxes, confidences, classIDs, idxs

    def draw_bounding_boxes(self,image, boxes, confidences, classIDs, idxs):
        if len(idxs) > 0:
            for i in idxs.flatten():
                # extract bounding box coordinates
                x, y = boxes[i][0], boxes[i][1]
                w, h = boxes[i][2], boxes[i][3]

                # draw the bounding box and label on the image
                color = [int(c) for c in self.__colors[classIDs[i]]]
                cv2.rectangle(image, (x, y), (x + w, y + h), color, 2)
                text = "{}: {:.4f}".format(self.LABELS[classIDs[i]], confidences[i])
                cv2.putText(image, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

        return image

if __name__ == "__main__":
    img = cv2.imread("./test_images/image7.jpg")
    model = Model("./model/yolov4-tiny-custom_best.weights","./model/yolov4-tiny-custom.cfg","./model/obj.names")
    model.load_yolo()
    boxes, confidences, classIDs, idxs = model.make_prediction(img)
    print(boxes,confidences,classIDs)
    img = model.draw_bounding_boxes(img,boxes,confidences,classIDs,idxs)

    cv2.imshow("window",img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


# encoding: UTF-8
# refer: https://nga.178.com/read.php?tid=11838545
# python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python pyautogui numpy

import re
import pyautogui
import cv2
import numpy as np
import time

global LOGFILE, encoding, preImg
pyautogui.FAILSAFE = False
LOGFILE = "C:\\Program Files (x86)\\Hearthstone\\Logs\\Power.log"
encoding = "UTF-8"
preImg = [cv2.imread(f"./hs/{i}.png") for i in range(3)]

def screenshot(x=376, y=292 + 30, w=530, h=430 - 30):
    img = pyautogui.screenshot(region=[x, y, w, h])  # x,y,w,h
    img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
    return img

def imgSave(i=9):
    img = screenshot()
    cv2.imwrite(f"./hs/{i}.png", img)
    cv2.imshow(str(i), img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def ORB_img_similarity(img1, img2):
    try:
        orb = cv2.ORB_create()
        kp1, des1 = orb.detectAndCompute(img1, None)
        kp2, des2 = orb.detectAndCompute(img2, None)
        bf = cv2.BFMatcher(cv2.NORM_HAMMING)
        matches = bf.knnMatch(des1, trainDescriptors=des2, k=2)
        good = [m for (m, n) in matches if m.distance < 0.75 * n.distance]
        similary = len(good) / len(matches)
        return similary
    except:
        return float(0)

def compare(img):
    result = 9
    p = 0.4
    for i in range(3):
        res = float(ORB_img_similarity(preImg[i][277:380, 0:530], img[277:380, 0:530]))
        if res > p:
            p = res
            result = i
    print(f"res = {result}, p = {p}")
    return result

def movClick(x, y, t=0.7):
    pyautogui.moveTo(x, y, duration=t, tween=pyautogui.easeInOutQuad)
    pyautogui.click()

def gaming():
    flagGameover = 0
    flagTimesleep = 0
    with open(LOGFILE, 'r', encoding=encoding) as log:
        while log.readline():
            pass
        while True:
            line = log.readline()
            if line:
                flagTimesleep = 0
                if re.findall(r"tag=STEP value=MAIN_ACTION", line):
                    time.sleep(10)
                    logLine = log.readline()
                    while logLine:
                        if re.findall(r"tag=STEP value=FINAL_GAMEOVER", logLine):
                            flagGameover += 1
                        logLine = log.readline()
                    movClick(572, 501)
                    movClick(632, 436)
                    movClick(861, 506)
                    time.sleep(1)
                    movClick(861, 506)
                elif re.findall(r"tag=STEP value=FINAL_GAMEOVER", line):
                    time.sleep(3)
                    logLine = log.readline()
                    while logLine:
                        if re.findall(r"tag=STEP value=FINAL_GAMEOVER", logLine):
                            flagGameover += 1
                        logLine = log.readline()
                    flagGameover += 1
            else:
                time.sleep(1)
                flagTimesleep += 1
                if flagTimesleep % 30 == 0:
                    print(flagTimesleep/30)
            if flagTimesleep > 90:
                flagTimesleep = 0
                movClick(572, 501)
                movClick(632, 436)
                time.sleep(1)
                movClick(632, 436)
                movClick(861, 506)
                time.sleep(1)
                movClick(563, 514)
                movClick(708, 641)
                movClick(563, 514)
                movClick(708, 641)
                time.sleep(5)
                movClick(586, 512)
                movClick(511, 522)
                movClick(481, 514)
                movClick(455, 521)
                movClick(828, 650)
                movClick(828, 650, 0.1)
                time.sleep(3)
                movClick(861, 506)
                movClick(828, 650)
            if flagGameover >= 1:
                print("game over")
                return

if __name__ == '__main__':
    print(time.time())
    while True:
        time0= time.time()
        img = screenshot()
        res = compare(img)
        movClick(466, 460)
        time.sleep(1)
        movClick(828, 650)
        time.sleep(3)
        movClick(443, 453)
        movClick(828, 650)
        movClick(597, 553)
        movClick(828, 650)
        time.sleep(2)
        for _ in range(3):
            movClick(586, 512)
            movClick(511, 522)
            movClick(481, 514)
            movClick(455, 521)
            movClick(828, 650, 0.1)
            movClick(828, 650, 0.1)
            gaming()
            time.sleep(13)  # 1
            movClick(828, 650, 0.1)
            time.sleep(3)
            movClick(828, 650, 0.1)
            time.sleep(3)
            movClick(563, 514)
            movClick(708, 641)
            movClick(563, 514)
            movClick(708, 641)
            time.sleep(5)
        movClick(828, 650)
        movClick(565, 400)
        movClick(828, 650)
        gaming()
        time.sleep(13)
        movClick(828, 650, 0.1)
        time.sleep(3)
        movClick(828, 650, 0.1)
        time.sleep(13)
        movClick(828, 650, 0.1)
        movClick(510, 602, 0.2)
        movClick(650, 450, 0.2)
        movClick(782, 627, 0.2)
        movClick(510, 602, 0.2)
        movClick(650, 450, 0.2)
        movClick(782, 627, 0.2)
        time.sleep(2)
        movClick(654, 549)
        time.sleep(8)
        movClick(631, 647)
        time.sleep(7)
        print(str((time.time()-time0)/60.0)+"\tdone")


from itertools import combinations
import copy
def solution(n, info):
    answer = []
    answer_score = -55
    info = info[::-1]
    li = []
    apach_got = []

    for i in range(11):
        if info[i] > 0: apach_got.append(i)
        # (필요 화살, 점수)
        li.append((info[i] + 1, i))

    apach_score = sum(apach_got)

    for i in range(1, 12):
        combi = list(combinations(li, i))
        print(combi)

        for j in combi:
            lion_score = 0
            apa_score = apach_score
            summ = 0

            for num_n, score in j:
                summ += num_n

                if score in apach_got:
                    apa_score -= score

                lion_score += score

            if summ <= n and apa_score < lion_score:
                li_j = list(j)

                for _ in range(n - summ):
                    li_j.append((1, 0))

                if answer_score == lion_score:
                    answer.append(copy.deepcopy(li_j))

                elif answer_score < lion_score:
                    answer_score = lion_score
                    answer = [copy.deepcopy(li_j)]

    if len(answer) == 0: return [-1]

    new_answer = []

    for i in answer:
        a = [0] * 11
        for num_n, score in i:
            a[score] += num_n
        new_answer.append(a)
    new_answer.sort()
    return new_answer[-1][::-1]

solution(10, [0,0,0,0,0,0,0,0,3,4,3])


# import datetime
import random
People = []
Compliment = []
with open('People.txt') as f:
    for line in f:
        l = line.strip()
        People.append(l)

with open('Compliment.txt') as f:
    for line in f:
        l = line.strip()
        Compliment.append(l)
f.close()

input("Do you want a compliment? ")
C = random.randrange(26)
P = random.randrange(26)
print(People[P] + " " + Compliment[C])

# x = datetime.datetime.now()
# print()
# print("The date and time are:")
# print(str(x.day) + "/" + str(x.month) + "/" + str(x.year) + " at " + str(x.hour))


import logging
import os
import pickle
import random
import json

import numpy as np
import torch
import glob
import re
import shutil

try:
    from torch.utils.tensorboard import SummaryWriter
except:
    from tensorboardX import SummaryWriter

from torch import nn
from torch.distributions import Categorical
from torch.utils.data import DataLoader, Sampler, SequentialSampler, RandomSampler
from torch.utils.data.distributed import DistributedSampler

from collections import defaultdict, deque
from tqdm import tqdm, trange
from transformers import AdamW, get_linear_schedule_with_warmup
from apex import amp

from .util import set_seed, load_and_cache_examples
from .trainer import Trainer

logger = logging.getLogger(__name__)

class DomSampler(nn.Module):
    def __init__(self, model):
        super().__init__()
        self.domain_embedding = model.domain_cls.predictions.decoder
        self.sim_fn = nn.CosineSimilarity(-1)
        self.domain_cnts = defaultdict(int)

    def forward(self):
        with torch.no_grad():
            # laptop uses 0.1, restaurant uses 0.13
            tp = 0.1 # 0.13
            logits = self.sim_fn(self.domain_embedding.weight.data[0], self.domain_embedding.weight.data) / tp
            # logits = torch.matmul(self.domain_embedding.weight.data[0], self.domain_embedding.weight.data.transpose(1, 0))
            probs = torch.softmax(logits.float(), 0)
            self.sampler = Categorical(probs)

class DomainSampler(Sampler):
    def __init__(self, dataset, domain_sampler):
        self.domain_data_dict = defaultdict(list)
        for ex_idx, ex in enumerate(dataset):
            self.domain_data_dict[ex[0].item()].append(ex_idx)
        logger.info("total number of target domain examples: %s", str(len(self.domain_data_dict[0])))
        for domain_idx in self.domain_data_dict:
            random.shuffle(self.domain_data_dict[domain_idx])
        self.domain_sampler = domain_sampler
        self.domain_offsets = {key: 0 for key in self.domain_data_dict}

    def __iter__(self):
        ex_cnt = 0
        while ex_cnt < len(self.domain_data_dict[0]):
            domain_idx = self.domain_sampler.sampler.sample().item()
            while len(self.domain_data_dict[domain_idx]) == 0:
                domain_idx = self.domain_sampler.sampler.sample().item()
            self.domain_sampler.domain_cnts[domain_idx] += 1
            yield self.domain_data_dict[domain_idx][self.domain_offsets[domain_idx]]
            ex_cnt += 1
            self.domain_offsets[domain_idx] += 1
            if self.domain_offsets[domain_idx] >= len(self.domain_data_dict[domain_idx]):
                random.shuffle(self.domain_data_dict[domain_idx])
                self.domain_offsets[domain_idx] = 0

    def __len__(self):
        return len(self.domain_data_dict[0])

class DomTrainer(Trainer):
    def _build_train_data_loader(self, args, train_dataset, model):
        with open("data/pt/domain_tag/doi_domain.json") as f:
            domain_dict = json.load(f)
        self.id_to_domain = {domain_dict[domain]: domain for domain in domain_dict}

        self.meta_model = DomSampler(model)
        self.meta_model()

        self.train_sampler = DomainSampler(train_dataset, self.meta_model)
        train_dataloader = DataLoader(train_dataset, sampler=self.train_sampler, batch_size=args.train_batch_size)
        return self.train_sampler, train_dataloader

    def _post_step(self, args, outputs):
        # outputs: 0 is the total loss, 1 is the lm_loss, 2 is the domain_cls loss.
        if args.gradient_accumulation_steps > 1:
            lm_loss = outputs[1] / args.gradient_accumulation_steps
            domain_cls_loss = outputs[2] / args.gradient_accumulation_steps
        self.lm_loss += lm_loss.item()
        self.domain_cls_loss += domain_cls_loss.item()

    def _post_training(self):
        self.meta_model() # update the sampler

    def _init_logging(self):
        super()._init_logging()
        self.lm_loss, self.logging_lm_loss, self.domain_cls_loss, self.logging_domain_cls_loss = 0.0, 0.0, 0.0, 0.0

    def _train_writer(self, logging_steps):
        super()._train_writer(logging_steps)
        self.tb_writer.add_scalar("lm_loss", (self.lm_loss - self.logging_lm_loss)/logging_steps, self.global_step)
        self.tb_writer.add_scalar("domain_cls_loss", (self.domain_cls_loss - self.logging_domain_cls_loss)/logging_steps, self.global_step)
        self.logging_lm_loss = self.lm_loss
        self.logging_domain_cls_loss = self.domain_cls_loss

        cnt_rank = [self.id_to_domain[k]+": "+str(v) for k_id, (k, v) in enumerate(sorted(self.meta_model.domain_cnts.items(), key=lambda item: item[1], reverse=True)) if k_id < 30]
        logger.info("total sampled examples: %s", str(sum(list(self.meta_model.domain_cnts.values()))))
        logger.info("top-30 examples (domains : counts) \n%s\n", "\n".join(cnt_rank))
        self.meta_model.domain_cnts = defaultdict(int) # reset

        with torch.no_grad():
            probs, domain_ids = torch.topk(self.meta_model.sampler.probs, 30)
            domain_rank = [self.id_to_domain[domain_id.item()]+": "+str(float(probs[rank_id])) for rank_id, domain_id in enumerate(domain_ids)]
        logger.info("top-30 probs (domains: probs) \n%s\n", "\n".join(domain_rank))


# -*- coding: utf-8 -*-
import os
import time
import datetime
import xml.etree.ElementTree as ET
from caches import check_databases, clean_databases
from caches.trakt_cache import clear_trakt_list_contents_data
from apis.trakt_api import trakt_sync_activities
from modules import kodi_utils, settings
from modules.nav_utils import sync_MyAccounts
from modules.settings_reader import get_setting, set_setting, make_settings_dict

logger = kodi_utils.logger
ls, monitor, path_exists, translate_path, is_playing = kodi_utils.local_string, kodi_utils.monitor, kodi_utils.path_exists, kodi_utils.translate_path, kodi_utils.player.isPlaying
get_property, set_property, clear_property, get_visibility = kodi_utils.get_property, kodi_utils.set_property, kodi_utils.clear_property, kodi_utils.get_visibility

class InitializeDatabases:
	def run(self):
		logger('EZRA', 'InitializeDatabases Service Starting')
		check_databases()
		return logger('EZRA', 'InitializeDatabases Service Finished')

class CheckSettingsFile:
	def run(self):
		logger('EZRA', 'CheckSettingsFile Service Starting')
		clear_property('ezra_settings')
		profile_dir = translate_path('special://profile/addon_data/plugin.video.ezra/')
		if not path_exists(profile_dir): kodi_utils.make_directorys(profile_dir)
		settings_xml = translate_path('special://profile/addon_data/plugin.video.ezra/settings.xml')
		if not path_exists(settings_xml):
			__addon__ = kodi_utils.addon()
			addon_version = __addon__.getAddonInfo('version')
			__addon__.setSetting('version_number', addon_version)
			monitor.waitForAbort(0.5)
		make_settings_dict()
		set_property('ezra_kodi_menu_cache', get_setting('kodi_menu_cache'))
		return logger('EZRA', 'CheckSettingsFile Service Finished')

class SyncMyAccounts:
	def run(self):
		logger('EZRA', 'SyncMyAccounts Service Starting')
		sync_MyAccounts(silent=True)
		return logger('EZRA', 'SyncMyAccounts Service Finished')

class ReuseLanguageInvokerCheck:
	def run(self):
		logger('EZRA', 'ReuseLanguageInvokerCheck Service Starting')
		addon_xml = translate_path('special://home/addons/plugin.video.ezra/addon.xml')
		tree = ET.parse(addon_xml)
		root = tree.getroot()
		current_addon_setting = get_setting('reuse_language_invoker', 'true')
		refresh, text = True, '%s\n%s' % (ls(33021), ls(33020))
		for item in root.iter('reuselanguageinvoker'):
			if item.text == current_addon_setting: refresh = False; break
			item.text = current_addon_setting
			tree.write(addon_xml)
			break
		if refresh and kodi_utils.confirm_dialog(text=text): kodi_utils.execute_builtin('LoadProfile(%s)' % kodi_utils.get_infolabel('system.profilename'))
		return logger('EZRA', 'ReuseLanguageInvokerCheck Service Finished')

class ViewsSetWindowProperties:
	def run(self):
		logger('EZRA', 'ViewsSetWindowProperties Service Starting')
		kodi_utils.set_view_properties()
		return logger('EZRA', 'ViewsSetWindowProperties Service Finished')

class AutoRun:
	def run(self):
		logger('EZRA', 'AutoRun Service Starting')
		if settings.auto_start_ezra(): kodi_utils.execute_builtin('RunAddon(plugin.video.ezra)')
		return logger('EZRA', 'AutoRun Service Finished')

class DatabaseMaintenance:
	def run(self):
		time = datetime.datetime.now()
		current_time = self._get_timestamp(time)
		due_clean = int(get_setting('database.maintenance.due', '0'))
		if current_time >= due_clean:
			logger('EZRA', 'Database Maintenance Service Starting')
			monitor.waitForAbort(10)
			clean_databases(current_time, database_check=False, silent=True)
			next_clean = str(int(self._get_timestamp(time + datetime.timedelta(days=3))))
			set_setting('database.maintenance.due', next_clean)
			return logger('EZRA', 'Database Maintenance Service Finished')

	def _get_timestamp(self, date_time):
		return int(time.mktime(date_time.timetuple()))

class TraktMonitor:
	def run(self):
		logger('EZRA', 'TraktMonitor Service Starting')
		trakt_service_string = 'TraktMonitor Service Update %s - %s'
		update_string = 'Next Update in %s minutes...'
		if not kodi_utils.get_property('ezra_traktmonitor_first_run') == 'true':
			clear_trakt_list_contents_data('user_lists')
			kodi_utils.set_property('ezra_traktmonitor_first_run', 'true')
		while not monitor.abortRequested():
			while is_playing() or get_visibility('Container().isUpdating') or get_property('ezra_pause_services') == 'true': monitor.waitForAbort(10)
			if not kodi_utils.get_property('ezra_traktmonitor_first_run') == 'true': monitor.waitForAbort(5)
			value, interval = settings.trakt_sync_interval()
			next_update_string = update_string % value
			status = trakt_sync_activities()
			if status == 'success':
				logger('EZRA', trakt_service_string % ('EZRA TraktMonitor - Success', 'Trakt Update Performed'))
				if settings.trakt_sync_refresh_widgets():
					kodi_utils.widget_refresh()
					logger('EZRA', trakt_service_string % ('EZRA TraktMonitor - Widgets Refresh', 'Setting Activated. Widget Refresh Performed'))
				else: logger('EZRA', trakt_service_string % ('EZRA TraktMonitor - Widgets Refresh', 'Setting Disabled. Skipping Widget Refresh'))
			elif status == 'no account':
				logger('EZRA', trakt_service_string % ('EZRA TraktMonitor - Aborted. No Trakt Account Active', next_update_string))
			elif status == 'failed':
				logger('EZRA', trakt_service_string % ('EZRA TraktMonitor - Failed. Error from Trakt', next_update_string))
			else:# 'not needed'
				logger('EZRA', trakt_service_string % ('EZRA TraktMonitor - Success. No Changes Needed', next_update_string))
			monitor.waitForAbort(interval)
		return logger('EZRA', 'TraktMonitor Service Finished')


import pygame
from random import choice

#pygame alustus
pygame.init()
naytto = pygame.display.set_mode((640, 480))
kello = pygame.time.Clock()
naytto_r = 30
naytto_g = 30
naytto_b = 30
#kuvat
robo = pygame.image.load("robo.png")
hirviokuva = pygame.image.load("hirvio.png")
tele_kuva = pygame.image.load("ovi.png")
kolikko_kuva = pygame.image.load("kolikko.png")

#koordinaatit
robo_x = 320-robo.get_width()
robo_y = 240-robo.get_height()

hiiri_x = 0
hiiri_y = 0

tele_x1 = -100
tele_y1 = -100
tele_x2 = -100
tele_y2 = -100

kolikko_x = 0
kolikko_y = 0

#satunnaiskoordinaatit
randomkipina = [-5,-1,1,2,-2,0,5,]

class Perks:
    perk_list = []
    laser_bounce = ["Laser Bounce",50,1,"Laser Bounces Once"]
    laser_explosion = ["Explosive Laser",50,2,"Targets Explode"]
    vampire_laser = ["Bravery Laser",50,3,"Laser Lowers Spook"]
    teleport_vacuum = ["Vacuum Teleport",50,4,"Teleport Destroys Ghosts"]
    combo_boost = ["Combo Boost",50,5,"Combo Increases Attributes"]
    saldo = ["Coins available",None,None]
    perk_list.append(laser_bounce)
    perk_list.append(laser_explosion)
    perk_list.append(vampire_laser)
    perk_list.append(teleport_vacuum)
    perk_list.append(combo_boost)
    perk_list.append(saldo)

#päivityksiä
class Upgrades:
    upgrade_list = []
    laser_damage = ["Laser Damage",1,1]
    nopeus_upgrade = ["Robo-Speed",1,2]
    energia_kulutus_upgrade = ["Battery Efficiency",1,3]
    patteri_overcharge = ["Battery Over-charge",1,4]
    patteri_recharge = ["Battery recharge speed",1,5]
    combo_upgrade = ["Maximum Combo Upgrade",1,6]
    saldo = ["Coins available",None,None]
    upgrade_list.append(laser_damage)
    upgrade_list.append(nopeus_upgrade)
    upgrade_list.append(energia_kulutus_upgrade)
    upgrade_list.append(patteri_overcharge)
    upgrade_list.append(patteri_recharge)
    upgrade_list.append(combo_upgrade)

    upgrade_list.append(saldo)

#attribuutteja
class Attributes:
    suurin_combo = 0
    maximi_combo = 4
    maximi_patteri = 100
    patteri = 100
    laser_teho = 1
    energia_kulutus = 0.7
    robo_spook = 0
    robo_nopeus = 1.5
    pisteet = 0
    manaukset = 0
    kolikot = 0
    kolikkoja_keratty = 0
    robo_lataus_nopeus = 1
    reboot_nopeus = 1
    tele_energia = 25
    tele_kesto = 4
    kolikko_haavi = 1

#taso
taso = 1

#hirvioita
hirvio_hp = 100
hirvio_suunta = 1
hirvio_nopeus = 1
hirvio_nopeus_variaatio = [1,1.1,1.2,1.3,1.4,1.5]
hirviolista = []
hirviomaara = 10
suunnat = [1,2,3,4]

#totuusarvot
virta_paalla = True
oikealle = False
vasemmalle = False
alas = False
ylos = False
laser = False
palojalki = False
palojaljet = []
paloajastin = 1
kipinat = False
teleport = False
kolikko = False
kolikko_pelissa = False
isommaksi = True
pienemmaksi = False
isommaksi_g = True
pienemmaksi_g = False
isommaksi_b = True
pienemmaksi_b = False
intro = False
#perks
bounce = False
vampire = False
vacuum = False
boost = False
explosion = False
#ajastimet
tele_ajastin = 2
kolikko_ajastin = 0
combo = 0

def start_game():
    r = 254
    g = 254
    b = 254
    for i in range(640):

            pygame.draw.line(naytto, (r, g, b), (i,0), (i, 480), 1)
            if r> 1:
                r-=1
            if r<= 1 and g>1:
                g-=1
            if g<2:
                b-=1
    while True:
        for tapahtuma in pygame.event.get():
            if tapahtuma.type == pygame.QUIT:
                quit()
            if tapahtuma.type == pygame.KEYDOWN:

                return
        fontti = pygame.font.SysFont("Futura", 100)
        fontti2 = pygame.font.SysFont("Futura", 90)
        fontti3 = pygame.font.SysFont("Futura", 20)
        teksti = "ROBO-EXORCIST"
        teksti2 = "ROBO-EXORCIST"
        teksti3 = "Manaa kummituksia ja kerää kolikoita"
        teksti4 = "Kerrytät comboa kunnes kummitus osuu robottiin tai kolikko valuu ohi"
        teksti5 = "Combo vaikuttaa pisteisiin ja rahaan"
        teksti6 = "Käytä rahaa robotin päivittämiseksi"
        teksti7 = "Paina näppäintä aloittaaksesi"
        teksti = fontti.render(teksti, True, (0, 0, 0))
        teksti2 = fontti2.render(teksti2, True, (255, 255, 255))
        teksti3 = fontti3.render(teksti3, True, (0, 0, 0))
        teksti4 = fontti3.render(teksti4, True, (0, 0, 0))
        teksti5 = fontti3.render(teksti5, True, (0, 0, 0))
        teksti6 = fontti3.render(teksti6, True, (0, 0, 0))
        teksti7 = fontti3.render(teksti7, True, (0, 0, 0))
        pygame.draw.rect(naytto, (255, 255, 255), ((320-teksti4.get_width()/2, 180, 445,100)))
        naytto.blit(teksti, (320-teksti.get_width()/2, 100))
        naytto.blit(teksti2, (320-teksti2.get_width()/2, 100))
        naytto.blit(teksti3, (320-teksti3.get_width()/2, 180))
        naytto.blit(teksti4, (320-teksti4.get_width()/2, 200))
        naytto.blit(teksti5, (320-teksti5.get_width()/2, 220))
        naytto.blit(teksti6, (320-teksti6.get_width()/2, 240))
        naytto.blit(teksti7, (320-teksti7.get_width()/2, 260))
        pygame.display.flip()
        kello.tick(60)

def game_over():
    r = 1
    g = 1
    b = 1
    for i in range(640):

            pygame.draw.line(naytto, (r, g, b), (i,0), (i, 480), 1)
            if r< 255:
                r+=1
            if r>= 254 and g<254:
                g+=1
            if g>=254:
                b+=1
    while True:
        for tapahtuma in pygame.event.get():
            if tapahtuma.type == pygame.QUIT:
                quit()
            if tapahtuma.type == pygame.KEYDOWN:
                quit()
        fontti = pygame.font.SysFont("Futura", 100)
        fontti2 = pygame.font.SysFont("Futura", 90)
        fontti3 = pygame.font.SysFont("Futura", 30)
        teksti = "GAME OVER"
        teksti2 = "GAME OVER"
        teksti3 = f"You scored {int(Attributes.pisteet)} points!"
        teksti4 = f"You exorsized {Attributes.manaukset} ghosts!"
        teksti5 = f"You collected {Attributes.kolikkoja_keratty} coins!"
        teksti6 = f"Your best combo was {Attributes.suurin_combo}!"
        teksti = fontti.render(teksti, True, (0, 0, 0))
        teksti2 = fontti2.render(teksti2, True, (255, 255, 255))
        teksti3 = fontti3.render(teksti3, True, (0, 0, 0))
        teksti4 = fontti3.render(teksti4, True, (0, 0, 0))
        teksti5 = fontti3.render(teksti5, True, (0, 0, 0))
        teksti6 = fontti3.render(teksti6, True, (0, 0, 0))
        naytto.blit(teksti, (320-teksti.get_width()/2, 240))
        naytto.blit(teksti2, (320-teksti2.get_width()/2, 240))
        naytto.blit(teksti3, (320-teksti3.get_width()/2, 300))
        naytto.blit(teksti4, (320-teksti3.get_width()/2, 330))
        naytto.blit(teksti5, (320-teksti3.get_width()/2, 360))
        naytto.blit(teksti6, (320-teksti3.get_width()/2, 390))
        pygame.display.flip()
        kello.tick(60)
def perks():

        fontti = pygame.font.SysFont("Futura", 48)
        teksti = f"ROBO-PERKS"
        kauppa_teksti = fontti.render(teksti, True, (255, 15, 15))
        naytto.fill((0, 0, 0))
        naytto.blit(kauppa_teksti, (320-kauppa_teksti.get_width()/2, 0))
        upgrade_ohjeet = []
        for i in (Perks.perk_list):
            upgrade_nimi = i[0]
            upgrade_taso = i[1]
            upgrade_nappula = i[2]
            upgrade_ohje_alku = "OPTION ["
            upgrade_ohje_keski = "COST ["
            upgrade_ohje_loppu ="€] PRESS TO UNLOCK-->"
            upgrade_ohje_koko = upgrade_ohje_alku+upgrade_nimi+"]"+" "*(25-len(upgrade_nimi))+upgrade_ohje_keski+str(upgrade_taso)+upgrade_ohje_loppu +str(upgrade_nappula)
            if upgrade_taso == None:
                upgrade_ohje_koko = f"WORK IN PROGRESS, SORRY! PRESS (U) for Upgrades"
            upgrade_ohjeet.append(upgrade_ohje_koko)
        for i in range(len(upgrade_ohjeet)):
            fontti = pygame.font.SysFont("Futura", 24)
            upgrade_ohje_teksti = fontti.render(upgrade_ohjeet[i], True, (248,248,255))
            if i+1 == len(upgrade_ohjeet):
                fontti = pygame.font.SysFont("Futura", 36)
                upgrade_ohje_teksti = fontti.render(upgrade_ohjeet[i], True, (248,50,255))
            naytto.blit(upgrade_ohje_teksti, (0,30*(i+1)))

def upgrades():
        fontti = pygame.font.SysFont("Futura", 48)
        teksti = f"ROBO-UPGRADES"
        kauppa_teksti = fontti.render(teksti, True, (255, 15, 15))
        naytto.fill((0, 0, 0))
        naytto.blit(kauppa_teksti, (320-kauppa_teksti.get_width()/2, 0))
        upgrade_ohjeet = []
        for i in (Upgrades.upgrade_list):
            upgrade_nimi = i[0]
            upgrade_taso = i[1]
            upgrade_nappula = i[2]
            upgrade_ohje_alku = "OPTION ["
            upgrade_ohje_keski = "COST ["
            upgrade_ohje_loppu ="€] PRESS TO UPGRADE-->"
            upgrade_ohje_koko = upgrade_ohje_alku+upgrade_nimi+"]"+" "*(25-len(upgrade_nimi))+upgrade_ohje_keski+str(upgrade_taso)+upgrade_ohje_loppu +str(upgrade_nappula)
            if upgrade_taso == None:
                upgrade_ohje_koko = f"Money available: [{Attributes.kolikot}€] PRESS (P) for perks"
            upgrade_ohjeet.append(upgrade_ohje_koko)
        for i in range(len(upgrade_ohjeet)):
            fontti = pygame.font.SysFont("Futura", 24)
            upgrade_ohje_teksti = fontti.render(upgrade_ohjeet[i], True, (248,248,255))
            if i+1 == len(upgrade_ohjeet):
                fontti = pygame.font.SysFont("Futura", 36)
                upgrade_ohje_teksti = fontti.render(upgrade_ohjeet[i], True, (248,50,255))
            naytto.blit(upgrade_ohje_teksti, (0,30*(i+1)))

def kauppa():
    fontti = pygame.font.SysFont("Futura", 48)
    teksti = f"ROBO-SHOP"
    kauppa_teksti = fontti.render(teksti, True, (255, 15, 15))
    naytto.fill((0, 0, 0))
    naytto.blit(kauppa_teksti, (320-kauppa_teksti.get_width()/2, 0))
    upgrades()
    while True:
        for tapahtuma in pygame.event.get():
            if tapahtuma.type == pygame.QUIT:
                return
            if tapahtuma.type == pygame.KEYDOWN:
                if tapahtuma.key == pygame.K_ESCAPE or tapahtuma.key == pygame.K_TAB:
                    return
            if tapahtuma.type == pygame.KEYDOWN:
                pygame.display.flip()
                kello.tick(60)
                if tapahtuma.key == pygame.K_1 and Attributes.kolikot>=Upgrades.laser_damage[1]:
                    Attributes.kolikot -= Upgrades.laser_damage[1]
                    Upgrades.laser_damage[1]+=1
                    Attributes.laser_teho += 0.2
                    upgrades()
                if tapahtuma.key == pygame.K_2 and Attributes.kolikot>=Upgrades.nopeus_upgrade[1]:
                    Attributes.kolikot -= Upgrades.nopeus_upgrade[1]
                    Upgrades.nopeus_upgrade[1]+=1
                    Attributes.robo_nopeus += 0.2
                    upgrades()
                if tapahtuma.key == pygame.K_3 and Attributes.kolikot>=Upgrades.energia_kulutus_upgrade[1]:
                    Attributes.kolikot -= Upgrades.energia_kulutus_upgrade[1]
                    Upgrades.energia_kulutus_upgrade[1]+=1
                    Attributes.energia_kulutus *= 0.95
                    upgrades()
                if tapahtuma.key == pygame.K_4 and Attributes.kolikot>=Upgrades.patteri_overcharge[1]:
                    Attributes.kolikot -= Upgrades.patteri_overcharge[1]
                    Upgrades.patteri_overcharge[1]+=1
                    Attributes.maximi_patteri += 2
                    upgrades()
                if tapahtuma.key == pygame.K_5 and Attributes.kolikot>=Upgrades.patteri_recharge[1]:
                    Attributes.kolikot -= Upgrades.patteri_recharge[1]
                    Upgrades.patteri_recharge[1]+=1
                    Attributes.robo_lataus_nopeus += 0.2
                    upgrades()
                if tapahtuma.key == pygame.K_6 and Attributes.kolikot>=Upgrades.combo_upgrade[1]:
                    Attributes.kolikot -= Upgrades.combo_upgrade[1]
                    Upgrades.combo_upgrade[1]+=1
                    Attributes.maximi_combo += 2
                    upgrades()
                if tapahtuma.key == pygame.K_p:
                    naytto.fill((0, 0, 0))
                    perks()
                if tapahtuma.key == pygame.K_u:
                    naytto.fill((0, 0, 0))
                    upgrades()

        pygame.display.flip()
        kello.tick(60)
#tapahtumia
while True:
    if intro == False:
        start_game()
        intro = True
    for tapahtuma in pygame.event.get():
        if tapahtuma.type == pygame.MOUSEMOTION:
            hiiri_x = tapahtuma.pos[0]
            hiiri_y = tapahtuma.pos[1]
            if palojalki == True:
                if (hiiri_x,hiiri_y,paloajastin) not in palojaljet:
                    palojaljet.append([hiiri_x,hiiri_y,paloajastin])

        if tapahtuma.type == pygame.MOUSEBUTTONDOWN:
            if Attributes.patteri > 0:
                palojalki = True
                kipinat = True
                laser = True

        if tapahtuma.type == pygame.MOUSEBUTTONUP:
            laser = False
            palojalki = False
            kipinat = False
        if tapahtuma.type == pygame.KEYDOWN:
            if tapahtuma.key == pygame.K_a:
                vasemmalle = True
            if tapahtuma.key == pygame.K_d:
                oikealle = True
            if tapahtuma.key == pygame.K_w:
                ylos = True
            if tapahtuma.key == pygame.K_s:
                alas = True

            if tapahtuma.key == pygame.K_SPACE:
                if Attributes.patteri > Attributes.tele_energia:
                    teleport = True
                    Attributes.patteri -= 50
                    tele_x1 = hiiri_x-(tele_kuva.get_width()/2)
                    tele_y1 = hiiri_y-(tele_kuva.get_height()/2)
                    tele_x2 = robo_x
                    tele_y2 = robo_y

            if tapahtuma.key == pygame.K_ESCAPE or tapahtuma.key == pygame.K_TAB:
                kauppa()
        if tapahtuma.type == pygame.KEYUP:
            if tapahtuma.key == pygame.K_a:
                vasemmalle = False
            if tapahtuma.key == pygame.K_d:
                oikealle = False
            if tapahtuma.key == pygame.K_w:
                ylos = False
            if tapahtuma.key == pygame.K_s:
                alas = False

        if tapahtuma.type == pygame.QUIT:
            exit()

    if oikealle and virta_paalla:
        if robo_x < 640-robo.get_width():
            robo_x += 0.8*Attributes.robo_nopeus
    if vasemmalle and virta_paalla:
        if robo_x > 0:
            robo_x -= 0.8*Attributes.robo_nopeus
    if alas and virta_paalla:
        if robo_y < 480-robo.get_height():
            robo_y += 0.8*Attributes.robo_nopeus
    if ylos and virta_paalla:
        if robo_y > 0:
            robo_y -= 0.8*Attributes.robo_nopeus

    #näytön piirto
    naytto.fill((naytto_r, naytto_g, naytto_b))#tausta

    fontti = pygame.font.SysFont("Futura", 24)#tekstit
    fontti2 = pygame.font.SysFont("Futura", 48)
    score = f"Battery depleted, rebooting..."
    Attributes.patteri_teksti = fontti.render(score, True, (255, 15, 15))
    if Attributes.patteri > 50:
        score = f"Battery: {int(Attributes.patteri)}%"
        Attributes.patteri_teksti = fontti.render(score, True, (34, 139, 13))
    elif Attributes.patteri > 0:
        score = f"Battery: {int(Attributes.patteri)}%"
        Attributes.patteri_teksti = fontti.render(score, True, (255, 215, 0))

    if Attributes.robo_spook < 50:
        spookmeter = f"Spook-O-meter: {int(Attributes.robo_spook)}%"
        spook_teksti = fontti.render(spookmeter, True, (128, 3, 3))
    elif Attributes.robo_spook >= 50 and Attributes.robo_spook<90:
        spookmeter = f"Spook-O-meter: {int(Attributes.robo_spook)}% WARNING: SCARY!"
        spook_teksti = fontti.render(spookmeter, True, (128, 3, 3))
    else:
        spookmeter = f"Spook-O-meter: {int(Attributes.robo_spook)}% WARNING: EXTREME SPOOK LEVELS DETECTED!"
        spook_teksti = fontti.render(spookmeter, True, (128, 3, 3))

    pistestring = f"{int(Attributes.pisteet)}"
    piste_teksti1 = fontti.render(pistestring, True, (245,255,250))
    pistestring2 = f"Points:"
    piste_teksti2 = fontti.render(pistestring2, True, (245,255,250))

    kolikkostring = f"{str(Attributes.kolikot)} €"
    kolikko_teksti = fontti2.render(kolikkostring, True, (245,255,250))

    combostring = f"Combo {combo}x!"
    combo_teksti = fontti.render(combostring, True, (245,255,250))

    ohje1 = "MOVE: WASD or Arrowkeys"
    ohje_teksti1 = fontti.render(ohje1, True, (0,245,255))
    ohje2 = "LASER: MOUSE"
    ohje_teksti2 = fontti.render(ohje2, True, (0,245,255))
    ohje3 = "TELEPORT: SPACEBAR"
    ohje_teksti3 = fontti.render(ohje3, True, (0,245,255))
    ohje4 = "SHOP: TAB or ESC"
    ohje_teksti4 = fontti.render(ohje4, True, (0,245,255))

    #info & ohjeet
    pygame.draw.rect(naytto, (0, 0, 100), (0, 0, 640,0+kolikko_kuva.get_height()))

    pygame.draw.rect(naytto, (0, 0, 100), (420, 410, 640,480))
    pygame.draw.rect(naytto, (0, 255, 0), (0, 480-kolikko_kuva.get_height(), 150,480-kolikko_kuva.get_height()))
    naytto.blit(kolikko_kuva, (0, 480-kolikko_kuva.get_height()))
    naytto.blit(kolikko_teksti, (kolikko_kuva.get_width()+8,480-kolikko_teksti.get_height()))
    naytto.blit(spook_teksti, (0, 20))
    naytto.blit(Attributes.patteri_teksti, (0, 0))
    if combo>1:
        naytto.blit(combo_teksti,(640-combo_teksti.get_width(),20))
    naytto.blit(ohje_teksti1, (640-ohje_teksti1.get_width(),480-ohje_teksti1.get_height()))
    naytto.blit(ohje_teksti2, (640-ohje_teksti2.get_width(),480-(ohje_teksti2.get_height()*2)))
    naytto.blit(ohje_teksti3, (640-ohje_teksti3.get_width(),480-(ohje_teksti2.get_height()*3)))
    naytto.blit(ohje_teksti4, (640-ohje_teksti4.get_width(),480-(ohje_teksti2.get_height()*4)))
    naytto.blit(piste_teksti1, (640-piste_teksti1.get_width(),0))
    naytto.blit(piste_teksti2, (520,0))

    suunta = choice(suunnat)

    if teleport:
        naytto.blit(tele_kuva,(tele_x1,tele_y1))
        naytto.blit(tele_kuva,(tele_x2,tele_y2))
        tele_ajastin -= 0.01*Attributes.tele_kesto
        if tele_ajastin < 0:
            teleport = False
            tele_ajastin = 1
    if abs(tele_x1-robo_x) < 5 and abs(tele_y1-robo_y) < 5 and teleport:
        if vasemmalle:
            robo_x = tele_x2-10
            robo_y = tele_y2
        if oikealle:
            robo_x = tele_x2+10
            robo_y = tele_y2
        if alas:
            robo_x = tele_x2
            robo_y = tele_y2+10
        if ylos:
            robo_x = tele_x2
            robo_y = tele_y2-10
    if abs(tele_x2-robo_x) < 5 and abs(tele_y2-robo_y) < 5 and teleport:
        if vasemmalle:
            robo_x = tele_x1-10
            robo_y = tele_y1
        if oikealle:
            robo_x = tele_x1+10
            robo_y = tele_y1
        if alas:
            robo_x = tele_x1
            robo_y = tele_y1+10
        if ylos:
            robo_x = tele_x1
            robo_y = tele_y1-10

    if len(hirviolista)< hirviomaara and suunta==1 or taso == 1 and len(hirviolista)<hirviomaara:
        hirvio_x = [number-hirviokuva.get_width() for number in range(641)]
        hirvio_y = [-number for number in range(50,400)]
        hirvio_suunta_x = 0
        hirvio_suunta_y = 1
        ylahirvio = [choice(hirvio_x),choice(hirvio_y),hirviokuva,hirvio_hp,hirvio_suunta_x,hirvio_suunta_y,hirvio_nopeus*choice(hirvio_nopeus_variaatio)]
        hirviolista.append(ylahirvio)
    if len(hirviolista)<hirviomaara and taso >= 2 and suunta==2:
        hirvio_x = [number-hirviokuva.get_width() for number in range(641)]
        hirvio_y = [number+530 for number in range(100)]
        hirvio_suunta_x = 0
        hirvio_suunta_y = -1
        alahirvio = [choice(hirvio_x),choice(hirvio_y),hirviokuva,hirvio_hp,hirvio_suunta_x,hirvio_suunta_y,hirvio_nopeus*choice(hirvio_nopeus_variaatio)]
        hirviolista.append(alahirvio)
    if len(hirviolista)<hirviomaara and taso >= 3 and suunta==3:
        hirvio_x = [number+690 for number in range(100)]
        hirvio_y = [number-hirviokuva.get_height() for number in range(481)]
        hirvio_suunta_x = -1
        hirvio_suunta_y = 0
        vasenhirvio = [choice(hirvio_x),choice(hirvio_y),hirviokuva,hirvio_hp,hirvio_suunta_x,hirvio_suunta_y,hirvio_nopeus*choice(hirvio_nopeus_variaatio)]
        hirviolista.append(vasenhirvio)
    if len(hirviolista)<hirviomaara and taso >= 4 and suunta==4:
        hirvio_x = [-number for number in range(50,300)]
        hirvio_y = [number-hirviokuva.get_height() for number in range(50,590)]
        hirvio_suunta_x = 1
        hirvio_suunta_y = 0
        oikeahirvio = [choice(hirvio_x),choice(hirvio_y),hirviokuva,hirvio_hp,hirvio_suunta_x,hirvio_suunta_y,hirvio_nopeus*choice(hirvio_nopeus_variaatio)]
        hirviolista.append(oikeahirvio)

    naytto.blit(robo, (robo_x, robo_y)) #pelaaja

    for hirvio in hirviolista:
        naytto.blit(hirvio[2], (hirvio[0], hirvio[1]))
        if hirvio[5]==-1 and hirvio[1] < -30:
            hirviolista.remove(hirvio)
        if hirvio[5]==1 and hirvio[1] > 510:
            hirviolista.remove(hirvio)
        if hirvio[4]==-1 and hirvio[0] < -30:
            hirviolista.remove(hirvio)
        if hirvio[4]==1 and hirvio[0] > 670:
            hirviolista.remove(hirvio)

        hirvio[1]+=hirvio[5]*hirvio[6]
        hirvio[0]+=hirvio[4]*hirvio[6]

        if abs((hirvio[0]+(hirviokuva.get_width()/2))-(hiiri_x)) < 20 and abs((hirvio[1]+(hirviokuva.get_height()/2))-(hiiri_y)) < 20 and laser:
            hirvio[3]-= 5*Attributes.laser_teho
        if hirvio[3]<0: #hirvion tuhoaminen
            Attributes.pisteet += 1+1*combo
            Attributes.manaukset += 1
            if combo < Attributes.maximi_combo:
                combo += 1
            hirviolista.remove(hirvio)

        if abs((hirvio[0]+(hirviokuva.get_width()/2))-(robo_x+(robo.get_width()/2))) < 30 and abs((hirvio[1]+(hirviokuva.get_height()/2))-(robo_y+(robo.get_height()/2))) < 30:
            if combo > Attributes.suurin_combo:
                Attributes.suurin_combo = combo
            combo = 0
            hirvio[0] = robo_x
            hirvio[1] = robo_y
            Attributes.robo_spook += 0.5
        if Attributes.robo_spook > 100:
            game_over()

    if laser:
        pygame.draw.line(naytto, (238, 0, 0), (robo_x+15, robo_y+15), (hiiri_x, hiiri_y), 2)
        pygame.draw.line(naytto, (238, 0, 0), (robo_x+30, robo_y+15), (hiiri_x+15, hiiri_y), 2)
        Attributes.patteri -= 1.5*Attributes.energia_kulutus
        if Attributes.patteri <= 0:
            virta_paalla = False
            laser = False
            kipinat = False
            palojalki = False
            Attributes.patteri = -20
    if kipinat:
        for i in range(3):
            pygame.draw.line(naytto, (248,248,255), (hiiri_x, hiiri_y), (hiiri_x+choice(randomkipina), hiiri_y+choice(randomkipina)), 1)
            pygame.draw.line(naytto, (248,248,255), (hiiri_x+15, hiiri_y), (hiiri_x+15+choice(randomkipina), hiiri_y+choice(randomkipina)), 1)
    for jalki in palojaljet:
        if jalki[2]<=0:
            palojaljet.remove(jalki)
        pygame.draw.circle(naytto, (40, 40, 40), (jalki[0], jalki[1]), 5)
        pygame.draw.circle(naytto, (40, 40, 40), (jalki[0]+15, jalki[1]), 5)
        jalki[2] -= 0.05

    if kolikko:
        if kolikko_pelissa == False:
            kolikko_x = choice([number-kolikko_kuva.get_width() for number in range(30,610)])
            kolikko_y = -100
            kolikko_pelissa = True
        naytto.blit(kolikko_kuva,(kolikko_x,kolikko_y))
        kolikko_y += 1
    if abs(kolikko_x-robo_x) < 30*Attributes.kolikko_haavi and abs(kolikko_y-robo_y) < 30*Attributes.kolikko_haavi and kolikko:
        Attributes.kolikkoja_keratty += 1
        if combo >= 1:
            Attributes.kolikot += 1*combo
        elif combo == 0:
            Attributes.kolikot += 1
        Attributes.pisteet += 50
        kolikko = False
        kolikko_pelissa = False
        if combo < Attributes.maximi_combo:
            combo += 1
    if kolikko_y >500:
        kolikko = False
        kolikko_pelissa = False
        combo = 0
    #attribuuttimuutokset
    if Attributes.patteri < Attributes.maximi_patteri and laser == False and virta_paalla== True:
        Attributes.patteri += 0.2*Attributes.robo_lataus_nopeus
    if virta_paalla == False:
        Attributes.patteri += 0.2*Attributes.reboot_nopeus
    if Attributes.patteri > 0:
        virta_paalla = True

    if Attributes.robo_spook>0:
        Attributes.robo_spook -=0.01
    if kolikko_ajastin > 0 and kolikko == False:
        kolikko_ajastin -= 0.01
    if kolikko_ajastin <= 0:
        kolikko = True
        kolikko_ajastin = 1
    Attributes.pisteet += 0.01*combo

    if Attributes.pisteet < 100:
        hirviomaara = 5
        taso = 1
    elif Attributes.pisteet > 200 and Attributes.pisteet < 500:
        hirviomaara = 8
        taso = 2
    elif Attributes.pisteet > 500 and Attributes.pisteet < 1000:
        hirviomaara = 11
        taso = 3
    elif Attributes.pisteet > 1000:
        hirviomaara = 12
        taso = 4
    if Attributes.pisteet > 10000:
        hirvio_nopeus += Attributes.pisteet/100000
    if Attributes.pisteet > 10000:
        hirviomaara += Attributes.pisteet/10000

    pygame.display.update()
    if naytto_r < 255 and isommaksi:
        naytto_r +=0.01*combo
    if naytto_r == 255:
        pienemmaksi = True
        isommaksi = False
    if naytto_r > 0 and pienemmaksi:
        naytto_r -=0.01*combo
    if naytto_r == 0:
        pienemmaksi = False
        isommaksi = True

    if naytto_g < 255 and isommaksi_g:
        naytto_g +=0.005*combo
    if naytto_g > 254:
        pienemmaksi_g = True
        isommaksi_g = False
    if naytto_g > 0 and pienemmaksi_g:
        naytto_g -=0.005*combo
    if naytto_g < 1:
        pienemmaksi_g = False
        isommaksi_g = True

    if naytto_b< 255 and isommaksi_b:
        naytto_b+=0.0125*combo
    if naytto_b> 254:
        pienemmaksi_b= True
        isommaksi_b= False
    if naytto_b> 1 and pienemmaksi_b:
        naytto_b-=0.0125*combo
    if naytto_b< 0 and pienemmaksi_b:
        pienemmaksi_b= False
        isommaksi_b= True

    kello.tick(60)


import librosa, librosa.display
import matplotlib.pyplot as plt
import glob,os
import numpy as np
from scipy.ndimage.interpolation import shift
import warnings
import cv2 as cv
import pandas as pd

class Data_augmentation:
    def __init__(self,labels,root_path='./data/dataset_aug/'):
        super(Data_augmentation, self).__init__()

        self.root_path = root_path
        self.labels = labels
        self.folders = ['images/time','images/mel']
        self.dir_v1 = './data/dataset_v1/audio/'

        self.cnt = 0

    # Generate aug folders
    def make_aug_folders(self,status=False):
        try:
            if status == True:
                for folder in self.folders:
                    for label in self.labels:
                        os.makedirs(os.path.join(self.root_path,folder,label))
                print("Complete folders generation")
        except:
            print("You already have folders")

    # Data Augmentation methods
    def m_Scaling(self,X,f_range_1=0.5, f_range_2=2.0):
        X = np.expand_dims(X,axis=1)
        scalingFactor = np.random.uniform(low=f_range_1, high=f_range_2, size=(1,X.shape[1]))
        myNoise = np.matmul(np.ones((X.shape[0],1)), scalingFactor)
        scaled_X = np.squeeze(X*myNoise,axis=1)
        return scaled_X

    def m_Jitter(self,X,low=0,high=0.01):
        sigma = np.random.uniform(low, high)
        myNoise = np.random.normal(loc=0, scale=sigma, size=X.shape)
        return X+myNoise

    def m_Shifting(self,X,range_1=-300,range_2=1000):
        shift_inv = np.random.randint(range_1,range_2)
        fill_time_noise = np.random.normal(loc=0, scale=0.003, size=abs(shift_inv))
        shift_X = shift(X, shift_inv, cval=np.nan)
        where_nan = np.isnan(shift_X)
        shift_X[where_nan] = fill_time_noise
        return shift_X

    def data_aug(self,sound_samples, label, n):
        aug_samples = []
        cnt = 0
        for i in range(n):
            if label == 'OH':
                Sc_sound_samples = self.m_Scaling(sound_samples,0.5,2.0)
                J_sound_samples = self.m_Jitter(Sc_sound_samples,0,0.01)
                ch_sound_samples = J_sound_samples
            elif label == 'CH' or label == 'R':
                Sc_sound_samples = self.m_Scaling(sound_samples,0.2,1.5)
                J_sound_samples = self.m_Jitter(Sc_sound_samples,0,0.03)
                ch_sound_samples = J_sound_samples
            elif label == 'rest':
                Sc_sound_samples = self.m_Scaling(sound_samples,0.5,2.0)
                J_sound_samples = self.m_Jitter(Sc_sound_samples,0,0.01)
                Sh_sound_samples = self.m_Shifting(J_sound_samples,-1000,0)
                ch_sound_samples = Sh_sound_samples
            elif label == 'B+CH' or label == 'B' or label == 'B+OH' or label == 'B+R':
                Sc_sound_samples = self.m_Scaling(sound_samples,1.5,2.5)
                J_sound_samples = self.m_Jitter(Sc_sound_samples,0,0.01)
                Sh_sound_samples = self.m_Shifting(J_sound_samples,-300,1000)
                ch_sound_samples = Sh_sound_samples
            else:
                Sc_sound_samples = self.m_Scaling(sound_samples,0.5,2.0)
                J_sound_samples = self.m_Jitter(Sc_sound_samples,0,0.01)
                Sh_sound_samples = self.m_Shifting(J_sound_samples,-300,1000)
                ch_sound_samples = Sh_sound_samples
            aug_samples.append(ch_sound_samples)
        return aug_samples

    def export_data(self,aug_n,label_n):
        label = self.labels[label_n]
        s_dir = os.path.join(self.dir_v1,label)
        for s in os.listdir(s_dir):
            sample_dir = os.path.join(s_dir,s)
            sample, sr = librosa.load(sample_dir)

            aug_samples = self.data_aug(sample, label, aug_n)

            for sample in aug_samples:
                warnings.filterwarnings(action='ignore')
                # time
                plt.figure(figsize=(6.898,4.719))
                plt.plot(sample)
                plt.xlim(0, len(sample))
                plt.ylim(-0.7,0.7)
                plt.axis('off')
                plt.savefig(fname= self.root_path + self.folders[0] + '/'                             + label + '/' + str(self.cnt) + '_aug.jpg', bbox_inches='tight', pad_inches=0)
                plt.close()
                # mel
                plt.figure(figsize=(6.898,4.719))
                f_sample=librosa.feature.melspectrogram(sample)
                librosa.display.specshow(librosa.power_to_db(f_sample), cmap='jet', y_axis='mel')
                plt.clim(-70,20)
                plt.axis('off')
                plt.savefig(fname= self.root_path + self.folders[1] + '/'                             + label + '/' + str(self.cnt) + '_aug.jpg', bbox_inches='tight', pad_inches=0)
                plt.close()

                self.cnt += 1

        print("Complete data augementation")

class Dataset_overview:
    def __init__(self,labels,data_v,root_path='./data'):
        super(Dataset_overview, self).__init__()
        self.root_path = root_path
        self.img_path = 'images/time'

        self.labels = labels
        self.folders = data_v

    def overview(self):
        data_frame = []
        for folder in self.folders:
            data_cnt = []
            for label in self.labels:
                data_files = glob.glob(os.path.join(self.root_path,folder,self.img_path,label,'*'))
                data_cnt.append(len(data_files))
            data_frame.append(data_cnt)
        df = pd.DataFrame(data_frame,index=self.folders, columns=self.labels)
        df = df.transpose()
        return df

    def confirm_size(self):
        error_cnt = 0
        for folder in self.folders:
            for label in self.labels:
                data_files = glob.glob(os.path.join(self.root_path,folder,self.img_path,label,'*'))
                for data_file in data_files:
                    img = cv.imread(data_file)
                    img_size = img.shape
                    if img_size != (256,384,3):
                        error_cnt += 1
        if error_cnt == 0:
            print("All images size is (256,384,3)")
        else:
            print("Number of wrong image size :" + int(error_cnt) )


from mighty.management import BaseCommand
from mighty.models import Missive
import sys, re

class Command(BaseCommand):
    mail = None
    msgid = None

    def makeJob(self):
        self.mail = "\n".join(sys.stdin)
        self.get_msgid()

    def get_msgid(self):
        match = re.findall(r'Message-Id: (.*)$', self.mail, re.MULTILINE)
        if len(match):
            self.msgid = match[-1]
            self.send_status()

    def send_status(self):
        try:
            missive = Missive.objects.get(msg_id=self.msgid)
            missive.trace = self.mail
            missive.to_error()
            missive.save()
        except Missive.DoesNotExist:
            pass


class Solution:
    def solve(self, nums):
        odd = 0
        for num in nums:
            if num % 2 != 0:
                odd += 1

        if odd % 2 != 0:
            return -1

        return odd // 2

nums = [1, 1, 3, 7, 6, 12]
s = Solution()
result = s.solve(nums)
print(result)


import discord
from discord.ext import commands
from discord.utils import get
import argparse
from collections import deque

from concurrent.futures import ThreadPoolExecutor
import asyncio

import os
from dotenv import load_dotenv
import sys

# Import custom functions from the oogabooga library
from oogabooga import init_llm, generate_llm
from speech2text import init_whisper, generate_whisper
from text2speech import init_bark, generate_bark, init_tortoise, generate_tortoise, audio_combine, init_emotion, get_emotion
from udp_server import init_udp_server, udp_server

import tempfile
from tortoise.utils.text import split_and_recombine_text

parser = argparse.ArgumentParser()
parser.add_argument("--reboot", action="store", help="Helper for rebooting the bot (message_id) (don't use this except you are a bot)")
parser.add_argument("--channel", action="store", help="Helper for rebooting the bot (channel_id)(don't use this except you are a bot)")

# Load environment variables from a .env file
load_dotenv()
model_url = os.environ.get("MODEL_URL")
llm_debug = eval(os.environ.get("LLM_DEBUG", "False"))

use_whisper = os.environ.get("USE_WHISPER", "1")
whisper_model = os.environ.get("WHISPER_MODEL", "base")

use_bark = os.environ.get("USE_BARK", "0")
bark_use_small_model = os.environ.get("BARK_USE_SMALL_MODEL", "1")
bark_speaker = os.environ.get("BARK_SPEAKER", "v2/en_speaker_7")

use_tortoise = os.environ.get("USE_TORTOISE", "1")
tortoise_voice = os.environ.get("TORTOISE_VOICE", "angie")
tortoise_diffusion_iterations = int(os.environ.get("TORTOISE_DIFFUSION_ITERATIONS", "50"))
tortoise_num_autoregressive_samples = int(os.environ.get("TORTOISE_NUM_AUTOREGRESSIVE_SAMPLES", "2"))
tortoise_temperature = float(os.environ.get("TORTOISE_TEMPERATURE", "0.2"))
tortoise_use_deepspeed = eval(os.environ.get("TORTOISE_USE_DEEPSPEED", "False"))
tortoise_kv_cache = eval(os.environ.get("TORTOISE_KV_CACHE", "True"))
tortoise_half = eval(os.environ.get("TORTOISE_HALF", "True"))

use_emotion = os.environ.get("USE_EMOTION", "1")

use_unity = os.environ.get("USE_UNITY", "0")

discord_token = os.environ.get("DISCORD_TOKEN")

with open("discord_info.txt", "r") as file:
    discord_info = file.read()

# Set up Discord intents
intents = discord.Intents.default()
intents.message_content = True
intents.voice_states = True
intents.members = True

# Initialize the modeles
llm_chain = init_llm(model_url, llm_debug)

if use_tortoise == "1" and use_bark == "1":
    print("Tortoise and Bark cannot be used at the same time")
    sys.exit()

if use_whisper == "1":
    whisper_model = init_whisper(whisper_model)

if use_bark == "1":
    init_bark(bark_use_small_model)

if use_tortoise == "1":
    tortoise_tts = init_tortoise(tortoise_use_deepspeed, tortoise_kv_cache, tortoise_half, tortoise_num_autoregressive_samples)

if use_emotion == "1":
    if use_tortoise == "1" or use_bark == "1":
        text2emotion = init_emotion()
    else:
        print("Tortoise or Bark must be enabled because emotion detection is used for them exclusively exept in generate_emotion_test")
        sys.exit()

if use_unity == "1":
    init_udp_server()

bot = discord.Bot(intents=intents)
connectet_voice_channel = None

@bot.event
async def on_ready():
    # This method is called when the bot successfully logs in to Discord
    print("Login successful")
    if parser.parse_args().reboot and parser.parse_args().channel:
        channel_id = int(parser.parse_args().channel)
        message_id = int(parser.parse_args().reboot)

        response_msg = await bot.get_channel(channel_id).fetch_message(message_id)
        await response_msg.edit(content="Reboot successful")

@bot.command(description="Join a voice channel")
async def join(ctx, channel: discord.VoiceChannel = None):
    global connectet_voice_channel
    if channel is None:
        if ctx.author.voice is None:
            await ctx.respond("Not connected to a voice channel, pls specify a channel or join one")
            return
        channel = ctx.author.voice.channel
    connectet_voice_channel = await channel.connect()
    await ctx.respond("Connected to voice channel")

@bot.command(description="Leave a voice channel")
async def leave(ctx):
    if ctx.voice_client is None:
        await ctx.respond("Not connected to a voice channel")
        return
    global connectet_voice_channel
    connectet_voice_channel = None
    await ctx.voice_client.disconnect()
    await ctx.respond("Disconnected from voice channel")

@bot.event
async def on_message(message):
    # This method is called whenever a message is sent in any channel (also direct messages) the bot can access

    # Ignore messages sent by the bot itself to avoid potential infinite loops
    if message.author == bot.user:
        return

    if (message.content == None or message.content == "") and message.attachments == None:
        return

    print("Nachricht von " + str(message.author) + " enthält " + message.content)

    # Acknowledge receipt of the command by replying to the original message
    response_msg = await message.reply("Processing your request...")

    # If the message contains an audio file, transcribe it and use the transcription as input
    if message.attachments:
        if 'audio' in message.attachments[0].content_type:
            if use_whisper == "1":
                message.content = generate_whisper(whisper_model, message.attachments[0].url)
            else:
                await response_msg.edit(content="Whisper is disabled")
                return

    # Start the time-consuming task asynchronously
    result = await generate_llm_thread(llm_chain, message.content)

    # Edit the "Processing your request..." message with the final response
    await response_msg.edit(content=result)

    if use_tortoise == "1" or use_bark == "1":
        audio_file = await generate_tts(result)
        await response_msg.edit(file=discord.File(audio_file))

@bot.command(description="Show all commands and other information")
async def info(ctx):
    await ctx.respond(discord_info)

@bot.command(description="Show help")
async def help(ctx):
    await ctx.send("Commands: /join, /leave, /info, /delete_short_mem, /reboot, /help, /generate_bark_test, /generate_tortoise_test, /generate_whisper_test")

#Function that deltets the files located in the shortmem directory
@bot.command(description="Delete shortmem located files")
@commands.has_permissions(manage_channels=True)
async def delete_short_mem(ctx):
    if os.path.exists("shortmem"):
        for item in os.listdir("shortmem"):
            if os.path.isfile(os.path.join("shortmem", item)):
                os.remove(os.path.join("shortmem", item))
        await ctx.respond("shortterm memory deleted, restarting bot")
        response = await ctx.send("pls wait")
        os.execl(sys.executable, sys.executable, *sys.argv, '--reboot', str(response.id), '--channel', str(ctx.channel.id))
    else:
        await ctx.respond("shortterm memory is not existed")

@bot.command(description="Reboot the bot")
@commands.has_permissions(manage_channels=True)
async def reboot(ctx):
    if ctx.voice_client != None:
        await ctx.voice_client.disconnect()

    await ctx.respond("rebooting bot")
    response = await ctx.send("pls wait")
    os.execl(sys.executable, sys.executable, *sys.argv, '--reboot', str(response.id), '--channel', str(ctx.channel.id))

@bot.command(description="Generate audio from text")
async def generate_bark_test(ctx, text: str=None):
    if use_bark == "1":
        response = await ctx.respond(f"Generating audio from text")
        if text is None:
            text = "Hello this is a bark generation test."
        file = await generate_tts(text)
        await response.edit_original_response(file=discord.File(file))
    else:
        await ctx.respond("Bark generation is disabled")

@bot.command(description="Generate text from audio")
async def generate_whisper_test(ctx, file: discord.Attachment):
    if use_whisper == "1":
        if 'audio' in file.content_type:
            response = await ctx.respond(f"Generating text from audio")
            await response.followup.send(generate_whisper(whisper_model, file.url))
        else:
            await ctx.respond("Please send an audio file")
    else:
        await ctx.respond("Whisper is disabled")

@bot.command(description="Generate audio from text")
async def generate_tortoise_test(ctx, text: str=None):
    if use_tortoise == "1":
        response = await ctx.respond(f"Generating audio from text")
        if text is None:
            text = "Hello this is a tortoise generation test."
        file = await generate_tts(text)
        await response.edit_original_response(file=discord.File(file))
    else:
        await ctx.respond("Tortoise is disabled")

@bot.command(description="Generate emotion from text")
async def generate_emotion_test(ctx, text: str=None):
    if use_emotion == "1":
        response = await ctx.respond(f"Generating emotion from text")
        if text is None:
            text = "Hello this is a emotion generation test."
        emotion = get_emotion(text, text2emotion)
        await response.followup.send(str(emotion))
    else:
        await ctx.respond("Emotion is disabled")

semaphore_llm = asyncio.Semaphore(1)

async def generate_llm_thread(llm_chain, content):
    global semaphore_llm

    # Use a semaphore to ensure that only one thread is running this function at a time and to maintain the order of requests
    async with semaphore_llm:
        # Use ThreadPoolExecutor to run the synchronous function in a separate thread
        # This prevents the event loop from being blocked during the time-consuming task
        with ThreadPoolExecutor() as executor:
            result = await bot.loop.run_in_executor(executor, generate_llm, llm_chain, content)

    return result

semaphore_tts = asyncio.Semaphore(1)

async def generate_tts(text):
    global semaphore_tts

    # Use a semaphore to ensure that only one thread is running this function at a time and to maintain the order of requests
    async with semaphore_tts:

        emotion = None

        if use_emotion == "1":
            emotion = get_emotion(text, text2emotion)
            emotion_tts = f"[{emotion}] "
            len_emotion = len(emotion_tts)

        # Use ThreadPoolExecutor to run the synchronous function in a separate thread
        # This prevents the event loop from being blocked during the time-consuming task
        with ThreadPoolExecutor() as executor:
            if use_tortoise == "1":
                max_length = 300
                desired_length = 200
                if use_emotion == "1":
                    desired_length = desired_length - len_emotion
                    max_length = max_length - len_emotion
                texts = split_and_recombine_text(text, desired_length=desired_length, max_length=max_length)
                audio_parts = []
                for text in texts:
                    if use_emotion == "1":
                        text = emotion_tts + text
                    result = await bot.loop.run_in_executor(executor, generate_tortoise, text, tortoise_tts, tortoise_diffusion_iterations, tortoise_num_autoregressive_samples, tortoise_temperature, tortoise_voice)
                    await play_audio(result, emotion)
                    audio_parts.append(result)

                result = audio_combine(audio_parts)

            if use_bark == "1":
                if use_emotion == "1":
                    text = emotion_tts + text
                result = await bot.loop.run_in_executor(executor, generate_bark, text, bark_speaker)
                await play_audio(result, emotion)

    return result

audio_queue = deque()

async def play_audio(audio_file, emotion=None):
    global connectet_voice_channel
    global audio_queue

    if connectet_voice_channel is not None:

        if audio_file:  # Check if both audio_file and emotion are provided
            # Add the audio file to the queue
            audio_queue.append((audio_file, emotion))

        if not connectet_voice_channel.is_playing() and audio_queue:
            # If the voice channel is not currently playing audio and the queue is not empty, start playback
            audio_file, emotion = audio_queue.popleft()
            if use_unity == "1" and emotion:
                udp_server(emotion)
            connectet_voice_channel.play(discord.FFmpegPCMAudio(audio_file), after=on_audio_complete)

def on_audio_complete(_):
    # This function is called when audio playback is complete
    asyncio.run(play_audio("", ""))  # Continue playing the next audio, pass appropriate audio file and emotion

bot.run(discord_token)


from ozioma import chat_bot_2, calculator
from ozioma.function_module import exercises
from ozioma import class_task

if __name__ == "__main__":
    natives_1 = []
    natives_2 = []
    natives_3 = []

    native_1 = class_task.Native("Ozi", "Ozo", "SCN01", "F")

    native_2 = class_task.Native("Assi", "Iye", "SCN02", "M")

    native_3 = class_task.Native("Mata", "Joy", "SCN03", "M")
    natives_1.append(native_1)
    natives_1.append(native_2)
    natives_1.append(native_3)

    native_4 = class_task.Native("Seyi", "Ale", "SCN04", "F")
    native_5 = class_task.Native("Inno", "Alli", "SCN05", "M")
    native_6 = class_task.Native("Mono", "Bali", "SCN06", "M")
    natives_2.append(native_4)
    natives_2.append(native_5)
    natives_2.append(native_6)

    native_7 = class_task.Native("Esi", "Haru", "SCN07", "F")
    native_8 = class_task.Native("Sura", "Ipo", "SCN08", "M")
    native_9 = class_task.Native("Wena", "Yula", "SCN09", "M")
    natives_3.append(native_7)
    natives_3.append(native_8)
    natives_3.append(native_9)

    cohorts = []

    new_cohort_1 = class_task.Cohorts("1", natives_1, "First cohort.")
    new_cohort_2 = class_task.Cohorts("2", natives_2, "Second cohort.")
    new_cohort_3 = class_task.Cohorts("3", natives_3, "Third cohort.")

    cohorts.append(new_cohort_1)
    cohorts.append(new_cohort_2)
    cohorts.append(new_cohort_3)

    semicolon_building = class_task.Building("Semicolon", cohorts)
    print(semicolon_building.name)

    for me in semicolon_building.cohorts:
        if me.cohort_name == "1":
            print(me.cohort_name + ":")
            print("SCN  No.|   First name   |   Last name   |    Sex")
            for native in me.natives:
                print(native.native_id + "  |    " + native.first_name + "   |    " + native.last_name)
        elif me.cohort_name == "2":
            print(me.cohort_name + ":")
            print("SCN  No.|   First name   |   Last name   |    Sex")
            for native in me.natives:
                print(native.native_id + "  |    " + native.first_name + "   |    " + native.last_name)
        elif me.cohort_name == "3":
            print(me.cohort_name + ":")
            print("SCN  No.|   First name   |   Last name   |    Sex")
            for native in me.natives:
                print(native.native_id + "  |    " + native.first_name + "   |    " + native.last_name)

# while True:
#     value = int(input('Enter number between 1 and 11: '))
#     if value == 1:
#         print('Finding the maximum of three numbers')
#         print(exercises.max_of_three_numbers())
#     elif value == 2:
#         print('Adding values in a list')
#         print(exercises.add_values())
#     elif value == 3:
#         print('Summing of numbers in a list')
#         print(exercises.sum_of_numbers_in_a_list())
#     elif value == 4:
#         print('Multiplying numbers in a list')
#         print(exercises.multiply_numbers_in_a_list())
#     elif value == 5:
#         print('Reversing a string')
#         print(exercises.reverse_a_string())
#     elif value == 6:
#         print('Finding the factorial of a number')
#         print(exercises.factorial_of_a_number())
#     elif value == 7:
#         print('Checking if a number is within a range of inputted numbers')
#         print(exercises.check_number_within_a_range())
#     elif value == 8:
#         print('Counting the number of upper and lower cases in a list')
#         print(exercises.check_upper_and_lowercase_in_sentence())
#     elif value == 9:
#         print('Creating a list of unique values from a larger list')
#         print(exercises.create_a_list_with_unique_elements_of_given_list())
#     elif value == 10:
#         print('Checking if a number is prime or not')
#         print(exercises.find_prime_number())
#     elif value == 11:
#         print('Printing even numbers in a list')
#         print(exercises.print_even_number_from_a_list())
#     elif value == -1:
#         print('Thank you for partaking in our game.')
#         break


import streamlit as st
import numpy as np
import nltk
import pdb
import pickle
import string
from os import getcwd
from utils import cosine_similarity

def nearest_neighbor(v, candidates, k=1, cosine_similarity=cosine_similarity):
    """
    Input:
      - v, the vector you are going find the nearest neighbor for
      - candidates: a set of vectors where we will find the neighbors
      - k: top k nearest neighbors to find
    Output:
      - k_idx: the indices of the top k closest vectors in sorted form
    """
    similarity_l = []

    # for each candidate vector...
    for row in candidates:
        # get the cosine similarity
        cos_similarity = cosine_similarity(v, row)

        # append the similarity to the list
        similarity_l.append(cos_similarity)

    # sort the similarity list and get the indices of the sorted list
    sorted_ids = np.argsort(np.array(similarity_l))

    # Reverse the order of the sorted_ids array
    sorted_ids = np.flip(sorted_ids)

    # get the indices of the k most similar candidate vectors
    k_idx = sorted_ids[:k]
    return k_idx

# add folder, tmp2, from our local workspace containing pre-downloaded corpora files to nltk's data path
filePath = f"{getcwd()}/tmp2/"
nltk.data.path.append(filePath)

# Load english and french word embedding
en_embeddings_subset = pickle.load(open("./data/en_embeddings.p", "rb"))
fr_embeddings_subset = pickle.load(open("./data/fr_embeddings.p", "rb"))

st.title("Machine Translation English to French")
st.write("The full dataset for English embeddings is about 3.64 gigabytes, and the French embeddings are about 629 megabytes. To safety for memory, in this project I will use subset of the embeddings for the words that we'll use in this assignment. So with some word in English you may not translate it")

with open("R.npy", "rb") as f:
    R_train = np.load(f)

with open("Y.npy", "rb") as f:
    Y_subset = np.load(f)

english_word = st.text_input("Your english word: ")

if english_word in en_embeddings_subset:
    english_word_embedding = en_embeddings_subset[english_word]
    french_word_embedding = np.dot(english_word_embedding, R_train)
    idx = nearest_neighbor(french_word_embedding, Y_subset, 1)
    for i in fr_embeddings_subset.keys():
        if (np.array_equal(fr_embeddings_subset[i], Y_subset[idx.item()])):
            st.write("French word is: ", i)
else:
    st.write("Can't translate")


from scamp import *

s = Session()

trumpet = s.new_part("trumpet")
trombone = s.new_part("trombone")

def trumpet_part(clock: Clock):
    while s.beat() < 3:
        trumpet.play_note(67, 1, 0.5)
    clock.set_rate_target(0.5, 6, duration_units="time")
    while s.beat() < 12:
        trumpet.play_note(67, 1, 0.5)

s.set_tempo_target(100, 9)
trumpet_clock = s.fork(trumpet_part)
trombone_based_performance = s.start_transcribing()
trumpet_based_performance = s.start_transcribing(clock=trumpet_clock)

while s.beat() < 12:
    trombone.play_note(60, 1, 1)

s.stop_transcribing(trombone_based_performance)
s.stop_transcribing(trumpet_based_performance)

trombone_based_performance.to_score("3/4", title="Trombone Clock").show_xml()
trumpet_based_performance.to_score("3/4", title="Trumpet Clock").show_xml()


# Copyright (c) 2014, Adam J. Rossi. All rights reserved. See README for licensing details.
import sys, uuid, string, os
import Chain, Analyze

class StageBase:

    MAX_INPUT_STAGES = sys.maxint

    def __init__(self, inputStages=None, stageDoc="", parameterDoc=None):
        self.__stageDoc = stageDoc
        if (parameterDoc==None): self.__parameterDoc = {}
        else:                    self.__parameterDoc = parameterDoc
        self._properties = {}
        self.__inputStages = []
        self.__outputStages = []
        self.__outputCache = None
        self.__prepared = False
        self._uid = uuid.uuid1()
        if (inputStages!=None):
            self.AddInputStage(inputStages)
        import StageRegistry
        if ("registry" in dir(StageRegistry) and
            StageRegistry.registry.IsInitialized()):
            StageRegistry.registry.AddInstance(self)

    def AddInputStage(self, stages):
        self.__prepared = False
        if (isinstance(stages, list)):
            self.__inputStages += stages
            for stage in stages: stage.AddOutputStage(self)
        else:
            self.__inputStages.append(stages)
            stages.AddOutputStage(self)

    def AddOutputStage(self, stages):
        if (isinstance(stages, list)):  self.__outputStages += stages
        else:                           self.__outputStages.append(stages)

    def RemoveConnections(self):
        for outputStage in self.__outputStages:
            outputStage.__inputStages.remove(self)
        for inputStage in self.__inputStages:
            inputStage.__outputStages.remove(self)

    def GetInputStages(self):
        return self.__inputStages

    def GetOutputStages(self):
        return self.__outputStages

    def NumInputStages(self):
        return len(self.__inputStages)

    def GetPropertyMap(self):
        d = {}
        for n in self._properties:
            d[n] = type(self._properties[n])
        return d

    def GetPackageName(self):
        return str(self.__class__).split(".")[0]

    def GetStageName(self):
        return self.__class__.__name__

    def GetStageDescription(self):
        return self.__stageDoc

    def GetPropertyDescription(self, name):
        if (name in self.__parameterDoc.keys()):
            return self.__parameterDoc[name]
        else:
            raise Exception("Property does not exist: " + name)

    def SetPropertyDescription(self, name, desc):
        self.__parameterDoc[name] = desc

    def GetProperty(self, name):
        if (name in self._properties.keys()):
            return self._properties[name]
        else:
            raise Exception("Property does not exist: " + name)

    def SetProperty(self, name, val):
        if (name in self._properties.keys()):
            self._properties[name] = val
        else:
            raise Exception("Property does not exist: " + name)

    def __GetInputStagesInterfaces(self):
        # return list of dictionaries that represent the input stages' interface
        return [stage.GetOutputInterface() for stage in self.__inputStages]

    def Reset(self):
        self.__prepared = False
        for stage in self.GetInputStages(): stage.Reset()

    def Prepare(self):
        # check:
        #   - parameters
        #   - inputs' outputs
        #   - max number of input stages

        # depth-first prepare
        for stage in self.GetInputStages(): stage.Prepare()
        if (self.__prepared): return

        # clear cache
        self.__outputCache = None

#        # validate interface names/types
#        myInputInterface = self.GetInputInterface()
#        for stage in self.__inputStages:
#            inputStageInterface = stage.GetOutputInterface()
#            for inputKey in myInputInterface.keys():
#                if (not inputStageInterface.has_key(inputKey)):
#                    raise Exception("[%s:Prepare] Input (%s) interface does not include: %s:%s" % (self.__class__.__name__,stage.__class__.__name__,inputKey,myInputInterface[inputKey]))
#                if (inputStageInterface[inputKey] != myInputInterface[inputKey]):
#                    raise Exception("[%s:Prepare] Invalid input (%s) interface type: expected %s, received %s" % (self.__class__.__name__,inputStageInterface[inputKey].__class__.__name__,inputStageInterface[inputKey],myInputInterface[inputKey]))

        # ensure input interface is consistent with input stage's output interface

        myInputInterface = self.GetInputInterface()
        if (myInputInterface != None):
            for kv in myInputInterface.items():

                try:
                    inputName,(inputIndex,inputType) = kv
                except:
                    raise Exception("[%s:Prepare] Input interface definition error" % (self.__class__.__name__))

                if (isinstance(inputIndex,tuple)):
                    for iIndex in range(inputIndex[0], inputIndex[0]+inputIndex[1]):
                        if (iIndex < self.NumInputStages()):  # check only valid input stage indices
                            if (not self.__inputStages[iIndex].GetOutputInterface().has_key(inputName)):
                                raise Exception("[%s:Prepare] Input stage %d does not include %s:%s" % \
                                                (self.__class__.__name__,iIndex,inputName,inputType))

                            if (not issubclass(self.__inputStages[iIndex].GetOutputInterface()[inputName],inputType)):
                                raise Exception("[%s:Prepare] Input stage %d's output parameter (%s) type is %s, type should be %s" % \
                                                (self.__class__.__name__,
                                                 iIndex,
                                                 inputName,
                                                 self.__inputStages[iIndex].GetOutputInterface()[inputName],
                                                 inputType))
                else:
                    if (inputIndex >= self.NumInputStages()):
                        raise Exception("[%s:Prepare] Expected input stage at index %d" % \
                                        (self.__class__.__name__,inputIndex))

                    if (not self.__inputStages[inputIndex].GetOutputInterface().has_key(inputName)):
                        raise Exception("[%s:Prepare] Input stage %d does not include %s:%s" % \
                                        (self.__class__.__name__,inputIndex,inputName,inputType))

                    if (not issubclass(self.__inputStages[inputIndex].GetOutputInterface()[inputName], inputType) and
                        not issubclass(inputType, self.__inputStages[inputIndex].GetOutputInterface()[inputName])):
                        raise Exception("[%s:Prepare] Input stage %d's output parameter (%s) type is %s, type should be %s" % \
                                        (self.__class__.__name__,
                                         inputIndex,
                                         inputName,
                                         self.__inputStages[inputIndex].GetOutputInterface()[inputName],
                                         inputType))

        # successfully prepared stage
        self.__prepared = True

    def __InitializeOutputCache(self):
        self.__outputCache = {}
        if (self.GetOutputInterface()!=None):
            for k in self.GetOutputInterface().keys():
                self.__outputCache[k] = None

    def __ValidateCompleteOutputCache(self):
        for k,v in self.__outputCache.items():
            if (v==None):
                raise Exception("[%s::__ValidateCompleteOutputCache] Developer error, output parameter (%s) not filled" % \
                                (self.__class__.__name__,k))

            if (str(type(v)) == "<type 'instance'>" or
                str(type(v)).startswith("<class '")):
                if (issubclass(v.__class__, self.GetOutputInterface()[k])):
                    pass
                elif (str(self.GetOutputInterface()[k]) not in [v.__class__.__name__, "%s.%s" % (v.__module__, v.__class__.__name__)]):
                    raise Exception("[%s::__ValidateCompleteOutputCache] Developer error, output parameter (%s) type is %s, type should be %s" % \
                                    (self.__class__.__name__,k,v.__class__.__name__,self.GetOutputInterface()[k]))
            else:
                if (self.GetOutputInterface()[k] != type(v)):
                    raise Exception("[%s::__ValidateCompleteOutputCache] Developer error, output parameter (%s) type is %s, type should be %s" % \
                                    (self.__class__.__name__,k,type(v),self.GetOutputInterface()[k]))

    def GetOutput(self):
        # this method is called by the next stage
        # the outputs of this stage are cached within this class by ensuring Execute is only called when necessary
        self.Prepare()

        if (self.__outputCache==None):
            self.__InitializeOutputCache()
            self.Execute()
            self.__ValidateCompleteOutputCache()

        return self.__outputCache

    def GetOutputByKey(self, key):

        if (not self.__outputCache.has_key(key)):
            raise Exception("[%s:GetOutputByKey] Invalid output key: %s" % \
                            (self.__class__.__name__,key))

        return self.__outputCache[key]

    def GetInputStageValue(self, index, key):
        if (index >= self.NumInputStages()):
            raise Exception("[%s:GetInputStageValue] Invalid input stage index: %d" % \
                            (self.__class__.__name__,index))

        outputs = self.GetInputStages()[index].GetOutput()

        if (not outputs.has_key(key)):
            raise Exception("[%s:GetInputStageValue] Invalid input stage (%s) key: %s" % \
                            (self.__class__.__name__,self.GetInputStages()[index].__class__.__name__,key))

        return outputs[key]

    def SetOutputValue(self, key, value):
        if (not self.__outputCache.has_key(key)):
            raise Exception("[%s:SetOutputValue] Unknown output parameters: %s" % \
                            (self.__class__.__name__,key))

        # TODO: validate value's type
        self.__outputCache[key] = value

    def StartProcess(self):
        name = self.__class__.__name__
        if (len(self._properties)>0):
            sargs = ["%s = %s" %(str(x),self._properties[x]) for x in sorted(self._properties.keys())]
            name = "%s [%s]" % (name, string.join(sargs,", "))
        Analyze.StartProcess(name)

    def RunCommand(self, exe, args="", cwd=None, shell=True, captureCout=False):
        import Common

        # find executable for given platform
        exe = Common.Utility.GetExePath(sys.modules[self.__class__.__module__].__file__, exe)
        cmd = "\"%s\" %s" % (exe, args)
        return Common.Utility.RunCommand(cmd, cwd=cwd, shell=shell, captureCout=captureCout)

    # pure virtual methods...
    def GetInputInterface(self):
        # return dictionary of input types, keyed by name (name->type)
        raise Exception("Derived class (%s) must implement GetInputInterface" % self.__class__.__name__)

    def GetOutputInterface(self):
        # return dictionary of output types, keyed by name (name->type)
        raise Exception("Derived class (%s) must implement GetOutputInterface" % self.__class__.__name__)

    def Execute(self):
        # carry out execution
        # note, this is called by GetOutputs
        # return dictionary of results keyed by name (name->object)
        raise Exception("Derived class (%s) must implement Execute" % self.__class__.__name__)


# Problem Statement: https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/

from typing import List

class Solution:
    def findMaximumXOR(self, nums: List[int]) -> int:
        """
        let ni and nj be the numbers such that xor between them produces maximum
        value among other pairs. let m be the max value.

        m = ni ^ nj
        => m ^ nj = (ni ^ nj) ^ nj
        =>        = ni ^ (nj ^ nj) # xor is associative
        =>        = ni ^ 0
        =>        = ni

        so, m ^ nj = ni

        We note that m is 31-bit integer so we guess bits of m and and with each nj,
        we check if the combination of m and nj will produce ni.

        So time complexity becomes O(32N) = O(N)
        :param nums:
        :return:
        """
        m, mask = 0, 0

        for i in range(32)[::-1]:
            mask |= 1 << i
            prefixes = {n & mask for n in nums}

            tmp = m | (1 << i)

            if any(prefix ^ tmp in prefixes for prefix in prefixes):
                m = tmp

        return m

Medium/421. Maximum XOR of Two Numbers in an Array.py