import numpy as np
import pandas as pd
from scipy import interpolate as intp
from scipy import optimize
import matplotlib.pyplot as plt
import gsw
from tqdm import tqdm
import multiprocessing
from joblib import Parallel,delayed

def find_sigma0_z(salinity, temperature, pressure, latitude, longitude, sigmas):
    """
    Find the depth of the isopycnal using T/S from a cast
    Inputs:
        salinity    (array) : Salinity in PSU
        temperature (array) : In-situ temperature (C)
        latitude    (array) : Latitude of the sample
        longitude   (array) : Longitude of the sample
        sigmas      (array) : Isopycnals for which to find the depth
    Outputs:
        sigma_z     (array) : Depth of the isopycnals
    Algorithm:
        1. Convert in-situ salinity and temperature to Absolute Salinity and Conservative Temperature
        2. Calculate sigma0
        3. Check to ensure the isopycnal surface spans the density range of the water column
        4. Build interpolating functions for both T and S
        5. Sweep down and find the first place where the specified density exists in between adjacent points
        6. Use the EOS to find the where the zero crossing is
    """

    def dens_diff(pressure, SA_f, CT_f, target_sigma0):
        return np.square(gsw.sigma0(SA_f(pressure),CT_f(pressure)) - target_sigma0)

    def return_early(is_scalar):
        if is_scalar:
            return np.nan
        else:
            return np.nan*np.ones(sigmas.shape)

    # Promote to single element array if only one level requested
    valid = (~np.isnan(salinity)) & (~np.isnan(temperature)) & (~np.isnan(pressure))
    salinity = salinity[valid]
    temperature = temperature[valid]
    pressure = pressure[valid]
    longitude = longitude[valid]
    latitude = latitude[valid]

    is_scalar = type(sigmas) == type(0.)
    if is_scalar:
        sigmas = np.array([sigmas])

    if valid.sum() < 3:
        return return_early(is_scalar)

    pressure = np.array(pressure)
    SA = gsw.SA_from_SP(salinity, pressure, longitude, latitude)
    CT = gsw.CT_from_t(salinity, temperature, pressure)

    P_sort = np.unique(pressure)
    if len(P_sort) < 3:
        return return_early(is_scalar)

    SA_sort = np.zeros(P_sort.shape)
    CT_sort = np.zeros(P_sort.shape)
    # Loop through all pressures that overlap, average the temperatures and salinity accordingly
    for idx, P in enumerate(P_sort):
        presidx = (pressure == P)
        SA_sort[idx] = SA[presidx].mean()
        CT_sort[idx] = CT[presidx].mean()

    SA_intp = intp.interp1d(P_sort, SA_sort, kind='quadratic')
    CT_intp = intp.interp1d(P_sort, CT_sort, kind='quadratic')

    sigma0 = gsw.sigma0(SA_sort,CT_sort)
    sigma0_max = sigma0.max()
    sigma0_min = sigma0.min()

    sigma0_z = np.zeros(len(sigmas))

    for sigidx, siglev in enumerate(sigmas):
        if (siglev < sigma0_min) or (siglev > sigma0_max):
            sigma0_z[sigidx] = np.nan
        else:
            for botidx in range(len(sigma0)-1):
                if (siglev >= sigma0[botidx]) & (siglev <= sigma0[botidx+1]):
                    start_idx = botidx
                    break

            out = optimize.minimize_scalar(dens_diff,
                                            bounds=[P_sort[botidx],P_sort[botidx+1]],
                                            method='Bounded',
                                            args=(SA_intp, CT_intp, siglev))

            sigma0_z[sigidx] = out.x

    if is_scalar:
        sigma0_z = np.squeeze(sigma0_z)

    return sigma0_z

def process_cruise(cruise_df,sigma0_vals):
    nsigma0 = len(sigma0_vals)
    stations = cruise_df.station.unique()
    cols = ['latitude','longitude'] + [ f'{sig0}_z' for sig0 in sigma0_vals ]
    df_out = pd.DataFrame(columns = cols)
    for station in stations:
        df = cruise_df[ cruise_df.station == station ]
        sigma0_z = find_sigma0_z(df.salinity,df.temperature,df.pressure,df.latitude,df.longitude,sigma0_vals)
        if (np.isnan(sigma0_z).sum() != len(sigma0_vals)):
            out = np.nan*np.ones(nsigma0+2)
            out[0] = df.latitude.mean()
            out[1] = df.longitude.mean()
            out[2:] = sigma0_z
            df_out = df_out.append( pd.DataFrame([out], columns = cols), ignore_index = True )

    return df_out

if __name__ == '__main__':
  num_cores = multiprocessing.cpu_count()
  path = '/home/ashao/data/glodap/'
  path = ''
  glodap = pd.read_csv(path+'GLODAPv2.2019_Merged_Master_File.csv')
  cruise_ids = glodap.cruise.unique()
  glodap_by_cruise = [ glodap[(glodap.cruise == cruise_id) & (glodap.salinityqc == 1)] for cruise_id in cruise_ids ]
  inputs = tqdm( glodap_by_cruise )
  siglevels = np.linspace(26,27,11)
  out = Parallel(n_jobs=num_cores)(delayed(process_cruise)(cruise_df.replace(-9999,np.nan),siglevels) for cruise_df in inputs)
  out = pd.concat(out,ignore_index=True)
  out.to_csv('sigma_levels_z.csv')


import numpy as np
from sympy import Matrix
import random
from modules.alphabet import getAlphabet

def getModularMatrix(matrix):

    '''
    ------------
    DESCRIPCIÓN:
    Función que se encarga de encontrar la matriz modular inversa.

    :param matrix:  (numpy matrix)
        Representa la llave que se utiliza para el cifrado. Debe ser
        una matriz cuadrada cuyo determinante sea distinto de 0 ya que debe
        ser posible invertirla.

    :return:        (numpy matrix)
        La función da como salida una matriz que representa la matriz modular
        inversa.
    '''

    ALPHABET = getAlphabet()
    inverse_matrix = Matrix(matrix)
    # matriz modular inversa
    inverse_matrix = inverse_matrix.inv_mod(len(ALPHABET))
    inverse_matrix = np.array(inverse_matrix)

    # cambio de tipo de datos.
    new_matrix = []
    for row in inverse_matrix:
        for i in row:
            new_matrix.append(int(i))

    new_matrix = np.array(new_matrix).reshape(np.shape(matrix)[0],np.shape(matrix)[1])

    return (new_matrix)

def getRandomKey(mod):
    '''
    ------------
    DESCRIPCIÓN:
    Función que de generar una key valida para hacer el cifrado.

    :param mod:  (int)
        Como es necesario que la matriz a generar tenga una inversa modular
        es necesario saber por que modulo se debe realizar.

    :return:        (numpy matrix)
        La función da como salida una matriz que representa la llave (key).
    '''
    sizekey = [2,3,4,5,6]

    size = sizekey[random.randint(0, len(sizekey)-1)]

    det = 0
    key = []
    while det == 0:
        key = []
        for _ in range(size*size):
            key.append(random.randint(0,29))
        key = np.array(key)

        key = np.reshape(key,(size,size))

        try:
            inverse_matrix = Matrix(key)
            inverse_matrix = inverse_matrix.inv_mod(mod)
            det = 1
        except:
            det = 0

    return(key)


#!/usr/bin/env python3
import os
import sys
import psutil
import subprocess
import time
from pathlib import Path

import typer
from unoserver import converter

# from pdf2pdfa import pdf2pdfa

def start_uno_server():
    if uno_server_running():
        return

    subprocess.Popen(
        Path(Path.home(), ".local/bin/unoserver"),
        start_new_session=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.STDOUT,
    )
    time.sleep(3)  # Wait for server to start up

def uno_server_running():
    for process in psutil.process_iter():
        if process.name() == "unoserver":
            return True

    return False

def unoconv2x(source_path: str, target_path: str):
    """
    Convert spreadsheet, MS Word or rtf files to pdf or html.
    Spreadsheet files can be converted to html or pdf specified with the extension of target_path.
    Word and rtf files can only be converted to pdf.

    Example: python3 -m bin.unoconv2x ./example/testfile.xls ./result pdf
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

    Supported mime types:
        - application/vnd.ms-excel
        - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
        - application/msword
        - application/rtf

    Args:
        source_path: path for the file to be converted
        target_path: path for the converted file
    Returns:
        Nothing if successful otherwise exits with exit code 1
    """

    start_uno_server()
    target_ext = Path(target_path).suffix
    _converter = converter.UnoConverter()
    result = _converter.convert(source_path, None, target_path, target_ext)

    if not Path(target_path).is_file() or result is not None:
        sys.exit(1)

if __name__ == "__main__":
    typer.run(unoconv2x)


import dateutil
import functools
import json
import random
import requests
import urllib

import common.constants as const

from common.anilist import add_anotd_bl, anilist_search, anilist_rand_series, rm_anotd_bl
from common.arg_parsers import mal_arg_parser
from common.mal import mal_url_info
from common.utils import find_true_name, gen_uhtml_img_code, curr_cal_date, \
                         monospace_table_row, is_url, is_uhtml, birthday_text, leaderboard_uhtml
from user import User

class Command():
    def __init__(self, **kwargs):
#       bot, full_command, room, caller, is_pm, pm_only, room_only,
#       usage_msg, req_rank, allowed_rooms, min_args, max_args, req_rank
        for k, v in kwargs.items():
            setattr(self, k, v)

        self.find_rank()

        self.command = self.full_command[0]
        self.args = self.full_command[1:]

        if not self.room_only:
            self.allowed_rooms.append('')

        self.msg = ''

        if 'req_rank_pm' not in kwargs:
            self.req_rank_pm = self.req_rank

    @property
    def num_args(self):
        return len(self.args)

    def usage_with_error(self, error):
        return f'{error} Usage: {self.usage_msg}'

    def check_eligible(self):
        """ Returns 0 if is eligible.
        """
        if self.room not in self.allowed_rooms:
            self.msg = f'{self.room} is not a legal room for this command.'
            return 1

        if not User.compare_ranks(self.caller_rank, self.req_rank) and not \
                (self.is_pm and User.compare_ranks(self.caller_rank, self.req_rank_pm)):
            self.msg = ''
            return 2

        if self.is_pm and self.room_only:
            self.msg = f']{self.command} can only be used in rooms.'
            return 3
        elif not self.is_pm and self.pm_only:
            self.msg = f']{self.command} can only be used in PMs.'
            return 4

        if self.num_args > self.max_args:
            self.msg = self.usage_with_error('Too many arguments.')
            return 5
        elif self.num_args < self.min_args:
            self.msg = self.usage_with_error('Too few arguments.')
            return 6

        return 0

    def find_rank(self):
        if self.true_caller == 'hippopotas':
            self.caller_rank = '~'
        self.caller_rank = self.caller_info['group']
        if self.room:
            for r in self.caller_info['rooms']:
                if r[1:] == self.room:
                    if User.compare_ranks(r[0], self.caller_rank):
                        self.caller_rank = r[0]
                    break

    async def pm_msg(self, message):
        if message:
            await self.bot.outgoing.put(f'|/w {self.true_caller}, {message}')

