# -*- coding: utf-8 -*-
"""
Created on Thur Dec 14 17:48 2017
@author: WSD
"""
import tensorflow as tf
import numpy as np
import os

# 读取文件名和标签
def get_files(file_dir):
    # file_dir 图片存放路径
    # 返回shuffle 后的图片和标签

    cats = []
    label_cats = []
    dogs = []
    label_dogs = []
    # load image path and label
    for file in os.listdir(file_dir):
        name = file.split('.')
        if name[0] == 'cat':
            cats.append(file_dir + file)
            label_cats.append(0)
        else:
            dogs.append(file_dir + file)
            label_dogs.append(1)
    print("There are %d cats and %d dogs" % (len(cats), len(dogs)))

    # shuffle
    image_list = np.hstack((cats, dogs))
    label_list = np.hstack((label_cats, label_dogs))
    temp = np.array([image_list, label_list])
    temp = temp.T
    np.random.shuffle(temp)
    image_list = list(temp[:, 0])
    label_list = list(temp[:, 1])
    label_list = [int(i) for i in label_list]
    return image_list, label_list

# 生成相同大小的批次
def get_batch(image, label, image_w, image_h, batch_size, capacity):
    # image, label: 要生成batch的图像和标签list
    # image_W, image_H: 图片的宽高
    # batch_size: 每个batch有多少张图片
    # capacity: 队列容量
    # return: 图像和标签的batch
    # 将python list 转换为tf可识别的格式
    image = tf.cast(image, tf.string)
    label = tf.cast(label, tf.int32)

    # 生成队列
    input_queue = tf.train.slice_input_producer([image, label])
    image_contents = tf.read_file(input_queue[0])
    label = input_queue[1]
    image = tf.image.decode_jpeg(image_contents, channels=3)
    image = tf.image.resize_image_with_crop_or_pad(image, image_w, image_h)
    image = tf.cast(image, tf.float32)
    image = tf.image.per_image_standardization(image)  # 标准化数据
    image_batch, label_batch = tf.train.batch([image, label], batch_size=batch_size, num_threads=64, capacity=capacity)
    label_batch = tf.reshape(label_batch, [batch_size])
    image_batch = tf.cast(image_batch, tf.float32)
    return image_batch, label_batch

if __name__ == '__main__':
    BATCH_SIZE = 2
    CAPACITY = 256
    IMG_W = 208
    IMG_H = 208

    train_dir = "./dataset/train/"
    test_dir = "./dataset/test/"
    train_list, train_label_list = get_files(train_dir)
    test_list, test_label_list = get_files(test_dir)


def bin_search(ourlist, key):
    left = 0 # I assign left position to zero
    right = len(ourlist)-1 # I assign right position by defining the length of ourlist minus one
    matched = False
    while(left<=right and not matched): # the loop will continue untill the left element is less or equal to the right element and the matched is True
        mid = (left+right)//2 # I find the position of the middle element
        if ourlist[mid] == key: # if the middle element correponds to the key element
             matched = True
        else: #otherwise
            if key < ourlist[mid]: # if key element is less than the middle element
                right = mid - 1 #I assign the position of the right element as mid - 1
            else: #otherwise
                left = mid + 1 #left position will become the middle position plus 1
    return matched

print(bin_search([1, 3, 9, 15], 17))
print(bin_search([1, 3, 9, 15], 3))


# image_segmentation.py
"""Volume 1: Image Segmentation.
Marcelo Leszynski
Math 345 Sec 005
11/06/20
"""

import numpy as np
import math
from scipy import linalg as la
from scipy import sparse
from imageio import imread
from scipy.sparse.linalg import eigsh
from matplotlib import pyplot as plt

# Problem 1
def laplacian(A):
    """Compute the Laplacian matrix of the graph G that has adjacency matrix A.

    Parameters:
        A ((N,N) ndarray): The adjacency matrix of an undirected graph G.

    Returns:
        L ((N,N) ndarray): The Laplacian matrix of G.
    """
    # calculate the degree matrix
    D = np.diag(np.sum(A, axis = 0))
    # return the laplacian matrix
    return D - A

# Problem 2
def connectivity(A, tol=1e-8):
    """Compute the number of connected components in the graph G and its
    algebraic connectivity, given the adjacency matrix A of G.

    Parameters:
        A ((N,N) ndarray): The adjacency matrix of an undirected graph G.
        tol (float): Eigenvalues that are less than this tolerance are
            considered zero.

    Returns:
        (int): The number of connected components in G.
        (float): the algebraic connectivity of G.
    """
    # create a laplacian of A and find its eigenvalues #########################
    L = laplacian(A)
    eigens = np.sort(np.real(la.eigvals(L)))  # sort to make finding algebraic connectivity easier
    num_connected = 0

    # calculate number of connected nodes ######################################
    for i in eigens:
        if i < tol:
            num_connected += 1

    return num_connected, eigens[1]

# Helper function for problem 4.
def get_neighbors(index, radius, height, width):
    """Calculate the flattened indices of the pixels that are within the given
    distance of a central pixel, and their distances from the central pixel.

    Parameters:
        index (int): The index of a central pixel in a flattened image array
            with original shape (radius, height).
        radius (float): Radius of the neighborhood around the central pixel.
        height (int): The height of the original image in pixels.
        width (int): The width of the original image in pixels.

    Returns:
        (1-D ndarray): the indices of the pixels that are within the specified
            radius of the central pixel, with respect to the flattened image.
        (1-D ndarray): the euclidean distances from the neighborhood pixels to
            the central pixel.
    """
    # Calculate the original 2-D coordinates of the central pixel.
    row, col = index // width, index % width

    # Get a grid of possible candidates that are close to the central pixel.
    r = int(radius)
    x = np.arange(max(col - r, 0), min(col + r + 1, width))
    y = np.arange(max(row - r, 0), min(row + r + 1, height))
    X, Y = np.meshgrid(x, y)

    # Determine which candidates are within the given radius of the pixel.
    R = np.sqrt(((X - col)**2 + (Y - row)**2))
    mask = R < radius
    return (X[mask] + Y[mask]*width).astype(np.int), R[mask]

# Problems 3-6
class ImageSegmenter:
    """Class for storing and segmenting images."""

    # Problem 3
    def __init__(self, filename):
        """Read the image file. Store its brightness values as a flat array."""
        self._original = imread(filename) / 255
        self._is_grayscale = True
        self._num_rows = np.shape(self._original)[0]
        self._num_cols = np.shape(self._original)[1]
        if len(np.shape(self._original)) != 2:
            self._is_grayscale = False
        if self._is_grayscale:
            self._brightness = np.ravel(self._original)
        else:
            self._brightness = np.ravel(self._original.mean(axis = 2))

    # Problem 3
    def show_original(self):
        """Display the original image."""
        if self._is_grayscale:
            plt.imshow(self._original, cmap='gray')
        else:
            plt.imshow(self._original)
        plt.axis('off')
        plt.show()

    # Problem 4
    def adjacency(self, r=5., sigma_B2=.02, sigma_X2=3.):
        """Compute the Adjacency and Degree matrices for the image graph."""
        # initialize A and D ###################################################
        dim_A = self._num_rows * self._num_cols
        A = sparse.lil_matrix((dim_A, dim_A), dtype='float')
        D = np.array([0] * dim_A, dtype='float')

        # compute weights and degrees ##########################################
        for i in range(0, dim_A):
            neighbors, distances = get_neighbors(i, r, self._num_rows, self._num_cols)
            # calculate weights ################################################
            weights = [math.exp(-abs(self._brightness[i]-self._brightness[neighbors[j]]) / sigma_B2 - distances[j] / sigma_X2) for j in range(len(neighbors))]
            A[i, np.array(neighbors)] = weights
            # calculate D ######################################################
            D[i] = np.sum(weights)

        return A.tocsc(), D

    # Problem 5
    def cut(self, A, D):
        """Compute the boolean mask that segments the image."""
        # construct Laplacian and D^(-1/2) #####################################
        L = sparse.csgraph.laplacian(A)
        processed_D = sparse.diags(D)
        processed_D = processed_D.power(-1/2)  # TODO: seems sketch

        # perform DLD operation, calculate eigenvector, and construct mask #####
        DLD = processed_D @ L @ processed_D
        e_vals, e_vectors = eigsh(DLD, k=2, which='SM')
        mask = e_vectors[:,1].reshape((self._num_rows, self._num_cols)) > 0

        return mask

    # Problem 6
    def segment(self, r=5., sigma_B=.02, sigma_X=3.):
        """Display the original image and its segments."""
        # create the image mask ################################################
        A, D = self.adjacency(r, sigma_B, sigma_X)
        mask = self.cut(A, D)

        # plot a grayscale image ###############################################
        if self._is_grayscale:
            plt.subplot(131)
            plt.imshow(self._original, cmap='gray')
            plt.axis('off')
            plt.subplot(132)
            plt.imshow(self._original*mask, cmap='gray')
            plt.axis('off')
            plt.subplot(133)
            plt.imshow(self._original*(~mask), cmap='gray')
            plt.axis('off')

        # plot a colored image #################################################
        else:
            shape_size = [mask] * np.shape(self._original)[2]
            mask = np.dstack(shape_size)
            plt.subplot(131)
            plt.imshow(self._original)
            plt.axis('off')
            plt.subplot(132)
            plt.imshow(self._original*mask)
            plt.axis('off')
            plt.subplot(133)
            plt.imshow(self._original*(~mask))
            plt.axis('off')
        plt.show()


#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Note that all formatting functions require a config that has gone through normalizer.normalize()

