import torch
import numpy as np
import torch.multiprocessing as mp
import os,sys
import queue
import time
import psutil
import pynvml
import numpy as np

from track_sequence import track_sequence,im_to_vid

import argparse

pynvml.nvmlInit()

sys.path.insert(0,"I24-video-ingest")
from utilities import get_recording_params, find_files

def get_recordings(ingest_session_path):
    params = get_recording_params(ingest_session_path,verbose = False)
    file_list = find_files(params[0],params[1],params[2],drop_last_file = True,verbose = False)

    # print("INGEST SESSION PATH: {}".format(ingest_session_path))
    # print(file_list)

    keepers = [item[1].split(".mp4")[0] for item in file_list]
    # recording_names = []
    # last_recording_num = {}
    # for item in os.listdir(os.path.join(ingest_session_path,"recording")):
    #     recording_names.append(item.split(".mp4")[0])

    # # remove all recordings that are currently being written to
    # keepers = []
    # for item in recording_names:
    #     for other_item in recording_names:
    #         camera1 = item.split("_")[1]
    #         camera2 = other_item.split("_")[1]
    #         if camera1 == camera2:
    #             num1 = int(item.split("_")[2].split(".mp4")[0])
    #             num2 = int(other_item.split("_")[2].split(".mp4")[0])
    #             if num1 < num2:
    #                 keepers.append(item) # there exists a recording with greater number than item for that camera

    return keepers

def get_outputs(ingest_session_path):
    recording_names = []
    for item in os.listdir(os.path.join(ingest_session_path,"tracking_outputs")):
        recording_names.append(item.split("_track_outputs")[0])
    return recording_names

def get_in_progress(in_progress):
    in_progress_names = []
    for key in in_progress.keys():
        in_progress_names.append(in_progress[key])
    return in_progress_names

def write_to_log(log_file,message,show = False):
    """
    All messages passed to this file should be of the form (timestamp, key, message)
        valid Keys - START_PROC_SESSION - start of a processing session
                     END_PROC_SESSION - end of a processing session
                     INFO - general information
                     SYS - CPU, GPU, mem utilization info, etc.
                     WORKER_START - a tracker process has started (name and PID should be given)
                     WORKER_END - a tracker process has finished (name and PID should be given)
                     WORKER_TERM - a tracker process has been terminated after finishing (name and PID should be given)
                     WARNING - parameters outside of normal operating conditions
                     ERROR - an error has been caught
        timestamp - time.time()
        message - string
    """

    # format time
    milliseconds = str(np.round(message[0],4)).split(".")[1]
    formatted_time = time.strftime('%Y-%m-%d %H:%M:%S.{}', time.localtime(message[0])).format(milliseconds)

    line = "[{}] {}: {} \n".format(formatted_time,message[1],message[2])
    if show:
        if message[1] not in ["SYS"]:
            print(line[:-2])
    with open (log_file,"a+") as f:
        f.writelines([line])

def log_system(log_file,process_pids = None):
    """
    Logs system utilization metrics to log file
    """
    # log cpu util
    cpu_util = psutil.cpu_percent()
    cpu_util_ind = psutil.cpu_percent(percpu = True)
    ts = time.time()
    key = "INFO"
    message = "CPU util: {}% -- Individual utils 1-24: {}".format(cpu_util,cpu_util_ind[:24])
    write_to_log(log_file,(ts,key,message))
    message = "CPU util: {}% -- Individual utils 25-48: {}".format(cpu_util,cpu_util_ind[24:])
    write_to_log(log_file,(ts,key,message))

    # log GPU util and memory
    try:
        max_gpu_util = 0
        deviceCount = pynvml.nvmlDeviceGetCount()
        for idx in range(deviceCount):
            handle = pynvml.nvmlDeviceGetHandleByIndex(idx)
            board_num = pynvml.nvmlDeviceGetBoardId(handle)
            name = "GPU {}: {}  (ID {})".format(idx,pynvml.nvmlDeviceGetName(handle).decode("utf-8"),board_num)
            util = pynvml.nvmlDeviceGetUtilizationRates(handle)
            fan_util = pynvml.nvmlDeviceGetFanSpeed(handle)
            pcie_counter = pynvml.nvmlDeviceGetPcieReplayCounter(handle)
            pcie_util = pynvml.nvmlDeviceGetPcieThroughput(handle,pcie_counter)
            gpu_util = util.gpu
            mem_util = util.memory

            message = "{}: Kernel:{}%  Mem:{}% Fan:{}% PCIe: {}MB/s".format(name,gpu_util,mem_util,fan_util,round(pcie_util/1000,1))
            ts = time.time()
            key = "INFO"
            write_to_log(log_file,(ts,key,message))

            if gpu_util > max_gpu_util:
                max_gpu_util = gpu_util

    except pynvml.NVMLError as error:
        print(error)

    # log memory util
    mem_util = psutil.virtual_memory()
    used = round(mem_util.used / 1e+9,2)
    total = round(mem_util.total / 1e+9,2)
    ts = time.time()
    key = "INFO"
    message = "Memory util: {}%  ({}/{}GB)".format(round(used/total*100,2),used,total)
    write_to_log(log_file,(ts,key,message))

    pid_statuses = []
    warning = False
    if process_pids is not None:
        for key in process_pids:
            pid = process_pids[key]

            try:
                os.kill(pid,0)
                RUNNING = "running"
            except OSError:
                RUNNING = "stopped"
                warning = True

            pid_statuses.append("{} ({}): {}\n".format(key,pid,RUNNING))

        ts = time.time()
        key = "INFO"
        if warning:
            key = "WARNING"
        write_to_log(log_file,(ts,key,pid_statuses))

    last_log_time = time.time()
    return last_log_time, max_gpu_util