class SimpleCommand(Command):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        if self.command == 'jibun':
            self.allowed_rooms = [const.ANIME_ROOM]
            self.room_only = True

        if self.command == 'mal_set':
            self.command = 'mal_add'

        if self.command == 'mal_add':
            self.usage_msg += 'MAL_USERNAME'

    async def evaluate(self):
        if self.check_eligible():
            await self.pm_msg(self.msg)
            return ''

        if self.command == 'help':
            self.msg = 'o3o [[README <https://github.com/Hippopotas/hippobotas/blob/master/README.md>]] o3o'
        elif self.command == 'dab':
            self.msg = '/me dabs'
        elif self.command == 'owo':
            self.msg = 'uwu'
        elif self.command == 'google':
            self.msg = 'Don\'t be mad someone is faster at googling than you :3c'
        elif self.command == 'joogle':
            self.msg = 'Don\'t be mad someone is faster at joogling than you :3c'
        elif self.command == 'bing':
            self.msg = 'Have you heard of google?'
        elif self.command == 'jing':
            self.msg = 'Have you heard of joogle?'
        elif self.command == 'jibun':
            self.msg = '/announce JIBUN WOOOOOOOOOO'

        elif self.command == 'mal_add':
            mal_user = ''.join(self.args)
            self.msg += await self.bot.mal_man.set_user(self.true_caller, mal_user, self.bot.jikan_man)

        elif self.command == 'wpm_reset':
            try:
                self.bot.wpms.loc[self.true_caller]
            except KeyError:
                pass
            else:
                self.bot.wpms.loc[self.true_caller, ['top_wpm', 'avg_wpm', 'recent_runs']] = 0, 0, []
                self.bot.wpms.to_csv(const.WPMFILE)
            self.msg = f'Reset {self.caller}\'s typing speed record to 0 WPM.'

        elif self.command == 'wpm':
            wpm_user = self.caller
            true_wpm_user = self.true_caller
            if self.args:
                wpm_user = ' '.join(self.args)
                true_wpm_user = find_true_name(wpm_user)

            try:
                wpminfo = self.bot.wpms.loc[true_wpm_user]
            except KeyError:
                self.msg = f'{wpm_user} has not taken a typing test.'
            else:
                top_wpm = wpminfo['top_wpm']
                avg_wpm = wpminfo['avg_wpm']
                run_count = len(wpminfo['recent_runs'])
                self.msg = f'{wpm_user} - Top speed: {top_wpm} WPM. Average of past {run_count} runs: {avg_wpm} WPM.'

        return self.msg

class UhtmlCommand(Command):
    def __init__(self, **kwargs):
        if kwargs['is_pm'] and len(kwargs['full_command']) > 1:
            kwargs['room'] = find_true_name(kwargs['full_command'][1])

        super().__init__(**kwargs)

        if self.is_pm:
            if self.command in ['mal', 'anime', 'manga']:
                self.room = const.ANIME_ROOM
            else:
                self.min_args += 1
                self.usage_msg += '[ROOM] '

        if self.command in ['anime', 'manga']:
            self.usage_msg += 'SERIES NAME'

        if self.command in ['randanime', 'randmanga']:
            self.usage_msg += '[GENRES]'

        if self.command == 'mal':
            self.req_rank_pm = ' '

            self.usage_msg += '[USERNAME] [-r CATEGORIES]'
            self.mal_args = mal_arg_parser(' '.join(self.args), self.true_caller)

            if self.mal_args.roll is not None:
                self.pm_response = self.is_pm

    async def evaluate(self):
        self.msg = '/adduhtml '

        eligibility = self.check_eligible()

        if eligibility and eligibility != 2:
            await self.pm_msg(self.msg)
            return ''
        elif eligibility:
            if self.is_pm and not self.room:
                await self.pm_msg(self.usage_with_error(''))
                return ''
            elif self.is_pm and self.bot.roomlist[self.room].get_user(self.caller):
                self.msg = f'/sendprivateuhtml {self.true_caller}, '
            else:
                await self.pm_msg(f'You can only use {self.command} in PMs. '
                                   'Make sure you\'re in the specified room.')
                return ''
        elif self.is_pm:
            self.msg = f'/sendprivateuhtml {self.true_caller}, '

        if self.command == 'plebs':
            uhtml = gen_uhtml_img_code(const.PLEB_URL, height_resize=250)
            self.msg += f'hippo-pleb, {uhtml}'

        elif self.command == 'calendar':
            curr_day_str = curr_cal_date()
            calendar = json.load(open(const.CALENDARFILE))

            if self.room not in calendar:
                calendar[self.room] = {curr_day_str: []}
                json.dump(calendar, open(const.CALENDARFILE, 'w'), indent=4)
            if not calendar[self.room][curr_day_str]:
                return 'No images found for this date.'

            date_imgs = calendar[self.room][curr_day_str]
            uhtml = gen_uhtml_img_code(random.choice(date_imgs), height_resize=200)
            self.msg += f'hippo-calendar, {uhtml}'

        elif self.command == 'wpm_top':
            metric = 'avg_wpm'
            metric_title = '(Last 5 Runs Avg.)'
            if '-s' in self.args or '--single' in self.args:
                metric = 'top_wpm'
                metric_title = '(Single Run)'

            wpmboard = self.bot.wpms.sort_values(metric, ascending=False)
            if metric == 'avg_wpm':
                wpmboard = wpmboard[wpmboard['recent_runs'].map(len) >= 5]
            wpmboard = wpmboard.reset_index().head(n=5)[['user', metric]].values.tolist()

            self.msg += leaderboard_uhtml(wpmboard, f'Fastest WPM {metric_title}', name='wpmboard', metric='WPM')

        elif self.command == 'birthday':
            self.msg += await birthday_text(self.bot, automatic=False, room=self.room)

        elif self.command == 'anime':
            query = ' '.join(self.args)
            self.msg += await anilist_search('anime', query, self.bot.anilist_man)

        elif self.command == 'manga':
            query = ' '.join(self.args)
            self.msg += await anilist_search('manga', query, self.bot.anilist_man)

        elif self.command == 'randanime':
            genres = []
            tags = []

            true_args = list(map(find_true_name, self.args))

            for g in const.ANILIST_GENRES:
                if find_true_name(g) in true_args:
                    genres.append(g)
            for t in list(const.ANILIST_TAGS):
                if find_true_name(t) in true_args:
                    tags.append(t)

            self.msg += await anilist_rand_series('anime', self.bot.anilist_man, genres=genres, tags=tags)

        elif self.command == 'randmanga':
            genres = []
            tags = []

            true_args = list(map(find_true_name, self.args))

            for g in const.ANILIST_GENRES:
                if find_true_name(g) in true_args:
                    genres.append(g)
            for t in list(const.ANILIST_TAGS):
                if find_true_name(t) in true_args:
                    tags.append(t)

            self.msg += await anilist_rand_series('manga', self.bot.anilist_man, genres=genres, tags=tags)

        elif self.command == 'mal':
            true_mal_user = find_true_name(''.join(self.mal_args.username))

            if self.mal_args.roll is not None:
                media = ['anime', 'manga']
                if 'anime' not in self.mal_args.roll:
                    media.remove('anime')
                if 'manga' not in self.mal_args.roll:
                    media.remove('manga')

                return_msg = await self.bot.mal_man.user_rand_series(true_mal_user, media, anotd=self.is_anotd)

                if return_msg.startswith('rolled'):
                    self.msg = f'{self.caller} {return_msg}'
                else:
                    self.msg = return_msg

            else:
                return_msg = await self.bot.mal_man.show_user(true_mal_user, self.bot.jikan_man)

                if is_uhtml(return_msg):
                    self.msg += f'hippo-{true_mal_user}mal, {return_msg}'
                elif self.is_pm:
                    self.pm_response = self.is_pm
                    self.msg = return_msg
                else:
                    self.msg = return_msg

        return self.msg

class ModifiableCommand(Command):
    def __init__(self, **kwargs):
        if kwargs['is_pm'] and len(kwargs['full_command']) > 1:
            kwargs['room'] = kwargs['full_command'][1]

        super().__init__(**kwargs)

        if self.is_pm:
            self.min_args += 1

    @functools.cached_property
    def json_info(self):
        return json.load(open(self.file, encoding='utf-8'))

class DatabaseCommand(Command):
    def __init__(self, **kwargs):
        if kwargs['is_pm'] and len(kwargs['full_command']) > 1:
            kwargs['room'] = kwargs['full_command'][1]

        super().__init__(**kwargs)

        if self.is_pm:
            self.min_args += 1

    @property
    def db_man(self):
        return self.bot.roomdata_man

class TopicCommand(ModifiableCommand):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        if 'list' in self.command:
            self.req_rank = '+'
            self.usage_msg += '[ROOM]'
        elif 'rm' in self.command:
            self.req_rank = '%'
            self.min_args += 1
            self.usage_msg += '[ROOM] TOPIC_ID'
        elif self.command == 'topic':
            if self.num_args:
                self.req_rank = '%'
                self.min_args += 1
                self.usage_msg += '[ROOM] TOPIC_TEXT'
            else:
                self.usage_msg += '(use in a room)'

    async def evaluate(self):
        if self.check_eligible():
            await self.pm_msg(self.msg)
            return ''

        if self.room not in self.json_info:
            self.json_info[self.room] = {'current': '', 'random': []}
        room_topics = self.json_info[self.room]

        if self.command == 'topic':
            if self.num_args:
                new_topic = ' '.join(self.args)
                if self.is_pm:
                    new_topic = ' '.join(self.args[1:])
                room_topics['current'] = new_topic

            curr_topic = room_topics['current']
            if not curr_topic:
                self.msg = '/announce No topic right now!'
            else:
                self.msg = f'/announce {curr_topic}'

        elif self.command == 'topic_list':
            pass

        json.dump(self.json_info, open(self.file, 'w'), indent=4)

        return self.msg

