import cv2 as cv
import math
from PIL import Image
import numpy as np
from PIL import ImageDraw

# YOLOv3-608 has been trained with these 80 categories from COCO:
# Lin, Tsung-Yi, et al. "Microsoft COCO: Common Objects in Context."
# European Conference on Computer Vision. Springer, Cham, 2014.

def load_label_categories(label_file_path):
    categories = [line.rstrip('\n') for line in open(label_file_path)]
    return categories

LABEL_FILE_PATH = './data/lishui_0902/trafficlights2.names'
ALL_CATEGORIES = load_label_categories(LABEL_FILE_PATH)

# 确定有80个类别:
CATEGORY_NUM = len(ALL_CATEGORIES)
assert CATEGORY_NUM == 2

class PreprocessYOLO(object):
    """装载图像，然后reshape成yolov3-608需要的分辨率.
    """

    def __init__(self, yolo_input_resolution):
        """指定yolov3的输入分辨率.

        Keyword arguments:
        yolo_input_resolution -- two-dimensional tuple with the target network's (spatial)
        input resolution in HW order
        """
        self.yolo_input_resolution = yolo_input_resolution

    def process(self, input_image_path):
        """载入图像，然后进行预处理，如resize，归一化等等

        Keyword arguments:
        input_image_path -- string path of the image to be loaded
        """
        image_raw, image_resized = self._load_and_resize(input_image_path)
        # cv.imwrite("/home/sc/keepgoing/model_format_convert/yolov3/py_preprocess_light.png",cv.cvtColor(image_resized,cv.COLOR_RGB2BGR))
        image_preprocessed = self._shuffle_and_normalize(image_resized)
        return image_raw, image_preprocessed

    def _load_and_resize(self, input_image_path):
        """对图像进行resize，然后返回numpy对象

        Keyword arguments:
        input_image_path -- string path of the image to be loaded
        """

        image_raw = Image.open(input_image_path) #PIL默认是rgb order

        new_resolution = (
            self.yolo_input_resolution[1],
            self.yolo_input_resolution[0])
        image_resized = image_raw.resize(
            new_resolution, resample=Image.BICUBIC)

        image_resized = np.array(image_resized, dtype=np.float32, order='C')
        return image_raw, image_resized

    def _shuffle_and_normalize(self, image):
        """将图像归一化到[0,1]之间，然后将HWC结构转换成NCHW结构

        Keyword arguments:
        image -- image as three-dimensional NumPy float array, in HWC format
        """
        image /= 255.0
        # HWC -> CHW :
        image = np.transpose(image, [2, 0, 1])
        # CHW -> NCHW
        image = np.expand_dims(image, axis=0)
        # j将图像转换成row-major order,如 "C order":
        image = np.array(image, dtype=np.float32, order='C')
        return image

class PostprocessYOLO(object):
    """后处理yolov3-608的三个输出tensor."""

    def __init__(self,
                 yolo_masks,
                 yolo_anchors,
                 obj_threshold,
                 nms_threshold,
                 yolo_input_resolution):
        """Initialize with all values that will be kept when processing several frames.
        Assuming 3 outputs of the network in the case of (large) YOLOv3.

        Keyword arguments:
        yolo_masks -- a list of 3 three-dimensional tuples for the YOLO masks
        yolo_anchors -- a list of 9 two-dimensional tuples for the YOLO anchors
        object_threshold -- threshold for object coverage, float value between 0 and 1
        nms_threshold -- threshold for non-max suppression algorithm,
        float value between 0 and 1
        input_resolution_yolo -- two-dimensional tuple with the target network's (spatial)
        input resolution in HW order
        """
        self.masks = yolo_masks
        self.anchors = yolo_anchors
        self.object_threshold = obj_threshold
        self.nms_threshold = nms_threshold
        self.input_resolution_yolo = yolo_input_resolution

    def process(self, outputs, resolution_raw):
        """Take the YOLOv3 outputs generated from a TensorRT forward pass, post-process them
        and return a list of bounding boxes for detected object together with their category
        and their confidences in separate lists.

        Keyword arguments:
        outputs -- outputs from a TensorRT engine in NCHW format
        resolution_raw -- the original spatial resolution from the input PIL image in WH order
        """
        outputs_reshaped = list()
        for output in outputs:
            outputs_reshaped.append(self._reshape_output(output))

        boxes, categories, confidences = self._process_yolo_output(
            outputs_reshaped, resolution_raw)

        return boxes, categories, confidences

    def _reshape_output(self, output):
        """Reshape a TensorRT output from NCHW to NHWC format (with expected C=255),
        and then return it in (height,width,3,85) dimensionality after further reshaping.

        Keyword argument:
        output -- an output from a TensorRT engine after inference
        """
        output = np.transpose(output, [0, 2, 3, 1])
        _, height, width, _ = output.shape
        dim1, dim2 = height, width
        dim3 = 3
        # There are CATEGORY_NUM=80 object categories:
        dim4 = (4 + 1 + CATEGORY_NUM)
        return np.reshape(output, (dim1, dim2, dim3, dim4))

    def _process_yolo_output(self, outputs_reshaped, resolution_raw):
        """Take in a list of three reshaped YOLO outputs in (height,width,3,85) shape and return
        return a list of bounding boxes for detected object together with their category and their
        confidences in separate lists.

        Keyword arguments:
        outputs_reshaped -- list of three reshaped YOLO outputs as NumPy arrays
        with shape (height,width,3,85)
        resolution_raw -- the original spatial resolution from the input PIL image in WH order
        """

        # E.g. in YOLOv3-608, there are three output tensors, which we associate with their
        # respective masks. Then we iterate through all output-mask pairs and generate candidates
        # for bounding boxes, their corresponding category predictions and their confidences:
        boxes, categories, confidences = list(), list(), list()
        for output, mask in zip(outputs_reshaped, self.masks):
            box, category, confidence = self._process_feats(output, mask)
            box, category, confidence = self._filter_boxes(
                box, category, confidence)
            boxes.append(box)
            categories.append(category)
            confidences.append(confidence)

        boxes = np.concatenate(boxes)
        categories = np.concatenate(categories)
        confidences = np.concatenate(confidences)

        # Scale boxes back to original image shape:
        width, height = resolution_raw
        image_dims = [width, height, width, height]
        boxes = boxes * image_dims

        # Using the candidates from the previous (loop) step, we apply the non-max suppression
        # algorithm that clusters adjacent bounding boxes to a single bounding box:
        nms_boxes, nms_categories, nscores = list(), list(), list()
        for category in set(categories):
            idxs = np.where(categories == category)
            box = boxes[idxs]
            category = categories[idxs]
            confidence = confidences[idxs]

            keep = self._nms_boxes(box, confidence)

            nms_boxes.append(box[keep])
            nms_categories.append(category[keep])
            nscores.append(confidence[keep])

        if not nms_categories and not nscores:
            return None, None, None

        boxes = np.concatenate(nms_boxes)
        categories = np.concatenate(nms_categories)
        confidences = np.concatenate(nscores)

        return boxes, categories, confidences

    def _process_feats(self, output_reshaped, mask):
        """Take in a reshaped YOLO output in height,width,3,85 format together with its
        corresponding YOLO mask and return the detected bounding boxes, the confidence,
        and the class probability in each cell/pixel.

        Keyword arguments:
        output_reshaped -- reshaped YOLO output as NumPy arrays with shape (height,width,3,85)
        mask -- 2-dimensional tuple with mask specification for this output
        """

        # Two in-line functions required for calculating the bounding box
        # descriptors:
        def sigmoid(value):
            """Return the sigmoid of the input."""
            return 1.0 / (1.0 + math.exp(-value))

        def exponential(value):
            """Return the exponential of the input."""
            return math.exp(value)

        # Vectorized calculation of above two functions:
        sigmoid_v = np.vectorize(sigmoid)
        exponential_v = np.vectorize(exponential)

        grid_h, grid_w, _, _ = output_reshaped.shape

        anchors = [self.anchors[i] for i in mask]

        # Reshape to N, height, width, num_anchors, box_params:
        anchors_tensor = np.reshape(anchors, [1, 1, len(anchors), 2])
        box_xy = sigmoid_v(output_reshaped[..., :2])
        box_wh = exponential_v(output_reshaped[..., 2:4]) * anchors_tensor
        box_confidence = sigmoid_v(output_reshaped[..., 4])

        box_confidence = np.expand_dims(box_confidence, axis=-1)
        box_class_probs = sigmoid_v(output_reshaped[..., 5:])

        col = np.tile(np.arange(0, grid_w), grid_w).reshape(-1, grid_w)
        row = np.tile(np.arange(0, grid_h).reshape(-1, 1), grid_h)

        col = col.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)
        row = row.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)
        grid = np.concatenate((col, row), axis=-1)

        box_xy += grid
        box_xy /= (grid_w, grid_h)
        box_wh /= self.input_resolution_yolo
        box_xy -= (box_wh / 2.)
        boxes = np.concatenate((box_xy, box_wh), axis=-1)

        # boxes: centroids, box_confidence: confidence level, box_class_probs:
        # class confidence
        return boxes, box_confidence, box_class_probs

    def _filter_boxes(self, boxes, box_confidences, box_class_probs):
        """Take in the unfiltered bounding box descriptors and discard each cell
        whose score is lower than the object threshold set during class initialization.

        Keyword arguments:
        boxes -- bounding box coordinates with shape (height,width,3,4); 4 for
        x,y,height,width coordinates of the boxes
        box_confidences -- bounding box confidences with shape (height,width,3,1); 1 for as
        confidence scalar per element
        box_class_probs -- class probabilities with shape (height,width,3,CATEGORY_NUM)

        """
        box_scores = box_confidences * box_class_probs
        box_classes = np.argmax(box_scores, axis=-1)
        box_class_scores = np.max(box_scores, axis=-1)
        pos = np.where(box_class_scores >= self.object_threshold)

        boxes = boxes[pos]
        classes = box_classes[pos]
        scores = box_class_scores[pos]

        return boxes, classes, scores

    def _nms_boxes(self, boxes, box_confidences):
        """Apply the Non-Maximum Suppression (NMS) algorithm on the bounding boxes with their
        confidence scores and return an array with the indexes of the bounding boxes we want to
        keep (and display later).

        Keyword arguments:
        boxes -- a NumPy array containing N bounding-box coordinates that survived filtering,
        with shape (N,4); 4 for x,y,height,width coordinates of the boxes
        box_confidences -- a Numpy array containing the corresponding confidences with shape N
        """
        x_coord = boxes[:, 0]
        y_coord = boxes[:, 1]
        width = boxes[:, 2]
        height = boxes[:, 3]

        areas = width * height
        ordered = box_confidences.argsort()[::-1]

        keep = list()
        while ordered.size > 0:
            # Index of the current element:
            i = ordered[0]
            keep.append(i)
            xx1 = np.maximum(x_coord[i], x_coord[ordered[1:]])
            yy1 = np.maximum(y_coord[i], y_coord[ordered[1:]])
            xx2 = np.minimum(x_coord[i] + width[i],
                             x_coord[ordered[1:]] + width[ordered[1:]])
            yy2 = np.minimum(y_coord[i] + height[i],
                             y_coord[ordered[1:]] + height[ordered[1:]])

            width1 = np.maximum(0.0, xx2 - xx1 + 1)
            height1 = np.maximum(0.0, yy2 - yy1 + 1)
            intersection = width1 * height1
            union = (areas[i] + areas[ordered[1:]] - intersection)

            # Compute the Intersection over Union (IoU) score:
            iou = intersection / union

            # The goal of the NMS algorithm is to reduce the number of adjacent bounding-box
            # candidates to a minimum. In this step, we keep only those elements whose overlap
            # with the current bounding box is lower than the threshold:
            indexes = np.where(iou <= self.nms_threshold)[0]
            ordered = ordered[indexes + 1]

        keep = np.array(keep)
        return keep