if __name__ == "__main__":

    #add argparse block here so we can optionally run from command line
    try:
        parser = argparse.ArgumentParser()
        parser.add_argument("Ingest_session_directory", help= '<Required> string, Path to ingest session main directory',type = str)
        parser.add_argument("Configuration_file", help= '<Required> string, Path to configuration file',type = str)
        parser.add_argument("--verbose", help="bool, Show or suppress log messages in terminal", action = "store_true")

        args = parser.parse_args()
        ingest_session_path = args.Ingest_session_directory
        config_file = args.Configuration_file
        if args.verbose:
            VERBOSE = True
        else:
            VERBOSE = False
    except:

        print("Using default path instead")
        ingest_session_path = "/home/worklab/Data/cv/video/ingest_session_00011"
        ingest_session_path = "/home/worklab/Data/cv/video/5_min_18_cam_October_2020/ingest_session_00005"
        config_file = "/home/worklab/Documents/derek/I24-video-processing/config/lambda_quad.config"
        VERBOSE = True
    log_rate = 5
    process_hang_max = 30
    last_log_time = 0

    # create directory for outputs if needed
    if not os.path.exists(os.path.join(ingest_session_path,"tracking_outputs")):
        os.mkdir(os.path.join(ingest_session_path,"tracking_outputs"))

    # define unique log file for processing session
    log_subidx = 0
    log_idx = 0
    while True:
        log_file = os.path.join(ingest_session_path,"logs","cv_tracking_manager_{}_{}.log".format(str(log_idx).zfill(3),log_subidx))
        if os.path.exists(log_file):
            log_idx += 1
        else:
            break

    write_to_log(log_file,(time.time(),"INFO","STARTED PROCESSING SESSION."),show = VERBOSE)

    # get GPU list
    g = torch.cuda.device_count()

    # availability monitor
    available = np.ones(g)
    in_progress = {}

    # create shared queue
    manager = mp.Manager()
    ctx = mp.get_context('spawn')
    com_queue = ctx.Queue()
    all_workers = {}
    process_pids = {"manager":manager._process.ident}
    DONE = False

    time_of_last_message = {}
    time_of_last_gpu_util = time.time()

    while not DONE:

        try:
            try:
                for idx in range(g):
                    # initially, start gpu_count processes

                    if available[idx] == 1:
                        in_prog = get_in_progress(in_progress)
                        recordings = get_recordings(ingest_session_path)
                        done = get_outputs(ingest_session_path)

                        if len(in_prog) == 0 and len(recordings) <= len(done):
                            DONE = True

                        avail_recording = None
                        for item in recordings:
                            if item in in_prog or item in done:
                                continue
                            else:
                                avail_recording = item
                                break

                        if avail_recording is not None:
                            # assign this recording to this worker

                            in_progress[idx] = avail_recording
                            available[idx] = 0

                            input_file_dir = get_recording_params(ingest_session_path)[0][0]
                            input_file = os.path.join(input_file_dir,avail_recording+".mp4")
                            # change to use Will's utilities

                            output_directory = os.path.join(ingest_session_path,"tracking_outputs")
                            camera_id = input_file.split("/")[-1].split("_")[1].upper()

                            args = [input_file, output_directory, config_file,log_file]
                            kwargs = {"worker_id":idx, "com_queue":com_queue,"com_rate": log_rate,"config":camera_id}

                            worker = ctx.Process(target=track_sequence,args = args, kwargs=kwargs)
                            all_workers[idx] = (worker)
                            all_workers[idx].start()

                            # write log message
                            ts = time.time()
                            key  = "DEBUG"
                            text = "Manager started worker {} (PID {}) on video sequence {}".format(idx,all_workers[idx].pid,in_progress[idx])
                            write_to_log(log_file,(ts,key,text),show = VERBOSE)
            except Exception as e:
                ts = time.time()
                key  = "ERROR"
                text = "Manager had error {} starting a new process running".format(e)
                write_to_log(log_file,(ts,key,text),show = VERBOSE)
                raise KeyboardInterrupt

            try:
                # periodically, write device status to log file
                if time.time() - last_log_time > log_rate:
                    last_log_time,max_gpu_util = log_system(log_file,process_pids)
                    if max_gpu_util > 10:
                        time_of_last_gpu_util = time.time()

            except Exception as e:
                ts = time.time()
                key  = "ERROR"
                text = "Manager had error {} logging system info".format(e)
                write_to_log(log_file,(ts,key,text),show = VERBOSE)
                raise KeyboardInterrupt

            # monitor queue for messages
            try:
               message = com_queue.get(timeout = 0)
            except queue.Empty:
                continue

            # strip PID from message and use to update process_pids
            try:
                if "Loader " in message[2]:
                    pid = int(message[2].split("PID ")[1].split(")")[0])
                    id = int(message[2].split("Loader ")[1].split(" ")[0])
                    process_pids["loader {}".format(id)] = pid
                elif "Worker " in message[2]:
                    pid = int(message[2].split("PID ")[1].split(")")[0])
                    id = int(message[2].split("Worker ")[1].split(" ")[0])
                    process_pids["worker {}".format(id)] = pid
            except Exception as e:
                ts = time.time()
                key  = "ERROR"
                text = "Manager error {} parsing PID and ID from message: {}".format(e,message[2])
                write_to_log(log_file,(ts,key,text),show = VERBOSE)
                raise KeyboardInterrupt

            try:
                # write message to log file
                worker_id = message[3]
                message = message[:3]
                write_to_log(log_file,message,show = VERBOSE)

            except Exception as e:
                ts = time.time()
                key  = "ERROR"
                text = "Manager error '{}' writing message '{}' to log file.".format(e,message)
                write_to_log(log_file,(ts,key,text),show = VERBOSE)
                raise KeyboardInterrupt

            try:
                time_of_last_message[worker_id] = time.time()

                # if message is a finished task, update manager
                key = message[1]
                if key == "WORKER_END":
                    worker_pid = all_workers[worker_id].pid

                    all_workers[worker_id].terminate()
                    all_workers[worker_id].join()
                    del all_workers[worker_id]

                    # write log message
                    ts = time.time()
                    key  = "DEBUG"
                    text = "Manager terminated worker {} (PID {}) on video sequence {}".format(worker_id,worker_pid,in_progress[worker_id])
                    write_to_log(log_file,(ts,key,text),show = VERBOSE)

                    # update progress tracking
                    available[worker_id] = 1
                    del in_progress[worker_id]
                    del time_of_last_message[worker_id]
                    del process_pids["worker {}".format(worker_id)]
                    del process_pids["loader {}".format(worker_id)]

            except Exception as e:
                ts = time.time()
                key  = "ERROR"
                text = "Manager error {} shutting down finished process".format(e)
                write_to_log(log_file,(ts,key,text),show = VERBOSE)
                raise KeyboardInterrupt

            try:
                # randomly check one GPU for unresponsive processes (no output messages in last 60 seconds, and restart these)
                worker_id = np.random.randint(0,g)
                if worker_id in time_of_last_message.keys():
                    if time.time() - time_of_last_message[worker_id] > process_hang_max:
                        # kill process

                        # write log message
                        ts = time.time()
                        key  = "WARNING"
                        text = "Manager detected unresponsive worker {}".format(worker_id)
                        write_to_log(log_file,(ts,key,text),show = VERBOSE)

                        worker_pid = all_workers[worker_id].pid
                        print("Trying to terminate")
                        all_workers[worker_id].terminate()
                        print("Terminated")
                        all_workers[worker_id].join()
                        print("Joined")

                        # write log message
                        ts = time.time()
                        key  = "WARNING"
                        text = "Manager terminated unresponsive worker {} (PID {}) on video sequence {}".format(worker_id,worker_pid,in_progress[worker_id])
                        write_to_log(log_file,(ts,key,text),show = VERBOSE)

                        # update progress tracking
                        available[worker_id] = 1
                        del all_workers[worker_id]
                        del in_progress[worker_id]
                        del time_of_last_message[worker_id]
                        del process_pids["worker {}".format(worker_id)]
                        del process_pids["loader {}".format(worker_id)]
            except Exception as e:
                ts = time.time()
                key  = "ERROR"
                text = "Manager error {} terminating unresponsive process".format(e)
                write_to_log(log_file,(ts,key,text),show = VERBOSE)
                #raise KeyboardInterrupt

            try:
                # make new log file if necessary
                if os.stat(log_file).st_size > 1e+07: # slice into 10 MB log files
                    log_subidx += 1
                    log_file = os.path.join(ingest_session_path,"logs","cv_tracking_manager_{}_{}.log".format(str(log_idx).zfill(3),log_subidx))
            except Exception as e:
                ts = time.time()
                key  = "ERROR"
                text = "Manager error {} creating new log file".format(e)
                write_to_log(log_file,(ts,key,text),show = VERBOSE)
                raise KeyboardInterrupt

            # determine whether GPUs are still running, and restart if necessary
            if time.time() - time_of_last_gpu_util > 120:
                ts = time.time()
                key  = "WARNING"
                text = "All GPUs have stopped processing. Terminating all worker processes to restart."
                write_to_log(log_file,(ts,key,text),show = VERBOSE)

                for worker in all_workers:
                    all_workers[worker].terminate()
                    all_workers[worker].join()

                ts = time.time()
                key  = "DEBUG"
                text = "All workers have been terminated. Sleeping for 60 seconds before restarting."
                write_to_log(log_file,(ts,key,text),show = VERBOSE)
                time.sleep(60)

        except KeyboardInterrupt:
            # interrupt log message
            ts = time.time()
            key = "WARNING"
            message = "Keyboard Interrupt error caught. Shutting down worker processes now."
            write_to_log(log_file,(ts,key,message),show = VERBOSE)

            # terminate all worker processes (they will in turn terminate their daemon loaders)
            for worker in all_workers:
                all_workers[worker].terminate()
                all_workers[worker].join()

            # interrupt log message
            ts = time.time()
            key = "DEBUG"
            message = "All worker processes have been terminated."
            write_to_log(log_file,(ts,key,message),show = VERBOSE)

            break # get out of processing main loop

    if DONE:
        print("Finished all video sequences")
        for key in all_workers:
            all_workers[key].terminate()
            all_workers[key].join()

    # end log message
    ts = time.time()
    key = "INFO"
    message = "ENDED PROCESSING SESSION."
    write_to_log(log_file,(ts,key,message),show = VERBOSE)


import os
from dotenv import load_dotenv
from notion_client import Client
from time import sleep
from SlackWrapper import SlackWrapper
import json
from RoadMap import RoadMap
from Status import Status

TASK_DB = "88de9a3cf5554dd9a20476bc465cc68f"
PROJECT_DB = "adddfaea7fa7475eb04e4fc530af6932"
DRI_USER_GROUP = "S058TKUAX60"
PROJECT_DRI_USER_GROUP = "S05A84CKV09"
TASK_DRI_USER_GROUP = "S059NSGGY1L"
NOTIF_CHANNEL = "#log_notion_notifs"

load_dotenv()

notion = Client(auth=os.getenv('NOTION_AUTH_KEY'))
slack_app = SlackWrapper(os.getenv("SLACK_KEY"))

task_db_identifier = TASK_DB
project_db_identifier = PROJECT_DB

overrides = json.load(open("override.json"))

roadmap = RoadMap(project_db_identifier, task_db_identifier, notion)

project_dris = []
task_dris = []

for project in roadmap.projects:
    if project.status == Status.IN_PROGRESS:

        project_dri_mentions = []
        for user in project.dri_emails:
            email = user.email

            if email in overrides.keys():
                email = overrides[email]

            try:
                uid = slack_app.members[email]
                if uid not in project_dris:
                    project_dris.append(uid)
                project_dri_mentions.append(f"<@{uid}>")
            except KeyError:
                continue

        block = [
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"*<{project.project_url}|{project.project_name}>*",
                }
            },
        ]

        if (len(project_dri_mentions) >= 1):
            block.append(
                {
                    "type": "section",
                    "text": {
                        "type": "mrkdwn",
                        "text": f':office_worker:: {""" """.join(project_dri_mentions)}'
                    }
                },
            )

        project_info = "\n• ".join(project.info())
        project_warning = "\n• ".join(project.warnings())
        project_errors = "\n• ".join(project.errors())

        if len(project_info) >= 1:
            block.append({
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f":information_source::\n• {project_info}"
                }
            }
            )

        if len(project_warning) >= 1:
            block.append({
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f":warning::\n• {project_warning}"
                }
            })

        if len(project_errors) >= 1:
            block.append({
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f":octagonal_sign::\n• {project_errors}"
                }
            })

        block += [
            {
                "type": "divider"
            }]

        if (project.has_issues() or project.has_sub_issues()):
            response = slack_app.client.chat_postMessage(
                channel=NOTIF_CHANNEL,
                link_names=True,
                blocks=block
            )
            sleep(1)  # Used to circumvent Slack rate limits

            project_thread = response.get("ts")

        for task in project.tasks:
            if task and task.status != Status.DONE:
                task_dri_mentions = []
                for user in task.dri_emails:
                    email = user.email

                    if email in overrides.keys():
                        email = overrides[email]

                    try:
                        uid = slack_app.members[email]
                        if uid not in task_dris:
                            task_dris.append(uid)
                        task_dri_mentions.append(f"<@{uid}>")
                    except KeyError:
                        continue

                block = [
                    {
                        "type": "section",
                        "text": {
                            "type": "mrkdwn",
                            "text": f"*<{task.notion_url}|{task.task_name}>*",
                        }
                    },
                ]

                if (len(task_dri_mentions) >= 1):
                    block.append(
                        {
                            "type": "section",
                            "text": {
                                "type": "mrkdwn",
                                "text": f':office_worker:: {""" """.join(task_dri_mentions)}'
                            }
                        },
                    )

                task_info = "\n• ".join(task.info())
                task_warning = "\n• ".join(task.warnings())
                task_errors = "\n• ".join(task.errors())

                if len(task_info) >= 1:
                    block.append({
                        "type": "section",
                        "text": {
                            "type": "mrkdwn",
                            "text": f":information_source:\n• {task_info}"
                        }
                    }
                    )

                if len(task_warning) >= 1:
                    block.append({
                        "type": "section",
                        "text": {
                            "type": "mrkdwn",
                            "text": f":warning:\n• {task_warning}"
                        }
                    })

                if len(task_errors) >= 1:
                    block.append({
                        "type": "section",
                        "text": {
                            "type": "mrkdwn",
                            "text": f":octagonal_sign:\n• {task_errors}"
                        }
                    })

                block += [
                    {
                        "type": "divider"
                    }]

                if task.has_issues():
                    slack_app.client.chat_postMessage(
                        channel=NOTIF_CHANNEL,
                        link_names=True,
                        blocks=block,
                        thread_ts=project_thread
                    )
                    sleep(1)  # Used to circumvent Slack rate limits

slack_app.client.usergroups_users_update(usergroup=PROJECT_DRI_USER_GROUP, users=",".join(project_dris))

slack_app.client.usergroups_users_update(usergroup=TASK_DRI_USER_GROUP, users=",".join(task_dris))


"""
=====
Decay
=====

This example showcases a sinusoidal decay animation.
"""

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