class BanlistCommand(DatabaseCommand):
    VALID_BANLISTS = {'anime': 'mal_id',
                      'manga': 'mal_id',
                      'anotd': 'mal_id'}

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        if self.args:
            self.banlist = self.args[0]
            if self.banlist in ['anime', 'manga', 'anotd']:
                self.room = 'animeandmanga'
            self.find_rank()

        if self.command == 'bl_add':
            self.min_args = 2
            self.usage_msg += 'LIST_TO_MODIFY THING_TO_BAN'
            self.pm_only = True
        elif self.command == 'bl_rm':
            self.min_args = 2
            self.usage_msg += 'LIST_TO_MODIFY THING_TO_UNBAN'
            self.pm_only = True
        elif self.command == 'bl_list':
            self.min_args = 1
            self.usage_msg += 'LIST_TO_VIEW'

    async def evaluate(self):
        if self.check_eligible():
            await self.pm_msg(self.msg)
            return ''

        if self.banlist not in self.VALID_BANLISTS:
            await self.pm_msg(f'{self.banlist} is not a valid banlist.')
            return ''
        else:
            self.bl_key = self.VALID_BANLISTS[self.banlist]

        if len(self.args) > 1:
            if self.banlist in ['anime', 'manga']:
                self.bl_value = self.args[1]
            elif self.banlist == 'anotd':
                try:
                    self.bl_value2, self.bl_value = mal_url_info(self.args[1])
                except TypeError:
                    await self.pm_msg(f'{self.args[1]} is not a valid MAL url.')
                    return ''

            self.where_clause = f"WHERE {self.bl_key}={self.bl_value}"
            if self.banlist in ['anime', 'manga']:
                self.where_clause += f" AND medium='{self.banlist}'"
                self.check_query = (f"SELECT * FROM mal_banlist {self.where_clause}")
            elif self.banlist == 'anotd':
                self.where_clause += f" AND medium='{self.bl_value2}'"
                self.check_query = (f"SELECT * FROM {self.banlist}_banlist {self.where_clause}")

        if self.command == 'bl_add':
            entry_exists = await self.db_man.execute(self.check_query)
            if entry_exists:
                await self.pm_msg(f'{self.bl_value} already in {self.banlist} banlist.')
                return ''

            if self.banlist in ['anime', 'manga']:
                await self.db_man.execute(f"INSERT INTO mal_banlist (medium, mal_id, manual) "
                                                f"VALUES ('{self.banlist}', {self.bl_value}, 1)")
            elif self.banlist == 'anotd':
                await add_anotd_bl(self.bl_value2, self.bl_value, self.bot.anilist_man, self.db_man)

            self.msg = f'{self.args[1]} added to {self.banlist} banlist.'

        elif self.command == 'bl_rm':
            entry_exists = await self.db_man.execute(self.check_query)
            if not entry_exists:
                await self.pm_msg(f'{self.bl_value} not in {self.banlist} banlist.')
                return ''

            if self.banlist in ['anime', 'manga']:
                await self.db_man.execute(f"DELETE FROM mal_banlist WHERE medium='{self.banlist}' AND mal_id={self.bl_value} AND manual=1")
            elif self.banlist == 'anotd':
                await rm_anotd_bl(self.bl_value2, self.bl_value, self.bot.anilist_man, self.db_man)

            self.msg = f'{self.args[1]} removed from {self.banlist} banlist.'

        elif self.command == 'bl_list':
            header_text = monospace_table_row([(self.banlist, 20)])
            if self.banlist == 'anotd':
                header_text = monospace_table_row([('Franchise/Title', 30)])
            header_text += '\n' + '-'*30

            box_text = ''
            if self.banlist in ['anime', 'manga']:
                mal_ids = await self.db_man.execute("SELECT mal_id FROM mal_banlist "
                                                        f"WHERE medium='{self.banlist}' AND manual=1")
                for mid in list(sum(mal_ids, ())):
                    box_text += monospace_table_row([(mid, 20)])
                    box_text += '\n'

            elif self.banlist == 'anotd':
                names = await self.db_man.execute("SELECT name FROM anotd_banlist")
                for name in list(sum(names, ())):
                    fixed_name = name.encode('ascii', 'ignore').decode()
                    box_text += monospace_table_row([(fixed_name, 30)])
                    box_text += '\n'

            r = requests.post(const.PASTIE_API, data=f'{header_text}\n{box_text}')
            if r.status_code == 200:
                self.msg = f"""https://pastie.io/raw/{r.json()['key']}"""
            else:
                self.msg = 'Cannot generate banlist info at this time.'

            if not self.is_pm:
                self.msg = (f'/addrankuhtml %, hippo-{self.banlist}bl, '
                            f'{self.banlist} banlist: {self.msg}
')

        return self.msg

class EmoteCommand(DatabaseCommand):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        if self.command == 'emote_add':
            self.min_args += 2
            self.req_rank = '#'
            self.usage_msg += 'EMOTE URL'
        elif self.command == 'emote_rm':
            self.min_args += 1
            self.req_rank = '#'
            self.usage_msg += 'EMOTE'

    async def evaluate(self):
        if self.check_eligible():
            await self.pm_msg(self.msg)
            return ''

        arg_offset = 1 if self.is_pm else 0

        if self.command == 'emote_add':
            emote = self.args[arg_offset].lower()
            if emote.endswith(','):
                emote = emote[:-1]

            if find_true_name(emote) != emote:
                await self.pm_msg('Emotes must be only letters and/or numbers.')
                return

            emote_url = self.args[arg_offset+1]
            if 'discordapp' in emote_url:
                await self.pm_msg('Discord URLs do not work as emotes.')
                return

            emote_exists = await self.db_man.execute("SELECT * FROM emotes WHERE "
                                                        f"room='{self.room} AND name={emote}'")
            if emote_exists:
                await self.db_man.execute(f"UPDATE emotes SET url='{emote_url}' "
                                            f"WHERE room='{self.room}' AND name='{emote}'")
            else:
                await self.db_man.execute("INSERT INTO emotes (room, name, url) "
                                            f"VALUES ('{self.room}', '{emote}', '{emote_url}')")

            self.msg = f'Set :{emote}: to show {emote_url}.'

        elif self.command == 'emote_rm':
            emote = find_true_name(self.args[arg_offset])

            emote_exists = await self.db_man.execute("SELECT * FROM emotes WHERE "
                                                        f"room='{self.room}' AND name='{emote}'")

            if not emote_exists:
                await self.pm_msg(f'{self.room} does not have emote {emote}.')
                return

            await self.db_man.execute("DELETE FROM emotes WHERE "
                                        f"room='{self.room}' AND name='{emote}'")
            self.msg = f'Removed {emote} from {self.room}.'

        elif self.command == 'emote_list':
            self.msg = 'No emotes found.'

            emote_list = await self.db_man.execute("SELECT name FROM emotes "
                                                        f"WHERE room='{self.room}'")

            if emote_list:
                # Flatten
                emote_list = list(sum(emote_list, ()))
                self.msg = f'!code {self.room} emotes: ' + ', '.join(emote_list)

        elif self.command == 'emote_stats':
            self.msg = f'No emotes found for {self.room}.'

            emote_list = await self.db_man.execute("SELECT name, times_used FROM emotes "
                                                    f"WHERE room='{self.room}'")

            if emote_list:
                header_text = monospace_table_row([('Emote', 30), ('Times Used', 12)])
                header_text += '\n' + '-'*44
                box_text = ''
                for e in sorted(emote_list, key=lambda x: x[1], reverse=True):
                    box_text += monospace_table_row([(e[0], 30), (e[1], 12)])
                    box_text += '\n'

                r = requests.post(const.PASTIE_API, data=f'{header_text}\n{box_text}')

                if r.status_code == 200:
                    self.msg = f"""https://pastie.io/raw/{r.json()['key']}"""
                else:
                    self.msg = 'Unable to generate emote stats at this time.'

        return self.msg

class SongCommand(DatabaseCommand):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.usage_msg += '[ROOM] '

        if self.command == 'song_add':
            self.min_args += 2
            self.usage_msg += 'TITLE URL'
        elif self.command == 'song_rm':
            self.min_args += 1
            self.usage_msg += 'TITLE'

    def check_eligible(self):
        eligibility = super().check_eligible()

        if not eligibility and self.command == 'song_add':
            if not is_url(self.args[-1]):
                eligibility = 101
                self.msg = self.usage_with_error('Please provide a valid URL.')

        return eligibility

    async def evaluate(self):
        if self.check_eligible():
            await self.pm_msg(self.msg)
            return ''

        arg_offset = 1 if self.is_pm else 0

        if self.command == 'song_add':
            title = ' '.join(self.args[arg_offset:-1])
            url = self.args[-1]

            song_exists = await self.db_man.execute("SELECT * FROM songs WHERE "
                                                        f"room='{self.room}' AND url='{url}'")

            if song_exists:
                self.msg = f'This url already exists in the song pool for {self.room}.'
            else:
                # Sqlite escape
                title = title.replace("'", "''")
                await self.db_man.execute("INSERT INTO songs (room, title, url) "
                                            f"VALUES ('{self.room}', '{title}', '{url}')")
                self.msg = f'Added {title} to {self.room} song pool.'

        elif self.command == 'song_rm':
            title = ' '.join(self.args[arg_offset:])
            self.msg = f'{title} not found in song pool.'

            room_songs = await self.db_man.execute("SELECT title FROM songs "
                                                    f"WHERE room='{self.room}'")

            for s in list(sum(room_songs, ())):
                if find_true_name(s) == find_true_name(title):
                    escaped_s = s.replace("'", "''")
                    await self.db_man.execute("DELETE FROM songs WHERE "
                                                f"room='{self.room}' AND title='{escaped_s}'")

            self.msg = f'Deleted all songs called {title} from song pool.'

        elif self.command == 'song_list':
            self.msg = f'No songs found for {self.room}.'

            song_exists = await self.db_man.execute("SELECT title, url FROM songs "
                                                    f"WHERE room='{self.room}'")

            if song_exists:
                room_songs = {}
                for song in song_exists:
                    room_songs[song[0]] = song[1]

                header_text = monospace_table_row([('Song Title', 100),
                                                   ('Link', 25)])
                header_text += '\n' + '-'*146
                box_text = ''
                for s in sorted(room_songs.keys()):
                    box_text += monospace_table_row([(s, 100),
                                                     (room_songs[s], 25)])
                    box_text += '\n'

                r = requests.post(const.PASTIE_API, data=f'{header_text}\n{box_text}'.encode('utf-8'))

                if r.status_code == 200:
                    self.msg = f"""https://pastie.io/raw/{r.json()['key']}"""
                else:
                    self.msg = 'Unable to generate song list at this time.'

        elif self.command == 'randsong':
            song_exists = await self.db_man.execute("SELECT title, url FROM songs "
                                                    f"WHERE room='{self.room}'")

            if not song_exists:
                self.msg = f'There are no songs for {self.room}!'
            else:
                rand_song = random.choice(song_exists)
                # Decode the URL because PS re-encodes it
                self.msg = f'[[{rand_song[0]}<{urllib.parse.unquote(rand_song[1])}>]]'

        return self.msg

class BirthdayCommand(DatabaseCommand):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.usage_msg += '[ROOM] '

        if self.command == 'birthday_add':
            self.min_args += 2
            self.usage_msg += 'NAME LINK IMAGE DATE'
        elif self.command == 'birthday_rm':
            self.min_args += 1
            self.usage_msg += 'NAME'

    def check_eligible(self):
        eligibility = super().check_eligible()

        if not eligibility and self.command == 'birthday_add':
            if not is_url(self.args[-2]) or not is_url(self.args[-3]):
                eligibility = 101
                self.msg = self.usage_with_error('Please provide a valid URL.')

            if not dateutil.parser.parse(self.args[-1]):
                eligibility = 101
                self.msg = self.usage_with_error('Please provide a recognizable day (with no space).')

        return eligibility

    async def evaluate(self):
        if self.check_eligible():
            await self.pm_msg(self.msg)
            return ''

        arg_offset = 1 if self.is_pm else 0

        if self.command == 'birthday_add':
            name = ' '.join(self.args[arg_offset:-3])
            link = self.args[-3]
            image = self.args[-2]
            day = dateutil.parser.parse(self.args[-1]).strftime('%B %#d')

            char_exists = await self.db_man.execute("SELECT * FROM birthdays WHERE "
                                                        f"room='{self.room}' AND name='{name}' AND day='{day}'")

            if char_exists:
                self.msg = f'This character is already in the birthdays for {self.room}.'
            else:
                # Sqlite escape
                name = name.replace("'", "''")
                await self.db_man.execute("INSERT INTO birthdays (name, room, day, image, link) "
                                            f"VALUES ('{name}', '{self.room}', '{day}', '{image}', '{link}')")
                self.msg = f'Added {name} to {self.room} birthdays.'

        elif self.command == 'birthday_rm':
            name = ' '.join(self.args[arg_offset:])
            self.msg = f'{name} not found in birthdays.'

            room_bdays = await self.db_man.execute("SELECT name FROM birthdays "
                                                    f"WHERE room='{self.room}'")

            for n in list(sum(room_bdays, ())):
                if find_true_name(n) == find_true_name(name):
                    escaped_n = n.replace("'", "''")
                    await self.db_man.execute("DELETE FROM birthdays WHERE "
                                                f"room='{self.room}' AND name='{escaped_n}'")

            self.msg = f'Deleted all birthdays of {name} in {self.room}.'

        return self.msg


from pathlib import Path
import openpyxl as xl
import datelist
import os

import master

step = "one"
status = ""
# making the dir if path not exist
path = Path("c:/it/PayrollAuto/")
if path.exists():
    # making temp directory if not exist
    if not Path(master.temppath).exists():
        os.mkdir(master.temppath)
    # checking the file exists to do automation
    if master.file.exists():
        # load the master file
        print("Step " + step)
        wb = xl.load_workbook(master.filepath+"empshiftsum.xlsx")
        sh1 = wb["Sheet1"]
        sh2 = wb.create_sheet("stepone")
        maxrow = sh1.max_row
        # print(maxrow)
        # loop through each row
        for row in range(1,maxrow+1):
            raw_data = sh1.cell(row,1).value
            raw_wrhr = sh1.cell(row,7).value
            # it will store the working hours in new sheet
            # print(row)
            # print(type(raw_wrhr))
            if isinstance(raw_wrhr,float) or isinstance(raw_wrhr,int):
                new_raw_wrhr = sh2.cell(row,5)
                new_raw_wrhr.value = raw_wrhr
            # it will check the rows with date and overcome the exception is it's run in the month of Jan
            # if it's not date than it means it's either company or employee
            if not raw_data.find(str(datelist.curt_year)) != -1 and not raw_data.find(str(datelist.curt_year-1)) != -1:
                # company
                if raw_data.upper().find(master.company) != -1:
                    new_raw_comp = sh2.cell(row,4)
                    new_raw_comp.value = raw_data
                    new_raw_compcode = sh2.cell(row,1)
                    new_raw_compcode.value = master.company_code
                # employee
                else:
                    # print(raw_data)
                    new_raw_emp = sh2.cell(row,2)
                    new_raw_emp.value = raw_data
                    new_raw_compcode = sh2.cell(row,1)
                    new_raw_compcode.value = master.company_code
            else:

                new_raw_compcode = sh2.cell(row, 1)
                new_raw_compcode.value = master.company_code
                # removing empty rows and taking only date
                if isinstance(raw_wrhr,float) or isinstance(raw_wrhr,int):
                    new_raw_date = sh2.cell(row,3)
                    new_raw_date.value = raw_data
        # saving in the workbook
        wb.save(master.temppath + "stepone.xlsx")
        status = "Done"
    else:
        print("Please copy the empshiftsum.xlsx inside c:/it/PayrollAuto/")
else:
    path = "c:/it/PayrollAuto/"
    os.mkdir(path)


"""ORM-like approach to neo4j nodes
"""
import json
from abc import ABC, abstractmethod
from typing import Literal

class _Neo4jObject(ABC):

    @property
    @abstractmethod
    def label(self) -> str:
        raise NotImplementedError('This method must be implemented')

    @classmethod
    @abstractmethod
    def create(cls, tx, **kwargs) -> int:
        raise NotImplementedError('This method must be implemented')

class _Node(_Neo4jObject):
    """
    """

    @classmethod
    def _raw_query(
        cls,
        tx,
        creation_action: Literal['MERGE', 'CREATE'],
        **kwargs
    ) -> int:
        obj = ', '.join([f'{k}: {json.dumps(v)}' for k, v in kwargs.items()])  # Creates a string as follow: key1: $key1, key2: $key2,
        query = f'{creation_action} (n:{cls.label} {{{obj}}}) RETURN ID(n) AS node_id'
        result = tx.run(query)
        record = result.single()
        return record['node_id']

    @classmethod
    def create(cls, tx, **kwargs) -> int:
        return cls._raw_query(tx, 'CREATE', **kwargs)

    @classmethod
    def get_or_create(cls, tx, **kwargs) -> int:
        return cls._raw_query(tx, 'MERGE', **kwargs)

class _Realtionship(_Neo4jObject):
    """
    """

    @classmethod
    def _raw_query(
        cls,
        tx,
        creation_action: Literal['CREATE', 'MERGE'],
        condition: str
    ) -> int:
        """Match two nodes and creates a relationship between them

        :param tx: Neo4j transaction object
        :param creation_action: How to create the relationship
        :param condition: How to find the two nodes: a, b
        """
        query = f'MATCH (a), (b) WHERE {condition} {creation_action} (a)-[r:{cls.label}]->(b) RETURN ID(r) as relationship_id'
        result = tx.run(query)
        record = result.single()
        return record['relationship_id']

class DeepRequestNode(_Node):
    label = 'DeepRequest'

class UserNode(_Node):
    label = 'UserNode'

class AdjectiveNode(_Node):
    label = 'AdjectiveNode'

class RequestAdjectiveRealtionship(_Realtionship):
    label = 'IS'

    @classmethod
    def get_or_create(cls, tx, node_a_id, node_b_id):
        cls._raw_query(tx, 'MERGE', f'ID(a) = {node_a_id} AND ID(b) = {node_b_id}')

class UserDeepRequestRealtionship(_Realtionship):
    label = 'REQUESTED'

    @classmethod
    def get_or_create(cls, tx, node_a_id, node_b_id):
        cls._raw_query(tx, 'MERGE', f'a.user_id = {node_a_id} AND ID(b) = {node_b_id}')

    # @staticmethod
    # def matched_nodes(tx, deep_id, number_of_related):
    #     query = """
    #     MATCH (d1:DeepRequest)-->(a:AdjectiveNode)<--(d2:DeepRequest)
    #     WHERE ID(d1) = $deep_id
    #     WITH d1, d2, collect(a) as related_adjectives
    #     WHERE size(related_adjectives) > $number_of_related
    #     RETURN d1, d2, related_adjectives
    #     """
    #     result = tx.run(query, deep_id=deep_id, number_of_related=number_of_related)
    #     record = result.single()
    #     return record['node_id']


import cv2
import matplotlib.pyplot as plt

img = cv2.imread('A.jpeg')
cv2.imshow('Original',img)
cv2.waitKey()

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('GrayScale',gray)
cv2.imwrite('gray.jpeg',gray)
cv2.waitKey()

hist = cv2.calcHist([gray],[0],None,[256],[0,256])

plt.xlabel('Pixel Value')
plt.ylabel('Number of Pixels')
plt.plot(hist)
plt.savefig('HistogramBefore')
plt.show()

equ = cv2.equalizeHist(gray)

hist = cv2.calcHist([equ],[0],None,[256],[0,256])

plt.xlabel('Pixel Value')
plt.ylabel('Number of Pixels')
plt.plot(hist)
plt.savefig('HistogramAfter')
plt.show()

cv2.imshow('Equalised Histogram',equ)
cv2.imwrite('HistEqu.jpeg',equ)
cv2.waitKey()


#!/usr/bin/env python3
import subprocess, time, re, socket, argparse, os, asyncio, sys
import urllib
import socket
import geoip2.database
from IPy import IP
from prometheus_client import Counter, start_http_server, Gauge

metric_labels = ['src_pod', 'src_user', 'src_org', 'dst_ip', 'dst_proto', 'dst_country', 'dst_continent']

geo_reader = geoip2.database.Reader('/opt/GeoLite2-Country.mmdb')

host_name = os.environ.get('HOSTNAME')
if host_name is None:
    host_name = socket.gethostname()
src_pod = host_name
try:
    host_name = urllib.parse.unquote(host_name.replace('-', '%')).partition('%')[2].rpartition('%')[0]
    (src_user, _, src_org) = host_name.partition('@')
except Exception as e:
    src_user = 'Unknown'
    src_org = 'Unknown'

# Helper for building regex.
def re_param(name, pattern):
    return f'(?P<{name}>{pattern})'

# Pre-compile regex for matching tcpdump output:
pattern = '.*' + '.*'.join([
    'proto ' + re_param('proto', '\w+') + ' ',
    'length ' + re_param('length', '\d+'),
    '\n\s*' + re_param('src', '[\w\d\.-]+') + '\.' + re_param('srcp', '[\w\d-]+') +
    ' > ' +
    re_param('dst', '[\w\d\.-]+') + '\.' + re_param('dstp', '[\w\d-]+'),
]) + '.*'
dump_matcher = re.compile(pattern)

# Parse output from tcpdump and update the Prometheus counters.
def parse_packet(line):
    m = dump_matcher.match(line)
    if not m:
        return
    metric_labels = ['src_pod', 'src_user', 'src_org', 'dst_ip', 'dst_proto', 'dst_country']
    dst_ip = m.group('dst')
    if IP(dst_ip).iptype() != 'PUBLIC':
        return

    proto = m.group('proto').lower()
    if proto != 'icmp':
        proto += '/' + m.group('dstp')
    else:
        dst_ip += '.' + m.group('dstp') # in icmp, dstp matches last part of ip

    try:
        geo_response = geo_reader.country(dst_ip)
        country = geo_response.country.name
        continent = geo_response.continent.name
    except Exception as e:
        country = 'Unknown'
        continent = 'Unknown'

    labels = {
        'src_pod': src_pod,
        'src_user': src_user,
        'src_org': src_org,
        'dst_ip': dst_ip,
        'dst_proto': proto,
        'dst_country': country,
        'dst_continent': continent
    }
    packets.labels(**labels).inc()
    throughput.labels(**labels).inc(int(m.group('length')))

# Run tcpdump and stream the packets out
async def stream_packets():
    p = await asyncio.create_subprocess_exec(
        'tcpdump', '-i', opts.interface, '-v', '-n', stdout=asyncio.subprocess.PIPE)
    start_time = time.time()
    while True:
        if time.time() - start_time > 60:
            packets._metrics.clear()
            throughput._metrics.clear()
            start_time = time.time()
        # When tcpdump is run with -v, it outputs two lines per packet;
        # readuntil ensures that each "line" is actually a parse-able string of output.
        line = await p.stdout.readuntil(b' IP ')
        if len(line) <= 0:
            # print(f'No output from tcpdump... waiting.')
            time.sleep(1)
            continue
        try:
            parse_packet(line.decode('utf-8'))
        except BaseException as e:
            # print(f'Failed to parse line "{line}" because: {e}')
            pass

if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('--interface', '-i', default=os.getenv('NOE_INTERFACE', 'eth0'),
        help='The network interface to monitor.')
    parser.add_argument('--port', '-p', default=int(os.getenv('NOE_PORT', 9000)),
        help='The Prometheus metrics port.')
    parser.add_argument('--metric_prefix', '-s', default=os.getenv('NOE_METRIC_PREFIX', 'noe'),
        help='Metric prefix (group) for Prometheus')
    opts = parser.parse_args()

    packets = Gauge(f'{opts.metric_prefix}_packets', 'Packets transferred per minute', metric_labels)
    throughput = Gauge(f'{opts.metric_prefix}_bytes', 'Bytes transferred per minute', metric_labels)

    start_http_server(int(opts.port))
    asyncio.run(stream_packets())


import unittest
from unittest.mock import patch

import cli
import click
from click.testing import CliRunner

order_data = {
    "data_format": "csv",
    "products": [
        {
            "product_category": "drink",
            "type": "coke_zero"
        },
        {
            "product_category": "pizza",
            "size": "small",
            "type": "custom",
            "toppings": []
        },
        {
            "product_category": "pizza",
            "size": "extra_large",
            "type": "pepperoni",
            "toppings": ["olive", "beef"]
        },

    ],
    "delivery_method": {
        "type": "foodora",
        "details": {
            "address": "27 random street",
            "order_no": 2
        }
    }
}

class TestCliUtilityFunctions(unittest.TestCase):
    def test_convert_to_csv(self):
        expected = "drink,coke_zero,\npizza,custom,small,\npizza,pepperoni,extra_large,olive|beef\nfoodora,27 random street,2"
        actual = cli.convert_to_csv(order_data)
        self.assertEqual(actual, expected)

class TestCli(unittest.TestCase):
    def setUp(self):
        pass

    @patch("cli.requests.get")
    def test_valid_full_menu(self, mock_get):
        mock_get.return_value.status_code = 200
        mock_get.return_value.json = lambda: {
            "Part A": {"Item 1": 1.00, "Item 2": 1.99}}
        runner = CliRunner()
        result = runner.invoke(cli.menu)
        self.assertTrue(result.exit_code == 0 and not result.exception)
        self.assertEqual(
            result.output,
            "Part A:\nItem 1       :  $1.0\nItem 2       :  $1.99\n\n")

    @patch("cli.requests.get")
    def test_valid_menu_item(self, mock_get):
        mock_get.return_value.status_code = 200
        mock_get.return_value.text = "1.00"
        result = CliRunner().invoke(cli.menu, args=["random_item"])
        self.assertTrue(result.exit_code == 0 and not result.exception)
        self.assertEqual(result.output, "random_item: $1.00\n")

    @patch("cli.requests.get")
    def test_invalid_menu_item(self, mock_get):
        mock_get.return_value.status_code = 400
        mock_get.return_value.text = "Error text"
        result = CliRunner().invoke(cli.menu, args=["random_item"])
        self.assertTrue(result.exit_code == 0 and not result.exception)
        self.assertEqual(
            result.output,
            "Error: random_item is not a valid menu item\n")

    def test_add_pizza_and_drink(self):
        expected = {"products": [{
                "product_category": "pizza",
                "size": "small",
                "type": "custom",
                "toppings": [
                    "olive",
                ]
            },
            {
                "product_category": "drink",
                "type": "coke",
            },
        ],
            "delivery_method": {
                "type": "pickup",
                "details": {}
            }
        }

        base_order = {
            "products": [],
            "delivery_method": {
                "type": "pickup",
                "details": {}
            }
        }
        context = {"current_order": base_order}
        result = CliRunner().invoke(
            cli.order,
            args=["pizza", "small", "custom", "-t", "olive"],
            obj=context)
        self.assertTrue(result.exit_code == 0 and not result.exception)
        result = CliRunner().invoke(
            cli.order,
            args=["drink", "coke"],
            obj=context)
        self.assertTrue(result.exit_code == 0 and not result.exception)
        self.assertEqual(context["current_order"], expected)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 15 14:55:14 2021

@author: sahyadri
"""

import json
import numpy as np
import re
import argparse
import glob
import os
from datetime import date

def find_star(data):
    """
    Function to find the position of a given star (Alpheratz; could be any other)
    in a hyg.json file

    Parameters
    ----------
    data : dict
        Json object contain the hyg.json data.

    Returns
    -------
    long : float
        Longitude of the specified star in the hyg.json file.

    """
    #want to find position of a star based on its name
    features = data['features']
    names = [x['properties']['name'] for x in features]
    pos = np.where([x=='Alpheratz' for x in names])[0][0] #can change name
    long = features[pos]['geometry']['coordinates'][0]
    return long

def load_json(filepath):
    """
    Opens a json file and stores its data as a dictionary

    Parameters
    ----------
    filepath : string
        Path to the json file to be opened.

    Returns
    -------
    data : dict
        Dictionary containing data from a json file.

    """
    file =  open(filepath)
    data = json.load(file)
    return data

def calc_diff(latest_long, prev_long):
    """
    Function to calculate the shift from one day to the other. Computes the diff
    in longitudes for one star accross consecutive hyg.json files.

    Parameters
    ----------
    latest_long : float
        Longitude of selected star from latest hyg.json file.
    prev_long : float
        Longitude of selected star from previous hyg.json file.

    Returns
    -------
    diff : float
        Difference between the two longitudes.

    """
    diff = latest_long - prev_long
    return diff

def compute_coords(prev_const, diff):
    """
    Function to update the constellations by addition of the difference to the
    longitudes for all points making up a constellation. The addition checks if
    the longitude jumps above 360 or below 0 and corrects for those. It uses
    list_comprehension to update the nested list structure in the const.json
    files.

    Parameters
    ----------
    prev_const : dict
        Dictionary with previous date's constalltion data.
    diff : float
        Diff b/w longitudes of selected star accross consecutive days.

    Returns
    -------
    updated_const : dictionary
        Dictionary containing constellation points with all points updated.

    """
    for i, item in enumerate(prev_const['constellations']):
        Lines = item['points']
        # 360-long if long exceeds 360 and 360+long if long becomes -ve.
        updated_coords = [[[360-(y[0]+diff),y[1]] if y[0]+diff >= 360
                           else [360+y[0]+diff,y[1]] if y[0]+diff < 0
                           else [y[0]+diff,y[1]] for y in x] for x in Lines]
        prev_const['constellations'][i]['points'] = updated_coords
    updated_const = prev_const
    return updated_const

def extract_date(latest_file_name):
    filename = latest_file_name.split('/')[-1]
    filename = filename.split('_')
    month, day = filename[1], filename[2]
    year = re.split('g', filename[0], 1)[1]
    const_filename = 'const{}_{}_{}_00_00_00.json'.format(year, month, day)
    return const_filename

#added an argument parser to add choice b/w past or today modes.
parser = argparse.ArgumentParser(description='Constellation update')
parser.add_argument('opt',
                    metavar='option',
                    type=str,
                    help='Choice of run mode: "today" or "past"')
args = parser.parse_args()
option = args.opt

#loading the reference hyg.json and constellation files
ref_hyg = load_json('var/www/FDL/json/ALL/hyg2010_01_31_00_00_00.json')
prev_const = load_json('var/www/FDL/json/ALL/const_01_31_2010.json')

if option == 'today':
    #iter_list = glob.glob('var/www/FDL/json/ALL/hyg*.json')
    #iter_list = glob.glob('/home/sahyadri/Desktop/CAMS-India/hyg*.json')
    #latest_file = max(iter_list, key=os.path.getctime) #most recently created file.
    today = str(date.today())
    date_list = today.split('-')
    year, month, day = date_list[0], date_list[1], date_list[2]
    file_name = 'var/www/FDL/json/ALL/hyg{}_{}_{}_00_00_00.json'.format(year,month,day)
    print(file_name)
    latest_hyg = load_json(file_name)
    latest_long = find_star(latest_hyg)
    ref_long = find_star(ref_hyg)
    diff = calc_diff(latest_long, ref_long)
    new_const = compute_coords(prev_const, diff) #updated const json object!
    new_filename = extract_date(file_name)
    #creating a new const.json file
    new_file = open(new_filename,'w+')
    json.dump(new_const, new_file)
    new_file.close()

elif option == 'past':
    #for hyg_file in glob.glob('var/www/FDL/json/ALL/hyg*.json'):
    for hyg_file in glob.glob('var/www/FDL/json/ALL/hyg*.json'):
        latest_hyg = load_json(hyg_file)
        latest_long = find_star(latest_hyg)
        ref_long = find_star(ref_hyg)
        diff = calc_diff(latest_long, ref_long)
        new_const = compute_coords(prev_const, diff) #updated const json object!
        new_filename = extract_date(hyg_file)
        #creating a new const.json file
        new_file = open(new_filename,'w+')
        json.dump(new_const, new_file)
        new_file.close()
else:
    print('invalid options...write only "today" or "past"')


# A subscribers example

import rx
from rx.subjects import Subject
from datetime import datetime

# You can choose which of these to use
# source = rx.from_([2, 3, 5, 7])
# source = rx.from_iterable([2, 3, 5, 7])
source = rx.from_list([2, 3, 5, 7])

class TimeStampSubject(Subject):
    """ Class implementing a Subject """

    def on_next(self, value):
        print('Subject Received', value)
        super().on_next((value, datetime.now()))

    def on_completed(self):
        print('Data Stream Completed')
        super().on_completed()

    def on_error(self, error):
        print('In Subject - Error Occurred', error)
        super().on_error(error)

def prime_number_reporter(value):
    print('Function Received', value)

print('Set up')

# Create the Subject
subject = TimeStampSubject()

# Set up subscribers for the subject
subject.subscribe(prime_number_reporter)
subject.subscribe(lambda value: print('Lambda Received', value))
subject.subscribe(
    on_next = lambda value: print('Received on_next', value),
    on_error = lambda exp: print('Error Occurred', exp),
    on_completed = lambda: print('Received completed notification')
)

# Subscribe the Subject to the observable source
source.subscribe(subject)

print('Done')


"""bussiness_admin URL Configuration."""

# Django
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include(('app.users.urls', 'users'), namespace='users')),
    path('', include(('app.companies.urls', 'companies'), namespace='companies')),
]


from collections import defaultdict
from typing import Dict, Any, List, Union
import re

from io import BytesIO
import serial
import bdDetect
import braille
import inputCore
from logHandler import log
import hwIo
from baseObject import ScriptableObject
import wx
import threading
from globalCommands import SCRCAT_BRAILLE
import ui
import time

from . import constants
from . import gestures

def bytesToInt(byteData: bytes):
	"""Converts bytes to its integral equivalent."""
	return int.from_bytes(byteData, byteorder="big", signed=False)

class BrailleDisplayDriver(braille.BrailleDisplayDriver, ScriptableObject):
	_dev: hwIo.IoBase
	# Used to for error checking.
	_awaitingFrameReceipts: Dict[int, Any]
	name = constants.name
	# Translators: Names of braille displays.
	description = constants.description
	isThreadSafe = True
	supportsAutomaticDetection = True
	timeout = 0.2
	supportedSettings = (
		braille.BrailleDisplayDriver.HIDInputSetting(useConfig=True),
	)

	@classmethod
	def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
		driverRegistrar.addUsbDevices(bdDetect.KEY_HID, {
			"VID_C251&PID_1122",  # Esys (version < 3.0, no SD card
			"VID_C251&PID_1123",  # Esys (version >= 3.0, with HID keyboard, no SD card
			"VID_C251&PID_1124",  # Esys (version < 3.0, with SD card
			"VID_C251&PID_1125",  # Esys (version >= 3.0, with HID keyboard, with SD card
			"VID_C251&PID_1126",  # Esys (version >= 3.0, no SD card
			"VID_C251&PID_1127",  # Reserved
			"VID_C251&PID_1128",  # Esys (version >= 3.0, with SD card
			"VID_C251&PID_1129",  # Reserved
			"VID_C251&PID_112A",  # Reserved
			"VID_C251&PID_112B",  # Reserved
			"VID_C251&PID_112C",  # Reserved
			"VID_C251&PID_112D",  # Reserved
			"VID_C251&PID_112E",  # Reserved
			"VID_C251&PID_112F",  # Reserved
			"VID_C251&PID_1130",  # Esytime
			"VID_C251&PID_1131",  # Reserved
			"VID_C251&PID_1132",  # Reserved
		})
		driverRegistrar.addUsbDevices(bdDetect.KEY_SERIAL, {
			"VID_28AC&PID_0012",  # b.note
			"VID_28AC&PID_0013",  # b.note 2
			"VID_28AC&PID_0020",  # b.book internal
			"VID_28AC&PID_0021",  # b.book external
		})

		driverRegistrar.addBluetoothDevices(lambda m: m.id.startswith("Esys"))

	@classmethod
	def getManualPorts(cls):
		return braille.getSerialPorts()

	def __init__(self, port="Auto"):
		super().__init__()
		self.numCells = 0
		self.deviceType = None
		self._deviceData = {}
		self._awaitingFrameReceipts = {}
		self._frameLength = None
		self._frame = 0x20
		self._frameLock = threading.Lock()
		self._hidKeyboardInput = False
		self._hidInputBuffer = b""

		for portType, portId, port, portInfo in self._getTryPorts(port):
			# At this point, a port bound to this display has been found.
			# Try talking to the display.
			self.isHid = portType == bdDetect.KEY_HID
			try:
				if self.isHid:
					self._dev = hwIo.Hid(
						port,
						onReceive=self._onReceive,
						# Eurobraille wants us not to block other application's access to this handle.
						exclusive=False
					)
				else:
					self._dev = hwIo.Serial(
						port,
						baudrate=constants.BAUD_RATE,
						bytesize=serial.EIGHTBITS,
						parity=serial.PARITY_EVEN,
						stopbits=serial.STOPBITS_ONE,
						timeout=self.timeout,
						writeTimeout=self.timeout,
						onReceive=self._onReceive
					)
			except EnvironmentError:
				log.debugWarning(f"Error while connecting to port {port}", exc_info=True)
				continue

			for i in range(3):
				# Request device identification
				self._sendPacket(constants.EB_SYSTEM, constants.EB_SYSTEM_IDENTITY)
				# Make sure visualisation packets are disabled, as we ignore them anyway.
				self._sendPacket(constants.EB_VISU, constants.EB_VISU_DOT, constants.EB_FALSE)
				# A device identification results in multiple packets.
				# Make sure we've received everything before we continue
				while self._dev.waitForRead(2 * self.timeout):
					continue
				if self.numCells and self.deviceType:
					break
			if self.numCells and self.deviceType:
				# A display responded.
				log.info("Found {device} connected via {type} ({port})".format(
					device=self.deviceType, type=portType, port=port))
				if self.deviceType.startswith(("bnote", "bbook")):
					# send identifier to bnote / bbook with current COM port
					comportNumber = f'{int(re.match(".*?([0-9]+)$", port).group(1)):02d}'
					identifier = f"NVDA/{comportNumber}".encode()
					log.debug(f"sending {identifier} to eurobraille display")
					self._sendPacket(constants.EB_SYSTEM, constants.EB_CONNECTION_NAME, identifier)
				break
			self._dev.close()

		else:
			raise RuntimeError("No supported Eurobraille display found")

		self.keysDown = defaultdict(int)
		self._ignoreCommandKeyReleases = False

	def terminate(self):
		try:
			if self.deviceType.startswith(("bnote", "bbook")):
				# reset identifier to bnote / bbook with current COM port
				self._sendPacket(constants.EB_SYSTEM, constants.EB_CONNECTION_NAME, b'')
			super().terminate()
		finally:
			# We must sleep before closing the port as not doing this can leave
			# the display in a bad state where it can not be re-initialized.
			time.sleep(self.timeout)
			self._dev.close()
			self._dev = None
			self._deviceData.clear()

	def _prepFirstByteStreamAndData(
			self,
			data: bytes
	) -> (bytes, Union[BytesIO, hwIo.IoBase], bytes):
		if self.isHid:
			# data contains the entire packet.
			# HID Packets start with 0x00.
			byte0 = data[0:1]
			assert byte0 == b"\x00", "byte 0 is %r" % byte0
			# Check whether there is an incomplete packet in the buffer
			if self._hidInputBuffer:
				data = self._hidInputBuffer + data[1:]
				self._hidInputBuffer = b""
			byte1 = data[1:2]
			stream = BytesIO(data)
			stream.seek(2)
			return byte1, stream, data
		else:  # is serial
			return data, self._dev, data

	def _onReceive(self, data: bytes):
		byte1, stream, data = self._prepFirstByteStreamAndData(data)

		if byte1 == constants.ACK:
			frame = ord(stream.read(1))
			self._handleAck(frame)
		elif byte1 == constants.STX:
			length = bytesToInt(stream.read(2)) - 2  # length includes the length itself
			packet: bytes = stream.read(length)
			if self.isHid and not stream.read(1) == constants.ETX:
				# Incomplete packet
				self._hidInputbuffer = data
				return
			packetType: bytes = packet[0:1]
			packetSubType: bytes = packet[1:2]
			packetData: bytes = packet[2:] if length > 2 else b""
			if packetType == constants.EB_SYSTEM:
				self._handleSystemPacket(packetSubType, packetData)
			elif packetType == constants.EB_MODE:
				if packetSubType == constants.EB_MODE_DRIVER:
					log.debug("Braille display switched to driver mode, updating display...")
					braille.handler.update()
				elif packetSubType == constants.EB_MODE_INTERNAL:
					log.debug("Braille display switched to internal mode")
			elif packetType == constants.EB_KEY:
				self._handleKeyPacket(packetSubType, packetData)
			elif packetType == constants.EB_IRIS_TEST and packetSubType == constants.EB_IRIS_TEST_sub:
				# Ping command sent by Iris every two seconds, send it back on the main thread.
				# This means that, if the main thread is frozen, Iris will be notified of this.
				log.debug("Received ping from Iris braille display")
				wx.CallAfter(self._sendPacket, packetType, packetSubType, packetData)
			elif packetType == constants.EB_VISU:
				log.debug("Ignoring visualisation packet")
			elif packetType == constants.EB_ENCRYPTION_KEY:
				log.debug("Ignoring encryption key packet")
			else:
				log.debug(f"Ignoring packet: type {packetType}, subtype {packetSubType}, data {packetData}")

	def _handleAck(self, frame: int):
		try:
			super()._handleAck()
		except NotImplementedError:
			log.debugWarning(f"Received ACK for frame {frame} while ACK handling is disabled")
		else:
			try:
				del self._awaitingFrameReceipts[frame]
			except KeyError:
				log.debugWarning(f"Received ACK for unregistered frame {frame}")

	def _handleSystemPacket(self, packetType: bytes, data: bytes):
		if packetType == constants.EB_SYSTEM_TYPE:
			deviceType = ord(data)
			self.deviceType = constants.DEVICE_TYPES[deviceType]
			if 0x01 <= deviceType <= 0x06:  # Iris
				self.keys = constants.KEYS_IRIS
			elif 0x07 <= deviceType <= 0x0d:  # Esys
				self.keys = constants.KEYS_ESYS
			elif 0x0e <= deviceType <= 0x11:  # Esitime
				self.keys = constants.KEYS_ESITIME
			elif 0x12 <= deviceType <= 0x13:
				self.keys = constants.KEYS_BNOTE
			elif 0x14 <= deviceType <= 0x15:
				self.keys = constants.KEYS_BBOOK
			else:
				log.debugWarning(f"Unknown device identifier {data}")
		elif packetType == constants.EB_SYSTEM_DISPLAY_LENGTH:
			self.numCells = ord(data)
		elif packetType == constants.EB_SYSTEM_FRAME_LENGTH:
			self._frameLength = bytesToInt(data)
		elif packetType == constants.EB_SYSTEM_PROTOCOL and self.isHid:
			protocol = data.rstrip(b"\x00 ")
			try:
				version = float(protocol[:4])
			except ValueError:
				pass
			else:
				self.receivesAckPackets = version >= 3.0
		elif packetType == constants.EB_SYSTEM_IDENTITY:
			return  # End of system information
		self._deviceData[packetType] = data.rstrip(b"\x00 ")

	def _handleKeyPacket(self, group: bytes, data: bytes):
		if group == constants.EB_KEY_USB_HID_MODE:
			assert data in [constants.EB_TRUE, constants.EB_FALSE]
			self._hidKeyboardInput = constants.EB_TRUE == data
			return
		if group == constants.EB_KEY_QWERTY:
			log.debug("Ignoring Iris AZERTY/QWERTY input")
			return
		if group == constants.EB_KEY_INTERACTIVE and data[0:1] == constants.EB_KEY_INTERACTIVE_REPETITION:
			log.debug(f"Ignoring routing key {data[1] - 1} repetition")
			return
		arg = bytesToInt(data)
		if arg == self.keysDown[group]:
			log.debug("Ignoring key repetition")
			return
		self.keysDown[group] |= arg
		isIris = self.deviceType.startswith("Iris")
		if not isIris and group == constants.EB_KEY_COMMAND and arg >= self.keysDown[group]:
			# Started a gesture including command keys
			self._ignoreCommandKeyReleases = False
		else:
			if isIris or group != constants.EB_KEY_COMMAND or not self._ignoreCommandKeyReleases:
				try:
					inputCore.manager.executeGesture(gestures.InputGesture(self))
				except inputCore.NoInputGestureAction:
					pass
				self._ignoreCommandKeyReleases = not isIris and (group == constants.EB_KEY_COMMAND or self.keysDown[constants.EB_KEY_COMMAND] > 0)  # noqa E501
			if not isIris and group == constants.EB_KEY_COMMAND:
				self.keysDown[group] = arg
			else:
				del self.keysDown[group]

	def _sendPacket(self, packetType: bytes, packetSubType: bytes, packetData: bytes = b""):
		packetSize = len(packetData) + 4
		packetBytes = bytearray(
			b"".join([
				constants.STX,
				packetSize.to_bytes(2, "big", signed=False),
				packetType,
				packetSubType,
				packetData,
				constants.ETX
		]))
		if self.receivesAckPackets:
			with self._frameLock:
				frame = self._frame
				# Assumption: frame will only ever be 1 byte, otherwise consider byte order
				packetBytes.insert(-1, frame)
				self._awaitingFrameReceipts[frame] = packetBytes
				self._frame = frame + 1 if frame < 0x7F else 0x20
		packetData = bytes(packetBytes)
		if self.isHid:
			self._sendHidPacket(packetData)
		else:
			self._dev.write(packetData)

	def _sendHidPacket(self, packet: bytes):
		assert self.isHid
		blockSize = self._dev._writeSize - 1
		# When the packet length exceeds C{blockSize}, the packet is split up into several block packets.
		# These blocks are of size C{blockSize}.
		for offset in range(0, len(packet), blockSize):
			bytesToWrite = packet[offset:(offset + blockSize)]
			hidPacket = b"".join([
				b"\x00",
				bytesToWrite,
				b"\x55" * (blockSize - len(bytesToWrite))  # padding
			])
			self._dev.write(hidPacket)

	def display(self, cells: List[int]):
		# cells will already be padded up to numCells.
		self._sendPacket(
			packetType=constants.EB_BRAILLE_DISPLAY,
			packetSubType=constants.EB_BRAILLE_DISPLAY_STATIC,
			packetData=bytes(cells)
		)

	def _get_hidKeyboardInput(self):
		return self._hidKeyboardInput

	def _set_hidKeyboardInput(self, state: bool):
		self._sendPacket(
			packetType=constants.EB_KEY,
			packetSubType=constants.EB_KEY_USB_HID_MODE,
			packetData=constants.EB_TRUE if state else constants.EB_FALSE
		)
		for i in range(3):
			self._dev.waitForRead(self.timeout)
			if state is self._hidKeyboardInput:
				break

	scriptCategory = SCRCAT_BRAILLE

	def script_toggleHidKeyboardInput(self, gesture: inputCore.InputGesture):
		def announceUnavailableMessage():
			# Translators: Message when HID keyboard simulation is unavailable.
			ui.message(_("HID keyboard input simulation is unavailable."))

		if not self.isHid:
			announceUnavailableMessage()
			return

		state = not self.hidKeyboardInput
		self.hidKeyboardInput = state

		if state is not self._hidKeyboardInput:
			announceUnavailableMessage()
		elif state:
			# Translators: Message when HID keyboard simulation is enabled.
			ui.message(_('HID keyboard simulation enabled'))
		else:
			# Translators: Message when HID keyboard simulation is disabled.
			ui.message(_('HID keyboard simulation disabled'))

	# Translators: Description of the script that toggles HID keyboard simulation.
	script_toggleHidKeyboardInput.__doc__ = _("Toggle HID keyboard simulation")

	__gestures = {
		"br(eurobraille.esytime):l1+joystick1Down": "toggleHidKeyboardInput",
		"br(eurobraille):switch1Left+joystick1Down": "toggleHidKeyboardInput",
		"br(eurobraille.esytime):l8+joystick1Down": "toggleHidKeyboardInput",
		"br(eurobraille):switch1Right+joystick1Down": "toggleHidKeyboardInput",
	}
	gestureMap = gestures._gestureMap


# To do:
#   1)Make sure start and end matches.
#       -Take last element in list and compare to click destination
#       -if (x orgin - x dest) < 5  and (y orgin - y dest) < 5
#       -if not remove

import pygame
import random
import keyboard
import os
import win32gui
import win32api
import time
import threading

os.environ['SDL_VIDEO_CENTERED'] = "1"

# Global Variables
DISPLAY_WIDTH = 1344
DISPLAY_HEIGHT = 756

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

GREEN = (0, 200, 0)
BRIGHT_GREEN = (0, 255, 0)

RED = (200, 0, 0)
BRIGHT_RED = (255, 0, 0)

RED_BUTTON_SIZE = 20

stop_thread = False
recording_mouse = False
mouse_path_list = []

def text_objects(text, fontsize):
    """Set text's size and color"""
    font = pygame.font.SysFont(None, fontsize)
    textSurface = font.render(text, True, BLACK)
    return textSurface, textSurface.get_rect()

def draw_red_button(screen, x, y):
    """Draw an interactive red button on screen"""
    mouse_position = pygame.mouse.get_pos()
    mouse_pos_x = mouse_position[0]
    mouse_pos_y = mouse_position[1]

    if x + RED_BUTTON_SIZE > mouse_pos_x > x and y + RED_BUTTON_SIZE > mouse_pos_y > y:
        pygame.draw.rect(screen, BRIGHT_RED, (x, y, RED_BUTTON_SIZE, RED_BUTTON_SIZE))
        return mouse_position
    else:
        pygame.draw.rect(screen, RED, (x, y, RED_BUTTON_SIZE, RED_BUTTON_SIZE))
    return False

def draw_green_button(screen, x, y):
    """Draw an interactive green button on screen"""
    mouse_position = pygame.mouse.get_pos()
    mouse_pos_x = mouse_position[0]
    mouse_pos_y = mouse_position[1]

    if x + 150 > mouse_pos_x > x and y + 75 > mouse_pos_y > y:
        pygame.draw.rect(screen, BRIGHT_GREEN, (x, y, 150, 75))
        return True
    else:
        pygame.draw.rect(screen, GREEN, (x, y, 150, 75))
    return False

def timer_text(screen, time_left):
    """Display a countdown Timer in the game"""
    textSurf, textRect = text_objects("Timer: " + str(time_left), 25)

    # Set Timer text at top right corner
    return screen.blit(textSurf, (1257, 10))

def points_text(screen, points):
    """Display the current point in the game"""
    textSurf, textRect = text_objects("Points: " + str(points), 25)

    # Set Points text at top left corner
    return screen.blit(textSurf, (10, 10))

def click(x, y):
    """Aimbot easter egg in the game."""
    fg_win = win32gui.GetForegroundWindow()
    x1, y1 = win32gui.ClientToScreen(fg_win, (x, y))
    x1 += 1
    y1 += 1
    win32api.SetCursorPos((x1, y1))

def record_mouse():
    """Records mouse movement and save it to a list"""
    global mouse_path_list
    while True:
        time.sleep(0.025)

        global recording_mouse
        if recording_mouse:
            x, y = pygame.mouse.get_pos()
            time_of_coords = len(mouse_path_list)
            mouse_path_list.append((x, y, time_of_coords))

        global stop_thread
        if stop_thread:
            break

def main():
    global stop_thread
    global recording_mouse
    global mouse_path_list

    clock = pygame.time.Clock()
    pygame.init()
    screen = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
    pygame.display.set_caption('Aim map')

    button_location_x = random.randint(86, 1238)
    button_location_y = random.randint(44, 692)

    # Game Information
    points = 0

    timer_secs = 30
    pygame.time.set_timer(pygame.USEREVENT, 1000)

    cursor_coordinates = False

    times_up = True
    reset = True

    t1 = threading.Thread(target=record_mouse)
    t1.start()

    file_counter = 1
    exist = True

    while exist:
        file_path = "./Recordings/recording" + str(file_counter) + ".txt"
        exist = os.path.isfile(file_path)

    with open(file_path, "w") as f:
        done = 0

        while not done:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    done = 1
                    break
                elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
                    if cursor_coordinates:
                        recording_mouse = True
                        if mouse_path_list:
                            f.write(str(mouse_path_list) + "\n")
                        f.write("Mouse: %s\n" % str(pygame.mouse.get_pos()))
                        mouse_path_list = []
                        points += 1
                        button_location_x = random.randint(86, 1238)
                        button_location_y = random.randint(44, 692)
                    elif reset:
                        timer_secs = 30
                        points = 0
                        reset = False
                        times_up = False
                elif event.type == pygame.USEREVENT:
                    if timer_secs > 0:
                        timer_secs -= 1
                    else:
                        times_up = True

                        # Disable red button
                        cursor_coordinates = False

            screen.fill(WHITE)

            if times_up:
                recording_mouse = False

                textSurf, textRect = text_objects("Game Over!", 100)
                textRect.center = (DISPLAY_WIDTH / 2), (DISPLAY_HEIGHT / 2 - 200)
                screen.blit(textSurf, textRect)

                textSurf, textRect = text_objects("Points: " + str(points), 70)
                textRect.center = (DISPLAY_WIDTH / 2), (DISPLAY_HEIGHT / 2 - 100)
                screen.blit(textSurf, textRect)

                reset = draw_green_button(screen, 597, 350)

            else:
                timer_text(screen, timer_secs)
                points_text(screen, points)

                # If cursor coordinates is in the button, store it in cursor_coordinates
                cursor_coordinates = draw_red_button(screen, button_location_x, button_location_y)

                if keyboard.is_pressed('q'):
                    times_up = True

                    # Disable red button
                    cursor_coordinates = False

                if keyboard.is_pressed('w'):
                    # Easter egg
                    click(button_location_x, button_location_y)

            pygame.display.update()
            clock.tick(60)

    stop_thread = True
    t1.join()

if __name__ == "__main__":
    main()


'''
@program: Otsu_Thresholding.py

@description: Otsu最佳全局阈值处理

@author: doubleZ

@create: 2019/12/14
'''
import cv2

def Otsu_Thresholding(image):
    '''
    :description: Otsu最佳全局阈值

    :param image: 原图

    :return gray: 原图的灰度图像
    :return thresh: 简单阈值处理后的图像
    :return th1: 对灰度图像进行Otsu最佳全局阈值处理后对图像
    :return blurred: 高斯模糊后的图像
    :return th2:对高斯滤波后的图像进行Otsu最佳全局阈值处理后的图像
    '''
    gray = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)     # rgb图像变换为灰度图像

    (T, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  # 简单阈值处理

    (T, th1) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)  # 对灰度图像进行Otsu最佳全局阈值处理

    blurred = cv2.GaussianBlur(gray, (5, 5), 0)     # 高斯滤波降噪

    (T, th2) = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)  # 对高斯滤波后对图像进行Otsu最佳全局阈值处理

    return [gray, thresh, th1, blurred, th2]