def draw(image, predictions):
    for prediction in predictions:
        x, y, w, h = prediction[0]
        score = prediction[1]
        cls = prediction[2]

        x1 = max(0, np.floor(x + 0.5).astype(int))
        y1 = max(0, np.floor(y + 0.5).astype(int))

        x2 = min(image.shape[1], np.floor(x + w + 0.5).astype(int))
        y2 = min(image.shape[0], np.floor(y + h + 0.5).astype(int))

        cv2.rectangle(image, (x1, y1), (x2, y2), (255, 0, 0), 2)
        cv2.putText(image, '{0} {1:.2f}'.format(cls, score),
                    (x1, y1-6),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    0.6, (0, 0, 255), 1,
                    cv2.LINE_AA)

        print('class: {0}, score: {1:.2f}'.format(cls, score))
        print('box coordinate x, y, w, h: {0}'.format(prediction[0]))
    return image

def draw_bboxes(image_raw, bboxes, confidences, categories, all_categories, bbox_color='blue'):
    """在原始输入图片上标记bounding box没然后返回结果.

    Keyword arguments:
    image_raw -- a raw PIL Image
    bboxes -- NumPy array containing the bounding box coordinates of N objects, with shape (N,4).
    categories -- NumPy array containing the corresponding category for each object,
    with shape (N,)
    confidences -- NumPy array containing the corresponding confidence for each object,
    with shape (N,)
    all_categories -- a list of all categories in the correct ordered (required for looking up
    the category name)
    bbox_color -- an optional string specifying the color of the bounding boxes (default: 'blue')
    """

    draw = ImageDraw.Draw(image_raw)
    print(bboxes, confidences, categories)
    for box, score, category in zip(bboxes, confidences, categories):
        x_coord, y_coord, width, height = box
        left = max(0, np.floor(x_coord + 0.5).astype(int))
        top = max(0, np.floor(y_coord + 0.5).astype(int))
        right = min(image_raw.width, np.floor(x_coord + width + 0.5).astype(int))
        bottom = min(image_raw.height, np.floor(y_coord + height + 0.5).astype(int))

        draw.rectangle(((left, top), (right, bottom)), outline=bbox_color)
        draw.text((left, top - 12), '{0} {1:.2f}'.format(all_categories[category], score), fill=bbox_color)

    return image_raw


# -*- coding: utf-8 -*-
"""
Created on Wed Apr 18 18:07:04 2018

@author: Kim Earl Lowell
"""

#%%
# This code reformats NCUA_Bank KPI data to be suitable for Tableau. It transposes
# information for each KPI for each CU from "horizontal" to "vertical" and
# assigns a date.
############## MAIN BODY OF PROGRAM #############
import pandas as pd
import numpy as np
#inpath = "C:/Analytics/DATA911/Arkatechture/NCUA_Data/NCUA_Data_Final/PYE_Output/"
inpath='C:/Analytics/DATA911/Arkatechture/FDIC_Data/FDIC_KPIs/'
#outpath = "C:/Analytics/DATA911/Arkatechture/ArkaTechVisualisations/"
outpath='C:/Analytics/DATA911/Arkatechture/FDIC_Data/FDIC_KPIs/'
#infile='KPIs_2013-17_5CUs.csv'
#outfile='KPIs_2013-17_5CUs_Transpose.csv'
infile='NCUA_and_Banks_KPIs.csv'
outfile='NCUA_and_Banks_KPIs_Transpose.csv'
# Read input file. Get column names. Set up list of first 8 to be used as
# identifiers. Then set up output dataframe.
dfin=pd.read_csv(inpath+infile)
incols=dfin.columns.values
idcols=[]
for i in range(8):
    idcols.append(incols[i])
idcols.append('year')
# Create list of out columns so we can return the df columns to their original
# order.
dfout=pd.DataFrame(columns=idcols)
yearlist=['2013','2014','2015','2016','2017']
# Now loop through each row transposing -- knowing that years represented are
# 2013-2017.
for i in range(dfin.shape[0]):
    if i%500==0:
        print('Now working on FI:',i)
# Add five rows with identifiers to the dataframe -- one for each of the
# 5 years.
    dftemp=pd.DataFrame(index=[0,1,2,3,4],columns=idcols)
# Now fill the rows with identifier information
    for j in range(5):
        for k in range(8):
            dftemp.iloc[j,k]=dfin.iloc[i,k]
        dftemp.iloc[j,8]=yearlist[j]
# Identifier information added to data frame. Now set up KPIs. Store KPI
# names for realphabetising.
    KPInames=[]
    for j in range(12):
        KPIlist=[]
        KPI_name=incols[8+j*5].split('_')[0]
        KPInames.append(KPI_name)
        for k in range(5):
            KPIlist.append(dfin.iloc[i,(8+j*5+k)])
        dftemp[KPI_name]=KPIlist
# Now add this to the output dataframe.
    dfout=dfout.append([dftemp],ignore_index=True)
for KPIname in KPInames:
    idcols.append(KPIname)
dfout=dfout[idcols]
dfout.to_csv(path_or_buf=outpath+outfile, index=False)


N, K = list(map(int, input().split()))
if K==0:
    print(N*N)
    exit()