from IPython.display import HTML

MILLIS_PER_SECOND = 1_000
DEFAULT_FPS = 24

def data_gen(t=0):
    cnt = 0
    while cnt < 1000:
        cnt += 1
        t += 0.1
        yield t, np.sin(2*np.pi*t) * np.exp(-t/10.)

def init():
    ax.set_ylim(-1.1, 1.1)
    ax.set_xlim(0, 10)
    del xdata[:]
    del ydata[:]
    line.set_data(xdata, ydata)
    return line,

def run(data):
    # update the data
    t, y = data
    xdata.append(t)
    ydata.append(y)
    xmin, xmax = ax.get_xlim()

    if t >= xmax:
        ax.set_xlim(xmin, 2*xmax)
        ax.figure.canvas.draw()
    line.set_data(xdata, ydata)

    return line,

def create_animation(fig, plt, animate, length_seconds=4, frames_per_second=DEFAULT_FPS):
    #Ref: https://github.com/khiner/notebooks/blob/master/ipython_animation.py
    anim = animation.FuncAnimation(fig, animate, frames=int(length_seconds * frames_per_second), interval=MILLIS_PER_SECOND/frames_per_second)
    video = HTML(anim.to_html5_video())
    plt.close()
    return video

if __name__ == "__main__":

    fig, ax = plt.subplots()
    line, = ax.plot([], [], color='red')
    ax.grid()
    xdata, ydata = [], []

    ani = animation.FuncAnimation(fig, run, data_gen, blit=False, interval=10,
                                  repeat=False, init_func=init)
    plt.show()

    # add this: vid = create_animation(fig, plt, animate)


import datetime
import json
import re
import requests
import logging

from yandex.Translater import Translater

import lib.eng_to_ipa as ipa
from lxml import html
from .word_entity import WordEntity

class WordParser:

    def __init__(self, file_path="./tmp/", log_file_name="log/word_parser.log", yandex_key=""):
        self.__headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}

        self.word = ""
        self.file_path = file_path
        self.__log_file_name = log_file_name
        self.__yandex_key = yandex_key

    def __word_hunt(self, entity):
        url = "https://wooordhunt.ru/word/" + entity.word

        r = requests.get(url)
        doc = html.fromstring(r.text)

        if entity.ipa_text == "":
            transcription = doc.xpath('//span[@class="transcription"]')

            if len(transcription) > 0:
                transcription_text = transcription[0].text_content()
                transcription_text = transcription_text.replace('|', '')
                entity.ipa_text = transcription_text

        if entity.ru_text == "":
            translate = doc.xpath('//span[@class="t_inline_en"]')

            if len(translate) > 0:
                entity.ru_text = self.__clear_string(translate[0].text_content())

        if entity.file_name == "" or entity.file_name is None:
            audio = doc.xpath('//audio[@id="audio_us"]//source')

            if len(audio) > 0:
                entity.file_url = "https://wooordhunt.ru" + audio[0].attrib['src']

    def __reverso_translate(self, entity):
        url = "https://context.reverso.net/translation/english-russian/" + entity.word
        r = requests.get(url, headers=self.__headers)
        doc = html.fromstring(r.text)
        nodes = doc.xpath('//div[@id="translations-content"]//a')

        word_list = []

        for node in nodes:
            word_list.append(self.__clear_string(node.text_content()))

        if len(word_list) > 0:
            entity.ru_text = ", ".join(word_list)

    def parse(self, entity):

        self.word = entity.word

        self.__word_hunt(entity)

        if entity.ipa_text == "":
            entity.ipa_text = ipa.convert(entity.en_text)

        if entity.ru_text == "":
            self.__reverso_translate(entity)

        if entity.ru_text == "":
            self.__reverso_translate(entity)

        if entity.ru_text == "":
            entity.ru_text = self.__yandex_translate(entity)

        if entity.file_name is None or entity.file_name == "":
            if entity.file_url == "":
                self.__dict_file_download(entity)

            if entity.file_url == "":
                self.__tureng_file_download(entity)

            if entity.file_url:
                self.__save_file(entity)

        return entity

    def __save_file(self, entity):
        r = requests.get(entity.file_url)
        header = r.headers
        content_length = header.get('content-length', 0)

        if content_length:
            entity.file_size = content_length
            name = entity.word.replace(" ", "_")
            name = name.replace("-", "_")
            entity.file_name = name
            open(self.file_path + name, 'wb').write(r.content)

    def __yandex_translate(self, entity):
        tr = Translater()
        tr.set_key(self.__yandex_key)
        tr.set_from_lang("en")
        tr.set_to_lang("ru")
        tr.set_text(entity.word)
        text = tr.translate()

        return text

    def __clear_string(self, str):
        text_tmp = re.sub('[^A-Za-z0-9-А-Яа-я  !,?.ё\'"]+', '', str)
        text_tmp = re.sub(' +', ' ', text_tmp)
        text_tmp = text_tmp.strip()

        return text_tmp

    def __error_log(self, text):
        pass
        now = datetime.datetime.now()
        logging.basicConfig(filename=self.__log_file_name, level=logging.INFO)
        msg = str(now)[:19] +" word:" + self.word + " Element not find query:" + text
        logging.info(msg)

    def __dict_file_download(self, entity):
        url = "https://www.dictionary.com/browse/" + entity.word

        r = requests.get(url, headers=self.__headers)
        doc = html.fromstring(r.text)

        nodeAudio = doc.xpath('//audio//source[2]')
        check_text = doc.xpath('//h1//text()')

        if len(check_text) > 0 and len(nodeAudio) > 0:
            check_text = check_text[0].replace(" ", "-")
            if check_text == entity.word:
                entity.file_url = nodeAudio[0].attrib['src']

    def __tureng_file_download(self, entity):
        url = "https://tureng.com/en/turkish-english/" + entity.word
        r = requests.get(url, headers=self.__headers)
        doc = html.fromstring(r.text)

        node = doc.xpath("//audio[@id='turengVoiceENTRENus']//source")
        if(len(node) > 0):
            file_path = "https:" + node[0].attrib['src']
            entity.file_url = file_path


import os
import Image
import math
import platform
import time
class getevopt(object):
	def __init__(self):
		if platform.system() == "Windows":
			import pygame.camera
			pygame.camera.init()
			clist = pygame.camera.list_cameras()

			if not clist:
				raise ValueError("Sorry, no cameras detected.")

			self.cam = pygame.camera.Camera(clist[0], (2304,1536), "YUYV") # define camera
	def capture(self, imagestring):
		import pygame.camera
		MyPlatform = platform.system()

		if MyPlatform == "Linux":
			execute("sudo fswebcam -q --jpeg 95 -d /dev/video0 -i 0 -r 2304x1536 --no-banner --no-timestamp %s"% imagestring) # -p YUYV, capture image

		elif MyPlatform == "Windows":
			#use pygame to capture image
			self.cam.start()
			surface = pygame.Surface((2304,1536))
			image = self.cam.get_image(surface)
			pygame.image.save(image, imagestring)
			self.cam.stop()

		time.sleep(0.25)
	def GetB(self, imagestring):
		image = Image.open(imagestring)
		pix = image.load()
		sumb = 0
		for x in range(image.size[0]):
			for y in range(image.size[1]):
				b = pix[x,y][0]*0.2126 + pix[x,y][1]*0.7152 + pix[x,y][2]*0.0722
				sumb += b
		bpre = sumb/(image.size[0]*image.size[1])
		return bpre
	def main(self):
		# take image with set ev
		os.system("v4l2-ctl --set-ctrl exposure_absolute=1000")

		timestart = time.time()
		self.capture("ev.jpg")
		timeused = time.time()-timestart

		bpre = self.GetB()

		evopt = 1000 + math.log(bpre,2) - math.log(2500/2, 2) # 2500/2 is just temporary

		print(evopt)
		return evopt

clas = getevopt()

sumb = 0
loopcount = 0
avgb = 0
while True:
	loopcount += 1
	#clas.capture("B opt images/%s.jpg"% str(loopcount))
	sumb += clas.GetB("B opt images/%s.jpg"% str(loopcount))
	avgb = sumb/loopcount
	print(avgb)

# x = open("evopt.txt")
# x.write(str(evopt))
# x.close()


import io
import wordcloud
import matplotlib.pyplot as plt

def calculate_frequencies(file_contents):
    # Here is a list of punctuations and uninteresting words you can use to process your text
    punctuations = '''!()-[]{};:'"\,<>./?@#$%^&*_~'''
    uninteresting_words = ["the", "a", "not", "in", "may", "then", "theres", "for", "on", "to", "if", "is", "it", "of", "and", "or", "an", "as", "i", "me", "my", \
    "we", "our", "ours", "you", "your", "yours", "he", "she", "him", "his", "her", "hers", "its", "they", "them", \
    "their", "what", "which", "who", "whom", "this", "that", "am", "are", "was", "were", "be", "been", "being", \
    "have", "has", "had", "do", "does", "did", "but", "at", "by", "with", "from", "here", "when", "where", "how", \
    "all", "any", "both", "each", "few", "more", "some", "such", "no", "nor", "too", "very", "can", "will", "just"]

    # Remove punctuations from the text
    for char in file_contents:
        if char in punctuations:
            file_contents = file_contents.replace(char, "")

    # Convert the text to lowercase and split it into words
    words = file_contents.lower().split()

    # Remove uninteresting words from the list of words
    filtered_words = [word for word in words if word not in uninteresting_words]

    # Create a dictionary of word frequencies
    word_freq = {}
    for word in filtered_words:
        if word not in word_freq:
            word_freq[word] = 1
        else:
            word_freq[word] += 1

    # Create a WordCloud object and generate the image
    cloud = wordcloud.WordCloud()
    # wordcloud = WordCloud(width=800, height=400, max_words=50, background_color="white").generate(text)
    cloud = wordcloud.WordCloud(width=1366, height=768,background_color="black")
    cloud.generate_from_frequencies(word_freq)
    return cloud.to_array()

def _upload():
    uploaded_file = input("Upload a file:")
    with open(uploaded_file, 'r') as f:
        file_contents = f.read()
    # Call the calculate_frequencies() function with the file contents
    myimage = calculate_frequencies(file_contents)

    # Display the word cloud image using matplotlib
    plt.imshow(myimage, interpolation='nearest')
    plt.axis('off')
    plt.show()

_upload()


import logging
import time

import requests