if __name__ == "__main__":

    image = cv2.imread('../Resources/bubble.jpeg')

    [gray, thresh, th1, blurred, th2] = Otsu_Thresholding(image)

    cv2.imshow('Original Noisy Image', gray)
    cv2.imshow('Global Thresholding (v=127)', thresh)
    cv2.imshow("Otsu's Thresholding", th1)
    cv2.imshow('Gaussian filtered Image', blurred)
    cv2.imshow("Otsu's Thresholding", th2)

    cv2.waitKey(0)
    cv2.destroyAllWindows()


# -*- encoding: utf-8 -*-
"""
-------------------------------------------------
   File Name：    vocabulary.py
   Description :
   Author :       Wings DH
   Time：         2020/1/4 2:47 下午
-------------------------------------------------
   Change Activity:
                   2020/1/3: Create
-------------------------------------------------
"""
from abc import ABC, abstractmethod
from collections import OrderedDict
import os

from tqdm import tqdm

from common.log import logger
from data_processing.text_processor import ITextProcessor
from data_processing.tokenizer import SpaceTokenizer, ITextTokenizer
import sentencepiece as spm

NO_LIMIT_MAX_N_WORD = -1
NO_LIMIT_MIN_FREQ = 0

class IVocabulary(ABC):

    @property
    @abstractmethod
    def n_tokens(self):
        return

    @abstractmethod
    def __len__(self):
        pass

    @abstractmethod
    def text_to_sequence(self, text, *args, **kwargs):
        pass