Only regression tests are used for these, because it's string output.
Just don't forget to replace data files if input file changes.
"""

# pylama: ignore=D102
# pylint: disable=C0116,C0330,W0212,C0103

from copy import deepcopy

import pytest

import pytabby.formatting as formatting
import pytabby.normalizer as normalizer

@pytest.mark.regression
@pytest.mark.run(order=2)
def test_regress__format_headers(data_regression, config_multiple):
    """Only multiple-type schema has headers; no need to normalize"""
    tab_num = 1  # minimum non-first ordinal of a multiple tab layout
    c = deepcopy(config_multiple)
    result = formatting._format_headers(c["tabs"], tab_num, 80)
    data = {"data": result}
    data_regression.check(data)

@pytest.mark.regression
@pytest.mark.run(order=3)
def test_regress__format_menu(data_regression, config_all_with_id):
    """Normalize first; call with different kinds of messages"""
    config, id_ = config_all_with_id
    c = deepcopy(config)
    data = {}
    if id_.find("multiple") != -1:
        tab_num = 1
    else:
        tab_num = 0
    c = normalizer.normalize(c)
    for message_type in ["string", "None"]:
        if message_type == "None":
            message = None
        elif message_type == "string":
            message = "This is a magic string, but it's okay"
    result = formatting.format_menu(c, tab_num, 80, message).split("\n")
    data["message={}".format(message)] = result
    data_regression.check(data)

@pytest.mark.regression
@pytest.mark.run(order=3)
class TestEdgeCases:
    """Edge cases to get 100% coverage. Will use only one config each"""

    def test_regress_tab_header_description_none(self, data_regression, config_multiple):
        _ = self.__class__  # just to get rid of codacy warning, I know, it's stupid
        c = deepcopy(config_multiple)
        c["tabs"][0]["tab_header_description"] = None
        result = formatting._format_headers(c["tabs"], 0, 80)
        data = {"data": result}
        data_regression.check(data)

    def test_regress_missing_tab_header_description(self, data_regression, config_multiple):
        _ = self.__class__  # just to get rid of codacy warning, I know, it's stupid
        c = deepcopy(config_multiple)
        if "tab_header_description" in c["tabs"][0].keys():
            del c["tabs"][0]["tab_header_description"]
        result = formatting._format_headers(c["tabs"], 0, 80)
        data = {"data": result}
        data_regression.check(data)

    def test_many_tabs_with_long_headers(self, data_regression, config_multiple):
        _ = self.__class__  # just to get rid of codacy warning, I know, it's stupid
        c = deepcopy(config_multiple)
        c["tabs"][0]["tab_header_input"] = "abcdefghij"
        c["tabs"][0]["tab_header_description"] = "klmnopqrstuvwxyz"
        c["tabs"][1]["tab_header_input"] = "abcdefghijx"
        c["tabs"][1]["tab_header_description"] = "klmnopqrstuvwxyzx"
        c["tabs"].append(c["tabs"][0])
        c["tabs"][-1]["tab_header_input"] = "xabcdefghij"
        c["tabs"][-1]["tab_header_description"] = "xklmnopqrstuvwxyz"
        result = formatting._format_headers(c["tabs"], 0, 80)
        data = {"data": result}
        data_regression.check(data)


import os
from model_related.classes import Results

# From stack overflow - https://stackoverflow.com/questions/736043/checking-if-a-string-can-be-converted-to-float-in-python
def isfloat(value):
    try:
        float(value)
        return True
    except ValueError:
        return False

def read_table(results, file_iterator, result_type):
    for line in file_iterator:
        if line == "\n":
            return
        if "---" in line:
            continue
        # print(line)

        performance_measure = ""
        elements = line.split()
        for ele in elements:
            if isfloat(ele):
                break
            performance_measure += " " + ele
        performance_measure = performance_measure.strip()

        sets = ["training", "validation", "test"]
        set_index = 0
        for ele in elements:
            if isfloat(ele):
                if result_type == "averages":
                    results.averages[sets[set_index]][performance_measure] = float(ele)
                    set_index += 1
                elif result_type == "stddevs":
                    results.stddevs[sets[set_index]][performance_measure] = float(ele)
                    set_index += 1

def read_single_results_file(filename):

    results = Results()
    f = open(filename)
    iter_f = iter(f)
    for line in iter_f:
        if "Performance measure" in line and "mean" in line:
            # print(line)
            read_table(results, iter_f, "averages")
        elif "Performance measure" in line and "stdev" in line:
            # print(line)
            read_table(results, iter_f, "stddevs")

    return results

def read_all_result_files(directory):

    result_objects = []
    for filename in os.listdir(directory):
        if not filename.lower().endswith(".out"):
            continue
        result_objects.append(read_single_results_file(directory + "\\" + filename))
    return result_objects

# Run this function to parse results
def parse_results(directory, output_filename):

    all_results = read_all_result_files(directory)
    averaged_results = Results.create_averaged_results_object(all_results)
    f = open(directory + "\\" + output_filename, "w")
    f.write("\n=> Summary Statistics\n")
    f.write("   ------------------\n\n\n")
    f.write("Average results across all trials:\n\n\n")
    f.write(str(averaged_results))
    f.write("\n\n\nIndividual results\n")
    f.write("------------------\n\n\n")

    for i in range(len(all_results)):
        f.write(str(i + 1) + ".\n")
        f.write(str(all_results[i]) + "\n\n")
    f.close()

# Code to execute for parsing results
directory = \
    r"C:\Users\uvern\PycharmProjects\DSRI\USNeedleClassificationWithDataAugmentation\Results_ComputeCanada\SMOTE_10-x"
output_filename = "SMOTE_10-x_summary.txt"
parse_results(directory, output_filename)

# ------------- TESTING ----------- #

# directory = r"C:\Users\uvern\PycharmProjects\DSRI\USNeedleClassificationWithDataAugmentation\Results_ComputeCanada\SMOTE_5-x"
# single_results = read_single_results_file(
#     r"C:\Users\uvern\PycharmProjects\DSRI\USNeedleClassificationWithDataAugmentation\Results_ComputeCanada\SMOTE_5-x\SMOTE_5-x-50184502.out")
#
# all_results = read_all_result_files(directory)
# averaged_results = Results.create_averaged_results_object(all_results)
#
# # LATER - Create A toString method
# print('Printing single results...')
# print("\nAverages for train, val, test sets:")
# print(single_results.averages)
# print("\nStddevs for train, val, test sets:")
# print(single_results.stddevs)
#
# print("\nReading in all result files...")
# print("Printing info for one of the results objects...")
# print("\nAverages for train, val, test sets:")
# print(all_results[0].averages)
# print("\nStddevs for train, val, test sets:")
# print(all_results[0].stddevs)
#
# print("\nAveraging results from all of the result files...")
# print("\nAverages for train, val, test sets:")
# print(averaged_results.averages)
# print("\nStddevs for train, val, test sets:")
# print(averaged_results.stddevs)
#
# print("\nWriting averaged results object to console...")
# print(averaged_results)

"""
Next steps:

1) Read in multiple result files (into multiple result objects)
2) Create a result object that is the average of these other result objects
3) Create a method in Results that appends individual output to a file in tabular format
4) Print analysis of all results to a text file. This includes both the average of all results, and all of the individual
   results.
5) Run the completed code on previously computed analyses to double check
6) Run this code on the remaining results to analyse
7) Continue to gather more results... according to work meeting notes

DONE ALL THE ABOVE... continue with below

8) Read about the various hypothesis testing methods, starting with confidence intervals
  Our hope: To get non-overlapping 95% CI intervals