from .urls import UNIPOLSAI_BASE, LOGIN_URL, HOME_URL, POST_LOGIN, API_URL
from .utils import PositionData
from .secrets import PLATE

logging.basicConfig(level=logging.WARNING, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)

class Unipolsai:
    def __init__(self, creds: dict, headers: dict):
        """Define Unipolsai object

        :param creds: dict with username and password
        :param headers: dict with headers needed to authenticate, see documentation.
        """
        self.creds = creds
        self.session = requests.session()
        self.session.headers.update(headers)
        self.is_authenticated = False

    def authenticate(self):
        """Authenticate the instance on the site
        :return: True if authentication was succesfull
        """
        self.session.head(UNIPOLSAI_BASE)
        self.session.post(UNIPOLSAI_BASE + LOGIN_URL, data=self.creds)
        self.session.head(UNIPOLSAI_BASE + HOME_URL)
        self._check_auth()
        if not self.is_authenticated:
            raise ConnectionError("There was some error connecting to the API")
        return self.is_authenticated

    def get_position(self, plate: str = PLATE, update: bool = False):
        """Get the latest position retrieved from the GPS Unibox

        :param plate: plate of the vehicle you want to locate
        :param update: if True it will request an update of the position and start a polling waiting for a new position
        :return: PositionData object with the last position retrieved
        """
        if not plate:
            raise AttributeError("If PLATE is not set in secrets.py you have to pass it as an argument")
        if not self._check_auth():
            self.authenticate()
        response = self.session.get(
            url=UNIPOLSAI_BASE + API_URL.format(plate=str(plate).upper(),
                                                update=str(update).lower())
        )
        if response.ok:
            if response.json().get("operationResult").get("type") == 0:
                raw_position = response.json().get('lastPosition')
                parsed_position = PositionData.parse_raw_position(raw_position)
                if update:
                    new_position = self._poll_position(plate=plate, last_position=parsed_position)
                    if new_position is None:
                        logger.warning("Requested updated position, couldn't return it. (Probably needed more time)")
                        logger.debug(str(parsed_position))
                        return parsed_position
                    logger.info("Requested updated position, returned it.")
                    logger.debug(str(new_position))
                    return new_position
                logger.info("Requested position without updating")
                return parsed_position
        else:
            print(str(response.status_code) + str(response.content))

    def _check_auth(self) -> bool:
        """Check if authentication was succesfull or not
        :return: True if authentication was succesfull, False if not
        """
        response = self.session.post(
            url=UNIPOLSAI_BASE + POST_LOGIN,
            data={'channel': "TPD_Web"})
        self.is_authenticated = response.status_code == 200
        if not self.is_authenticated:
            logger.error("Authentication failed: {}".format(response.content))
        return self.is_authenticated

    def _poll_position(self, plate: str, last_position: PositionData, initial_delay: int = 40, delay: int = 12,
                       backoff=1, tries: int = 5):
        import datetime
        """ This method polls the api to see if the position is changed since the update request

        :param plate: Plate of the vehicle
        :param last_position: Last position of the vehicle
        :param initial_delay: Seconds to wait before starting the polling
        :param delay: Seconds to wait after each try
        :param backoff: Multiplier for the delay
        :param tries: Number of tries
        :return: The new location if found, None if not able to get a different position
        """
        now = datetime.datetime.now().timestamp()
        ten_min_ago = str(now - (10 * 60))[:10]
        if ten_min_ago < last_position.unix_timestamp:
            logger.debug("5m ago: {} | lastPos: {}".format(ten_min_ago, last_position.unix_timestamp))
            logger.info("Requested an update too soon, returning the last position")
            # since the api won't respond I just skip that and return it instantly
            return last_position
        logger.debug("Waiting initial {} seconds".format(initial_delay))
        time.sleep(initial_delay)
        for n in range(tries):
            try:
                new_position = self.get_position(plate)
                if new_position.unix_timestamp == last_position.unix_timestamp:
                    logger.debug("#{}. Still not updated. Delay: {}".format(n, delay))
                    time.sleep(delay)
                    delay = int(delay * backoff)
                else:
                    logger.debug("Found new position on #{} after {} seconds".format(n, initial_delay + delay))
                    return new_position
            except AttributeError as a_e:
                logger.warning("Attribute Error: {}".format(a_e))
                pass
            except ConnectionError as c_e:
                logger.warning("Connection Error: {}".format(c_e))
        return None

    def __del__(self):
        logger.debug("Logging off")
        try:
            response = self.session.get(UNIPOLSAI_BASE + "myportal/logout", headers={"Connection": "close"})
        except requests.ConnectionError:
            # Don't really understand this
            pass
        logger.info("Succesfully logged off")
        self.session.close()


# assset - актив. Подразумевается, что это конкретный элемент из активов в портфеле на счете у брокера
import datetime
import typing

from tinkoff.invest import (
    PortfolioPosition
)
from tinkoff.invest.grpc.operations_pb2 import OperationsResponse, Operation

from traider.responses.user_info_responses import (
    AssetsShow,
    ShowMyMoney,
    CurrentAsset
)
from traider.traider_client import TraiderClient

class PortfolioUserInfo(TraiderClient):
    def __init__(self):
        super().__init__()
        self._portfolio = self._operations.get_portfolio(account_id=self.id_)

    def __create_asset_item(self, item: PortfolioPosition) -> AssetsShow:
        """Создает объект AssetsShow, который исспользуется для отображения
        усеченной информации об Активе, отображенного в списке всех активов.
        """
        item_name = self._get_asset_item(
            item.instrument_type, item.figi).name
        return AssetsShow(
            name=item_name,
            figi=item.figi,
            amount=self.resp_to_float(item.quantity),
            average_price=self.resp_to_float(
                item.average_position_price),
            item_type=item.instrument_type
        )

    def get_total_balance(self) -> ShowMyMoney:
        portfolio = self._portfolio.total_amount_portfolio
        return ShowMyMoney(
            units=portfolio.units,
            currency=portfolio.currency,
            yield_=self.resp_to_float(self._portfolio.expected_yield))

    def get_list_of_assets(self) -> list[AssetsShow]:
        my_assets = []
        for pos in self._portfolio.positions:
            my_assets.append(self.__create_asset_item(pos))
        return my_assets

    def __sum_price(self, item: PortfolioPosition) -> float:
        """Рассчет сумы всех активов после продажи"""
        amount = self.resp_to_float(item.quantity)
        avg_price = self.resp_to_float(item.average_position_price)
        exp_yield = self.resp_to_float(item.expected_yield)
        nkd = self.resp_to_float(item.current_nkd)
        tax = exp_yield * 0.013 if exp_yield else 0
        return (amount * avg_price) + exp_yield + (nkd * amount) - tax

    def get_price_after_selling(self) -> float:
        positions = self._portfolio.positions
        sell_sum = [self.__sum_price(item) for item in positions]
        sum_without_comission = sum(sell_sum)
        return sum_without_comission - (sum_without_comission * 0.003)

    def __get_current_asset_item(
            self, item: PortfolioPosition) -> CurrentAsset:
        return CurrentAsset(
            name=self._get_asset_item(
                item.instrument_type, item.figi).name,
            amount=self.resp_to_float(item.quantity),
            current_price=self.resp_to_float(item.current_price),
            average_price=self.resp_to_float(item.average_position_price),
            figi=item.figi,
            nkd=self.resp_to_float(item.current_nkd)
        )

    def get_current_asset(self, figi_callback: str) -> CurrentAsset | str:
        """Передается в переменную figi_callback строка вида
        ,например, Figi_HND123LKJ.
        """
        figi = figi_callback.split('_')[1]
        item = [i for i in self._portfolio.positions if i.figi == figi]
        if item:
            return self.__get_current_asset_item(item[0])
        return 'ничего не нафдено'

class UserOperations(TraiderClient):
    def __init__(self):
        super().__init__()

    @staticmethod
    def _days_int_to_datetime(days_ago: int) -> datetime:
        """Метод перевода количества дней в дату, предшествующую текущей на указанное количество дней."""
        today = datetime.datetime.now()
        delta = datetime.timedelta(days=days_ago)
        return today - delta

    def get_last_operations(
            self, days_ago: int = 10,
            figi: typing.Optional[str] = None) -> list[Operation]:
        """Возвращает последние операции пользователя за определенное количество дней.
            :param days_ago количество дней за которое необходимо узнать об операциях.
            :param figi неоьязательный аргумент для поиска операций по его идентификатору
        """
        params = {
            'account_id': self.id_,
            'from_': self._days_int_to_datetime(days_ago),
            'to': datetime.datetime.utcnow(),
        }
        if figi:
            params.update({'figi': figi})
            return self._operations.get_operations(**params).operations
        return self._operations.get_operations(**params).operations

user_info = PortfolioUserInfo()
user_operations = UserOperations()


# imported the requests library
import requests
import os
from bs4 import BeautifulSoup
import re
import urllib.request
# from urllib.request import Request, urlopen
import lxml
username = os.getlogin()
filestartswith1 = "coal"
filestartswith2 = "dynomite"
host_site = "https://archive.wrccdc.org/images/2020/wrccdc-2020-invitationals/rock.bottom/"
user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'
headers={'User-Agent':user_agent,}
request=urllib.request.Request(host_site,None,headers) #The assembled request
response = urllib.request.urlopen(request)
data = response.read() # The data u need
soup = BeautifulSoup(data, "lxml")
file_names = []
for link in soup.findAll('a'):
    if str(link).find(".ova") != -1:
        file_names.append(link.get('href'))
    else:
        pass
print(file_names)
for file_name in file_names:
    if file_name.startswith(filestartswith1) or file_name.startswith(filestartswith2):
        print("Downloading", file_name, "from", host_site, "...")
        path = "C:\\Users\\" + username + "\\Downloads\\Original-ova\\" + file_name
        file_url = host_site + "/" + file_name
        # URL of the image to be downloaded is defined as image_url
        r = requests.get(file_url) # create HTTP response object
        # send a HTTP request to the server and save
        # the HTTP response in a response object called r
        with open(path,'wb') as f:
            # Saving received content as a png file in
            # binary format
            # write the contents of the response (r.content)
            # to a new file in binary mode.
            f.write(r.content)
        print(file_name," download finished")


from django.shortcuts import get_object_or_404
from rest_framework import filters, viewsets
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.permissions import AllowAny

from posts.models import Comment, Group, Post

from .mixins import GetPostViewSet
from .permissions import AuthorOrReadOnly
from .serializers import (CommentSerializer, FollowSerializer, GroupSerializer,
                          PostSerializer)

class GroupViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Group.objects.all()
    permission_classes = (AllowAny,)
    serializer_class = GroupSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = (AuthorOrReadOnly,)
    pagination_class = LimitOffsetPagination

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

class CommentViewSet(viewsets.ModelViewSet):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer
    permission_classes = (AuthorOrReadOnly,)

    def get_post(self):
        post = get_object_or_404(Post, id=self.kwargs.get("post_id"))
        return post

    def get_queryset(self):
        post = self.get_post()
        return post.comments.all()

    def perform_create(self, serializer):
        post = self.get_post()
        serializer.save(author=self.request.user, post=post)

class FollowViewSet(GetPostViewSet):
    serializer_class = FollowSerializer
    filter_backends = (filters.SearchFilter,)
    search_fields = ('following__username',)

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

    def get_queryset(self):
        user = self.request.user
        return user.follower.all()


#!/usr/bin/env python
from Bio import SeqIO, Seq
from re import compile
import numpy as np
from sys import argv, stderr

p = compile("[actg]")
f = SeqIO.parse(open(argv[1]), "fasta")
#lowercase masked intron contigs

ep_hint_length = 10

contig_coords = {}
for rec in f:
  aseq = str(rec.seq)
  strip_seq = p.sub('', aseq)
  coords = np.zeros((len(aseq) + 1,), dtype=int)

  newseq = ""
  coord_d = {}
  i, j = 0, 0

  for b in aseq:
    i += 1
    if b.islower():
      j += 1
    else:
      coords[i] = i - j

  contig_coords[rec.name] = coords

for line in open(argv[2]):
  atoms = line.split()
  contig = atoms[0]
  prog = atoms[1]
  src = atoms[2]

  try:
    if contig in contig_coords:
      s, e = contig_coords[contig][int(atoms[3])], contig_coords[contig][int(atoms[4])]
      score = atoms[5]
      strand = atoms[6]
      note = atoms[-1]

      if e - s + 1 == ep_hint_length:
        print("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s" % (contig, prog, src, s, e, score, strand, ".", note))

  except IndexError:
    stderr.write("EP hint out of bounds: %s %s %s" % (contig, atoms[3], atoms[4]))


import os
from celery import Celery
from django.conf import settings
# Set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'baul.settings')
app = Celery('baul')
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

@app.task(bind=True)
def debug_task(self):
    print(f'Request: {self.request!r}')


from config import bots_list
from common_exceptions import IllegalApiBotManagerActionTypeException
from api.manage_data import DataManager
import warnings

class BotManager:
    def __init__(self):
        self.bot_list = bots_list
        self.data_manager = DataManager()

    def execute_the_bot_task(self, task_description_json, user_session):
        bot_name = task_description_json['task']['bot_name']
        bot = self.bot_list[bot_name]['bot_class']()
        shop_name = self.bot_list[bot_name]['shop']
        action_type = task_description_json['task']['action_type']
        profiles_idx, billing_idx, shipping_idx, proxies_idx, items_idx = \
            self.get_the_idx_for_the_data_types(task_description_json)

        profiles, billing, shipping, proxies, items = self.get_the_users_data(user_session=user_session,
                                                                              shop_name=shop_name,
                                                                              profile_idx=profiles_idx,
                                                                              billing_idx=billing_idx,
                                                                              shipping_idx=shipping_idx,
                                                                              items_idx=items_idx,
                                                                              proxies_idx=proxies_idx)

        if action_type == 'buy':
            item_link = task_description_json['task']['item_link']
            self.buy(bot, item_link=item_link, profiles=profiles, billing=billing, shipping=shipping, proxies=proxies)
        elif action_type == 'register':
            self.register(bot, profiles=profiles, billing=billing, shipping=shipping, proxies=proxies)
        elif action_type == 'login':
            self.login(bot, profiles=profiles)
        elif action_type == 'execute_whole_buying_process':
            self.execute_the_bot_task(bot, user_session=user_session)
        else:
            raise IllegalApiBotManagerActionTypeException(action_type)

    def get_the_users_data(self, user_session, profile_idx, shop_name, billing_idx, shipping_idx, proxies_idx, items_idx):
        ''' The function which gets the data for the bot execution, data like profiles or billing user data '''
        profiles = self.data_manager.profiles.get_the_data(session=user_session)
        billing = self.data_manager.billing.get_the_data(session=user_session)
        shipping = self.data_manager.shipping.get_the_data(session=user_session)
        proxies = self.data_manager.proxies.get_the_data(session=user_session)
        items = self.data_manager.items.get_the_data(session=user_session)
        # Getting the right data by the idx
        profiles = self.get_the_right_data_by_id(data_id=profile_idx, data=profiles, shop_name=shop_name)
        billing = self.get_the_right_data_by_id(data_id=billing_idx, data=billing, shop_name=shop_name)
        shipping = self.get_the_right_data_by_id(data_id=shipping_idx, data=shipping, shop_name=shop_name)
        proxies = self.get_the_right_data_by_id(data_id=proxies_idx, data=proxies, shop_name=shop_name)
        items = self.get_the_right_data_by_id(data_id=items_idx, data=items, shop_name=shop_name)

        return profiles, billing, shipping, proxies, items

    @staticmethod
    def get_the_right_data_by_id(data_id, shop_name, data):
        ''' Getting one instance by id of  the needed data with the correct shop '''
        data_with_correct_shop = []
        for instance in data:
            if instance['shop']['name'] == shop_name:
                data_with_correct_shop.append(instance)
        try:
            return data_with_correct_shop[data_id]
        except IndexError:
            warnings.warn('The data by the index {} doesn\'t exist'.format(data_id))
            return None

    @staticmethod
    def get_the_idx_for_the_data_types(task_description_json):
        profiles_idx = task_description_json['task']['profiles_id']
        billing_idx = task_description_json['task']['billing_id']
        shipping_idx = task_description_json['task']['shipping_id']
        proxies_idx = task_description_json['task']['proxies_id']
        items_idx = task_description_json['task']['item_id']

        return profiles_idx, billing_idx, shipping_idx, proxies_idx, items_idx

    @staticmethod
    def buy(bot, item_link, profiles=None, billing=None, shipping=None, proxies=None):
        bot.buy_item(item_link=item_link, billing_data=billing, profile_data=profiles, proxies_data=proxies,
                     shipping_data=shipping)

    @staticmethod
    def register(bot, profiles=None, billing=None, shipping=None, proxies=None):
        bot.register(billing_data=billing, shipping_data=shipping, profile_data=profiles, proxies_data=proxies)

    @staticmethod
    def login(bot, profiles):
        bot.login(profiles_data=profiles)

    def execute_whole_buying_process(self, bot, profiles, billing, shipping, proxies, items):
        pass


import pygame
import sys
import math
import random

# Inicialização do Pygame
pygame.init()

# Definições de tela
width, height = 800, 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Simulador de Futebol')

# Cores
white = (255, 255, 255)
green = (0, 255, 0)
blue = (0, 0, 255)
red = (255, 0, 0)

# Número de robôs
num_robots = 5

# Posições iniciais dos robôs e bola
robot_positions = [[random.randint(50, 750), random.randint(50, 550)] for _ in range(num_robots)]
ball_pos = [random.randint(50, 750), random.randint(50, 550)]

# Velocidade dos robôs
robot_speed = 2

# Carregar imagens
robot_image = pygame.image.load('horngirl.png')
robot_rect = robot_image.get_rect()

# Loop principal
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    # Encontrar o robô mais próximo da bola
    closest_robot_index = min(range(num_robots), key=lambda i: math.sqrt((robot_positions[i][0] - ball_pos[0])**2 + (robot_positions[i][1] - ball_pos[1])**2))

    # Atualizar posição do robô mais próximo em direção à bola
    angle = math.atan2(ball_pos[1] - robot_positions[closest_robot_index][1], ball_pos[0] - robot_positions[closest_robot_index][0])
    robot_positions[closest_robot_index][0] += robot_speed * math.cos(angle)
    robot_positions[closest_robot_index][1] += robot_speed * math.sin(angle)

    # Verificar se o robô mais próximo tocou na bola
    distance_to_ball = math.sqrt((ball_pos[0] - robot_positions[closest_robot_index][0])**2 + (ball_pos[1] - robot_positions[closest_robot_index][1])**2)
    if distance_to_ball < 20:
        # Se o robô mais próximo tocou na bola, mova a bola para uma nova posição aleatória
        ball_pos = [random.randint(50, 750), random.randint(50, 550)]

    # Desenhar campo de futebol
    screen.fill(green)
    pygame.draw.rect(screen, white, (50, 50, width - 100, height - 100), 2)

    # Desenhar robôs
    for i in range(num_robots):
        robot_rect.center = (int(robot_positions[i][0]), int(robot_positions[i][1]))
        screen.blit(robot_image, robot_rect)

    # Desenhar bola
    pygame.draw.circle(screen, blue, (int(ball_pos[0]), int(ball_pos[1])), 10)

    # Atualizar a tela
    pygame.display.flip()

    # Controlar a taxa de quadros
    pygame.time.Clock().tick(60)


# -*- coding: utf-8 -*-
"""
Created on Mon Mar 25 23:15:02 2019

@author: ljp
"""

import numpy as np
from scipy.stats import multivariate_normal
import random
from scipy.ndimage import convolve

##### Function that creates plans from parameters #####