def _save_vocab_to_file(vocab, save_file_path):
    """ 保存词库到txt文件
    :param save_file_path:
    :param vocab:
    Returns:
    """
    if save_file_path is not None:
        with open(save_file_path, 'w', encoding='utf-8') as f:
            for index in vocab.index_token:
                _token = vocab.index_token[index]
                f.write('{token}:{index}\n'.format(token=_token, index=index))
            logger.info('Save vocab into {vocab_file}'.format(vocab_file=save_file_path))

def _arrange_vocab_from_corpus(corpus_iter,
                               tokenizer=None,
                               text_processor=None,
                               max_n_tokens=NO_LIMIT_MAX_N_WORD,
                               min_freq=NO_LIMIT_MIN_FREQ):
    """
    从语料中获取词库
    :param corpus_iter: 关于corpus的迭代器, 每次迭代输出一个token列表
    :return vocab: 构建好的Vocabulary
    """

    if not corpus_iter:
        raise ValueError('file_path and dir_path cant be None in the same time!')

    if not tokenizer:
        tokenizer = SpaceTokenizer.new_instance()
    elif not isinstance(tokenizer, ITextTokenizer):
        raise ValueError('tokenizer:<{}> must instance of ITextTokenizer'.format(type(tokenizer)))

    vocab = Vocabulary(tokenizer=tokenizer, text_processor=text_processor)
    for line in tqdm(corpus_iter):
        # 如果需要经过文本预处理，那统计词频应当同样经过预处理
        if text_processor is not None:
            line = text_processor.process(line)

        if len(line) <= 0:
            continue

        tokens = tokenizer.tokenize(line)

        for token in tokens:
            vocab.count_token(token)

    vocab.build_vocab_from_word_count(max_n_tokens, min_freq)

    return vocab