"""


#!/usr/bin/env python3
#!/usr/bin/env python3

from sklearn.svm import LinearSVC, SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score, accuracy_score, confusion_matrix

import numpy as np
import pandas as pd
from sys import exit

import random
from collections import defaultdict
import json

from sklearn.exceptions import UndefinedMetricWarning
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)
warnings.filterwarnings("ignore", category=UndefinedMetricWarning)

datasets = []
methods = ['ktsne', 'bhtsne', 'fitsne', 'umap']
percentages = [0.005, 0.01, 0.02, 0.04, 0.08, 0.16, 0.32]

labels = np.ravel(pd.read_csv('../../data/larger_dblp_data/labels.txt', header=None).values)
results = defaultdict(lambda: defaultdict(list))

random.seed(666)
np.random.seed(666)

repeats = 100

for percentage in percentages:
    for method in methods:
        print(f"{'='*8} p = {percentage}, method = {method} {'='*8}")
        embedding = pd.read_csv(f"../emb/{method}_128d_dblp.emb", sep=" ", header=None).values

        scores = defaultdict(list)
        for _ in range(repeats):
            X_train, X_test, y_train, y_test = train_test_split(embedding, labels, train_size=percentage)

            svc = LinearSVC(dual=False).fit(X_train, y_train)
            y_pred = svc.predict(X_test)

            f1_macro = f1_score(y_test, y_pred, average='macro')
            f1_micro = f1_score(y_test, y_pred, average='micro')
            f1_weighted = f1_score(y_test, y_pred, average='weighted')
            accuracy = accuracy_score(y_test, y_pred)

            scores['f1_macro'].append(f1_macro)
            scores['f1_micro'].append(f1_micro)
            scores['f1_weighted'].append(f1_weighted)
            scores['accuracy'].append(accuracy)

        results[method]['f1_macro'].append((percentage, np.average(scores['f1_macro'])))
        results[method]['f1_micro'].append((percentage, np.average(scores['f1_micro'])))
        results[method]['f1_weighted'].append((percentage, np.average(scores['f1_weighted'])))
        results[method]['accuracy'].append((percentage, np.average(scores['accuracy'])))

        print(f"f1 macro = {results[method]['f1_macro'][-1][-1]}\n" \
              f"f1 micro = {results[method]['f1_micro'][-1][-1]}\n" \
              f"f1 weighted = {results[method]['f1_weighted'][-1][-1]}\n" \
              f"accuracy = {results[method]['accuracy'][-1][-1]}")

with open('results.json', 'w+') as fh:
    json.dump(results, fp=fh)


from PySide6.QtCore import QObject, QModelIndex, Qt
from PySide6.QtWidgets import (
    QCheckBox, QMenu, QMessageBox, QStyledItemDelegate, QTreeView
)
from PySide6.QtGui import QCursor

import numpy as np

from hexrdgui.hexrd_config import HexrdConfig
from hexrdgui.tree_views.base_tree_item_model import BaseTreeItemModel
from hexrdgui.tree_views.tree_item import TreeItem
from hexrdgui.tree_views.value_column_delegate import ValueColumnDelegate
from hexrdgui import constants
from hexrdgui.utils import is_int

# Global constants
FIXED = 0
REFINABLE = 1

KEY_COL = BaseTreeItemModel.KEY_COL
VALUE_COL = KEY_COL + 1
STATUS_COL = VALUE_COL + 1

class CalTreeItemModel(BaseTreeItemModel):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.root_item = TreeItem(['key', 'value', 'refinable'])
        self.cfg = HexrdConfig()
        self.rebuild_tree()

    def data(self, index, role):
        if not index.isValid():
            return None

        if role != Qt.DisplayRole and role != Qt.EditRole:
            return None

        item = self.get_item(index)

        value = item.data(index.column())
        if index.column() == STATUS_COL:
            if role == Qt.EditRole:
                return value
            if role == Qt.DisplayRole:
                return None

        if isinstance(value, np.generic):
            # Get a native python type for display. Otherwise,
            # it won't display anything...
            value = value.item()

        return value

    def setData(self, index, value, role):
        item = self.get_item(index)
        path = self.path_to_value(item, index.column())

        # If they are identical, don't do anything
        # (we exclude np.ndarray's from this)
        is_numpy = isinstance(value, np.ndarray) or \
            isinstance(item.data(index.column()), np.ndarray)
        if not is_numpy and value == item.data(index.column()):
            return True

        key = item.data(KEY_COL)
        # Note: We don't want todo this check for panel buffers as they
        # can be a list or numpy.ndarray
        if index.column() == VALUE_COL and key != constants.BUFFER_KEY:
            old_value = self.cfg.get_instrument_config_val(path)

            # As a validation step, ensure that the new value can be
            # converted to the old value's type
            try:
                value = type(old_value)(value)
            except ValueError:
                msg = ('Could not convert ' + str(value) + ' to type ' +
                       str(type(old_value).__name__))
                QMessageBox.warning(None, 'HEXRD', msg)
                return False

        item.set_data(index.column(), value)

        if item.child_count() == 0:
            parent = item.parent_item.data(KEY_COL)
            chi_path = ['oscillation_stage', 'chi', 'value']
            if path == chi_path:
                # Convert to radians before saving
                value = np.radians(value).item()
            if (parent == 'tilt' and
                    HexrdConfig().rotation_matrix_euler() is not None and
                    len(path) > 1 and path[-2] == 'value'):
                # Convert tilt values to radians before saving
                value = np.radians(value).item()
            self.cfg.set_instrument_config_val(path, value)
            dist_func_path = ['distortion', 'function_name', 'value']
            if len(path) > 4 and path[2:5] == dist_func_path:
                # Rebuild the tree if the distortion function changed
                QObject.parent(self).rebuild_tree()

        return True

    def flags(self, index):
        if not index.isValid():
            return Qt.NoItemFlags

        flags = super(CalTreeItemModel, self).flags(index)

        item = self.get_item(index)

        non_editable_keys = (
            'detector_type',
        )

        # The second and third columns with no children are editable
        editable = (
            index.column() == STATUS_COL or
            (index.column() == VALUE_COL and
             item.child_count() == 0 and
             item.data(KEY_COL) not in non_editable_keys)
        )

        if editable:
            flags = flags | Qt.ItemIsEditable

        return flags

    def add_tree_item(self, key, value, status, parent):
        # In the case of the panel buffer we don't want to added children
        # The editor will take care of this.
        if parent.data(KEY_COL) == constants.BUFFER_KEY:
            return

        data = [key, value, status]
        tree_item = TreeItem(data, parent)
        return tree_item

    def rebuild_tree(self):
        # Rebuild the tree from scratch
        self.clear()
        for key in self.cfg.internal_instrument_config.keys():
            tree_item = self.add_tree_item(key, None, REFINABLE,
                                           self.root_item)
            self.recursive_add_tree_items(
                self.cfg.internal_instrument_config[key], tree_item)
            self.update_parent_status(tree_item)

    def recursive_add_tree_items(self, cur_config, cur_tree_item):
        if isinstance(cur_config, dict):
            keys = cur_config.keys()
        elif isinstance(cur_config, list):
            keys = range(len(cur_config))
        else:
            # This must be a value. Set it.
            cur_tree_item.set_data(STATUS_COL, cur_config)
            return

        blacklisted_keys = []

        if ('source_distance' in keys and
                cur_config['source_distance']['value'] == np.inf):
            # Hide the source distance if it is infinite, as the infinite
            # value does not get displayed correctly by Qt
            # (maybe we need to register it as a custom type?)
            blacklisted_keys.append('source_distance')

        for key in keys:
            if key in blacklisted_keys:
                continue
            elif key == 'value':
                name = cur_tree_item.data(KEY_COL)
                data = cur_config[key]
                path = self.path_to_value(cur_tree_item, VALUE_COL)

                chi_path = ['oscillation_stage', 'chi', 'value']
                if path == chi_path:
                    data = np.degrees(data).item()
                elif (name == 'tilt' and
                      HexrdConfig().rotation_matrix_euler() is not None):
                    data = [np.degrees(rad).item() for rad in cur_config[key]]
                self.set_value(key, data, cur_tree_item)
                continue
            elif key == 'status':
                tree_item = cur_tree_item
            else:
                tree_item = self.add_tree_item(key, None, REFINABLE,
                                               cur_tree_item)
            if tree_item is not None:
                self.recursive_add_tree_items(cur_config[key], tree_item)

    def update_parent_status(self, parent):
        children = parent.child_items
        for child in children:
            if child.child_count() > 0:
                self.update_parent_status(child)
            if child.data(STATUS_COL):
                parent.set_data(STATUS_COL, FIXED)

    def path_to_value(self, tree_item, column):
        path = ['value'] if column == VALUE_COL else ['status']
        cur_tree_item = tree_item
        while True:
            text = cur_tree_item.data(KEY_COL)
            if is_int(text):
                path.append(int(text))
            else:
                path.insert(0, text)
            cur_tree_item = cur_tree_item.parent_item
            if cur_tree_item is self.root_item:
                break

        return path

    def set_value(self, key, cur_config, cur_tree_item):
        if isinstance(cur_config, list):
            children = cur_tree_item.child_items
            for child in children:
                value = cur_config[child.data(KEY_COL)]
                child.set_data(VALUE_COL, value)
        else:
            cur_tree_item.set_data(VALUE_COL, cur_config)
        return

class CheckBoxDelegate(QStyledItemDelegate):

    def __init__(self, parent=None):
        super(CheckBoxDelegate, self).__init__(parent)

    def createEditor(self, parent, option, index):
        check = QCheckBox(parent)

        # Only indicate the status has changed on user interaction
        check.clicked.connect(self.statusChanged)

        return check

    def statusChanged(self):
        self.commitData.emit(self.sender())

    def setModelData(self, check, model, index):
        item = self.parent().model().get_item(index)
        if item.child_count() > 0:
            self.setChildData(item, int(check.isChecked()))
        model.setData(index, int(check.isChecked()), Qt.DisplayRole)
        self.updateModel(index)

    def setChildData(self, parent, value):
        children = parent.child_items
        for child in children:
            child.set_data(STATUS_COL, value)
            if child.child_count() == 0:
                path = self.parent().model().path_to_value(child, STATUS_COL)
                self.parent().model().cfg.set_instrument_config_val(path,
                                                                    value)
            else:
                self.setChildData(child, value)

    def updateModel(self, index):
        end = self.parent().model().index(
            -1, STATUS_COL, self.parent().model().parent(index))
        self.parent().model().dataChanged.emit(index, end)

class CalTreeView(QTreeView):

    def __init__(self, parent=None):
        super(CalTreeView, self).__init__(parent)
        self.setModel(CalTreeItemModel(self))
        self.setItemDelegateForColumn(
            VALUE_COL, ValueColumnDelegate(self))
        self.setItemDelegateForColumn(
            STATUS_COL, CheckBoxDelegate(self))

        self.blockSignals(True)
        self.expand_rows()
        self.blockSignals(False)

        self.resizeColumnToContents(KEY_COL)
        self.resizeColumnToContents(VALUE_COL)
        self.resizeColumnToContents(STATUS_COL)

        self.header().resizeSection(KEY_COL, 200)
        self.header().resizeSection(VALUE_COL, 200)

        self.setup_connections()

    def setup_connections(self):
        self.collapsed.connect(self.update_collapsed_status)
        self.expanded.connect(self.update_collapsed_status)

    def contextMenuEvent(self, event):
        index = self.indexAt(event.pos())
        item = self.model().get_item(index)
        children = item.child_count()

        if index.column() == KEY_COL and children:
            menu = QMenu(self)
            collapse = menu.addAction('Collapse All')
            expand = menu.addAction('Expand All')
            check = None
            uncheck = None
            if children:
                menu.addSeparator()
                check = menu.addAction('Check All')
                uncheck = menu.addAction('Uncheck All')
            action = menu.exec(QCursor.pos())

            if action == collapse:
                self.collapse_selection(item, index)
            elif action == expand:
                self.expand_selection(item, index)
            elif action == check:
                self.itemDelegateForColumn(STATUS_COL).setChildData(
                    item, True)
                self.itemDelegateForColumn(STATUS_COL).updateModel(index)
            elif action == uncheck:
                self.itemDelegateForColumn(STATUS_COL).setChildData(
                    item, False)
                self.itemDelegateForColumn(STATUS_COL).updateModel(index)

    def rebuild_tree(self):
        # We rebuild it from scratch every time it is shown in case
        # the number of detectors have changed.
        self.model().rebuild_tree()

        self.blockSignals(True)
        self.expand_rows()
        self.blockSignals(False)

    def expand_rows(self, parent=QModelIndex()):
        # Recursively expands all rows
        for i in range(self.model().rowCount(parent)):
            index = self.model().index(i, KEY_COL, parent)
            item = self.model().get_item(index)
            path = self.model().path_to_value(item, KEY_COL)

            # Force open the editor for the panel buffer values
            if item.data(KEY_COL) == constants.BUFFER_KEY:
                self.openPersistentEditor(self.model().index(i, VALUE_COL,
                                          parent))

            if (HexrdConfig().collapsed_state is None
                    or path not in HexrdConfig().collapsed_state):
                self.expand(index)

            self.display_status_checkbox(i, parent)

            self.expand_rows(index)

    def expand_selection(self, parent, index):
        for child in range(parent.child_count()):
            self.expand_selection(
                parent.child_items[child],
                self.model().index(child, KEY_COL, index))
        self.expand(index)

    def collapse_selection(self, parent, index):
        for child in range(parent.child_count()):
            self.collapse_selection(
                parent.child_items[child],
                self.model().index(child, KEY_COL, index))
        self.collapse(index)

    def update_collapsed_status(self, index):
        item = self.model().get_item(index)
        path = self.model().path_to_value(item, KEY_COL)

        HexrdConfig().update_collapsed_state(path)

    # Display status checkbox for the row if the requirements are met
    def display_status_checkbox(self, row, parent=QModelIndex()):

        index = self.model().index(row, KEY_COL, parent)
        item = self.model().get_item(index)

        # If it has children, return
        if item.child_count() != 0:
            return

        # If the data is a string, return
        if isinstance(item.data(VALUE_COL), str):
            return

        # If the key is blacklisted, return
        blacklisted_keys = ['saturation_level', 'buffer', 'source_distance']
        if item.data(KEY_COL) in blacklisted_keys:
            return

        # If one of the parents of the item is blacklisted, return
        blacklisted_parents = ['pixels']
        parent_item = item.parent_item
        while parent_item is not None:
            if parent_item.data(KEY_COL) in blacklisted_parents:
                return

            parent_item = parent_item.parent_item

        # Show the checkbox
        editor_idx = self.model().index(row, STATUS_COL, parent)
        self.openPersistentEditor(editor_idx)


#! /usr/bin/env python

import time
import rospy
import json
from geometry_msgs.msg import Twist

initial_time = -1

def callback(msg):
    # read previous data
    print('here')

    with open('velocity_x.json', 'r') as openfile:
        jsonObject = json.load(openfile)
        openfile.close()
    print(time.time())

    # append the current coordinates
    (jsonObject['velocity']).append(msg.linear.x)

    global initial_time

    if initial_time == -1:
        (jsonObject['time']).append(0)
        initial_time = time.time()
    else:
        (jsonObject['time']).append(time.time() - initial_time)

    # write the updated data into json file

    with open("velocity_x.json", "w") as outfile:
        json.dump(jsonObject, outfile)
        outfile.close()

rospy.init_node('global_Subscriber_vel_x') #change name
sub=rospy.Subscriber('/mobile_base_controller/cmd_vel',Twist,callback)

rospy.spin()

if __name__ == '__main__':
    jsonObject = {'xCoordinates': []}

    callback()


import pygame
import random

group = []
class Particles(pygame.sprite.Sprite):
    "Creates particles starting from pos with a color"

    def __init__(self, pos, y_dir, color, sparse=0, turn="off"):
        super(Particles, self).__init__()
        self.particles_list = []
        self.pos = pos
        self.color = color
        self.y_dir = y_dir
        self.sparse = sparse # generate particles not from the same starting point
        # self.generate_particles()
        group.append(self)
        self.turn = turn # this makes the effect visible

    def choose_y_dir(self):
        "Makes particles go in every direction you want"

        # Make the flow go down
        if self.y_dir == "down":
            y_dir = 2

        elif self.y_dir == "up":
            y_dir = -2

        # Make the particles spread all y_dirs
        elif self.y_dir == "all":
            y_dir = random.randrange(-2, 2, 1)

        return y_dir

    def generate_particles(self):
        "List with position etc of particles"

        if self.sparse == 1:
            self.pos[0] = random.randint(0, 600)

        # setting the data for each particles
        origin = [self.pos[0], self.pos[1]] # Starting here each particles
        y_dir = self.choose_y_dir()
        x_dir = random.randint(0, 20) / 10 - 1
        dirs = [x_dir, y_dir] # movement
        radius = random.randint(4,6) # radius
        # Appending data to the list
        self.particles_list.append([origin, dirs, radius])
        self.generate_movements()

    def generate_movements(self):

        # Moving the coordinates and size of self.particles_list
        for particle in self.particles_list[:]:
            particle[0][0] += particle[1][0] # x pos += x_dir
            particle[0][1] += particle[1][1] # y pos += y_dir
            particle[2] -= 0.05 # how fast circles shrinks
            particle[1][1] += 0.01 # circles speed
            # if particle[2] <= 0:
            if particle[2] >= 0:
                self.particles_list.remove(particle)
            # do not call draw from here: it slows down the frame rate
            # self.draw()

    def draw(self):
        "Draws particles based on data in the self.particles_list"
        if self.turn == "on":
            for particle in self.particles_list:
                 pygame.draw.circle(
                    screen, (self.color),
                (round(particle[0][0]), round(particle[0][1])),
                 round(particle[2]))


import requests
import re

# function to check if URL is malicious
def is_malicious(url):
    try:
        response = requests.get(url, timeout=7)
        page_content = response.text
    except:
        return False

    # check for presence of viruses in the page content
    if re.search(r'malware|virus|trojan', page_content, re.IGNORECASE):
        return True

    # check for presence of cookies in the page content
    if re.search(r'cookie', page_content, re.IGNORECASE):
        return True

    # check if the URL is a known phishing site
    if "phishing" in url:
        return True
    else:
          return False

# main function to calculate the percentage of malicious URLs in a list
def calculate_percentage(urls):
    total_count = len(urls)
    malicious_count = 0

    for url in urls:
        if is_malicious(url):
            malicious_count += 1

    percentage = (malicious_count / total_count) * 100

    return percentage

# example usage
urls = [
    'https://www.gardensrestaurantandcatering.com',

]

percentage = calculate_percentage(urls)
print(f"Percentage of malicious URLs: {percentage}%")


# Import necessary libraries
import json
from flask import Flask, render_template, request, url_for, send_from_directory, jsonify
from werkzeug.utils import secure_filename
from flask_cors import CORS, cross_origin
import service as serve

app = Flask(__name__) # Create an instance of Flask
cors = CORS(app) # Enable CORS for the app

# Define the default route for the app
@app.route('/')
def hello_world():
    # When the root route is accessed, return the string 'Safe Vision'
    return 'Safe Vision'

# Define a new route for file uploading
@app.route('/uploader', methods=['GET', 'POST'])
def upload_file():
    abFrames = []  # Initialize an empty list for abnormal frames
    if request.method == 'POST': # If the request method is POST, process the uploaded file
        f = request.files['file'] # Retrieve the file from the request
        f.save(secure_filename("input." + f.filename.split('.')[-1]))  # Save the file securely
        filename = str("input." + f.filename.split('.')[-1])  # Store the filename for later use
        abFrames = serve.makePredict(filename) # Call a function to make a prediction on the uploaded file
        # serve.makeVideo()
        serve.objectDetection(filename)  # Call a function to perform object detection on the uploaded file
        # Prepare a response with the video and report file URLs and prediction results
        result = jsonify(
            {"url": url_for('static', filename='output.mp4'), "report": url_for('static', filename='report.txt'),
             "abnormals": abFrames})
        f = open("static/data.json", "w")  # Open a file to save the response
        json.dump(result.get_json(), f)  # Write the response to the file
        f.close()  # Close the file
        return result # Return the result

# Define a new route for serving video files
@app.route('/videos/<path:path>')
def serve_static(path):
    # When the route is accessed, return the corresponding video file
    return send_from_directory('videos', path, mimetype='video/mp4')

# Run the Flask app only if the script is executed directly
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')


# Time Complexity- O(N).
# Space Complexity - O(1)

class Solution:
    def reorderList(self, head: ListNode) -> None:
        """
        Do not return anything, modify head in-place instead.
        """
        if not head:
            return None
        fast, slow = head, head
        while fast and fast.next:
            slow, fast = slow.next, fast.next.next
        mid = slow
        prev, cur = None, mid
        while cur:
            cur.next, prev, cur = prev, cur, cur.next
        head_of_second_rev = prev
        first, second = head, head_of_second_rev
        while second.next:
            next_hop = first.next
            first.next = second
            first = next_hop
            next_hop = second.next
            second.next = first
            second = next_hop

parnamondal/Week - 5/Day - 2/Reorder List.py


'''
This file is to illustrate how to optimize run time in pandas.
Topics that are covered:
1. how to use loop in Pandas
2. how to use Pandas vectorized operations
3. how to use numpy vectorized operations

Other miner topics:
1. how to parse string dates to datetime dates
2. iterrows and itertuples
3. datetime data parsing
'''

import pandas as pd
import time
import sys
import numpy as np

# The timer function returns the average time that func needs to run n times

def timer(func):

    def wrapper(*args, **kwargs):
        t0 = time.time()
        for i in range(10):
            result = func(*args, **kwargs)
        t1 = time.time()
        t = (t1-t0)/10
        print(f'The average time for function {func.__name__} is {t}')
        return result

    return wrapper

electric = pd.read_csv('/Users/aaronpr_us/Documents/Academics/python/pandas/speedup_pd_s1/data/electricity.csv', header=0)
print(electric.head())

print(electric.date_time.dtype)

# As we can see, the data type for date_time column is object, sometimes we want to change object data type into datetime datatype

# @timer
# def convert(df, col_name):
#     # we can use df[col_name] to select a specific column
#     return pd.to_datetime(df[col_name])
#
# convert(electric, 'date_time')

# As you can see on average it takes 1 sec to do the conversion. It doesn't seem to bad, but as our data size increases, it will takes longer to do that. Can we do better?

@timer
def convert_with_format(df, col_name):
    return pd.to_datetime(df[col_name], format='%d/%m/%y %H:%M')

electric['date_time'] = convert_with_format(electric, 'date_time')

# After we specified the format, the average time is 0.03 second, which is more than 30 times faster. The reason is that without specifying the format, pandas will use the dateutil package to convert each string to a date. However, if you the format is given, pandas can immediately take a fast route to parse the dates. Note that we can also specify the format when we read the data with pandas, like read_csv

################################################################################

# Looping over pandas
# Now we are going to calculate the price for each time period. If the price is fix for different time period, say $0.28. We can easily do that by the following:

electric['cost'] = electric['energy_kwh'] * 0.28
print(electric.head())

# However, if we want to charge different price for different time period like the following:
###########################
# time range  # price/kwh #
###########################
# 17:00-24:00 #    28     #
###########################
# 07:00-17:00 #    20     #
###########################
# 00:00-07:00 #    12     #
###########################

def tariff(kwh, hour):
    if 0 <= hour < 7:
        p = 0.12
    elif 7 <= hour < 17:
        p = 0.2
    elif 17 <= hour < 24:
        p = 0.28
    else:
        raise ValueError(f'Invalid hour: {hour}')

    return p * kwh

# An intuitive way is to write a Loop

# @timer
# def apply_tariff(df):
#     cost = []
#     for i in range(len(df)):
#         energy_used = df.iloc[i]['energy_kwh']
#         time = df.iloc[i]['date_time'].hour
#         cost.append(tariff(energy_used, time))
#     df['cost'] = cost
#
# apply_tariff(electric)
# print(electric.head())

# As you can see, the average time for python loop to calculate the cost is 3.3 sec. There are three drawback with these method:
# 1. it needs to create an empty list
# 2. it needs to append to a list, and use the list to create a df
# 3. the biggest issue is the time cost of the calculation

# pd has two buildin loop that allows us to speed up if we really want to use a loop, df.itertuples() and df.iterrows()
# Note that df.iterrows() returns a tuple of a row, the first element is the index of the row; the second element is the pd.series of the corresponding data. Since it is a pd.series, we can use [col_name] or [col_index] to specify the column we want

# @timer
# def apply_tariff(df):
#     cost = []
#     for index, data in df.iterrows():
#         kwh = data['energy_kwh']
#         hour = data['date_time'].hour
#         cost.append(tariff(kwh, hour))
#     df['cost'] = cost
#
# apply_tariff(electric)

# By using iterrows(), it takes only 0.75 second to do the same thing, how about itertuples?

# @timer
# def apply_tariff(df):
#     cost = []
#     for row in df.itertuples():
#         kwh = row.energy_kwh
#         hour = (row.date_time).hour
#         cost.append(tariff(kwh, hour))
#     df['cost'] = cost
#
# apply_tariff(electric)
# print(electric.head())

# By using itertuples(), it takes only 0.05 second to finish the calculation, which is faster than 0.75 sec

# @timer
# def apply_tariff(df):
#     df['cost'] = df.apply(lambda row: tariff(row['energy_kwh'], row['date_time'].hour),axis=1)
#
# apply_tariff(electric)
# print(electric.head())

# It takes 0.25 sec to process, it is not as fast as itertuples, but still better than iterrows

# Can we do better? As we know the fundamental unit of Pandas are DataFrame and series, and both of them are based on arrays, instead of sequentially operating on an individual values(scalars), vectorized operations are the preferable & much fast ways to execute b/c array operations are fully optimized

# @timer
# def apply_tariff(df):
#     peak = df['date_time'].dt.hour.isin(range(17, 24))
#     shoulder = df['date_time'].dt.hour.isin(range(7, 17))
#     off_peak = df['date_time'].dt.hour.isin(range(0, 7))
#
#     df.loc[peak, 'cost'] = df.loc[peak, 'energy_kwh'] * 0.28
#     df.loc[shoulder, 'cost'] = df.loc[shoulder, 'energy_kwh'] * 0.2
#     df.loc[off_peak, 'cost'] = df.loc[off_peak, 'energy_kwh'] * 0.12
#
# apply_tariff(electric)

# By using verctorized operation, the average run time is 0.01 sec, which is the fastest method so faster. There is one drawback in this method. We are acutally manually type in every cases, but what if we have 24 different price range, we have to type in all 24 cases, which it horrible. Now we can try to use pd.cut() method to make things easier

# @timer
# def apply_tariff(df):
#     price = pd.cut(df['date_time'].dt.hour, bins= [0,7,17,24], labels = [0.12, 0.20, 0.28],include_lowest=True).astype(float)
#     df['cost'] = df['energy_kwh'] * price
#
# apply_tariff(electric)

# By using pd.cut(), we not only make the program more progammatic, but more efficient. It only takes 0.003 sec to process

# Since pandas are build on top of numpy, it adds some pandas functionality. If those functionality is not crucial, we can turn pandas dataframe/series into numpy array to maximize our speed

@timer
def apply_tariff(df):
    price = np.array([0.12, 0.20, 0.28])
    index = np.digitize(df['date_time'].dt.hour, [7, 17, 24], right=False)
    df['cost'] = df['energy_kwh'] * price[index]

apply_tariff(electric)

# By using verctorized numpy operation, it improve the run time from 0.003 to 0.001

"""
In conclusion:
---------------------------------
function                   time
---------------------------------
crappy loop                3.3s
---------------------------------
iterrows                   0.75s
---------------------------------
itertuples                 0.05s
---------------------------------
.apply                     0.25s
---------------------------------
chunk_vect ops             0.01s
---------------------------------
pd.cut                     0.003s
---------------------------------
np vect ops                0.001s
---------------------------------
"""


n = int(input())
box = list(map(int, input().split()))

dp = [0] * len(box)
dp[0] = 1
for i in range(1, len(box)):
    dp[i] = 1
    for j in range(i):
        if box[i] > box[j]:
            dp[i] = max(dp[j] + 1, dp[i])

print(max(dp))


import pygame
import sys

class grid_game:
    def __init__(self, screen):
        self.screen = screen
        self.lines = [((200, 0), (200, 600)), ((400, 0), (400, 600)), ((0, 200), (600, 200)), ((0, 400), (600, 400)), ]

    def show(self):
        for lines in self.lines:
            pygame.draw.line(self.screen, (0, 0, 0), lines[0], lines[1], 2)

class game:

    def __init__(self):
        self.screen = pygame.display.set_mode((600, 600))
        pygame.display.set_caption('Morpion')
        self.game_on = True
        self.grid_game = grid_game(self.screen)

    def game_event(self):
        while self.game_on:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()

                # Event du click
                if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0]:
                    # position de la souris
                    position = pygame.mouse.get_pos()
                    print(position)

            self.screen.fill((240, 240, 240))
            self.grid_game.show()

            pygame.display.flip()

if __name__ == '__main__':
    pygame.init()
    game().game_event()
    pygame.quit()


def solver():
    T = int(input())
    for _ in range(T):
        N,B = map(int,input().split())
        ans = 0
        for i in range(B):
            arr =[int(x) for x in input().split()[1:]]
            result = 1
            for e in arr:
                result*=e
                result = result%N
            ans+=result
        print(ans%N)

solver()


class Solution(object):
    def spiralOrder(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[int]
        """
        if not matrix or len(matrix) == 0 or len(matrix[0]) == 0:
            return []
        px = [0, 1, 0, -1]
        py = [1, 0, -1, 0]
        m = len(matrix)
        n = len(matrix[0])
        used = [[0 for _ in xrange(n)] for _ in xrange(m)]
        result = []
        q = [(0, 0, 0, 1)]
        while q:
            last = q.pop()
            x = last[0]
            y = last[1]
            dx = last[2]
            dy = last[3]
            result.append(matrix[x][y])
            used[x][y] = 1
            newX = x + dx
            newY = y + dy
            if newX >= 0 and newX < m and newY >= 0 and newY < n and used[newX][newY] == 0:
                q.append((newX, newY, dx, dy))
            else:
                for i in xrange(4):
                    newX = x + px[i]
                    newY = y + py[i]
                    if newX >= 0 and newX < m and newY >= 0 and newY < n and used[newX][newY] == 0:
                        q.append((newX, newY, px[i], py[i]))
                        break
        return result