def unet_create_plans(number_of_plans, plan_size, num_mean, num_std, info_neuron, coord_threshold):

    """Function that creates stack of plans from parameters.

    %%%%% INPUTS %%%%%
    - number_of_plans: final number of stacked plans in output (integer)
    - plan_size: size of each plan in pixels (vector of 2 integers)
    - num_mean: mean number of neurons per plan (integer)
    - num_std: standard deviation of number of neurons per plan (integer)
    - info_neuron: series of 8 floats describing each neuron, comprising:
            - neu_mean: mean intensity
            - neu_std: standard deviation of intensity
            - cor_mean: mean covariance (inclinaison)
            - cor_std: standard deviation of covariance
            - xvar_mean: mean variance in the x-axis direction
            - xvar_std: standard deviation of the variance in the x-axis direction
            - yvar_mean: mean variance in the y-axis direction
            - yvar_std: standard deviation of the variance in the y-axis direction

    %%%%% OUTPUTS %%%%%
    - plans_temp: plans with neurons stacked along first dimension ((number_of_plans, plan_size[0], plan_size[1]) matrix)
    - coord_temp: coordinates of all neurons, with associated plan ((number_of_plans, plan_size[0], plan_size[1]) matrix)
    """

    # Retriving information on neurons
    neu_mean, neu_std, cor_mean, cor_std, xvar_mean, xvar_std, yvar_mean, yvar_std = info_neuron

    # Creating initial set of plans
    plans_temp = np.zeros((number_of_plans, plan_size[0], plan_size[1]))
    # Defining coordinates vector
    coord_temp = np.zeros((number_of_plans, plan_size[0], plan_size[1]))

    # Creating Xfield and Yfield vectors
    Xfield, Yfield = np.mgrid[-6:7, -6:7]
    Xfield = Xfield.flatten()[:, np.newaxis]
    Yfield = Yfield.flatten()[:, np.newaxis]

    # Defining number of neurons per plan
    numfin = np.round_(num_mean + num_std*np.random.randn(number_of_plans))
    # Loop on each plan
    for i in range(number_of_plans):
        # Loop on each potential neuron in plan i
        for j in range(int(numfin[i])):
            # Finding available space for neuron
            finding = -1
            numround = 0
            numlim = 50
            while finding == -1 and numround < numlim:
                randx = int(np.round_(np.random.rand() * (plan_size[0] - 15)) + 7)
                randy = int(np.round_(np.random.rand() * (plan_size[1] - 15)) + 7)
                anafield = plans_temp[i, (randx-7):(randx+6), (randy-7):(randy+6)]
                if np.count_nonzero(anafield) == 0:
                    break
                numround += 1
            if numround == numlim:
                continue
            # Defining neuron's information
            matcorval = cor_mean + cor_std * np.random.randn()
            matrixstd = np.array([[xvar_mean + xvar_std*np.random.randn(), matcorval],
                                 [matcorval, yvar_mean + yvar_std*np.random.randn()]])
            if np.linalg.det(matrixstd) < 0:
                continue
            # Making matrix with neuron's information
            numval = (neu_mean + neu_std*np.random.randn()) * np.sqrt((2*np.pi)**2 * np.linalg.det(matrixstd))
            mvn = multivariate_normal(mean = np.array([0, 0]), cov = matrixstd)
            valexp = numval * mvn.pdf(np.hstack((Xfield, Yfield)))
            if numval <= 0:
                continue
            # Replacing in final plan
            plan_temp = valexp.reshape(13, 13)
            plans_temp[i, (randx-7):(randx+6), (randy-7):(randy+6)] = plan_temp
            # Adding neuron detection in coord_temp
            coord_temp[i, (randx-7):(randx+6), (randy-7):(randy+6)] = 1 * (plan_temp > neu_mean/coord_threshold)

    return plans_temp, coord_temp

##### Function that stacks plans from create_plans function #####

def unet_stack_plans(nstacks, plans_dataset, coord_dataset, cropped_size, stack_mean, stack_std, noise_mean, noise_std):

    """Function that randomly stack plans given as inputs.

    %%%%% INPUTS %%%%%
    - nstacks: final number of stacked plans (integer)
    - plans_dataset: plans dataset obtained from unet_create_plans (3d matrix)
    - coord_dataset: coordinates dataset obtained from unet_create_plans (3d matrix)
    - cropped_size: final size of plans after cropped (integer)
    - stack_mean: mean number of plans stacked for one final plan (integer)
    - stack_std: standard deviation of number of plans stacked for one final plan (integer)
    - noise_mean: mean of noise plan added to stacked plans (float)
    - noise_std: standard deviation of noise plan added to stacked plans (float)

    %%%%% OUTPUTS %%%%%
    - plans_stack: final plans stacked along first dimension ((nstacks, cropped_size, cropped_size) matrix)
    - coord_stack: coordinates of all neurons, with associated final plan ((number of neurons, 3) matrix)
    """

    # First defining final matrices
    plans_stack = np.zeros((nstacks, cropped_size, cropped_size))
    coord_stack = np.zeros((nstacks, cropped_size, cropped_size))

    # Number of stacks in plans_dataset
    nstacks_old = plans_dataset.shape[0]

    # Parameters for cropping
    xcrop = plans_dataset.shape[1] - cropped_size
    ycrop = plans_dataset.shape[2] - cropped_size

    # Filter for noise, will be convolved to have continuous noise
    filter_shape = 5
    filter_noise = np.zeros((filter_shape, filter_shape))
    for i in range(filter_shape):
        for j in range(filter_shape):
            radius_temp = np.sqrt((i-(filter_shape-1)/2)**2 + (j-(filter_shape-1)/2)**2)
            if radius_temp <= 1:
                filter_noise[i, j] = 1
            elif radius_temp <= 2:
                filter_noise[i, j] = 0.5

    # Launching loop
    for i in range(nstacks):
        # Selecting number of stacks
        stack_f = int(np.round_(stack_mean + stack_std*np.random.randn()))
        if stack_f <= 0:
            stack_f = 1
        # Creating temporary plan
        plans_temp = np.zeros((stack_f+1, cropped_size, cropped_size))
        # Creating a temporaty coordinates matrix
        coords_temp = np.zeros((stack_f, cropped_size, cropped_size))
        # Chosing plans to use
        plan_use = np.floor(nstacks_old*np.random.rand(stack_f)).astype(int)
        # Second for loop for each plan
        for j in range(stack_f):
            # Loading plan and coordinates
            plan_temp = plans_dataset[plan_use[j], :, :]
            coord_temp = coord_dataset[plan_use[j], :, :]
            # Cropping
            xcrop_init = random.randint(0, xcrop) #np.random.random_integers(0, xcrop)
            ycrop_init = random.randint(0, ycrop) #np.random.random_integers(0, ycrop)
            plan_temp = plan_temp[xcrop_init:(xcrop_init+cropped_size), ycrop_init:(ycrop_init+cropped_size)]
            coord_temp = coord_temp[xcrop_init:(xcrop_init+cropped_size), ycrop_init:(ycrop_init+cropped_size)]
            # Rotating
            rotnum = random.randint(0, 3) #np.random.random_integers(0, 3)
            for k in range(rotnum):
                plan_temp = plan_temp.T[::-1, :]
                coord_temp = coord_temp.T[::-1, :]
            # Adding to temporary stack
            plans_temp[j, :, :] = plan_temp
            coords_temp[j, :, :] = coord_temp
        # Adding noise plan
        plan_noise = noise_mean + np.abs(noise_std*np.random.randn(cropped_size, cropped_size))
        plans_temp[-1, :, :] = convolve(plan_noise, filter_noise, mode="constant") # convolution to filter
        # Merging stacks into stack_plan
        stack_plan_temp = np.max(plans_temp, axis=0)
        stack_plan_temp[stack_plan_temp < 0] = 0
        plans_stack[i, :, :] = stack_plan_temp
        # Deleting doublons in stack_coord
        argmax_plan_temp = np.argmax(plans_temp, axis=0) + 1
        coord_stack[i, :, :] = argmax_plan_temp * np.max(coords_temp, axis=0)

    # Returning values
    return plans_stack, coord_stack


import frappe
from frappe_notification import (
    NotificationTemplate,
)
from .utils import validate_template_access

def fork_template(template: str):
    """
    Fork a template
    You will need read access on the template being forked
    """
    validate_template_access(template=template, ptype="read")

    d: NotificationTemplate = frappe.get_doc("Notification Template", template)
    fork = d.fork()

    return fork


#!flask/bin/python
from flask import Flask, request, jsonify, make_response, abort
import cPickle as pickle

from main import *

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

app = Flask(__name__)

#app.run(threaded=True)

questions = [
	{
		'qId': 1,
		'qText': 'Dummy Question',
		'qParts': [],
		'qFocus': [],
		'qFocRoots': [],
		'qMod': [],
		'qClass': [],
		'qPnoun': [],
		'qSubj': [],
		'qTransPhrase': [],
		'qTranslation': [],
		'qQuery': [],
		'qRelated_doc_ids': [],
		'qRelated_doc_titles': [],
		'qRelated_doc_texts': [],
		'done': False
		}
	]

question = []

@app.route('/hc-api/v0.1/dev', methods=['GET'])
def get_questions():
	return jsonify({'questions':questions})

@app.route('/hc-api/v0.1/devMass', methods=['POST'])
def mass_evaluate():
	print("HC_API: Running Mass Evaluator")
	if not request.json or not 'evalDataFile' in request.json:
		abort(400)

	dataPath = request.json['evalDataFile']
	topDocsNum = int(request.json['topDocs']) # we don't use it in mass, right?

	# READ DATA FILE (to fill these lists:)

	questionList, focusListAnnotatedT, modListAnnotatedT, classListAnnotated, parsedBefore, answerList = mainReadDataFile(dataPath)

	# RUN the SYSTEM on EVERY QUESTION (to fill these lists:)

	#total = len(questionList) # just for debugging
	# ['dummy']*total

	if topDocsNum == 1:
		bypassDocs=False
	else:
		bypassDocs=True

	focusListFoundT, modListFoundT, classListFound, transPhraseList, transList, relatedDocs, answerFoundInDocs, queries = mainEval(questionList, answerList, parsedBefore, dataPath, topDocs=topDocsNum, bypassDocs=bypassDocs)
	# format of relatedDocs -> [[titles, texts], [titles, texts], ...]

	print("HC_API: Compiling response ...")
	responseData = {
		'questionTexts': questionList,
		'answerList': answerList,
		'focusListAnnoT': focusListAnnotatedT,
		'focusListFoundT': focusListFoundT,
		'modListAnnoT': modListAnnotatedT,
		'modListFoundT': modListFoundT,
		'classListAnno': classListAnnotated,
		'classListFound': classListFound,
		'transPhraseList': transPhraseList,
		'transList': transList,
		'relatedDocs': relatedDocs,
		'answerFoundDocs': answerFoundInDocs,
		'queries': queries
			}

	print("HC_API: Posting response...")
	return jsonify({'responseData':responseData}), 201