def _load_from_token_count_txt(path, tokenizer=None, text_processor=None):
    vocab = Vocabulary(tokenizer=tokenizer, text_processor=text_processor)
    try:
        logger.info('Start load token_count txt')
        with open(path, 'r', encoding='utf-8') as f:
            for line in f:
                try:
                    coef = line.strip().split(':')

                    # 防止token=:的情况
                    _token = coef[0]
                    _index = coef[-1]

                    vocab.token_index[_token] = int(_index)
                    vocab.index_token[int(_index)] = _token
                except ValueError:
                    logger.warning('Invalid line:{}'.format(line))

        logger.info('End   load token_count txt, read {nb_tokens} tokens'.format(nb_tokens=len(vocab)))
    except FileNotFoundError:
        logger.warning(
            'File not exit, please check {error_file}'.format(error_file=path))
    return vocab

class Vocabulary(IVocabulary):
    """
    词汇库类
    """

    @property
    def n_tokens(self):
        return len(self.index_token)

    TOKEN_PAD = '<pad>'
    TOKEN_UNKNOWN = '<unk>'
    TOKEN_START = '<s>'
    TOKEN_END = '</s>'

    INDEX_PAD = 0
    INDEX_UNKNOWN = 1
    INDEX_START = 2
    INDEX_END = 3
    INDEX_ORIGIN_CUSTOM = 4

    @property
    def index_token(self):
        return self._index_token

    @property
    def token_index(self):
        return self._token_index

    @property
    def token_count(self):
        return self._token_count

    @classmethod
    def new_from_corpus(cls, corpus_iter,
                        tokenizer=None,
                        text_processor=None,
                        max_n_tokens=NO_LIMIT_MAX_N_WORD,
                        min_freq=NO_LIMIT_MIN_FREQ):
        return _arrange_vocab_from_corpus(corpus_iter, tokenizer, text_processor, max_n_tokens, min_freq)

    @classmethod
    def new_from_save_file(cls, f_path, tokenizer=None, text_processor=None):
        return _load_from_token_count_txt(f_path, tokenizer, text_processor=text_processor)

    @staticmethod
    def save_vocab(vocab, f_path):
        """
        保存vocab到文件
        :param vocab: 需要保存的Vocabulary实例
        :param f_path: 保存路径
        :return:
        """
        _save_vocab_to_file(vocab, f_path)

    def __init__(self, tokenizer=None, text_processor=None):

        # 初始化词库
        self._token_index = {}
        self._index_token = {}
        self._token_count = OrderedDict()

        # 初始化分词器
        if tokenizer is None or not isinstance(tokenizer, ITextTokenizer):
            # 默认使用空格来做分词
            self.tokenizer = SpaceTokenizer.new_instance()
        else:
            self.tokenizer = tokenizer

        # 初始化文本处理器
        if text_processor is not None and not isinstance(text_processor, ITextProcessor):
            raise TypeError("text_processor isn't instance of ITextProcessor but {}".format(type(text_processor)))
        self.text_processor = text_processor

    def count_token(self, token):
        if token in self.token_count:
            self.token_count[token] += 1
        else:
            self.token_count[token] = 1

    def _add_token_index(self, token, index):
        self._token_index[token] = index
        self._index_token[index] = token

    def build_vocab_from_word_count(self, max_n_tokens=NO_LIMIT_MAX_N_WORD, min_freq=NO_LIMIT_MIN_FREQ):
        self._token_index = {}
        self._index_token = {}

        # 默认占前4位索引
        self._add_token_index(Vocabulary.TOKEN_PAD, Vocabulary.INDEX_PAD)
        self._add_token_index(Vocabulary.TOKEN_UNKNOWN, Vocabulary.INDEX_UNKNOWN)
        self._add_token_index(Vocabulary.TOKEN_START, Vocabulary.INDEX_START)
        self._add_token_index(Vocabulary.TOKEN_END, Vocabulary.INDEX_END)

        index = Vocabulary.INDEX_ORIGIN_CUSTOM

        # 根据词频排序，只保留高频词
        wcounts = list(self.token_count.items())
        wcounts.sort(key=lambda x: x[1], reverse=True)

        for cnt, (w, c) in enumerate(wcounts):
            if max_n_tokens != NO_LIMIT_MAX_N_WORD and cnt > max_n_tokens - 1:
                break

            if c < min_freq:
                break

            self._add_token_index(w, index)
            index += 1
        logger.info('Build vocab, volume:{size_word_index}'.format(size_word_index=len(self.token_index)))

    def tokens_to_sequence(self, tokens, add_start=False, add_end=False):
        """
        将一句话的token转成序列
        :param tokens:
        :param add_start:
        :param add_end:
        :return:
        """
        sequence = []
        if add_start:
            sequence.append(self.token_index[Vocabulary.TOKEN_START])

        sequence.extend(
            [self.token_index.get(c, self.token_index[Vocabulary.TOKEN_UNKNOWN]) for c in tokens if c != ' '])

        if add_end:
            sequence.append(self.token_index[Vocabulary.TOKEN_END])

        return sequence

    def text_to_sequence(self, text, add_start=False, add_end=False, *args, **kwargs):
        """
        文本转成序列
        :param text:
        :param add_start:
        :param add_end:
        :return:
        """

        # 文本预处理
        if self.text_processor is not None:
            text = self.text_processor.process(text)

        # 用分词器将一段文本转成tokens
        tokens = self.tokenizer.tokenize(text)

        # token转为索引
        return self.tokens_to_sequence(tokens, add_start=add_start, add_end=add_end)

    def texts_to_sequences(self, texts, add_start=False, add_end=False):
        """
        多个文本转成序列
        :param texts:
        :param add_start:
        :param add_end:
        :return:
        """
        sequences = []
        for text in texts:
            seq = self.text_to_sequence(text, add_start=add_start, add_end=add_end)
            sequences.append(seq)
        return sequences

    def sequences_to_texts(self, sequences):
        texts = []
        for seq in sequences:
            texts.append([self.index_token.get(token, Vocabulary.TOKEN_UNKNOWN) for token in seq])
        return texts

    def __len__(self):
        return len(self._token_index)

    def __contains__(self, item):
        return item in self._token_index

    def __getitem__(self, item):
        return self.token_index.get(item, self.token_index[Vocabulary.TOKEN_UNKNOWN])

    def __str__(self):
        """
        Returns: summary str
        """
        return 'Word Total: {total}'.format(total=len(self))