ans = 0
r = 1
for b in range(K+1, N+1):
    ans += (N//b)*r + max((N%b)-K+1 ,0)
    r += 1

print(ans)


# 39. 수식 최대화

'''
Not solve this problem by myself. I think 80% I did, but I don`t know
how to calculate formula.
'''
import re
from itertools import permutations
def solution(expression):
    answer = 0
    operators = [x for x in ['-', '+', '*'] if x in expression]
    operators_perm = list(permutations(operators))

    expression = re.split('([^0-9])', expression)
    for order in operators_perm:
        expression_cpy = expression[:]
        for operator in order:
            # 이 부분 주목
            while operator in expression_cpy:
                operator_idx = expression_cpy.index(operator)
                formula_cost = str(eval(expression_cpy[operator_idx - 1] +
                                        expression_cpy[operator_idx] +
                                        expression_cpy[operator_idx + 1]))
                expression_cpy[operator_idx - 1] = formula_cost
                expression_cpy = expression_cpy[:operator_idx] + expression_cpy[operator_idx + 2:]
        answer = max(answer, abs((int(expression_cpy[-1]))))
    return answer

expression_1 = '100-200*300-500+20'
expression_2 = '50*6-3*2'

# print(solution(expression_1))
# print(solution(expression_2))

'''
100-200*300-500+20 이 예의 경우
['100', '-', '200], ['200', '*', '300'], ... , ['500', '+', '20']
형태로 만드는 것은 성공하였고, 각 연산자 별로 우선순위를 조합으로 만드는 것까지
성공하였으나,
계산을 수행할 때 바뀌는 과정을 어떻게 구현해야할지 감이 안 잡힘.
'''
import re
from itertools import permutations
def solution_mine(expression):
    answer = 0

    # [('100', '-'), '200], [('200', '*'), '300], ...
    p = re.compile('(\d+)([-+*]?)')
    expression = p.findall(expression)
    formula_lst = []
    for (express1_num, operator), express2 in zip(expression, expression[1:]):
        formula_lst.append([express1_num, operator, express2[0]])
    print(formula_lst)

    # 연산자 우선순위 순열
    operators = set([i[1] for i in formula_lst if i[1] in ['-', '+', '*']])
    operators_perm = list(permutations(operators, len(operators)))
    print(operators_perm)

    answer_lst = []
    for order in operators_perm:
        formula_cost = 0
        for operator in order:
            for formula in formula_lst:
                if operator in formula:
                    formula_cost += eval(''.join(formula))
                    del formula_lst[formula_lst.index(formula)]
        answer_lst.append(formula_cost)

    print(answer_lst)
    return answer

# 다른 풀이(재귀)
def calculate(priority, n, expression):
    if n == 2:
        return str(eval(expression))

    if priority[n] == '*':
        result = eval('*'.join([calculate(priority, n + 1, e)
                                for e in expression.split('*')]))
    if priority[n] == '+':
        result = eval('+'.join([calculate(priority, n + 1, e)
                                for e in expression.split('+')]))
    if priority[n] == '-':
        result = eval('-'.join([calculate(priority, n + 1, e)
                                for e in expression.split('-')]))
    return str(result)

def solution_other(expression):
    answer = 0

    priorities = (list(permutations(['+', '-', '*'], 3)))
    for priority in priorities:
        result = int(calculate(priority, 0, expression))
        answer = max(answer, abs(result))

    return answer

# print(solution_other(expression_1))
# print(solution_other(expression_2))

# 제일 좋다고 생각되는 풀이(재귀랑 거의 비슷한 구조)
def solution_best(expression):
    answer = []

    operations = [('+', '-', '*'),('+', '*', '-'),('-', '+', '*'),('-', '*', '+'),('*', '+', '-'),('*', '-', '+')]
    for operator in operations:
        first = operator[0]
        second = operator[1]
        temp_list = []
        for e in expression.split(first):
            temp = [f'({i})' for i in e.split(second)]
            temp_list.append(f'{second.join(temp)}')
        answer.append(abs(eval(first.join(temp_list))))
    return max(answer)

print(solution_best(expression_1))
print(solution_best(expression_2))


#!/usr/bin/env python3

"""
 Collects log entries in real time and provides extensions/callbacks to ship
 entries to any remote collector for log aggregation, metrics or operational
 use.

"""
import os
import time
import errno
import stat
import sys

class LogCollector(object):
    """Looks for changes in files of a given directory. Watches entries in real time
       and allows callbacks. """

    def __init__(self, watch_dir, callback, extensions=["log"], tail_lines=1, maxsize=1048576):
        """Arguments:
            (str) @watch_dir:
                the directory to watch
            (callable) @callback:
                a callback function that will be invoked everytime a new log entry in
                encountered.
            (list) @extensions:
                only watch files with these extensions, default to .log
            (int) @tail_lines:
                read last N lines from the log file(s)
            (int) @maxsize:
                    specifies the maximum number of bytes to read from a file on every
                    iteration, defaults to 1Mb
        """
        self.watch_dir = os.path.realpath(watch_dir)
        self.extensions = extensions
        self._callback = callback
        self.maxsize = maxsize
        self._files_to_watch = {}
        self._maxsize = maxsize

        assert os.path.isdir(self.watch_dir), self.watch_dir
        assert callable(self._callback), repr(callback)
        self.update_files()
        for id, file in self._files_to_watch.items():
            file.seek(os.path.getsize(file.name))
            if tail_lines:
                try:
                    lines = self.tail(file.name, tail_lines)
                except IOError as err:
                    if err.errno != errno.ENOENT:
                        raise
                    else:
                        if lines:
                            self._callback(file.name, lines)

    def __enter__(self):
        return self

    def __exit__(self,*args):
        self.close()

    def __del__(self):
        self.close()

    def loop(self,interval=0.1,blocking=True):
        """ Start a loop checking for any changes to files in files_to_watch list
        if blocking is False then just run once and exit the loop"""
        while True:
            self.update_files()
            for file in list(self._files_to_watch.items()):
                self.readlines(file)
                if not blocking:
                    return
            time.sleep(interval)

    def log(self, line):
        """Log a file when it is unwatched."""
        print(line)

    def listdir(self):
        """List directory and filter files to watch based on the
        matching extensions."""
        dirlist = os.listdir(self.watch_dir)
        if self.extensions:
            return [x for x in dirlist if os.path.splitext(x)[1][1:] in self.extensions]
        return dirlist


# Assignment 7: The Book Browser application displays a list of books found in the Books database.
# The user can sort the list by Title or Author, search by a specified value across all columns,
# and view the details of a selected book from the list.

import tkinter
import sqlite3
import os

db = None  # initialize the global variable for the database connection

class BookBrowser:
    def __init__(self, rows):
        # GUI information
        font = "Arial 14 normal"
        padding = 10
        bg_color = "MediumTurquoise"
        btn_bg_color = "PaleTurquoise"
        btn_padding = 25
        btn_font="Arial 10 normal"

        self.main_window = tkinter.Tk()
        self.main_window.configure(background=bg_color)
        self.main_window.title("Award Winning Books")
        self.main_window.geometry('1000x780')  # (width x height)

        try:
            # Header
            tkinter.Label(self.main_window, text="Award Winning Books Browser", font=font, padx=padding, pady=padding, background=bg_color).grid(row=0, columnspan=4)

            # Title and Author sort Buttons.
            # When a button is clicked, the self.sort_books function is called to display the books in Title or Author order
            tkinter.Button(self.main_window, text='Title', background=btn_bg_color, padx=btn_padding, font=btn_font, command=lambda: self.sort_books('Title')).grid(row=1, column=0)
            tkinter.Button(self.main_window, text='Author', background=btn_bg_color, padx=btn_padding, font=btn_font, command=lambda: self.sort_books('Author')).grid(row=1, column=1)

            # Search Entry field and Button.
            # Entry field can be used by the user to specify a search value.
            # When the search Button is clicked, the self.search_books function is called to find all books that contain the search value in any of its columns
            self.searchvalue = tkinter.StringVar()
            self.searchterm_entry = tkinter.Entry(self.main_window, textvariable=self.searchvalue, width=20).grid(row=1, column=2)
            tkinter.Button(self.main_window, text='Search', command=self.search_books, background=btn_bg_color, padx=btn_padding, font=btn_font).grid(row=1, column=3)

            # When the window is initially displayed, all books in the database are displayed
            self.display_rows(rows)

            tkinter.mainloop()
        except IndexError as err:
            print('Index error: ', err)
        except Exception as err:
            print('An error occurred: ', err)

    # Display the Title and Author of the books found in the rows variable.
    # This function is called when the window is initially displayed, and by the sort and search functions.
    # It is a general purpose function that displays whatever rows are passed to it.
    def display_rows(self, rows):
        #GUI customization variables
        padding_side = 20
        padding_len = 5
        font = "Garamond 11 normal"
        bg_color = "MediumTurquoise"
        # Clear any previous rows of data before displaying the books found in the rows variable
        for label in self.main_window.grid_slaves():
            if int(label.grid_info()['row']) > 1:
                label.grid_forget()
        self.clear_book_details()    # clear book details (if present)

        # Book titles are displayed as labels with a Radiobutton.
        # Each Radiobutton has a variable with a unique value defined by the book ISBN (self.book_isbn)
        self.book_isbn = tkinter.StringVar()    # variable, with a unique value, that is associated with each book
        self.book_isbn.set("not selected yet")  # forces the radio buttons to initially display as not selected

        try:
            if rows==[]:
                tkinter.Label(self.main_window, text="No results found",padx=padding_side, font=font, background=bg_color).grid(row=2)
            else:
                # Loop through each tuple in the rows variable and create a Radiobutton with the book Title, followed by a Label with the Author
                r = 2
                for book in rows:
                    tkinter.Radiobutton(self.main_window, text=book[1], variable=self.book_isbn, value=book[0], command=self.get_book_details, padx=padding_side, font=font, background=bg_color).grid(row=r, column=0, sticky=tkinter.constants.W)
                    tkinter.Label(self.main_window, text=book[2], padx=padding_side, font=font, background=bg_color).grid(row=r, column=1, sticky=tkinter.constants.W)
                    r += 1
        except IndexError as err:
            print('Index error: ', err)
        except Exception as err:
            print('An error occurred: ', err)

    # Sort the books by the value in the column variable.
    def sort_books(self, column):
        # Clear the book details (if present) before displaying the sorted results
        self.clear_book_details()

        # Create the SQL statement, execute the query, fetch the results, and call self.display_rows(rows)
        try:
            cursor = db.cursor()
            sql = "SELECT * FROM book ORDER BY " + column
            cursor.execute(sql)
            rows = cursor.fetchall()
            self.display_rows(rows)
        except sqlite3.IntegrityError as err:
            print('Integrity Error:', err)
        except sqlite3.OperationalError as err:
            print('Operational Error:', err)
        except sqlite3.Error as err:
            print('Error:', err)

    # Search the books by the value specified in the search Entry field.
    # The list of books should contain all books where any column contains the search value
    def search_books(self):
        value = self.searchvalue.get()  # "user-specified search value"

        # Create the SQL statement, execute the query, fetch the results, and call self.display_rows(rows)
        try:
            cursor = db.cursor()
            sql = "SELECT * FROM book WHERE isbn LIKE '%" + value + "%' OR title LIKE '%" + value + "%' OR author LIKE '%" + value + "%' OR publisher LIKE '%" + value + "%' OR format LIKE '%" + value + "%' OR subject LIKE '%" + value + "%'"
            cursor.execute(sql)
            rows = cursor.fetchall()
            self.display_rows(rows)
        except sqlite3.IntegrityError as err:
            print('Integrity Error:', err)
        except sqlite3.OperationalError as err:
            print('Operational Error:', err)
        except sqlite3.Error as err:
            print('Error:', err)

    # When the user clicks a Radiobutton, use the associated ISBN to query the database for that specific book.
    def get_book_details(self):
        isbn = self.book_isbn.get() #"ISBN value associated with the book Title that was clicked"
        # Create the SQL statement, execute the query, fetch the results.
        # Call self.display_book_details(rows) to display the details for the book (ISBN, Title, Author, Publisher, Format, Subject)
        try:
            cursor = db.cursor()
            sql = "SELECT * FROM book WHERE isbn ='" + isbn + "'"
            cursor.execute(sql)
            rows = cursor.fetchall()
            self.display_book_details(rows)
        except sqlite3.IntegrityError as err:
            print('Integrity Error:', err)
        except sqlite3.OperationalError as err:
            print('Operational Error:', err)
        except sqlite3.Error as err:
            print('Error:', err)

    # Display the details for a specific book
    def display_book_details(self, rows):
        # Clear the previous book details (if present)
        self.clear_book_details()

        # GUI customization variables
        bg_color = "White"
        bg_color_heading = "MediumSpringGreen"
        font = "Arial 12 normal"
        padding=5
        padding_header = 30

        # Create a frame inside of the grid to contain the book details
        self.details_frame = tkinter.Frame(self.main_window, background=bg_color)
        self.details_frame.grid(row=3, column=2, rowspan=20, columnspan=2)

        self.isbn_text=tkinter.StringVar()
        self.title_text = tkinter.StringVar()
        self.author_text = tkinter.StringVar()
        self.publisher_text = tkinter.StringVar()
        self.format_text = tkinter.StringVar()
        self.subject_text = tkinter.StringVar()
        isbn_result = "ISBN: " + rows[0][0]
        self.isbn_text.set(isbn_result)
        title_result = "Title: " + rows[0][1]
        self.title_text.set(title_result)
        author_result = "Author: " + rows[0][2]
        self.author_text.set(author_result)
        publisher_result = "Publisher: " + rows[0][3]
        self.publisher_text.set(publisher_result)
        format_result = "Format: " + rows[0][4]
        self.format_text.set(format_result)
        subject_result = "Subject: " + rows[0][5]
        self.subject_text.set(subject_result)

        try:
            # Each book detail (ISBN, Title, Author, Publisher, Format, Subject) is displayed as a Label.
            # Each Label is laid out in a single column grid inside the Frame.
            # For example, each Label would be defined as follows:
            tkinter.Label(self.details_frame, text="Details for selected award winning book", background=bg_color_heading, font=font, padx=padding_header).grid(row=1, column=0)
            tkinter.Label(self.details_frame, textvariable=self.isbn_text, background=bg_color, font=font, padx=padding).grid(row=2, column=0, sticky=tkinter.constants.W)
            tkinter.Label(self.details_frame, textvariable=self.title_text, background=bg_color, font=font, padx=padding).grid(row=3, column=0, sticky=tkinter.constants.W)
            tkinter.Label(self.details_frame, textvariable=self.author_text, background=bg_color, font=font, padx=padding).grid(row=4, column=0, sticky=tkinter.constants.W)
            tkinter.Label(self.details_frame, textvariable=self.publisher_text, background=bg_color, font=font, padx=padding).grid(row=5, column=0, sticky=tkinter.constants.W)
            tkinter.Label(self.details_frame, textvariable=self.format_text, background=bg_color, font=font, padx=padding).grid(row=6, column=0, sticky=tkinter.constants.W)
            tkinter.Label(self.details_frame, textvariable=self.subject_text, background=bg_color, font=font, padx=padding).grid(row=7, column=0, sticky=tkinter.constants.W)
        except IndexError as err:
            print('Index error: ', err)
        except Exception as err:
            print('An error occurred: ', err)

    # Remove the Frame with the book details from the window using the destroy function.
    # This is needed to remove the previous book details when sorting or displaying new book details
    def clear_book_details(self):
        try:
            self.details_frame.destroy()
        except Exception as err:
            print("No problem, there is no Frame to destroy")

# Connect to the BOOKS database, execute the query to retrieve all of the books.
# Create the BookBrowser GUI and pass it the rows variable that contains the list of books.
def main():
    global db
    try:
        dbname = 'books.db'
        if os.path.exists(dbname):
            db = sqlite3.connect(dbname)
            cursor = db.cursor()
            sql = 'SELECT * FROM BOOK'
            cursor.execute(sql)
            rows = cursor.fetchall()
            BookBrowser(rows)
            db.close()
        else:
            print('Error:', dbname, 'does not exist')
    except sqlite3.IntegrityError as err:
        print('Integrity Error on connect:', err)
    except sqlite3.OperationalError as err:
        print('Operational Error on connect:', err)
    except sqlite3.Error as err:
        print('Error on connect:', err)

main()


# !pip install xgboost --user
# !pip install tqdm --user
# !pip install seaborn --user
import pandas as pd
from sklearn.metrics import *
import numpy as np
import xgboost as xgb
from sklearn.model_selection import StratifiedKFold, KFold
from gen_feas import load_data
import matplotlib.pyplot as plt
import seaborn as sns
import gc
from utils import *
from tqdm import tqdm

train, test, no_featuress, features = load_data()
sample_submission = pd.read_feather('data/sample_submission.feather')

n_fold = 5
y_scores = 0
test_size = test.shape[0]
y_pred_all_l1 = np.zeros(test_size)

fea_importances = np.zeros(len(features))

label = ['target']
train[label] = train[label].astype(int)
print(train[label])

def pred(X_test, model, batch_size=10000):
    iterations = (X_test.shape[0] + batch_size - 1) // batch_size
    print('iterations', iterations)

    y_test_pred_total = np.zeros(test_size)
    print(f'predicting {i}-th model')
    for k in tqdm(range(iterations)):
        y_pred_test = model.predict_proba(X_test[k * batch_size:(k + 1) * batch_size])[:, 1]
        y_test_pred_total[k * batch_size:(k + 1) * batch_size] += y_pred_test
    return y_test_pred_total

# [1314, 4590]
kfold = StratifiedKFold(n_splits=n_fold, shuffle=False, random_state=1314)
for i, (train_index, valid_index) in enumerate(kfold.split(train[features], train[label])):
    print("n。{}_th fold".format(i))
    X_train, y_train, X_valid, y_valid = train.loc[train_index][features], train[label].loc[train_index], \
                                         train.loc[valid_index][features], train[label].loc[valid_index]
    bst = xgb.XGBClassifier(learning_rate=0.1,
                            n_estimators=1000,
                            max_depth=5,
                            min_child_weight=1,
                            gamma=0,
                            subsample=0.8,
                            colsample_bytree=0.8,
                            objective='binary:logistic',
                            nthread=20,
                            scale_pos_weight=1,
                            seed=2
                            )
    bst.fit(X_train, y_train,
            eval_set=[(X_valid, y_valid)],
            eval_metric=['logloss', 'auc'],
            verbose=True,
            early_stopping_rounds=10)
    valid_pred = bst.predict(X_valid)
    # print("accuracy:",accuracy_score(y_valid, valid_pred))
    print("f1-score:", f1_score(y_valid, valid_pred))
    y_pred_all_l1 += pred(test[features], bst)
    y_scores += bst.best_score

    # 训练完成 发送邮件
    mail(str(i) + "xgb cpu 训练完成，cv f1-score:{}".format(f1_score(y_valid, valid_pred)))

    fea_importances += bst.feature_importances_
    del bst
    del valid_pred
    gc.collect()

r = y_pred_all_l1 / n_fold
sample_submission['target'] = r
sample_submission.to_csv('result/xgb_prob.csv', index=False, sep=",")

sample_submission['target'] = [1 if x > 0.50 else 0 for x in r]
print(sample_submission['target'].value_counts())
sample_submission.to_csv('result/xgb_result.csv', index=False)

fea_importance_df = pd.DataFrame({
    'features': features,
    'importance': fea_importances
})
fea_importance_df.sort_values(by="importance", ascending=False).to_csv('tmp/fea_importance.csv', index=None)

# plt.figure(figsize=(14, 30))
# sns.barplot(x="importance", y="features", data=fea_importance_df.sort_values(by="importance", ascending=False))
# plt.title('Features importance (averaged/folds)')
# plt.tight_layout()
# plt.show()


import gzip
import os
import shutil

import numpy as np
from six.moves import urllib
import tensorflow as tf
import glob, os
from pathlib import Path
from .audio import read_wav, crop_random_wav, fix_length
from .audio import wav2melspec_db, normalize_db
import math
import random
random.seed(123456)
from sklearn.utils import resample
import  pandas as pd
from voice_embedding.voice.constant import VOICE_STFT_T

def load_random_segment_wav(wavfile_path, params):
    wav = read_wav(wavfile_path, params.signal["sr"])
    # wav = trim_wav(wav)
    length = int(params.signal["duration"] * params.signal["sr"])
    wav = crop_random_wav(wav, length=length)
    wav = fix_length(wav, length, mode='reflect')
    return wav  # (t, n_mel)

def sample_labelwav_batch(dict_label2waves, label_per_batch, wav_per_label):
    batch_samples = []

    all_labels = list(dict_label2waves.keys())
    # Sample classes from the dataset
    if len(all_labels) < label_per_batch:
        batch_labels = resample(all_labels, replace=True, n_samples=label_per_batch)
    else:
        batch_labels = resample(all_labels, replace=False, n_samples=label_per_batch)

    for lab in batch_labels:
        if len(dict_label2waves[lab]) < wav_per_label:
            batch_label_wav = resample(dict_label2waves[lab], replace=True, n_samples=wav_per_label)
        else:
            batch_label_wav = resample(dict_label2waves[lab], replace=False, n_samples=wav_per_label)

        batch_samples += list(zip(batch_label_wav, [lab]*wav_per_label))

    random.shuffle(batch_samples)
    #print(batch_samples[:2])

    return batch_samples

def dataset_old(directory, params, num_epochs, type_dataset="train"):
    if type_dataset == "train":
        batch_size = params.train["label_per_batch"] * params.train["wav_per_label"]
    elif type_dataset == "eval":
        batch_size = params.eval["batch_size"]

    list_wavfile_paths = glob.glob('{}/**/**/*.wav'.format(directory))
    samples = [(wavfile_path, Path(wavfile_path).parents[1].name) for wavfile_path in list_wavfile_paths]
    random.shuffle(samples)
    labels = list(sorted(list(set([sample[1] for sample in samples]))))
    num_people = len(labels)
    dict_label2id = {lab: i for i, lab in enumerate(labels)}

    tf.logging.info("The number of original samples = {}".format(len(samples)))
    tf.logging.info("The number of people = {}".format(num_people))
    tf.logging.info("The number of epochs = {}".format(num_epochs))
    num_run_steps = math.ceil(len(samples) * num_epochs / batch_size)
    tf.logging.info("The number of steps need to go through data = {}".format(num_run_steps))

    tf.logging.info(samples[:10])

    def generator_samples():
        # instead of repeating num_epochs using tf.dataset.repeat (no different samples, just repeat)
        # we repeat manually in here and each time we sample randomly different segment of the original audio file
        i = 0
        for epoch in range(num_epochs):
            for wavfile_path, person_id in samples:
                wav = load_random_segment_wav(wavfile_path, params)
                mel_spec = wav2melspec_db(wav, params.signal["sr"], params.signal["n_fft"], params.signal["win_length"],
                                          params.signal["hop_length"], params.signal["n_mels"])
                mel_spec = normalize_db(mel_spec, max_db=params.signal["max_db"], min_db=params.signal["min_db"])
                i += 1
                if i%params.train_size == 0:
                    tf.logging.info("Loading up to sample: {} and has shape {}".format(i, mel_spec.shape))

                person_label = dict_label2id[person_id]
                yield mel_spec, person_label

    return tf.data.Dataset.from_generator(generator_samples, (tf.float32, tf.int32), (tf.TensorShape([None, None]), tf.TensorShape([])))

#global_dict_label2id =  None
def dataset(directory, params, num_epochs, type_dataset="train", mapping_label_id_file=None):
    audio_supported_types = ["wav", "flac", "m4a"]
    if type_dataset == "train":
        batch_size = params.train["label_per_batch"] * params.train["wav_per_label"]
    elif type_dataset in ["eval", "pred"]:
        batch_size = params.eval["batch_size"]
    else:
        tf.logging.error("Don't support type_dataset = {}".format(type_dataset))

    print("audio directory = {}".format(directory))
    if mapping_label_id_file is None: # train or eval
        list_wavfile_paths = []
        for audio_ext_type in audio_supported_types:
            list_wavfile_paths += glob.glob('{}/**/**/*.{}'.format(directory, audio_ext_type))
        samples = [(wavfile_path, Path(wavfile_path).parents[1].name) for wavfile_path in list_wavfile_paths]
        mapping_label_id_file = "{}/mapping_label_id.csv".format(str(Path(directory).parent.absolute()))
    else: # prediction
        list_wavfile_paths = []
        for audio_ext_type in audio_supported_types:
            list_wavfile_paths += glob.glob('{}/**/*.{}'.format(directory, audio_ext_type), recursive=True)
        #list_wavfile_paths = glob.glob('{}/**/*.flac'.format(directory), recursive=True) + glob.glob('{}/**/*.wav'.format(directory), recursive=True)
        samples = [(wavfile_path, None) for wavfile_path in list_wavfile_paths]

    print("mapping_label_id_file = {}".format(mapping_label_id_file))
    #random.shuffle(samples)
    if type_dataset == "train":
        dict_label2waves = {}
        for wav_path, lab in samples:
            if lab not in dict_label2waves:
                dict_label2waves[lab] = []
            dict_label2waves[lab].append(wav_path)

        labels = list(sorted(list(set([str(sample[1]) for sample in samples]))))
        dict_label2id = {lab: i for i, lab in enumerate(labels)}
        label_id_pairs = [[i, lab] for i, lab in enumerate(labels)]
        df = pd.DataFrame(label_id_pairs, columns=["id", "person"])
        df.to_csv(mapping_label_id_file, index=False)
        tf.logging.info("Wrote mapping_label_id_file to {}".format(mapping_label_id_file))
    elif type_dataset == "eval":
        # Load the saved dict_label2id
        df = pd.read_csv(mapping_label_id_file)
        tf.logging.info("Loaded mapping_label_id_file to {}".format(mapping_label_id_file))
        dict_label2id = {str(row["person"]): row["id"] for index, row in df.iterrows()}

    tf.logging.info("The number of original samples = {}".format(len(samples)))
    if type_dataset != "pred":
        num_people = len(dict_label2id)
        tf.logging.info("The number of people = {}".format(num_people))
    tf.logging.info("The number of epochs = {}".format(num_epochs))
    num_step_per_epoch = math.ceil(len(samples) / batch_size)
    num_run_steps = math.ceil(len(samples) * num_epochs / batch_size)
    tf.logging.info("The number of steps need to go through data = {}".format(num_run_steps))

    tf.logging.info(samples[:10])
    #global global_dict_label2id
    #global_dict_label2id = dict_label2id

    def yield_samples(list_samples, dict_counter):
        for wavfile_path, person_id in list_samples:
            dict_counter["idx"] += 1
            if dict_counter["idx"] == 1 or dict_counter["idx"] % params.train_size == 0:
                tf.logging.info("Loading up to sample: {}".format(dict_counter["idx"]))
            yield wavfile_path, person_id

    def generator_samples_train():
        # instead of repeating num_epochs using tf.dataset.repeat (no different samples, just repeat)
        # we repeat manually in here and each time we sample randomly different segment of the original audio file
        dict_counter = {"idx": 0}
        for epoch in range(num_epochs):
            for step_epoch in range(num_step_per_epoch):
                batch_samples = sample_labelwav_batch(dict_label2waves, params.train["label_per_batch"], params.train["wav_per_label"])
                yield from yield_samples(batch_samples, dict_counter)

    def generator_samples_eval():
        # instead of repeating num_epochs using tf.dataset.repeat (no different samples, just repeat)
        # we repeat manually in here and each time we sample randomly different segment of the original audio file
        dict_counter = {"idx": 0}
        list_samples = samples
        yield from yield_samples(list_samples, dict_counter)

    def generator_samples_pred():
        all_samples = []
        for wavfile_path, _ in samples:
            wav = load_random_segment_wav(wavfile_path, params)
            mel_spec = wav2melspec_db(wav, params.signal["sr"], params.signal["n_fft"], params.signal["win_length"],
                                      params.signal["hop_length"], params.signal["n_mels"])
            mel_spec = normalize_db(mel_spec, max_db=params.signal["max_db"], min_db=params.signal["min_db"])

            person_label = "0"
            all_samples.append((mel_spec, person_label))
        return all_samples

    if type_dataset == "train":
        return tf.data.Dataset.from_generator(generator_samples_train, (tf.string, tf.string), (tf.TensorShape([]), tf.TensorShape([])))
    elif type_dataset == "eval":
        return tf.data.Dataset.from_generator(generator_samples_eval, (tf.string, tf.string), (tf.TensorShape([]), tf.TensorShape([])))
    elif type_dataset == "pred":
        all_samples = generator_samples_pred()
        def pred_generator():
            for el in all_samples:
                yield el
        return tf.data.Dataset.from_generator(pred_generator, (tf.float32, tf.string), (tf.TensorShape([None, None]), tf.TensorShape([])))
        #return tf.data.Dataset.from_tensor_slices(all_samples)

from .constant import params as global_params

def data_transform_fn(tf_wavfile_path, tf_person_id):
    params = global_params
    dict_label2id = global_dict_label2id

    def _tranf_fn(wavfile_path, person_id):
        person_id = person_id.decode("utf-8") # convert from binary string to normal string
        wav = load_random_segment_wav(wavfile_path, params)
        mel_spec = wav2melspec_db(wav, params.signal["sr"], params.signal["n_fft"], params.signal["win_length"],
                                  params.signal["hop_length"], params.signal["n_mels"])
        mel_spec = normalize_db(mel_spec, max_db=params.signal["max_db"], min_db=params.signal["min_db"])

        #mel_spec = np.random.rand(VOICE_STFT_T, params.signal["n_mels"])
        if dict_label2id is None or len(dict_label2id) == 0:
            print("Wrong for dict_label2id")
            exit()
        else:
            #print("dict_label2id = {}".format(dict_label2id))
            #print("Good dict_label2id")
            pass
        person_label = dict_label2id[person_id]
        #print(dict_label2id)
        return mel_spec, person_label

    tf_mel_spec, tf_person_label = tf.py_func(_tranf_fn, [tf_wavfile_path, tf_person_id], [tf.float64, tf.int64])
    tf_mel_spec.set_shape([VOICE_STFT_T, params.signal["n_mels"]])
    tf_person_label.set_shape([])
    #tf.Print(tf_mel_spec, [tf_mel_spec], message="tf_mel_spec = ")
    #tf.Print(tf_person_label, [tf_person_label], message="tf_person_label = ")
    #print(tf_mel_spec)
    #print(tf_person_label)
    return tf_mel_spec, tf_person_label

def train(params):
    """tf.data.Dataset object for training data."""
    directory = params.train["data_path"]
    num_epochs = params.num_segments

    return dataset(directory, params, num_epochs, type_dataset="train")

def test(params):
    """tf.data.Dataset object for test data."""
    directory = params.eval["data_path"]
    num_epochs = params.num_segments
    return dataset(directory, params, num_epochs, type_dataset="eval")

def predict(params, data_directory, mapping_label_id_file):
    """tf.data.Dataset object for predict data."""
    directory = data_directory
    num_epochs = params.num_segments
    return dataset(directory, params, num_epochs, type_dataset="pred", mapping_label_id_file=mapping_label_id_file)


import pygame
import sys
from mouse import Mouse
from pygame.locals import *

class Controller(object):

    key_bind = {
        'esc': K_ESCAPE,
        'ret': K_RETURN,
        'up': K_UP,
        'down': K_DOWN,
        'right': K_RIGHT,
        'left': K_LEFT,
        'wait': K_z
    }

    instance = None

    @classmethod
    def get_instance(cls):
        if cls.instance is None:
            cls.instance = cls()
        return cls.instance

    def __init__(self):

        self.mouse = Mouse.get_instance()
        self.state = None

        self.components = {}

    def bind_to_state(self, state):
        self.state = state
        self.mouse.bind_to_state(state)

    def unbind(self):
        self.state = None
        self.mouse.unbind()

    def add_component(self, component, c_id):
        self.components[c_id] = component

    def remove_component(self, c_id):
        del self.components[c_id]

    def turn_off_move_control(self):
        self.remove_component('move_control')

    def handle_input(self):

        mouse_moved = False

        for event in pygame.event.get():

            if event.type == QUIT:
                self.end_program()

            elif event.type == KEYDOWN:
                if event.key == self.key('esc'):
                    self.end_program()

                elif event.key == self.key('ret'):
                    pass

                else:
                    for component in self.components.values():
                        component.press(event.key)

            elif event.type == MOUSEBUTTONDOWN:

                if event.button == 1:
                    self.mouse.click()

                elif event.button == 3:
                    self.mouse.right_click()

            elif event.type == MOUSEMOTION:
                mouse_moved = True
                self.mouse.motion()

            elif event.type == MOUSEBUTTONUP:
                self.mouse.button_up()

        if not mouse_moved:
            self.mouse.hover()
        else:
            self.mouse.reset_hover()

    def key(self, k):
        cls = Controller
        return cls.key_bind[k]

    def end_program(self):
        pygame.quit()
        sys.exit()


from math import sin, cos, radians, sqrt

# all measurements are in base metric units, all angles are in radians

# compare two border lines and return true if they intersect
def intersect(border1, border2):
    # eliminates duplicate comparisons, like line to vertical and vertical to line, in order to reduce the number of if statements needed
    # from 9 to 6
    if (border1.__class__.__name__ == 'Vertical' != border2.__class__.__name__) or \
       (border1.__class__.__name__ == 'Line' and border2.__class__.__name__ == 'Arc'):
        temp = border1
        border1 = border2
        border2 = temp

    # if border1 is a arc, then border2 can be an arc, line, or vertical
    if border1.__class__.__name__ == 'Arc':
        # for comparison to another circle, checks if the distance between then centers is less than the sum of the cirlces' radii
        if border2.__class__.__name__ == 'Arc':
            return sqrt((border1.center[0] - border2.center[0]) ** 2 +
                   (border1.center[1] - border2.center[1]) ** 2) <= border1.radius + border2.radius

        # for comparison to a line, finds if the line passes through the circle or if one of its endpoints lies within the circle
        elif border2.__class__.__name__ == 'Line':
            # this convoluted formula finds the x coordinate of the point of intersection of a line and the shortest path (a perpendicular
            # line) to a certain point (the center of the circle)
            x = (border1.center[0] - border2.y_intercept * border2.slope + border1.center[1] * border2.slope) / (border2.slope ** 2 + 1)
            y = border2.slope * x + border2.y_intercept

            return (border2.domain[0] <= x <= border2.domain[1] and
                   sqrt((x - border1.center[0]) ** 2 + (y - border1.center[1]) ** 2) <= border1.radius) or \
                   sqrt((border2.domain[0] - border1.center[0]) ** 2 +
                   (border2.slope * border2.domain[0] + border2.y_intercept - border1.center[1]) ** 2) <= border1.radius or \
                   sqrt((border2.domain[1] - border1.center[0]) ** 2 +
                   (border2.slope * border2.domain[1] + border2.y_intercept - border1.center[1]) ** 2) <= border1.radius

        # for comparison to a vertical line, find if the line passes through the circle or ends within the circle
        elif border2.__class__.__name__ == 'Vertical':
            return (border2.y_range[0] <= border1.center[1] <= border2.y_range[1] and
                   abs(border1.center[0] - border2.x_coord) <= border1.radius) or \
                   sqrt((border2.x_coord - border1.center[0]) ** 2 + (border2.y_range[0] - border1.center[1]) ** 2) <= border1.radius or \
                   sqrt((border2.x_coord - border1.center[0]) ** 2 + (border2.y_range[1] - border1.center[1]) ** 2) <= border1.radius

    # if border1 is a line, then border2 can be either a line or a vertical
    elif border1.__class__.__name__ == 'Line':
        # for comparison to another line, checks if their point of intersection lies within their domains
        if border2.__class__.__name__ == 'Line':
            # if the lines are parallel, the difference of their slopes would be 0, which would result in division by 0
            try:
                x = (border2.y_intercept - border1.y_intercept) / (border1.slope - border2.slope)
            except ZeroDivisionError:
                return False
            return border1.domain[0] <= x <= border1.domain[1] and border2.domain[0] <= x <= border2.domain[1]

        # for comparison to a vertical line, checks if their intersection lies on the domain of the line and the range of the vertical
        elif border2.__class__.__name__ == 'Vertical':
            return border1.domain[0] <= border2.x_coord <= border1.domain[1] and \
                   border2.y_range[0] <= border1.slope * border2.x_coord + border1.y_intercept <= border2.y_range[1]

    # if border1 is a vertical, then so is border2
    # for comparison to another vertical, checks if they have the same x-coordinate and their ranges overlap
    elif border1.__class__.__name__ == 'Vertical':
        return border1.x_coord == border2.x_coord and (border2.y_range[0] <= border1.y_range[0] <= border2.y_range[1] or
                                                       border2.y_range[0] <= border1.y_range[1] <= border2.y_range[1] or
                                                       border1.y_range[0] <= border2.y_range[0] <= border1.y_range[1])

# for the border of a circle, called an arc because i can't call two things circles
class Arc:
    def __init__(self, center, radius):
        self.center = center
        self.radius = radius

# for a border of a rectangle that can be expressed using y = mx + b format
class Line:
    def __init__(self, slope=None, y_intercept=None, domain=None):
        self.slope = slope
        self.y_intercept = y_intercept
        self.domain = domain

# for a vertical border of a rectangle whose tilt is a multiple of 90 degrees
class Vertical:
    def __init__(self, x_coord=None, y_range=None,):
        self.x_coord = x_coord
        self.y_range = y_range

class Solid:
    def __init__(self, pos, velocity, tilt, angular_v, mass, material, static, f_coeff):
        self.tilt = tilt # angle of object, in degrees
        self.angular_v = angular_v # angular velocity, in degrees/sec
        self.mass = mass
        self.material = material # NEED DESCRIPTION ONCE I ACTUALLY KNOW WHAT IM GONNA DO WITH THIS
        self.static = static # if True, then the object cannot be moved
        self.f_coeff = f_coeff # IDK HOW THIS IS GONNA WORK, MIGHT BE IMPLEMENTED INTO MATERIALS

        # sets initial position because lists can't be kept as default values in function parameters
        if pos is None:
            self.pos = [0, 0]
        else:
            self.pos = pos
        if velocity is None:
            self.velocity = [0, 0]
        else:
            self.velocity = velocity

    # udpate position and tilt based on linear and rotational velocities
    def update_pos(self, t):
        for i in range(2):
            self.pos[i] += self.velocity[i] * t
        self.tilt += self.angular_v * t

# for creating a rectangular solid
class Rect(Solid):
    def __init__(self, pos=None, velocity=None, tilt=0., angular_v=0., mass=1., material=0, static=False, f_coeff=0., height=10., width=10.):
        Solid.__init__(self, pos, velocity, tilt, angular_v, mass, material, static, f_coeff)

        self.height = height
        self.width = width

        # contains 4 border objects for each of the 4 border lines of the rectangle, determined in the update method
        self.borders = [None for i in range(4)]

        # the length of the diagonal of the rectangle, used as a filter to prevent collision testing with two far-apart rectangles
        self.diagonal = sqrt(height ** 2 + width ** 2)

    def get_rect_borders(self):
        # a rectangle is the same if it is rotated by 180 degrees either way any number of times
        theta = self.tilt % 180

        # find the four corners of the rectangle
        x = self.pos[0]
        y = self.pos[1]
        adj_width = cos(radians(theta)) * self.width / 2
        opp_width = sin(radians(theta)) * self.width / 2
        adj_height = cos(radians(theta)) * self.height / 2
        opp_height = sin(radians(theta)) * self.height / 2

        tl = (x - adj_width - opp_height, # top left corner when tilt equals 0
              y + opp_width - adj_height)
        tr = (x + adj_width - opp_height, # tops right corner when tilt equals 0
              y - opp_width - adj_height)
        bl = (x - adj_width + opp_height, # bottom left corner when tilt equals 0
              y + opp_width + adj_height)
        br = (x + adj_width + opp_height, # bottom right corner when tilt equals 0
              y - opp_width + adj_height)

        # these three if statements define the lines that make up the rectangle, given the four corners
        # if tilt is 0 or 90 degrees, then we need to worry about vertical lines, so they are special cases
        # tilt cannot be a multiple of 90 that is not 0 or 90 because earlier in this function, we make sure that 0 <= tilt < 180
        if theta == 0:
            self.borders = [Line(slope=0, y_intercept=tl[1], domain=(tl[0], tr[0])),
                            Vertical(x_coord=tl[0], y_range=(bl[1], tl[1])),
                            Line(slope=0, y_intercept=bl[1], domain=(tl[0], tr[0])),
                            Vertical(x_coord=tr[0], y_range=(br[1], tr[1]))]

        # the main difference between when tilt is 0 versus when tilt is 90 degrees is that the two lines that are vertical and
        # the two lines that are normal swap
        elif theta == 90:
            self.borders = [Vertical(x_coord=tl[0], y_range=(tl[1], tr[1])),
                            Line(slope=0, y_intercept=tr[1], domain=(tl[0], bl[0])),
                            Vertical(x_coord=bl[0], y_range=(bl[1], br[1])),
                            Line(slope=0, y_intercept=tr[1], domain=(tr[0], br[0]))]

        # with any rotation that will not give us vertical lines, we can calculate the slope of lines 0 and 2, which are parallel, and then
        # use the perpendicular line formula (m_p = -1 / m) to find the slope of lines 1 and 3
        # the y_intercepts are calculated by rearranging y = mx + b into b = y - mx
        else:
            m1 = (tl[1] - tr[1]) / (tl[0] - tr[0])
            m2 = -1 / m1

            self.borders = [Line(slope=m1, y_intercept=tl[1] - m1 * tl[0]),
                            Line(slope=m2, y_intercept=tl[1] - m2 * tl[0], domain=(tl[0], bl[0])),
                            Line(slope=m1, y_intercept=br[1] - m1 * br[0]),
                            Line(slope=m2, y_intercept=br[1] - m2 * br[0], domain=(tr[0], br[0]))]

            # because the domain must be declared with the least value first, lines 0 and 2, which are initially the top and bottom
            # lines of the rectangle, must have the order of their domain reversed when the tilt is greater than 90 degrees
            if theta < 90:
                self.borders[0].domain = (tl[0], tr[0])
                self.borders[2].domain = (bl[0], br[0])
            else:
                self.borders[0].domain = (tr[0], tl[0])
                self.borders[2].domain = (br[0], bl[0])

# for creating a circular solid
class Circle(Solid):
    def __init__(self, pos=None, velocity=None, tilt=0., angular_v=0., mass=1., material=0, static=False, f_coeff=0., radius=5.):
        Solid.__init__(self, pos, velocity, tilt, angular_v, mass, material, static, f_coeff)

        self.radius = radius

        self.borders = None # contains Arc object to describe the circle's border

    def get_circle_borders(self):
        borders = Arc(self.pos, self.radius)


'''Es un error en tiempo de ejecucion, la sintaxis del codigo es correcta pero durante la ejecucion ha ocurrido "algo inseperado " '''

'''El problema es que en los lenguajes que ejecutan el codigo asia abajo, una vez que el rpgrama nos da error el resto de lineas no se ejecutan  '''

def suma(num1,num2):
    return num1+num2
def resta(num1,num2):
    return num1-num2
def multiplicacion(num1,num2):
    return num1*num2
def divide(num1,num2):
    try:
        return  num1/num2
    except ZeroDivisionError:
        print("No se puede vividir entre 0")
        return "Operacion erronea"

while(True):
    try:
        op1=(int(input("introduce el primer valor: ")))
        op2=(int(input("introduce el segundo valor: ")))
        break
    except ValueError:
        print("Los valores intorducidos no  son correctos ")

operacion=input("introduce la operacion a realizar(suma, resta, multiplicacion, divide)")

if operacion =="suma":
    print(suma(op1,op2))
elif operacion == "resta":
    print(resta(op1,op2))
elif operacion == "multiplicacion":
    print(multiplicacion(op1,op2))
elif operacion == "divide":
    print(divide(op1,op2))
else :
    print(f"Operacion no contemplada ")

print("Ejecucion del programa finalizada : continua con el progra")


import discord
import time

from discord.ext import commands
from random import randint
from methods import levels

class Levels:

    def __init__(self, bot):
        self.bot = bot

    async def get_cooldown(self, msg):
        return await self.bot.db.fetchone("SELECT cooldown FROM users WHERE user_id={} AND server_id={}".format(msg.author.id, msg.guild.id))

    async def get_xp(self, msg):
        xp = await self.bot.db.fetchone("SELECT xp FROM users WHERE user_id={} AND server_id={}".format(msg.author.id, msg.guild.id))
        return xp[0]

    async def set_xp(self, msg, current_time):
        xp = await self.get_xp(msg)
        await self.bot.db.execute("UPDATE users SET xp={}, cooldown='{}' WHERE user_id={} AND server_id={}".format(xp + randint(15, 25), current_time, msg.author.id, msg.guild.id))

    async def on_message(self, msg):
        user_exists = await self.bot.db.fetchone("SELECT * FROM users WHERE user_id={} AND server_id={}".format(msg.author.id, msg.guild.id))
        if not user_exists:
            if not msg.author.bot:
                current_time = time.strftime("%d-%m-%Y %H:%M")
                await self.bot.db.execute("INSERT INTO users (user_id, server_id, xp, cooldown) VALUES ({}, {}, 0, '{}')".format(msg.author.id, msg.guild.id, current_time))
        else:
            lvl_before = levels.get_level_from_xp(await self.get_xp(msg))
            cooldown = await self.bot.db.fetchone("SELECT cooldown FROM users WHERE user_id={} AND server_id={}".format(msg.author.id, msg.guild.id))
            current_time = time.strftime("%d-%m-%Y %H:%M")
            if cooldown[0] != current_time:
                await self.set_xp(msg, current_time)
            else:
                await self.bot.db.execute("UPDATE users SET cooldown='{}' WHERE user_id={} AND server_id={}".format(current_time, msg.author.id, msg.guild.id))
            lvl_after = levels.get_level_from_xp(await self.get_xp(msg))
            if(lvl_before != lvl_after):
                mention = await self.bot.db.fetchone("SELECT mention FROM users WHERE user_id={} AND server_id={}".format(msg.author.id, msg.guild.id))
                if mention[0] == 1:
                    rank_channel_id = await self.bot.db.fetchone("SELECT rank_channel_id FROM server WHERE server_id={}".format(msg.guild.id))
                    if not rank_channel_id[0]:
                        await msg.channel.send("Congratulations <@" + str(msg.author.id) + ">, you have advanced to level " + str(lvl_after))
                    else:
                        await self.bot.get_channel(rank_channel_id[0]).send("Congratulations <@" + str(msg.author.id) + ">, you have advanced to level " + str(lvl_after))

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


import unittest
import os
import logging
import tldextract
import pythonwhois
import dns.resolver
import geoip2.database
import core.google
import urllib.request
from ipwhois import IPWhois
from collections import OrderedDict
from ipwhois.ipwhois import IPDefinedError
from censys.ipv4 import CensysIPv4
from censys.certificates import CensysCertificates
from censys.base import CensysException
from django.conf import settings

logger = logging.getLogger(__name__)
current_directory = os.path.dirname(__file__)

def geolocate_ip(ip):

    geolocation_database = os.path.join(current_directory, 'GeoLite2-City.mmdb')
    reader = geoip2.database.Reader(geolocation_database)

    try:
        response = reader.city(ip)

        # Geo-location results - city, state / province, country
        results = OrderedDict({"city": response.city.name,
                               "province": response.subdivisions.most_specific.name,
                               "country": response.country.name})
        return results

    except ValueError:
        logger.debug("Invalid IP address passed")

    except geoip2.errors.AddressNotFoundError:
        logger.debug("IP address not found in database")

    except Exception as unexpected_error:
        logger.error("Unexpected error %s" % unexpected_error)

    return OrderedDict({"city": "", "province": "", "country": ""})

def resolve_domain(domain):

    # Set resolver to Google openDNS servers
    resolver = dns.resolver.Resolver()
    resolver.nameservers = ['8.8.8.8', '8.8.4.4']

    try:
        query_answer = resolver.query(qname=domain)
        answer = [raw_data.address for raw_data in query_answer]
        return answer

    except dns.resolver.NXDOMAIN:
        alert = "NX Domain"

    except dns.resolver.Timeout:
        alert = "Query Timeout"

    except dns.resolver.NoAnswer:
        alert = "No Answer"

    except dns.resolver.NoNameservers:
        alert = "No Name Server"

    except Exception:
        alert = "Unexpected error"

    return [alert]

def lookup_domain_whois(domain):

    # Extract base domain name for lookup
    ext = tldextract.extract(domain)
    delimiter = "."
    sequence = (ext.domain, ext.tld)
    domain_name = delimiter.join(sequence)

    try:
        # Retrieve parsed record
        record = pythonwhois.get_whois(domain_name)
        record.pop("raw", None)
        record['domain_name'] = domain_name
        return record

    except Exception as unexpected_error:
        logger.error("Unexpected error %s" % unexpected_error)

    return None

def lookup_ip_whois(ip):

    try:
        # Retrieve parsed record
        record = IPWhois(ip).lookup()
        record.pop("raw", None)
        record.pop("raw_referral", None)
        return record

    except ValueError:
        logger.debug("Invalid IP address passed")

    except IPDefinedError:
        logger.debug("Private-use network IP address passed")

    except Exception as unexpected_error:
        logger.error("Unexpected error %s" % unexpected_error)

    return None

# See docs: https://developers.google.com/safe-browsing/lookup_guide#HTTPGETRequest
def lookup_google_safe_browsing(domain):
    url = "https://sb-ssl.google.com/safebrowsing/api/lookup?client=" + settings.GOOGLE_SAFEBROWSING_API_CLIENT + "&key=" + settings.GOOGLE_SAFEBROWSING_API_KEY + "&appver=1.5.2&pver=3.1&url=" + domain
    response = urllib.request.urlopen(url)

    # We only get a request body when Google thinks the indicator is malicious. There are a few different values it might return.
    if response.status == 200:
        body = response.read().decode("utf-8")

    elif response.status == 400:
        logger.error("Bad request to Google SafeBrowsing API. Indicator:")
        logger.error(domain)
        body = "Bad Request to API"

    elif response.status == 401:
        logger.error("Bad API key for Google SafeBrowsing API.")
        body = "Bad Request to API"

    elif response.status == 503:
        logger.error("Google SafeSearch API is unresponsive. Potentially too many requests coming from our application, or their service is down.")
        body = "SafeBrowsing API offline or throttling our requests"

    # There is no body when the API thinks this inidcator is safe.
    else:
        body = "OK"

    return (response.status, body)

def lookup_ip_censys_https(ip):
    api_id = settings.CENSYS_API_ID
    api_secret = settings.CENSYS_API_SECRET

    try:
        ip_data = CensysIPv4(api_id=api_id, api_secret=api_secret).view(ip)
        return ip_data['443']['https']['tls']['certificate']['parsed']
    except KeyError:
        return {'status': 404, 'message': "No HTTPS certificate data was found for IP " + ip}
    except CensysException as ce:
        return {'status': ce.status_code, 'message': ce.message}

def google_for_indicator(indicator, limit=10, domain=None):
    """
    Find the top 'limit' Google search results for 'indicator' (excluding those from 'domain').

    Note: The domain will be wrapped in quotes before being submitted to Google.  It should therefore NOT be so wrapped
    when passed to this function.

    This method will also filter any results to ensure that none of the URLs returned actually point to the given domain
    (or any subdomain thereof).   In this manner, if you search for "domain.com," results such as
    "http://domain.com/page.html" and "http://sub.domain.com/file.pdf" will NOT be included in the results.

    :param indicator: The indicator value for which to search.  This should NOT be wrapped in quotation marks.
    :param limit: The maximum number of search results to return (optional, default: 10)
    :param domain: A domain from which results should be excluded
    :return: A list containing the URLs of the search results, in the order returned by Google
    """
    logger.debug("Searching Google for indicator '%s' (limit: %d)", indicator, limit)
    parameter = "\"" + indicator + "\""

    if domain is None:
        sifter = core.google.KeepSifter()
    else:
        sifter = core.google.DomainSifter(domain)
    result = list()
    try:
        for info in core.google.search(parameter, limit=limit, sifter=sifter):
            result.append(info.to_dict())
    except Exception:
        # Something went wrong, most likely when querying Google.  There's nothing we can really do about it, so we will
        # log the error and return an empty list
        logger.exception("Unexpected error performing Google search")
        result = list()
    if logger.isEnabledFor(logging.INFO):
        msg = "Found top %d/%d search result(s) for indicator '%s':" % (len(result), limit, indicator)
        rank = 0
        for info in result:
            rank += 1
            url = info["url"]
            msg += "\n\t%d - %s" % (rank, url)
        logger.info(msg)
    return result

def lookup_certs_censys(other, count):
    api_id = settings.CENSYS_API_ID
    api_secret = settings.CENSYS_API_SECRET

    try:
        cc = CensysCertificates(api_id=api_id, api_secret=api_secret)
        generator = cc.search(other)
        i = 0
        results = {'records':[]}
        for record in generator:
            if i == 0:
                results['total'] = generator.gi_frame.f_locals['payload']['metadata']['count']
            for sha256 in record['parsed.fingerprint_sha256']:
                results['records'].append(cc.view(sha256))
                i+=1
            if i >= count:
                break
        results['count'] = i
        return results
    except CensysException as ce:
        return {'status':ce.status_code,'message':ce.message}


try:
    import cPickle as pickle
except:
    import pickle
import os

class alias_saved:
    def __init__(self, dict_alias):
        self.dict_alias = dict_alias

def save_aliases(dict_alias):
    alias = alias_saved(dict_alias)
    data = []
    data.append(alias)
    home = os.getenv("HOME")
    try:
        os.makedirs(home + str("/.aliax/"))
    except OSError:
        pass

    filename = home + str("/.aliax/") + str("alias.ser")
    out_s = open(filename, 'wb')
    try:
        for o in data:
            pickle.dump(o, out_s)
    finally:
        out_s.close()

def load_aliases():
    home = os.getenv("HOME")
    filename = home + str("/.aliax/") + str("alias.ser")
    if os.path.isfile(filename):
        in_s = open(filename, 'rb')
        try:
            while True:
                try:
                    alias = pickle.load(in_s)
                except EOFError:
                    break
                else:
                    return alias
        finally:
            in_s.close()


import random
all_choices=["石头","剪刀","布"]
computer=random.choice(all_choices)
player=input("请出拳： ")

if player=='石头':
    if computer=='石头':
        print("平局")
    elif computer=='剪刀':
        print('you win')
    else:
        print('you lose')
elif player=='剪刀':
    if computer=='石头':
        print("you lose")
    elif computer=='剪刀':
        print('平局')
    else:
        print('you win')
else:
    if computer=='石头':
        print("you win")
    elif computer=='剪刀':
        print('you lose')
    else:
        print('平局')
print('your choice:%s,computer choice:%s'%(player,computer))