@app.route('/hc-api/v0.1/dev', methods=['POST'])
def post_question():
	print("HC_API: Running Single")
	if not request.json or not 'questionText' in request.json:
		abort(400)

	print("\n\n\n=================\n\n")
	#print(request.json['topDocs'])
	print("\n\n\n=================\n\n")

	qText = request.json['questionText']

	topDocs = int(request.json['topDocs'])

	qObj = mainParse(qText)

	qFoc, qFocRoots, qMod, qClass, qPnoun, qSubj = mainAnalyze(qObj, False, False)

	qTerms = mainBuildQuery(qObj)

	docs = mainQuerySingle(count=topDocs)

	titles, texts = mainRelated(docs)

	transPhrase = " ".join([ qPnoun, qMod + qFoc ])
	translation = mainTranslate(transPhrase)

	print("HC_API: Compiling response...")
	question = {
		'qId': questions[-1]['qId'] + 1,
		'qText': qObj.questionText,
		'qParts': qObj.questionParts,
		'qFocus': qFoc,
		'qFocRoots': qFocRoots,
		'qMod': qMod,
		'qClass': qClass,
		'qPnoun': qPnoun,
		'qSubj': qSubj,
		'qTransPhrase': transPhrase,
		'qTranslation': translation,
		'qQuery': str(qTerms),
		'qRelated_doc_ids': docs,
		'qRelated_doc_titles': titles,
		'qRelated_doc_texts': texts,
		'done': True
		}

	questions.append(question)

	print("HC_API: Posting response...")
	return jsonify({'question':question}), 201

"""
@app.route('/')
def index():
        return "Hello, World!"
"""

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

if __name__ == '__main__':
        app.run(port=8080,debug=True)


from flask import Blueprint,jsonify

import imp

beans = imp.load_package("beans","../beans")
services = imp.load_package("services","../services")
dao = imp.load_package("dao","../dao")

#from dao.UserDAO import registerUser
from beans.User import User
from services.IndexService import downloadLink,parseHTML, tokenize
from dao.UserDAO import registerUser, displayUsers
routes = Blueprint("routes",__name__)

@routes.route("/")
def default():
    user = User("arthur","arthur.grevin@gmail.com","mdp")
    user.history.append("history1")
    user.history.append("history2")
    return jsonify(user.serialize())

@routes.route("/absorber")
def linkAbsorber():
    return parseHTML("https://fr.wikipedia.org/wiki/Pharaon")

@routes.route("/register/<string:json>",methods=['POST','PUT'])
def register():
    user = request.get_json(force=True)
    user = User(user['login'],user['email'],user['password'])
    registerUser(user)
    return "test"

@routes.route("/test2")
def test2():
    displayUsers()
    return "test2"

@routes.route("/tokenize")
def tokenizeText():
    return tokenize("http://www.theverge.com/2015/12/10/9880594/microsoft-xbox-games-2016-interview-crackdown-3-quantum-break-recore")


import logging

from rich.logging import RichHandler

class Logger:
    def __init__(self):
        logger = logging.getLogger("dbt-coves logger")
        logger.setLevel(logging.INFO)

        c_handler = RichHandler(
            rich_tracebacks=True,
            show_level=False,
            markup=True,
            enable_link_path=False,
            show_path=False,
        )

        c_handler.setLevel(logging.INFO)
        logger.addHandler(c_handler)

        self.logger = logger
        self.format = format

    def set_debug(self):
        """Set loggers handlers to debug level."""
        self.logger.setLevel(logging.DEBUG)
        for handler in self.logger.handlers:
            handler.setLevel(logging.DEBUG)

log_manager = Logger()
LOGGER = log_manager.logger


import wx
from wx.lib.agw.floatspin import FloatSpin

from shs.input.fdf_options import ChoiceLine, MeasuredLine, NumberLine, ThreeNumberLine

try:
    from geom import Geom
except ImportError:
    from shs.geom import Geom

class Bravais(ChoiceLine):
    label = 'Composition'
    choices = ['BCC', 'FCC', 'SC']
    optional = False

class LatticeConstant(MeasuredLine):
    label = 'Lattice constant'
    value = 1.
    digits = 2
    increment = 0.01
    units = ['Bohr', 'Ang']
    optional = False

class DistortionLevel(NumberLine):
    label = 'Distortion level (in %)'
    value = 0.
    digits = 0
    increment = 1.
    range_val = (0., 100.)
    optional = False

class SuperCell(ThreeNumberLine):
    label = 'Supercell'
    optional = False

class ACInitDialog(wx.Dialog):

    def __init__(self, *args, **kwds):
        self.types = kwds.pop('types')
        wx.Dialog.__init__(self, *args, **kwds)
        self.bravais = Bravais(self)
        self.type_label = []
        self.typefs = []
        if len(self.types) == 0:
            self.add_type_btn = wx.Button(self, -1, "Add type")
            self.add_type_btn.Bind(wx.EVT_BUTTON, self.add_type)
        else:
            for t in self.types:
                self.type_label.append(wx.StaticText(self, -1, t))
                self.typefs.append(FloatSpin(self, -1, min_val=0, value=1., digits=0))

        self.sc = SuperCell(self)

        self.alat = LatticeConstant(self)
        self.dist = DistortionLevel(self)
        self.__set_properties()
        self.__do_layout()

    def __set_properties(self):
        self.SetTitle("Initialize geometry")

    def __do_layout(self):
        comp_label = wx.StaticBox(self, -1, 'Composition')
        comp_sizer = wx.StaticBoxSizer(comp_label, wx.HORIZONTAL)
        self.comp_inside = wx.GridSizer(2, len(self.types), 2, 2)

        for l in self.type_label:
            self.comp_inside.Add(l, 0, wx.ALIGN_CENTER, 0)
        for fs in self.typefs:
            self.comp_inside.Add(fs, 0, wx.ALIGN_CENTER, 0)

        comp_sizer.Add(self.comp_inside, 1, wx.ALL | wx.EXPAND, 5)
        if len(self.types) == 0:
            comp_sizer.Add(self.add_type_btn, 0, wx.ALL | wx.EXPAND, 5)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.bravais.sizer, 0, wx.EXPAND, 0)
        sizer.Add(comp_sizer, 0, wx.ALL | wx.EXPAND, 5)
        sizer.Add(self.alat.sizer, 0, wx.EXPAND, 0)
        sizer.Add(self.sc.sizer, 0, wx.EXPAND, 0)
        sizer.Add(self.dist.sizer, 0, wx.EXPAND, 0)
        sizer.Add(self.CreateSeparatedButtonSizer(wx.OK|wx.CANCEL), 0, wx.ALL|wx.EXPAND, 5)

        self.SetSizer(sizer)
        self.Fit()
        self.Layout()

    def add_type(self, evt):
        self.comp_inside.Clear()
        self.comp_inside.SetCols(self.comp_inside.GetCols()+1)
        self.type_label.append(wx.TextCtrl(self, -1))
        self.typefs.append(FloatSpin(self, -1, min_val=0, value=1., digits=0))
        for l in self.type_label:
            self.comp_inside.Add(l, 0, wx.ALIGN_CENTER, 0)
        for fs in self.typefs:
            self.comp_inside.Add(fs, 0, wx.ALIGN_CENTER, 0)
        self.Fit()
        self.Layout()

    def init_geom(self):
        bravais = self.bravais.GetValue()
        alat, unit = self.alat.GetValue()
        sc = self.sc.GetValue()
        dist = self.dist.GetValue()
        if len(self.types) == 0:
            comp = dict(zip([il.GetValue() for il in self.type_label], [ifs.GetValue() for ifs in self.typefs]))
        else:
            comp = dict(zip(self.types, [ifs.GetValue() for ifs in self.typefs]))
        g = Geom()
        g.initialize(bravais, comp, sc, alat, unit, dist_level=dist)
        g.geom2opts()
        return g.opts["AtomicCoordinatesAndAtomicSpecies"]


from rdflib.namespace import RDF
from source.utils import id2uri, g_add_with_valid
import csv
import json

def create_ttl(g, u, row: dict):
    """
    baid: 99415175
    activity: Active
    aid: 47346
    sid: 103186613
    cid: 44273608
    geneid: 10203
    pmid: 9438028
    aidtype: Confirmatory
    aidmdate: 20181015
    hasdrc: 0
    rnai: 0
    protacxn: Q16602
    acname: IC50
    acqualifier: =
    acvalue: 5
    aidsrcname: ChEMBL
    aidname: CGRP1 receptor affinity on human neuroblastoma cells SK-N-MC, which selectively express the human CGRP1 receptor.
    cmpdname: Yvptdvgseaf
    targetname: CALCRL - calcitonin receptor like receptor (human)
    targeturl: /gene/10203
    ecs: NULL
    repacxn: Q16602
    taxids: NULL
    cellids: NULL
    targettaxid
    """

    sid = id2uri(row["sid"], "sid")
    cid = id2uri(row["cid"], "cid")
    gid = id2uri(row["geneid"], "gid")
    pmid = id2uri(row["pmid"], "pmid")
    protein = id2uri(row["protacxn"], "protein")

    g_add_with_valid(g, sid, RDF.type, u.sid)
    g_add_with_valid(g, sid, u.sid2cid, cid)
    g_add_with_valid(g, sid, u.sid2pmid, pmid)

    g_add_with_valid(g, cid, RDF.type, u.cid)

    g_add_with_valid(g, gid, RDF.type, u.gid)
    g_add_with_valid(g, gid, u.gid2pmid, pmid)

    g_add_with_valid(g, pmid, RDF.type, u.pmid)

    g_add_with_valid(g, protein, RDF.type, u.protein)

    return g

if __name__ == "__main__":
    create_ttl(0,0,0)


#!/usr/bin/python3
#-*- coding: utf-8 -*-
from slackclient import SlackClient
import requests
import datetime
import pickle

# ================== CONFIGURATION ==================

URLS_TO_CHECK = ["http://example.com",
                 "https://anotherone.net:1337"]

# You have to have a token so you can send messages to a slack channel!
# https://api.slack.com/docs/oauth-test-tokens
SLACK_TOKEN = "YOUR_TOKEN_HERE"

# Where you want to receive your notifications ?

# you can get it using list_channels and channel_info or click on the channel name
# click on add app or integration and you can view it's id in the webpage redirection (you have to be fast because it redirects it to another page)
CHANNEL_ID = "G2LCBCXGF"

# ================== END CONFIGURATION ==================

slack_client = SlackClient(SLACK_TOKEN)

# ================== SLACK FUNCTIONS ==================
def list_channels():
    channels_call = slack_client.api_call("channels.list")
    if channels_call['ok']:
        return channels_call['channels']
    return None

def channel_info(channel_id):
    channel_info = slack_client.api_call("channels.info", channel=channel_id)
    if channel_info:
        return channel_info['channel']
    return None

def send_message(channel_id, message):
    response = slack_client.api_call(
        "chat.postMessage",
        channel=channel_id,
        text=message,
        username='UptimeMonitor',
        icon_emoji=':robot_face:'
    )
    if not response['ok']:
        print("Error sending notification to Slack -------> " + response['error'])