class SentencePieceVocabulary(IVocabulary):
    """
    应用Sentence piece工具分词
    https://github.com/google/sentencepiece/blob/master/python/
    """
    ARG_KEY_SPM_F_PATH = 'path'

    @property
    def n_tokens(self):
        return self.spm_processor.get_piece_size()

    @classmethod
    def new_instance(cls, *args, **kwargs):
        f_path = kwargs.get(cls.ARG_KEY_SPM_F_PATH, None)
        if f_path is None:
            raise ValueError('param: path can not be None!')
        elif not os.path.exists(f_path):
            raise FileExistsError('param: path {} must exist'.format(f_path))

        return cls(f_path)

    def tokenize_as_pieces(self, text):
        return self.spm_processor.EncodeAsPieces(text)

    def __len__(self):
        return self.spm_processor.get_piece_size()

    def text_to_sequence(self, text, *args, **kwargs):
        return self.spm_processor.EncodeAsIds(text)

    def sequences_to_texts(self, sequences):
        texts = []
        for seq in sequences:
            text = self.spm_processor.DecodeIds(seq.tolist())
            texts.append(text)
        return texts

    def __init__(self, spm_model_f_path):
        """
        :param spm_model_f_path: str, sentence piece 模型文件
        """
        self.spm_model_f_path = spm_model_f_path
        self.spm_processor = spm.SentencePieceProcessor()
        self.spm_processor.load(spm_model_f_path)