"""
Solution 2
"""
class Solution(object):
    def spiralOrder(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[int]
        """
        if not matrix or len(matrix) == 0 or len(matrix[0]) == 0:
            return []
        up, left = 0, 0
        right = len(matrix[0]) - 1
        down = len(matrix) - 1
        d = 0 # 0: go right | 1: go down | 2: go left | 3: go up
        result = []
        while True:
            if d == 0:
                for i in xrange(left, right+1):
                    result.append(matrix[up][i])
                up += 1
            if d == 1:
                for i in xrange(up, down+1):
                    result.append(matrix[i][right])
                right -= 1
            if d == 2:
                for i in xrange(right, left-1, -1):
                    result.append(matrix[down][i])
                down -= 1
            if d == 3:
                for i in xrange(down, up-1, -1):
                    result.append(matrix[i][left])
                left += 1
            if left > right or up > down:
                return result
            d = (d + 1) % 4


"""
Python script to summarize small and large text
"""
# =====================================================================
# Import
# =====================================================================

# import internal modules
import re
import requests
from typing import List, Set, Dict, TypedDict, Tuple, Optional

# import 3rd-party modules
from bs4 import BeautifulSoup as bs
from gensim.summarization import summarize as gensim_summarize
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, pipeline

# import local modules
from app.decorators import timer

# load pre-trained summarization pipeline
# global summarizer
# summarizer = pipeline("summarization")

# =====================================================================
# Functions
# =====================================================================

# decorator to measure runtime of function
@timer
def gensim_summary(text, ratio=0.2, word_count=None, split=False):
    """
    Function to perform extractive text summarization
    with Gensim
    * ratio = proportion of summary compared with text
    * word_count = number of words in summary
    """
    return gensim_summarize(text, ratio, word_count, split)

# =====================================================================
# Classes
# =====================================================================

class TransformersPipeline():
    """
    TransformersPipeline class is a wrapper for HuggingFace transformers
    """
    def __init__(self, model_identifier: str, pipeline) -> None:
        """
        Function to create an instance of PipelineSummarizer class
        model_identifier = string identifier of model:
        e.g. "facebook/bart-large-cnn"
        """
        self.tokenizer = AutoTokenizer.from_pretrained(model_identifier)
        self.model = AutoModelForSeq2SeqLM.from_pretrained(model_identifier)
        self.summarizer = pipeline("summarization", model=self.model, tokenizer=self.tokenizer)

    def chunk_text(self, text: str) -> List[str]:
        """
        Function to chunk long text
        according to tokenizer.model_max_length
        """
        # Get max number of inputs possible for model
        max_chunk_len = self.tokenizer.model_max_length

        # Replace [.?!] by [.?!]<EOS>
        pattern = re.compile(r'(?P<punctuation>[.?!])')
        text = pattern.sub('\g<punctuation><EOS>', text)

        # split in sentences
        sentences: str = text.split('<EOS>')

        # create list and current_chunk counter
        chunks: List[str] = []
        current_chunk: int = 0

        for sentence in sentences:
            if len(chunks) == current_chunk + 1:

                # if adding a sentence doesn't exceed max_chunk_len
                if len(chunks[current_chunk]) + len(sentence.split(' ')) <= max_chunk_len:

                    # add tokens to current chunk
                    chunks[current_chunk].extend(sentence.split(' '))

                # else add tokens to next chunk
                else:
                    current_chunk += 1
                    chunks.append(sentence.split(' '))

            # add tokens to 1st chunk
            else:
                chunks.append(sentence.split(' ')[:max_chunk_len])

        # for each chunk, join tokens to make a single string
        for i in range(len(chunks)):
            chunks[i] = ' '.join(chunks[i])

        return chunks

    # decorator to measure runtime of function
    @timer
    def summarize(self, text, min_length=30, max_length=200):
        """
        Function to summarize a text
        or list of text(to deal with long documents)
        """
        # summarize text
        summaries = self.summarizer(text, min_length=min_length, max_length=max_length, do_sample=False)
        summary = ' '.join([summary['summary_text'] for summary in summaries])

        return summary

# =====================================================================
# Main Function
# =====================================================================

def main():
    book_html_link = "https://www.gutenberg.org/files/103/103-h/103-h.htm"

    # scrape book page
    response = requests.get(book_html_link)
    print(book_html_link, response.status_code)

    # scrape
    soup = bs(response.text, 'html.parser')
    results = soup.find_all(['h4', 'p'])
    text = [result.text for result in results]
    book = ' '.join(text)

    # Extractive summary
    extractive_summary = gensim_summary(book)

    # Instantiate TransformersPipeline class
    facebook_bart_large_cnn = TransformersPipeline("facebook/bart-large-cnn", pipeline)
    extractive_summary_chunks = facebook_bart_large_cnn.chunk_text(extractive_summary)

    summary = facebook_bart_large_cnn.summarize(extractive_summary_chunks)

    # export to txt files
    with open("static/data/extractive_summary_gensim.txt", "w") as file:
        file.write(extractive_summary)

    with open("static/data/summary_facebook_bart.txt", "w") as file:
        file.write(summary)

# =====================================================================
# Run
# =====================================================================

# execute main() if you directly run this program
if __name__ == '__main__':
    main()


### resize image to 1920x1080 pixels ###

import cv2, math, os, glob, shutil

folder_fish = ['pod', 'ku_lare', 'see_kun', 'too',
                'khang_pan', 'hang_lueang', 'sai_dang', 'sai_dum']

for name_image in folder_fish:

    # create folder resized for add image resize here
    name_dir = f"resized/{name_image}"
    if not os.path.isdir(name_dir):
        os.makedirs(name_dir)

    images =[]
    images_path = glob.glob(f"{name_image}/*.jpg")

    for img_path in images_path:
        name_im = img_path.split("\\")[1]
        im = cv2.imread(img_path)

        height_img, width_img, channel = im.shape

        # resize to 1920, 1080
        if height_img < width_img and height_img > 1920 and width_img > 1080:
            div = width_img / 1920
            new_height = math.ceil(height_img / div)
            new_width = math.ceil(width_img /div)
            reimg = cv2.resize(im, (new_width, new_height))
            cv2.imwrite(f"resized/{name_image}/{name_im}",reimg)

        # image vertical
        elif height_img > width_img and height_img > 1920 and width_img > 1080:
            a = height_img / 1920
            new_width = math.ceil(width_img /a)
            new_height = math.ceil(height_img / a)
            shutil.copy2(f"augmented/{name_image}/{name_im}", f"resized/{name_image}")

        # image size small
        elif height_img <= 1920 or width_img <= 1920:
            shutil.copy2(f"augmented/{name_image}/{name_im}", f"resized/{name_image}")


import time

def execute_athena_query(output_location, query, athena_client):
    """Executes the given individual query against athena and return the result.

    Keyword arguments:
    output_location -- the s3 location to output the results of the execution to
    query -- the query to execute
    """
    print(
        f"Executing query and sending output results to '{output_location}'"
    )

    query_start_resp = athena_client.start_query_execution(
        QueryString=query, ResultConfiguration={"OutputLocation": output_location}
    )
    print(f"Query start response {query_start_resp}")
    if 'QueryExecutionId' in query_start_resp:
        execution_state = poll_athena_query_status(query_start_resp["QueryExecutionId"], athena_client)

        if execution_state != "SUCCEEDED":
            print(f"Non successful execution state returned: {execution_state}")
            raise KeyError(
                f"Athena query execution failed with final execution status of '{execution_state}'"
            )

        return athena_client.get_query_results(
            QueryExecutionId=query_start_resp["QueryExecutionId"]
        )
    else:
        raise Exception("Athena response didn't contain QueryExecutionId")

def poll_athena_query_status(id, athena_client):
    """Polls athena for the status of a query.

    Keyword arguments:
    id -- the id of the query in athena
    """
    print(f"Polling athena query status for id {id}")
    time_taken = 1
    while True:
        query_execution_resp = athena_client.get_query_execution(QueryExecutionId=id)

        state = query_execution_resp["QueryExecution"]["Status"]["State"]
        if state in ("SUCCEEDED", "FAILED", "CANCELLED"):
            print(
                f"Athena query execution finished in {str(time_taken)} seconds with status of '{state}'"
            )
            return state

        time.sleep(1)
        time_taken += 1


from google.appengine.ext import db#
import logging#
import myutils#
import cacheMgr

class StockPrice(db.Model):
    stock_id = db.StringProperty(required=True)
    price = db.StringProperty(required=True)
    detail = db.StringProperty(required=True)
    date = db.DateProperty(auto_now_add=True)

def getPriceList(stock_id):
    priceList = cacheMgr.getStockPrice(stock_id)
    logging.debug("get price from cache for price%s is None? %s" % (stock_id, \
                  str(priceList == None)))
    if priceList:
        return priceList
    query = StockPrice.gql("WHERE stock_id=:1 order by date desc",
		                                stock_id)
    query = query.fetch(limit=myutils.PER_PRICE_COUNT*myutils.PRICE_LINES)
    logging.debug("get price for %s , count is: %s" % (stock_id, str(len(query))))
    cacheMgr.cacheStockPrice(stock_id, query)
    return query


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

"""
Created on a windy day, unlike australia

@author: Helen Daly
@id: R00142752
@Cohort: SOFT8032_26756
"""

from sklearn import datasets
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import random as rnd

from sklearn import datasets
from sklearn import tree
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.model_selection import KFold
from sklearn.model_selection import RepeatedKFold
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB

from sklearn.svm import SVC

from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier

from sklearn.preprocessing import KBinsDiscretizer
from sklearn.model_selection import cross_validate
from sklearn.cluster import KMeans
from sklearn import preprocessing
from sklearn.preprocessing import KBinsDiscretizer

df = pd.read_csv("weatherAUS.csv", encoding = 'utf8')

def Task1():

    # Use 3 attributes to use machine learning to predict if it will rain tomorrow.
    # Experiment with 1 - 35 depth of decision tree.

    #print(df.info())
    newdf = df[['MinTemp', 'WindGustSpeed', 'Rainfall', 'RainTomorrow']].copy()
    #print(newdf.info())
    newdf = newdf.dropna()

    def testTrainPlot(X, y, df):

        attributes = list(df.columns)
        X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.33, random_state=42)
        trainResult = []
        testResult = []

        for maxdepthNo in range(1,36):
            tree_clf = tree.DecisionTreeClassifier(max_depth=maxdepthNo)
            tree_clf.fit(X_train, y_train)
            trainResult.append(tree_clf.score(X_train, y_train))
            testResult.append(tree_clf.score(X_test, y_test))

        title = ''
        for colTitle in attributes:
            title = title + colTitle + ' + '
        title = title + 'used to predict ' + y.columns
        plt.title(title)
        plt.plot(trainResult)
        plt.plot(testResult)
        plt.legend(['Train', 'Test'])
        plt.show()

    newdf1 = newdf[['MinTemp', 'WindGustSpeed', 'Rainfall']]
    newdf2 = newdf[['MinTemp', 'WindGustSpeed']]
    newdf3 = newdf[['MinTemp', 'Rainfall']]
    newdf4 = newdf[['WindGustSpeed', 'Rainfall']]

    X = (newdf1)
    y = newdf[['RainTomorrow']]
    testTrainPlot(X, y, newdf1)

    X = (newdf2)
    testTrainPlot(X, y, newdf2)

    X = (newdf3)
    testTrainPlot(X, y, newdf3)

    X = (newdf4)
    testTrainPlot(X, y, newdf4)

def Task2():
    newdf = df[['Pressure9am', 'Pressure3pm', 'Humidity9am', 'Humidity3pm', 'RainToday']]
    print(newdf.head)
    # To get an idea of how many null values in columns
    print(newdf.info())
    # To fill in blanks for pressure and humidity, to ensure average is correct
    #newdf.loc[newdf['Pressure9am'].isnull(), 'Pressure9am'] = newdf['Pressure3pm']
    #newdf.loc[newdf['Pressure3pm'].isnull(), 'Pressure3pm'] = newdf['Pressure9am']
    #newdf.loc[newdf['Humidity9am'].isnull(), 'Humidity9am'] = newdf['Humidity3pm']
    #newdf.loc[newdf['Humidity3pm'].isnull(), 'Humidity3pm'] = newdf['Humidity9am']

    # Fill up the remaining null values with average
    #newdf.loc[newdf['Pressure9am'].isnull(), 'Pressure9am'] = newdf['Pressure9am'].mean()
    #newdf.loc[newdf['Pressure3pm'].isnull(), 'Pressure3pm'] = newdf['Pressure3pm'].mean()
    #print(newdf.info())

    #newdf.dropna(subset=['RainToday'], inplace = True)
    #newdf.loc[newdf['Humidity9am'].isnull(), 'Humidity9am'] = newdf['Humidity9am'].mean()
    #newdf.loc[newdf['Humidity3pm'].isnull(), 'Humidity3pm'] = newdf['Humidity3pm'].mean()
    #print(newdf.info())

    newdf = newdf.dropna()
    newdf['Pressure'] = (newdf['Pressure9am'] + newdf['Pressure3pm'])/2
    newdf['Humidity'] = (newdf['Humidity9am'] + newdf['Humidity3pm'])/2
    print(newdf.info())

    models = []
    models.append(('KNN', KNeighborsClassifier()))
    models.append(('DTC', tree.DecisionTreeClassifier()))
    models.append(('NB', GaussianNB()))
    models.append(('SVM', SVC(kernel='linear')))
    models.append(('RFS',RandomForestClassifier()))

    #names = []
    results = {}

    X = newdf[['Pressure', 'Humidity']]
    y = newdf[['RainToday']]

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

    for name,model in models:
        cv_results = cross_validate(model, X, y, cv=5, scoring='accuracy', return_train_score=True)
        results[name] = cv_results
        print(cv_results)
    # for models in results:
    #     print(models)
    #     print('Training  ',results[models]['train_score'].mean())
    #     print('Test  ',results[models]['test_score'].mean())
    # return results

    df = pd.DataFrame()

    for models in results:

        print(models)
        model = []
        model.append(models)
        data = []
        print('Training  ',results[models]['train_score'].mean())
        data.append(results[models]['train_score'].mean())
        print('Test  ',results[models]['test_score'].mean())
        data.append(results[models]['test_score'].mean())
        ser = pd.Series(data=results[models])
        print(ser)
        df[models] = data

    df = df.transpose()

    df.columns = ['Test Score', 'Train Score']

    df.plot.bar(rot=0)

def Task3():

    return

def Task4():
    return

results = Task2()


tipo_cuentas: dict[int: str] = {
    1: 'Sueldo',
    2: 'Normal',
}

class User:

    def __init__(self, nombre: str, apellido: str) -> None:
        self.nombre = nombre
        self.apellido = apellido

    def __repr__(self) -> str:
        return f'{self.nombre} {self.apellido}'

class Cuenta:

    def __init__(self, tipo: str) -> None:
        self.tipo = tipo

    def __repr__(self) -> str:
        return f'{self.tipo}'

class BankAccount:

    def __init__(self, cuenta_numero: int, alias: str, usuario: User, clase_cuenta: Cuenta, balance: float = 0.0) -> None:
        self.cuenta_numero = cuenta_numero
        self.alias = alias
        self.usuario = usuario
        self.clase_cuenta = clase_cuenta
        self.balance = balance

    def depositar(self, monto: float) -> None:
        if self.clase_cuenta.tipo == 'Normal':
            self.balance += monto - (monto * 0.05)
            return
        self.balance += monto

    def retirar(self, monto: float) -> None:
        if self.clase_cuenta.tipo == 'Normal':
            self.balance -= monto + (monto * 0.05)
            return
        self.balance -= monto

    def __repr__(self) -> str:
        return f'BankAccount(cuenta_numero={self.cuenta_numero}, alias={self.alias}, usuario={self.usuario}, clase_cuenta={self.clase_cuenta}, balance={self.balance})'

if __name__ == '__main__':
    user = User('Juan', 'Perez')
    user2 = User('Martin', 'Garcia')
    cuenta = Cuenta(tipo_cuentas[1])
    cuenta2 = Cuenta(tipo_cuentas[2])
    bank_account = BankAccount(123, 'juanpe', user, cuenta)
    bank_account2 = BankAccount(124, 'marga', user2, cuenta2)
    bank_account.depositar(100)
    bank_account2.depositar(100)
    print(bank_account)
    print(bank_account2)
    bank_account.retirar(50)
    bank_account2.retirar(50)
    print(bank_account)
    print(bank_account2)


from elasticsearch import Elasticsearch

def analyze(sentence):
    results = Elasticsearch().indices.analyze(
        index = "data",
        body={
            "analyzer": "my_analyzer",
            "text": sentence
        }
    )
    print([key["token"] for key in results["tokens"]])

while(True):
    analyze(input(" : "))


from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split, StratifiedKFold, cross_val_score
from sklearn.pipeline import make_pipeline, Pipeline
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import accuracy_score, f1_score,precision_score,recall_score
import numpy as np
import pandas as pd

#code inspired by
    # https://www.kaggle.com/lbronchal/sentiment-analysis-with-svm

def fit(train,test):
    np.random.seed(1)

    kfolds = StratifiedKFold(n_splits=5, shuffle=True, random_state=1)
    np.random.seed(1)

    vectorizer = TfidfVectorizer(min_df = 5,
                                max_df = 0.8,
                                sublinear_tf = True,
                                use_idf = True)

    pipeline_svm = make_pipeline(vectorizer,
                                SVC(probability=True, kernel="rbf",
                                class_weight="balanced"))

    grid_svm = GridSearchCV(pipeline_svm,
                        param_grid = {'svc__C': [0.01, 0.1, 1]},
                        cv = kfolds,
                        scoring = "accuracy",
                        verbose=1,
                        n_jobs=-1)

    grid_svm.fit(train["text"], train["labels"])
    grid_svm.score(test["text"], test["labels"])
    return grid_svm

def report_results(model, X, y):
    pred_proba = model.predict_proba(X)[:, 1]
    pred = model.predict(X)

    acc = accuracy_score(y, pred)
    f1 = f1_score(y, pred,average = 'macro')
    prec = precision_score(y, pred,average = 'macro')
    rec = recall_score(y, pred,average = 'macro')
    result = { 'f1': f1, 'acc': acc, 'precision': prec, 'recall': rec}
    print(result)

def analysis():
    print("analysis! \n")
    data = pd.read_csv("Data/clean.csv")
    data['text'] = data["headline"] + " " + data["summary"]
    train, test = train_test_split(data, test_size=0.2, random_state=1)
    model = fit(train,test)
    report_results(model,test["text"],test["labels"])


###################################################
# [Practice] Euler Angles in OpenGL
import glfw
from OpenGL.GL import *
from OpenGL.GLU import *
import numpy as np
from OpenGL.arrays import vbo
import ctypes

gCamAng = 0.
gCamHeight = 1.

alpha = 0.
beta = 0.
gamma = 0.

def drawCube_glVertex():
    glBegin(GL_TRIANGLES)

    glNormal3f(0,0,1) # v0, v2, v1, v0, v3, v2 normal
    glVertex3f( -1 ,  1 ,  1 ) # v0 position
    glVertex3f(  1 , -1 ,  1 ) # v2 position
    glVertex3f(  1 ,  1 ,  1 ) # v1 position

    glVertex3f( -1 ,  1 ,  1 ) # v0 position
    glVertex3f( -1 , -1 ,  1 ) # v3 position
    glVertex3f(  1 , -1 ,  1 ) # v2 position

    glNormal3f(0,0,-1)
    glVertex3f( -1 ,  1 , -1 ) # v4
    glVertex3f(  1 ,  1 , -1 ) # v5
    glVertex3f(  1 , -1 , -1 ) # v6

    glVertex3f( -1 ,  1 , -1 ) # v4
    glVertex3f(  1 , -1 , -1 ) # v6
    glVertex3f( -1 , -1 , -1 ) # v7

    glNormal3f(0,1,0)
    glVertex3f( -1 ,  1 ,  1 ) # v0
    glVertex3f(  1 ,  1 ,  1 ) # v1
    glVertex3f(  1 ,  1 , -1 ) # v5

    glVertex3f( -1 ,  1 ,  1 ) # v0
    glVertex3f(  1 ,  1 , -1 ) # v5
    glVertex3f( -1 ,  1 , -1 ) # v4

    glNormal3f(0,-1,0)
    glVertex3f( -1 , -1 ,  1 ) # v3
    glVertex3f(  1 , -1 , -1 ) # v6
    glVertex3f(  1 , -1 ,  1 ) # v2

    glVertex3f( -1 , -1 ,  1 ) # v3
    glVertex3f( -1 , -1 , -1 ) # v7
    glVertex3f(  1 , -1 , -1 ) # v6

    glNormal3f(1,0,0)
    glVertex3f(  1 ,  1 ,  1 ) # v1
    glVertex3f(  1 , -1 ,  1 ) # v2
    glVertex3f(  1 , -1 , -1 ) # v6

    glVertex3f(  1 ,  1 ,  1 ) # v1
    glVertex3f(  1 , -1 , -1 ) # v6
    glVertex3f(  1 ,  1 , -1 ) # v5

    glNormal3f(-1,0,0)
    glVertex3f( -1 ,  1 ,  1 ) # v0
    glVertex3f( -1 , -1 , -1 ) # v7
    glVertex3f( -1 , -1 ,  1 ) # v3

    glVertex3f( -1 ,  1 ,  1 ) # v0
    glVertex3f( -1 ,  1 , -1 ) # v4
    glVertex3f( -1 , -1 , -1 ) # v7
    glEnd()

def createVertexArraySeparate():
    varr = np.array([
            (0,0,1),         # v0 normal
            ( -1 ,  1 ,  1 ), # v0 position
            (0,0,1),         # v2 normal
            (  1 , -1 ,  1 ), # v2 position
            (0,0,1),         # v1 normal
            (  1 ,  1 ,  1 ), # v1 position

            (0,0,1),         # v0 normal
            ( -1 ,  1 ,  1 ), # v0 position
            (0,0,1),         # v3 normal
            ( -1 , -1 ,  1 ), # v3 position
            (0,0,1),         # v2 normal
            (  1 , -1 ,  1 ), # v2 position

            (0,0,-1),
            ( -1 ,  1 , -1 ), # v4
            (0,0,-1),
            (  1 ,  1 , -1 ), # v5
            (0,0,-1),
            (  1 , -1 , -1 ), # v6

            (0,0,-1),
            ( -1 ,  1 , -1 ), # v4
            (0,0,-1),
            (  1 , -1 , -1 ), # v6
            (0,0,-1),
            ( -1 , -1 , -1 ), # v7

            (0,1,0),
            ( -1 ,  1 ,  1 ), # v0
            (0,1,0),
            (  1 ,  1 ,  1 ), # v1
            (0,1,0),
            (  1 ,  1 , -1 ), # v5

            (0,1,0),
            ( -1 ,  1 ,  1 ), # v0
            (0,1,0),
            (  1 ,  1 , -1 ), # v5
            (0,1,0),
            ( -1 ,  1 , -1 ), # v4

            (0,-1,0),
            ( -1 , -1 ,  1 ), # v3
            (0,-1,0),
            (  1 , -1 , -1 ), # v6
            (0,-1,0),
            (  1 , -1 ,  1 ), # v2

            (0,-1,0),
            ( -1 , -1 ,  1 ), # v3
            (0,-1,0),
            ( -1 , -1 , -1 ), # v7
            (0,-1,0),
            (  1 , -1 , -1 ), # v6

            (1,0,0),
            (  1 ,  1 ,  1 ), # v1
            (1,0,0),
            (  1 , -1 ,  1 ), # v2
            (1,0,0),
            (  1 , -1 , -1 ), # v6

            (1,0,0),
            (  1 ,  1 ,  1 ), # v1
            (1,0,0),
            (  1 , -1 , -1 ), # v6
            (1,0,0),
            (  1 ,  1 , -1 ), # v5

            (-1,0,0),
            ( -1 ,  1 ,  1 ), # v0
            (-1,0,0),
            ( -1 , -1 , -1 ), # v7
            (-1,0,0),
            ( -1 , -1 ,  1 ), # v3

            (-1,0,0),
            ( -1 ,  1 ,  1 ), # v0
            (-1,0,0),
            ( -1 ,  1 , -1 ), # v4
            (-1,0,0),
            ( -1 , -1 , -1 ), # v7
            ], 'float32')
    return varr

def drawCube_glDrawArray():
    global gVertexArraySeparate
    varr = gVertexArraySeparate
    glEnableClientState(GL_VERTEX_ARRAY)
    glEnableClientState(GL_NORMAL_ARRAY)
    glNormalPointer(GL_FLOAT, 6*varr.itemsize, varr)
    glVertexPointer(3, GL_FLOAT, 6*varr.itemsize, ctypes.c_void_p(varr.ctypes.data + 3*varr.itemsize))
    glDrawArrays(GL_TRIANGLES, 0, int(varr.size/6))

def render():
    global gCamAng, gCamHeight
    global alpha, beta, gamma

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    glEnable(GL_DEPTH_TEST)

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45, 1, 1,10)

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    gluLookAt(5*np.sin(gCamAng),gCamHeight,5*np.cos(gCamAng), 0,0,0, 0,1,0)

    drawFrame() # draw global frame

    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)
    glEnable(GL_RESCALE_NORMAL) # rescale normal

    glLightfv(GL_LIGHT0, GL_POSITION, (1.,2.,3.,1.))
    glLightfv(GL_LIGHT0, GL_AMBIENT, (.1,.1,.1,1.))
    glLightfv(GL_LIGHT0, GL_DIFFUSE, (1.,1.,1.,1.))
    glLightfv(GL_LIGHT0, GL_SPECULAR, (1.,1.,1.,1.))

    aAng = np.radians(alpha)
    bAng = np.radians(beta)
    gAng = np.radians(gamma)
    M = np.identity(4)
    Ra = Ra = np.array([[np.cos(aAng), -np.sin(aAng), 0],
                   [np.sin(aAng), np.cos(aAng), 0],
                   [0,0,1]]                       )
    Rb = np.array([[1,0,0],
                   [0, np.cos(bAng), -np.sin(bAng)],
                   [0, np.sin(bAng), np.cos(bAng)]])
    Rg = np.array([[np.cos(gAng), -np.sin(gAng), 0],
                   [np.sin(gAng), np.cos(gAng), 0],
                   [0,0,1]]                        )

    R = Ra @ Rb @ Rg

    M[:3,:3] = R
    glMultMatrixf(M.T)

    glScalef(.25,.25,.25)

    # draw cubes
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (.5,.5,.5,1.))
    drawCube_glDrawArray()

    glTranslatef(2.5,0,0)
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (1.,0.,0.,1.))
    drawCube_glDrawArray()

    glTranslatef(-2.5,2.5,0)
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (0.,1.,0.,1.))
    drawCube_glDrawArray()

    glTranslatef(0,-2.5,2.5)
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (0.,0.,1.,1.))
    drawCube_glDrawArray()

    glDisable(GL_LIGHTING)

def drawFrame():
    glBegin(GL_LINES)
    glColor3ub(255, 0, 0)
    glVertex3fv(np.array([0.,0.,0.]))
    glVertex3fv(np.array([1.,0.,0.]))
    glColor3ub(0, 255, 0)
    glVertex3fv(np.array([0.,0.,0.]))
    glVertex3fv(np.array([0.,1.,0.]))
    glColor3ub(0, 0, 255)
    glVertex3fv(np.array([0.,0.,0]))
    glVertex3fv(np.array([0.,0.,1.]))
    glEnd()

def key_callback(window, key, scancode, action, mods):
    global gCamAng, gCamHeight
    global alpha, beta, gamma
    if action==glfw.PRESS or action==glfw.REPEAT:
        if key==glfw.KEY_1:
            gCamAng += np.radians(-10)
        elif key==glfw.KEY_3:
            gCamAng += np.radians(10)
        elif key==glfw.KEY_2:
            gCamHeight += .1
        elif key==glfw.KEY_W:
            gCamHeight += -.1
        elif key == glfw.KEY_A:
            alpha += 10
        elif key == glfw.KEY_Z:
            alpha -= 10
        elif key == glfw.KEY_S:
            beta += 10
        elif key == glfw.KEY_X:
            beta -= 10
        elif key == glfw.KEY_D:
            gamma += 10
        elif key == glfw.KEY_C:
            gamma -= 10
        elif key == glfw.KEY_V:
            alpha = 0
            beta = 0
            gamma = 0

gVertexArraySeparate = None
def main():
    global gVertexArraySeparate

    if not glfw.init():
        return
    window = glfw.create_window(480,480,'2016025105', None,None)
    if not window:
        glfw.terminate()
        return
    glfw.make_context_current(window)
    glfw.set_key_callback(window, key_callback)
    glfw.swap_interval(1)

    gVertexArraySeparate = createVertexArraySeparate()

    while not glfw.window_should_close(window):
        glfw.poll_events()
        render()
        glfw.swap_buffers(window)

    glfw.terminate()

if __name__ == "__main__":
    main()


import websocket
import ssl
import erlang
from Logger import *
from erlang import *

class GatewayServer():
    '''
    Manages authentication and data transfer to/from http://gateway.discord.gg
    '''
    URL = "wss://gateway.discord.gg/?encoding=etf&v=6"

    class OPCODE:
        '''
        Taken from https://discordapp.com/developers/docs/topics/opcodes-and-status-codes#voice-opcodes
        '''
        # Name                  Code    Client Action   Description
        DISPATCH =              0  #    Receive         dispatches an event
        HEARTBEAT =             1  #    Send/Receive    used for ping checking
        IDENTIFY =              2  #    Send            used for client handshake
        STATUS =                3  #    Send            used to update the client status
        VOICE_STATE =           4  #    Send            used to join/move/leave voice channels
        #                       5  #    ???             ???
        RESUME =                6  #    Send            used to resume a closed connection
        RECONNECT =             7  #    Receive         used to tell clients to reconnect to the gateway
        REQUEST_GUILD_MEMBERS = 8  #    Send            used to request guild members
        INVALID_SESSION =       9  #    Receive         used to notify client they have an invalid session id
        HELLO =                 10 #    Receive         sent immediately after connecting, contains heartbeat and server debug information
        HEARTBEAT_ACK =         11 #    Sent immediately following a client heartbeat that was received
        GUILD_SYNC =            12 #    ???             ???

    def __init__(self, proxy_host, proxy_port):
        self.__proxy_host = proxy_host
        self.__proxy_port = proxy_port
        self.__ws = websocket.WebSocket(sslopt={"check_hostname": False, "cert_reqs": ssl.CERT_NONE})
        self.__session_settings = {}
        self.__ws.settimeout(5)

    def Connect(self, token):
        gateway_auth_data = {OtpErlangBinary('op',bits=8): 2,
                OtpErlangBinary('d',bits=8):
                    {OtpErlangBinary('properties',bits=8):
                        {OtpErlangBinary('client_version',bits=8): OtpErlangBinary('0.0.305',bits=8),
                        OtpErlangBinary('os',bits=8): OtpErlangBinary('Windows',bits=8),
                        OtpErlangBinary('os_version',bits=8): OtpErlangBinary('6.1.7601',bits=8),
                        OtpErlangBinary('os_arch',bits=8): OtpErlangBinary('x64',bits=8),
                        OtpErlangBinary('release_channel',bits=8): OtpErlangBinary('stable',bits=8),
                        OtpErlangBinary('client_build_number',bits=8): 44004,
                        OtpErlangBinary('browser',bits=8): OtpErlangBinary('Discord Client',bits=8),
                        OtpErlangBinary('client_event_source',bits=8): OtpErlangAtom('nil')
                        },
                    OtpErlangBinary('compress',bits=8): False,
                    OtpErlangBinary('token',bits=8): OtpErlangBinary("{}".format(token), bits=8),
                    OtpErlangBinary('presence',bits=8):
                        {OtpErlangBinary('status',bits=8): OtpErlangBinary('online',bits=8),
                        OtpErlangBinary('since',bits=8): 0,
                        OtpErlangBinary('afk',bits=8): False,
                        OtpErlangBinary('activities',bits=8): []
                        }
                    }
                }
        # Connect to gateway
        gateway_auth_data = erlang.term_to_binary(gateway_auth_data)
        if self.__proxy_host != False and self.__proxy_port != False:
            self.__ws.connect(self.URL, origin="https://discordapp.com", http_proxy_host=self.__proxy_host, http_proxy_port=self.__proxy_port, header={"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/0.0.305 Chrome/69.0.3497.128 Electron/4.0.8 Safari/537.36"})
        else:
            self.__ws.connect(self.URL, origin="https://discordapp.com", header={"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/0.0.305 Chrome/69.0.3497.128 Electron/4.0.8 Safari/537.36"})
        Logger.LogMessage('Gateway_wss connecting -> {}'.format(self.URL), log_level=LogLevel.OK)

        # Receive response
        response = self.__ws.recv()
        Logger.LogMessage('Gateway_wss received <- {} bytes'.format(len(response)))
        Logger.LogMessage('Gateway_wss data received \r\n', to_file=True, to_console=False, hex_data=response)

        # Send auth message
        Logger.LogMessage('Gateway_wss sending -> {} bytes'.format(len(gateway_auth_data)))
        self.__ws.send_binary(gateway_auth_data)
        Logger.LogMessage('Gateway_wss data sent -> \r\n', to_file=True, to_console=False, hex_data=gateway_auth_data)

        # Receive media_token
        response = self.__ws.recv()
        etf_data = erlang.binary_to_term(response)
        Logger.LogMessage('Gateway_wss received <- {} bytes'.format(len(response)))
        Logger.LogMessage('Gateway_wss data received <- \r\n', to_file=True, to_console=False, hex_data=response)
        erlang.etfDictToJson(self.__session_settings, etf_data[OtpErlangAtom('d')])
        Logger.LogMessage('Authenticated over gateway as {}'.format(self.__session_settings['user']['id']), log_level=LogLevel.OK)
        Logger.LogMessage('Session id: {}'.format(self.__session_settings['session_id']))

    def GetSessionId(self):
        if self.__session_settings.has_key('session_id'):
            return self.__session_settings['session_id']

    def GetUserId(self):
        if self.__session_settings.has_key('user_id'):
            return self.__session_settings['user_id']

    def GetServerId(self): # Discord also calls this "channel id"
        if self.__session_settings.has_key('channel_id'):
            return self.__session_settings['channel_id']

    def __recvUntilKey(self, target_key):
        while True:
            try:
                result = self.__ws.recv()
                etf_data = erlang.binary_to_term(result)
                erlang.etfDictToJson(self.__session_settings, etf_data[OtpErlangAtom('d')])
                if self.__session_settings.has_key(target_key): # TODO: this only searches 1 depth of dictionary, needs to be fixed
                    return
            except websocket._exceptions.WebSocketTimeoutException:
                return

    def StartScreenShare(self):
        self.__ws.send_binary('\x83t\x00\x00\x00\x02m\x00\x00\x00\x02opa\x04m\x00\x00\x00\x01dt\x00\x00\x00\x05m\x00\x00\x00\x08guild_ids\x03nilm\x00\x00\x00\nchannel_idm\x00\x00\x00\x12600792727298244639m\x00\x00\x00\tself_mutes\x04truem\x00\x00\x00\tself_deafs\x05falsem\x00\x00\x00\nself_videos\x04true')

    def RequestMediaToken(self, channel_id):
        if channel_id is None:
            raise Exception("channel_id is None!")
        ring_data = {OtpErlangBinary('op',bits=8): 4,
                    OtpErlangBinary('d',bits=8):
                        {
                        OtpErlangBinary('self_mute',bits=8): False,
                        OtpErlangBinary('channel_id',bits=8): OtpErlangBinary(channel_id,bits=8),
                        OtpErlangBinary('guild_id',bits=8): OtpErlangAtom('nil'),
                        OtpErlangBinary('self_deaf',bits=8): False,
                        OtpErlangBinary('self_video',bits=8): False
                        }
                    }
        ring_data = erlang.term_to_binary(ring_data)
        self.__ws.send_binary(ring_data)
        Logger.LogMessage("Sending -> {} bytes to media server".format(len(ring_data)))
        #Logger.LogMessage("Ring packet", to_file=True, hex_data=ring_data)
        self.__recvUntilKey('token')
        Logger.LogMessage("Received media token: {}".format(self.__session_settings['token']), log_level=LogLevel.OK)
        return self.__session_settings['token']

    def GetEndpoint(self):
        if self.__session_settings.has_key('endpoint'):
            return self.__session_settings['endpoint']


import random
import statistics
import time
import pygame
import sys

#####   PARAMETRES  #####
pygame.init()
DIMENSION_FENETRE = (1200, 760)
IPS = 30
NOIR = (0, 0, 0)
VERT = (0, 255, 0)
BLANC = (255, 255, 255)
RED = (255, 0, 0)
fenetre = pygame.display.set_mode(DIMENSION_FENETRE)
pygame.display.set_caption("Algorithme de Karger")

rect_100x = pygame.Rect(550, 30, 100, 50)
police_titre = pygame.font.SysFont('monospace', 30, True)
police = pygame.font.SysFont('monospace',55, True)
police_stats = pygame.font.SysFont('monospace', 30, True)

#####   Variables   #####
mx, my = 0,0

# variables pour 20 sommets
graphe = {}
Liste_coupe = []
temps20 = 0
dic20 = {'sommets':0,'aretes':0,'aretes':0,'min_deg':0,'max_deg':0,'min':0,'max':0,'moy':0}

# variables pour 200 sommets
graphe2 = {}
Liste_coupe2 = []
dic200 = {'sommets':0,'aretes':0,'aretes':0,'min_deg':0,'max_deg':0,'min':0,'max':0,'moy':0}
temps200 = 0

# Algorithme de Karger
def Coupe_Min(graphe,Liste_coupe):
    while len(graphe) > 2:
        # choisir deux sommets à 'fusionner'
        s1 = random.choice(list(graphe.keys()))
        # transforme les values des keys de graphe en listes == 1,2,3... et pick un nombre
        s2 = random.choice(graphe[s1])  # pick un sommet adjacent à s1

        # ajout de s2 dans s1
        for arete in graphe[s2]:
            if arete != s1:
                graphe[s1].append(arete)
        # supprimer les connections a s2 et les mettres vers s1
        for arete in graphe[s2]:
            graphe[arete].remove(s2)
            if arete != s1:
                graphe[arete].append(s1)

        graphe.pop(s2)
    coupe = len(graphe[list(graphe.keys())[0]])
    Liste_coupe.append(coupe)

def charger_graphe(graphe,bool):
    if bool:
        nom = 'matrice.txt'
        fichier = open(nom)
    else:
        nom = 'matrice2.txt'
        fichier = open(nom)

    for line in fichier:
        sommet = int(line.split()[0])
        aretes = []
        for arete in line.split()[1:]:
            if int(arete) != sommet:
                aretes.append(int(arete))
        graphe[sommet] = aretes

    fichier.close()

    nb = stats(nom)[2]
    connexite = [0] * nb
    for i in range(1, nb + 1):
        for value in graphe[i]:
            connexite[value - 1] = 1

    for j in range(0, nb):
        if not connexite[j]:
            sys.exit('Le graphe n est pas connexe')

def est_connexe(graphe,fichier):
    nb = stats(fichier)[2]
    connexite = [0]*nb
    for i in range(1,nb+1):
        for value in graphe[i]:
            connexite[value-1] = 1

    for j in range(0,nb):
        if not connexite[j]:
            sys.exit('Le graphe n est pas connexe')

def stats(nom):
    fichier = open(nom)
    min_deg = 0
    max_deg = 0
    nb_aretes = 0
    nb_sommets = 0
    tmp = 0
    flag = 1

    for line in fichier:

        nb_sommets += 1
        tmp = 0
        for arete in line.split()[1:]:
            tmp += 1
            nb_aretes += 1
        if int(line[0]) == 1 and flag:
            min_deg = tmp
            max_deg = tmp
            flag = 0
        if tmp > max_deg:
            max_deg = tmp
        if tmp < min_deg:
            min_deg = tmp
    fichier.close()

    return min_deg, max_deg, nb_sommets, nb_aretes

def afficher(dic20, dic200, temps20, temps200):

    pygame.draw.rect(fenetre, RED, rect_100x)
    message_100x = police_titre.render("100X", True, NOIR)
    fenetre.blit(message_100x, (563, 38))
    message_20_sommets = police.render("20 Sommets", True, BLANC)
    fenetre.blit(message_20_sommets, (115,25))
    message_200_sommets = police.render("200 Sommets", True, BLANC)
    fenetre.blit(message_200_sommets, (730, 25))
    rect_20 = pygame.Rect(115, 85, 330, 10)
    pygame.draw.rect(fenetre, RED, rect_20)
    rect_200 = pygame.Rect(730, 85, 365, 10)
    pygame.draw.rect(fenetre, RED, rect_200)

    fenetre.blit(write("Sommets", 600, 200, RED)[0],write("Sommets", 600, 200, RED)[1])
    fenetre.blit(write("Arêtes", 600, 270, RED)[0], write("Arêtes",600, 270, RED)[1])
    fenetre.blit(write("Degré min", 600, 340, RED)[0], write("Degré min", 600, 340, RED)[1])
    fenetre.blit(write("Degré max", 600, 410, RED)[0], write("Degré min", 600, 410, RED)[1])

    fenetre.blit(write("Coupe min", 600, 480, RED)[0], write("Coupe min", 600, 480, RED)[1])
    fenetre.blit(write("Coupe max", 600, 550, RED)[0], write("Coupe max", 600, 550, RED)[1])
    fenetre.blit(write("Coupe moyenne", 600, 620, RED)[0], write("Coupe moyenne", 600, 620, RED)[1])
    fenetre.blit(write("Temps d'exécution", 600, 690, RED)[0], write("Temps d'exécution", 600, 690, RED)[1])

    # Valeurs pour 20 sommets
    fenetre.blit(police_stats.render(str(dic20['sommets']), True, BLANC),(300,180))
    fenetre.blit(police_stats.render(str(dic20['aretes']), True, BLANC), (300, 250))
    fenetre.blit(police_stats.render(str(dic20['min_deg']), True, BLANC), (300, 320))
    fenetre.blit(police_stats.render(str(dic20['max_deg']), True, BLANC), (300, 390))
    fenetre.blit(police_stats.render(str(dic20['min']), True, BLANC), (300, 460))
    fenetre.blit(police_stats.render(str(dic20['max']), True, BLANC), (300, 530))
    fenetre.blit(police_stats.render(str(dic20['moy']), True, BLANC), (300, 600))
    fenetre.blit(police_stats.render(str(temps20), True, BLANC), (300, 670))

    # valeurs pour 200 sommets
    fenetre.blit(police_stats.render(str(dic200['sommets']), True, BLANC), (900, 180))
    fenetre.blit(police_stats.render(str(dic200['aretes']), True, BLANC), (900, 250))
    fenetre.blit(police_stats.render(str(dic200['min_deg']), True, BLANC), (900, 320))
    fenetre.blit(police_stats.render(str(dic200['max_deg']), True, BLANC), (900, 390))
    fenetre.blit(police_stats.render(str(dic200['min']), True, BLANC), (900, 460))
    fenetre.blit(police_stats.render(str(dic200['max']), True, BLANC), (900, 530))
    fenetre.blit(police_stats.render(str(dic200['moy']), True, BLANC), (900, 600))
    fenetre.blit(police_stats.render(str(temps200), True, BLANC), (900, 670))

def menu_presentation():
    pass

def write(text, x, y, couleur):
    text = police_stats.render(text, True, couleur)
    text_rect = text.get_rect(center=(x, y))
    return text, text_rect

def position_souris():
    global mx,my,rect_100x,flag,peut_clicker
    if rect_100x.collidepoint((mx, my)):
        if flag:
            main(graphe, Liste_coupe, 1)
            flag = False
            maj('matrice.txt',dic20,dic200,Liste_coupe, Liste_coupe2)
        elif not flag and peut_clicker:
            main(graphe2, Liste_coupe2, 0)
            maj('matrice2.txt',dic20,dic200,Liste_coupe, Liste_coupe2)
            peut_clicker = False

def maj(nom,dic20,dic200,Liste_coupe,Liste_coupe2):
    if nom == 'matrice.txt':
        dic20['sommets'] = stats(nom)[2]
        dic20['aretes'] = stats(nom)[3]
        dic20['min_deg'] = stats(nom)[0]
        dic20['max_deg'] = stats(nom)[1]
        dic20['min'] = min(Liste_coupe)
        dic20['max'] = max(Liste_coupe)
        dic20['moy'] = statistics.mean(Liste_coupe)
    else:
        dic200['sommets'] = stats(nom)[2]
        dic200['aretes'] = stats(nom)[3]
        dic200['min_deg'] = stats(nom)[0]
        dic200['max_deg'] = stats(nom)[1]
        dic200['min'] = min(Liste_coupe2)
        dic200['max'] = max(Liste_coupe2)
        dic200['moy'] = statistics.mean(Liste_coupe2)

def main(graphe, Liste_coupe,bool):
    global flag,temps20,temps200
    temps1 = time.time()
    i = 100
    while i>0 :
        graphe = {}
        charger_graphe(graphe,bool)
        Coupe_Min(graphe, Liste_coupe)
        i -= 1

    temps2 = time.time()
    if flag:
        temps20 = temps2 - temps1
        temps20 = round(temps20, 4)
    if not flag:
        temps200 = temps2 - temps1
        temps200 = round(temps200, 4)

flag = True
peut_clicker = True # pour ne pas lancer plusieurs fois l'algo
while True:
    fenetre.fill(NOIR)
    afficher(dic20,dic200,temps20,temps200)
    mx, my = pygame.mouse.get_pos()
    for evenement in pygame.event.get():
        if evenement.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if evenement.type == pygame.MOUSEBUTTONDOWN:
            if evenement.button == 1:
                position_souris()
        if evenement.type == pygame.KEYDOWN:
            if evenement.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()

    pygame.display.flip()
    pygame.time.Clock().tick(IPS)