# ================== NOTIFY FUNCTIONS ==================
def down_notifier(the_url):
    try:
        old_status_file = pickle.load(open("status.p", "rb"))
    except Exception as ex:
        print("The status.p file was not found. it will be recreated." + str(ex))
        send_message(CHANNEL_ID, ":no_entry: " + the_url + " is down.")
        return

    # in case we just added the url to our database
    if the_url not in old_status_file:
        send_message(CHANNEL_ID, ":no_entry: " + the_url + " is down.")
        return

    # if it's already in the database and last status was up
    if (the_url in old_status_file) and (old_status_file[the_url]['status'] == "up"):
        send_message(CHANNEL_ID, ":no_entry: " + the_url + " is down.")
    else:
        print("already down. skip notifying")

# if it was previously down, notify that it's back online
def back_online_notifier(the_url):
    print("found " + the_url + " back online.")
    try:
        old_status_file = pickle.load(open("status.p", "rb"))
    except Exception as ex:
        print("The status.p file was not found. it will be recreated." + str(ex))
        return

    if (the_url in old_status_file) and (old_status_file[the_url]['status'] == "down"):
        it_was_down_time = old_status_file[the_url]['time']
        current_time = datetime.datetime.now().replace(microsecond=0)
        send_message(CHANNEL_ID, ":herb: " + the_url + " is back online. It was down for " + str(current_time - it_was_down_time))
    else:
        print("skipping notifying that the url is online")

# --- getting only the head ---
def get_status_code(xurl):
    try:
        response = requests.head(xurl, allow_redirects=False, timeout=3)
        return response.status_code
    except:
        return -1

# ~~~~~~~~~~~~~~~~~~~~~~~~ THE MAIN ~~~~~~~~~~~~~~~~~~~~~~~~
if __name__ == '__main__':

    # First test if you have the correct token
    # print(slack_client.api_call("auth.test"))

    status_file = {}

    for url in URLS_TO_CHECK:
        if get_status_code(url) != 200:
            print(url + " is down.")
            down_notifier(url)
            status_file[url] = {'status': "down", 'time': datetime.datetime.now().replace(microsecond=0)}
        else:
            back_online_notifier(url)
            status_file[url] = {'status': "up", 'time': datetime.datetime.now().replace(microsecond=0)}

        pickle.dump(status_file, open("status.p", "wb"))


# Build image using projects.builds()
#
# https://cloud.google.com/compute/docs/images/export-image#exporting_an_image_with_a_single_command
# https://cloud.google.com/build/docs/api/reference/rest/v1/projects.builds

# Export image to bucket

import googleapiclient.discovery
from google.cloud import storage

import config as conf
import utils

cloudbuild = googleapiclient.discovery.build('cloudbuild', 'v1')
compute = googleapiclient.discovery.build('compute', 'v1')

export_image = cloudbuild.projects().builds().create(
    projectId='meilisearchimage',
    body=conf.EXPORT_IMAGE_CONFIG
).execute()

print('Waiting for image export operation')
IMAGE_EXPORT_OPERATION = utils.wait_for_build_operation(
    cloudbuild=cloudbuild,
    project=conf.GCP_DEFAULT_PROJECT,
    operation=export_image['metadata']['build']['id']
)
if IMAGE_EXPORT_OPERATION == utils.STATUS_OK:
    print(f'   Image exported: {conf.IMAGE_DESTINATION_URI}')
else:
    print('   Timeout waiting for image export')

# Make image public

print('Publishing image')
bucket = storage.Client().get_bucket(conf.IMAGE_DESTINATION_BUCKET_NAME)
policy = bucket.get_iam_policy(requested_policy_version=3)
policy.bindings.append(
    {'role': 'roles/storage.objectViewer', 'members': {'allUsers'}})
bucket.set_iam_policy(policy)
print('   Image is now public')

# Delete custom image

delete_image_operation = compute.images().delete(
    project=conf.GCP_DEFAULT_PROJECT,
    image=conf.PUBLISH_IMAGE_NAME
).execute()


#!/usr/bin/env venv/bin/python

"""Manages notifications from DBUS."""

import os
import shutil
import datetime
import json
from pathlib import Path
from dataclasses import dataclass
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import gi
gi.require_version("Gtk", "3.0")
gi.require_version("GdkPixbuf", "2.0")
from gi.repository import GLib, GdkPixbuf

@dataclass
class Notification:
    """Represents a notification read from the system."""

    ntf_id: int
    title: str
    body: str
    icon: str
    app: str
    urgency: int

CACHE_PATH = Path('/tmp/notification_cache')
ntf_cache: list[Notification] = []

def get_thumbnail(path, message):
    """Save the thumbnail if bytes are sent."""
    icon_data = message[6].get('image-data')
    if icon_data:
        GdkPixbuf.Pixbuf.new_from_bytes(
            width=icon_data[0],
            height=icon_data[1],
            has_alpha=icon_data[3],
            data=GLib.Bytes(bytes(list(icon_data[6]))),
            colorspace=GdkPixbuf.Colorspace.RGB,
            rowstride=icon_data[2],
            bits_per_sample=icon_data[4],
        ).savev(bytes(path), 'png')
        return True
    return False

def get_notif(_ , message_raw):
    """Get notifications from the system."""
    if not isinstance(message_raw, dbus.lowlevel.MethodCallMessage):
        return
    message = message_raw.get_args_list()
    ntf_id = int(datetime.datetime.now().timestamp() * 1e6)
    thumbnail_path = Path(f'{CACHE_PATH}/{ntf_id}.png')
    thumbnail_status = get_thumbnail(thumbnail_path, message)
    notification = Notification(
        ntf_id=int(ntf_id),
        title=str(message[3]),
        body=str(message[4]),
        icon=str(thumbnail_path) if thumbnail_status else '',
        app=str(message[0]),
        urgency=int(message[6].get('urgency'))
    )
    # print(json.dumps(notification.__dict__), flush=True)
    while len(ntf_cache) >= 20:
        os.remove(ntf_cache[0].icon)
        ntf_cache.pop(0)
    ntf_cache.append(notification)
    # with open(f'{CACHE_PATH}/cache.json', 'w', encoding='utf-8') as file:
    #     json.dump([item.__dict__ for item in ntf_cache],
    #               file)
    ntf_complete = {
            'last': notification.__dict__,
            'cache': [item.__dict__ for item in ntf_cache]
            }
    print(json.dumps(ntf_complete), flush=True)

if __name__ == "__main__":
    shutil.rmtree(CACHE_PATH, ignore_errors=True)
    os.makedirs(CACHE_PATH)
    DBusGMainLoop(set_as_default=True)
    bus = dbus.SessionBus()
    bus.add_match_string_non_blocking("eavesdrop=true, \
                                       interface='org.freedesktop.Notifications', \
                                       member='Notify'")
    bus.add_message_filter(get_notif)
    loop = GLib.MainLoop()
    try:
        loop.run()
    except KeyboardInterrupt:
        bus.close()


import os
import sys

import json
import requests
import pandas as pd
import logging

logger = logging.getLogger(__name__)

class ServingClient:
    def __init__(self, ip: str = "0.0.0.0", port: int = 5000):
        self.base_url = f"http://{ip}:{port}"
        logger.info(f"Initializing client; base URL: {self.base_url}")

        # any other potential initialization

    def predict(self, X: pd.DataFrame) -> pd.DataFrame:
        """
        Formats the inputs into an appropriate payload for a POST request, and queries the
        prediction service. Retrieves the response from the server, and processes it back into a
        dataframe that corresponds index-wise to the input dataframe.

        Args:
            X (Dataframe): Input dataframe to submit to the prediction service.
        """

        if X.empty:
            df_empty = pd.DataFrame()
            return df_empty

        # Remove the ground truth
        X_features = X.drop(labels=['Is Goal'], axis=1)

        # Send the request to the server to get the prediction (goal probability)
        request = requests.post(
            url = self.base_url + '/predict',
            json = json.loads(X_features.to_json()))

        # Get the response, in json format
        response = request.json() # Not sure, we should test if we actually got a valid answer!

        if len(response) == X_features.shape[0]:
            # Append the response to the dataframe
            X_out = X.copy()
            X_out['Shot probability'] = response
            return X_out

        else:
            return X

    def logs(self) -> dict:
        """Get server logs"""

        request = requests.get(
            url = self.base_url + '/logs')

        response = request.json()

        response = ''.join(response)
        return response

    def download_registry_model(self, workspace: str, model: str, version: str) -> dict:
        """
        Triggers a "model swap" in the service; the workspace, model, and model version are
        specified and the service looks for this model in the model registry and tries to
        download it.

        See more here:

            https://www.comet.ml/docs/python-sdk/API/#apidownload_registry_model

        Args:
            workspace (str): The Comet ML workspace
            model (str): The model in the Comet ML registry to download
            version (str): The model version to download
        """

        request_dict = {"workspace": workspace, "model": model, "version": version}

        # Send the request to the server to download the model
        _ = requests.post(
            url = self.base_url + '/download_registry_model',
            json = json.dumps(request_dict))

        return {}


#
# @lc app=leetcode id=410 lang=python3
#
# [410] Split Array Largest Sum
#

# @lc code=start
from typing import List

class Solution:
    def num_partitions(self, nums, x) -> int:
        """Calculate the number of partitions needed given a maximum sum limit 'x'."""
        partitions = 0
        i = 0
        while i < len(nums):
            current_sum = 0
            while i < len(nums) and current_sum + nums[i] <= x:
                current_sum += nums[i]
                i += 1
            partitions += 1
        return partitions

    def splitArray(self, nums: List[int], k: int) -> int:
        """Determine the maximum sum of a subarray when the array 'nums' is split into 'k' subarrays."""

        # Initialize the left boundary with the maximum number in 'nums'.
        # This is because any partition should at least be able to hold the largest element.
        left = max(nums)

        # Initialize the right boundary with the total sum of 'nums'.
        # This represents the sum if all numbers were in a single partition.
        right = sum(nums) + 1

        # Binary search to find the smallest maximum subarray sum.
        while left < right:
            mid = left + (right - left) // 2
            partitions_needed = self.num_partitions(nums, mid)

            # Adjust the search space based on the number of partitions needed with the current 'mid' value.
            if partitions_needed > k:
                left = mid + 1
            else:
                right = mid

        return left

# @lc code=end