import requests
import pandas as pd

API_URL = "https://data.binance.com/api/v3/ticker/24hr"

response = requests.get(API_URL)

if response.status_code == 200:
    data = response.json()
else:
    print("Failed to retrieve the data from the API")
    exit()

df = pd.DataFrame(data)

csv_filename ="api_data.csv"
df.to_csv(csv_filename, index=False)
print(f"CSV dataset saved as {csv_filename}")
df = pd.read_csv("api_data.csv")


import cv2
import glob
import os

inputFolder='/content/drive/My Drive/Dataset/test_set/right'
folderLen=len(inputFolder)
os.mkdir('right_test')
for img in glob.glob(inputFolder+"/*jpg"):
	image = cv2.imread(img)
	imgResized=cv2.resize(image,(256,256))
	cv2.imwrite("right_test"+img[folderLen:],imgResized)


# !/usr/bin/python3
# coding:utf-8

import json
import requests
from bs4 import BeautifulSoup
from datetime import datetime
import time
from datetime import timedelta
from collections import Counter
import sqlite3
from time import sleep
import json
import random

conn = sqlite3.connect('sqlite.db')
c = conn.cursor()

all_user_arr = []
save_user_arr = []
unsave_user_arr = []

# all_user_arr
SQL = "SELECT searchcode FROM pretestUser2019"
cursor = conn.execute(SQL).fetchall()

for i in cursor:
    all_user_arr.append(''.join(i))

# save_user_arr
SQL = "SELECT DISTINCT searchcode FROM pretestXapi2019"
cursor = conn.execute(SQL).fetchall()

for i in cursor:
    save_user_arr.append(''.join(i))

# unsave_user_arr
unsave_user_arr = list(set(all_user_arr).difference(set(save_user_arr)))
total = len(unsave_user_arr)

# test_arr = ['mailto:孫逸翔80@gmail.com', 'mailto:徐炫喆01@gmail.com']

now_web = []
all_data = []
anscode_arr = ['', 'L', 'N', 'P', 'T', 'U', 'V', 'X', 'Y', 'Z', 'F', 'W', 'I']

http_arr = ['http://198.161.237.181:80',
            'http://38.86.51.100:3128', 'http://153.92.5.186:8080']

http_num = 0
second = 0

proxies = {
    "http":  http_arr[http_num]
}

my_headers = {
    'Authorization': 'Basic YTEyNjg0OTAwMjpwcmluY2VwYW4=',
    'Content-Type': 'application/json',
    'Origin': 'https://cuesplateform.servehttp.com',
    'Referer': 'https://cuesplateform.servehttp.com/original_prototypes/StatementViewer/index.html',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
    'X-Experience-API-Version': '1.0.1'}

def get_data(searchcode):
    http_num = random.randint(0, len(http_arr)-1)
    proxies['http'] = http_arr[http_num]
    if searchcode.startswith('/'):
        r = requests.get('https://lrs.adlnet.gov' +
                         searchcode, headers=my_headers,  proxies=proxies)
    else:
        my_params = {
            'agent': '{"mbox":"' + searchcode + '"}',
            'limit': '0',
            'format': 'exact'
        }
        r = requests.get('https://lrs.adlnet.gov/xapi/statements',
                         params=my_params, headers=my_headers,  proxies=proxies)
    # print(requests.get('http://icanhazip.com', proxies=proxies).text)
    # if r.status_code == 200:
    return r.json()

def search_more(data):
    if data['more'] != "":
        return True
    else:
        return False

def get_all_data(name):
    time.sleep(1)
    if search_more(get_data(name)) == False:
        print('> '+'目前處理最後一頁')
        all_data.append(get_data(now_web[-1]))
        print('      ')
        return all_data
    else:
        if len(now_web) == 0:
            now_web.append(name)
        print('> '+'目前處理第 '+str(len(now_web)) + ' 頁')
        all_data.append(get_data(now_web[-1]))
        now_web.append(get_data(now_web[-1])['more'])
        # print(now_web)
        return get_all_data(now_web[-1])

def clear_data(data):
    for i in data:
        for j in i['statements']:
            arr = ['', '', '', '',
                   '', '', '', '', '']
            # arr = [timestamp, verb, description, code, matrixcode, completedSolutions, completedTime, matrix]
            type_id = j['verb']['display']['en-US']
            description = j['object']['definition']['description']['zh-TW']
            timestamp = datetime.strptime(
                j['timestamp'][0:j['timestamp'].find('+')], '%Y-%m-%dT%H:%M:%S.%f') + timedelta(hours=8)
            arr[0] = j['actor']['mbox']
            arr[1] = timestamp.strftime('%Y-%m-%dT%H:%M:%S.%f')
            arr[2] = type_id
            arr[3] = description
            if type_id == 'solved':
                temp = []
                arr[5] = list(Counter(j['result']['extensions']['ext:matrix'].replace(
                    '-2', '').replace('-1', '').replace('|', ' ').replace(',', ' ').split()).keys())
                for k in arr[5]:
                    # print(k)
                    temp.append(anscode_arr[int(k)])
                arr[5] = ' '.join(temp)
                arr[6] = j['result']['extensions']['ext:completedSolutions']
                if j['result']['extensions']['ext:completedSolutions'] == None:
                    arr[6] = 'None'
                else:
                    arr[6] = j['result']['extensions']['ext:completedSolutions']
                arr[7] = str(j['result']['extensions']['ext:completedTime'])
                arr[8] = j['result']['extensions']['ext:matrix']
            elif type_id == 'snap':
                temp = []
                arr[5] = list(Counter(j['result']['extensions']['ext:matrix'].replace(
                    '-2', '').replace('-1', '').replace('|', ' ').replace(',', ' ').split()).keys())
                for k in arr[5]:
                    # print(k)
                    temp.append(anscode_arr[int(k)])
                arr[5] = ' '.join(temp)
                arr[8] = j['result']['extensions']['ext:matrix']
            elif type_id == 'passed':
                arr[6] = j['result']['extensions']['ext:completedSolutions']
                if j['result']['extensions']['ext:completedSolutions'] == None:
                    arr[6] = 'None'
                else:
                    arr[6] = j['result']['extensions']['ext:completedSolutions']
                arr[7] = str(j['result']['extensions']['ext:completedTime'])
            elif type_id == 'operate':
                arr[4] = j['result']['extensions']['ext:code'].strip()
            sqlstr = 'insert into pretestXapi2019 values('+str(
                arr).strip('[]')+')'
            c.execute(sqlstr)
            conn.commit()

num = 0

if len(unsave_user_arr) != 0:
    print('使用者共有 ' + str(len(all_user_arr)) + ' 位')
    print('資料庫已儲存 ' + str(len(save_user_arr)) + ' 位')
    print('目前資料庫有 ' + str(len(unsave_user_arr)) + ' 個需要處理')
    print('  ')
    print(all_user_arr)
    print(save_user_arr)
    print(unsave_user_arr)
    print('  ')
    for user in unsave_user_arr:
        num += 1
        second = random.randint(2, 5)
        print(user+' '+str(num)+'/'+str(total))
        clear_data(get_all_data(user))
        now_web.clear()
        all_data.clear()
        for i in range(second):
            print('等待 '+str(second - i)+' 秒')
            time.sleep(1)
        print('開始執行下一個 user')
        print('  ')
else:
    print('使用者共有 ' + str(len(all_user_arr)) + ' 位')
    print('資料庫已儲存 ' + str(len(save_user_arr)) + ' 位')
    print('目前資料庫有 ' + str(len(unsave_user_arr)) + ' 個需要處理')
    print('> 無資料需要更新')

conn.close()