import atexit # For playing a sound when the program finishes
import os # Import the os module for navigating the file system
import math # Import the math module for the square root function
import pandas as pd # Import the pandas module for data manipulation
import platform # For getting the operating system name
from colorama import Style # For coloring the terminal
from tqdm import tqdm # For Generating the Progress Bars

# Macros:
class backgroundColors: # Colors for the terminal
	CYAN = "\033[96m" # Cyan
	GREEN = "\033[92m" # Green
	YELLOW = "\033[93m" # Yellow
	RED = "\033[91m" # Red

# Dataset Constants:
DATASETS_PATH = {"training":"dataset/digits/training", "test":"dataset/digits/test"} # The path for the training dataset

# KNN Constants:
TRAINING_DATASET_SIZE = [0.25, 0.5, 1] # The training dataset sizes
NEIGHBOURS_VALUES = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] # The K values for the KNN algorithm
SPLITS = {"1":1, "2":2, "3":3, "5":5} # The x and y splits for the feature extractor

# File Constants:
OUTPUT_DIRECTORY = "output" # The path for the output file
DATASET_FILES_FORMAT = ".csv" # The dataset files format
OUTPUT_FILE_FORMAT = ".csv" # The output file format

# Sound Constants:
SOUND_COMMANDS = {"Darwin": "afplay", "Linux": "aplay", "Windows": "start"} # The sound commands for each operating system
SOUND_FILE = "../../.assets/NotificationSound.wav" # The path to the sound file

# @brief: This function verifies if the test and training dataset exists
# @param: None
# @return: True if the dataset exists, False otherwise
def verify_datasets():
	for dataset_name, dataset_path in DATASETS_PATH.items(): # Loop through the datasets
		if not os.path.exists(dataset_path): # If the dataset does not exists
			print(f"{backgroundColors.RED}The {dataset_name} does not exists{Style.RESET_ALL}")
			return False # If the dataset does not exists
	return True # If all of the datasets exists

# @brief: This function verifies if the output directory exists, if not, it creates the output directory
# @param: output_path: The path for the output directory
# @return: None
def verify_output_directory(output_path):
	if not os.path.exists(output_path): # If the output directory does not exists
		os.mkdir(output_path) # Create the output directory

# @brief: This function initialize the results dictionary
# @param: none
# @return: results: The results dictionary
def initialize_results():
	results = {} # The results dictionary
	for neighbours_value in NEIGHBOURS_VALUES: # Loop through the neighbours values: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19
		results[neighbours_value] = {} # Create a new dictionary for the current neighbours value
		for x_split, y_split in SPLITS.items(): # Loop through the splits: 1x1, 2x2, 3x3 and 5x5.
			results[neighbours_value][f"{x_split}x{y_split}"] = {} # Create a new dictionary for the current split
			for training_dataset_size in TRAINING_DATASET_SIZE: # Loop through the training dataset sizes
				results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size] = {} # Create a new dictionary for the current training dataset size
				results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size]["Correct Predictions"] = 0 # Initialize the correct predictions to 0
				results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size]["Total Predictions"] = 0 # Initialize the total predictions to 0
				results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size]["Accuracy"] = 0.00 # Initialize the accuracy to 0.00
	return results # Return the results dictionary

# @brief: This function process the datasets
# @param: results: The results dictionary
# @return: results: The results dictionary
def process_datasets(results):
	# Create the progress bar
	with tqdm(total=len(NEIGHBOURS_VALUES) * len(SPLITS) * len(TRAINING_DATASET_SIZE), desc=f"{backgroundColors.GREEN}Processing Datasets{Style.RESET_ALL}") as progress_bar:
		for neighbours_value in NEIGHBOURS_VALUES: # Loop through the neighbours values: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19
			for x_split, y_split in SPLITS.items(): # Loop through the splits: 1x1, 2x2, 3x3 and 5x5.
				for training_dataset_size in TRAINING_DATASET_SIZE: # Loop through the training dataset sizes
					training_dataset, test_dataset = read_datasets(x_split, y_split, training_dataset_size) # Read the datasets
					# Create a new dictionary for the current neighbours value, split and training dataset size that will save the correct predictions, total predictions and accuracy
					results = process_test_dataset(training_dataset, test_dataset, neighbours_value, x_split, y_split, training_dataset_size, results) # Process each test dataset row
					# Update the progress bar
					progress_bar.update(1)
	return results # Return the results dictionary

# @brief: This function reads the datasets
# @param: x_split: The x split for the feature extractor
# @param: y_split: The y split for the feature extractor
# @param: training_dataset_size: The size of the training dataset
# @return: training_dataset: The training dataset
# @return: test_dataset: The test dataset
def read_datasets(x_split, y_split, training_dataset_size):
	# The path for the training dataset file
	training_file_path = f"{DATASETS_PATH['training']}/{x_split}x{y_split}-normalized-pixel_count{DATASET_FILES_FORMAT}"
	# Load the training dataset
	training_dataset = pd.read_csv(training_file_path)
	# Pick a random sample from the training dataset based on the training dataset size
	training_dataset = training_dataset.sample(frac=training_dataset_size)
	# The path for the test dataset file
	test_file_path = f"{DATASETS_PATH['test']}/{x_split}x{y_split}-normalized-pixel_count{DATASET_FILES_FORMAT}"
	# Load the test dataset
	test_dataset = pd.read_csv(test_file_path)
	# Return the training and test datasets
	return training_dataset, test_dataset

# @brief: This function process each test dataset row, calculating the euclidean distance between the test dataset row and the training dataset
# @param: training_dataset: The training dataset
# @param: test_dataset: The test dataset
# @param: neighbours_value: The K value for the KNN algorithm
# @param: x_split: The x split for the feature extractor
# @param: y_split: The y split for the feature extractor
# @param: training_dataset_size: The size of the training dataset
# @param: results: The results dictionary
# @return: results: The results dictionary
def process_test_dataset(training_dataset, test_dataset, neighbours_value, x_split, y_split, training_dataset_size, results):
	distances = {} # The euclidean distances dictionary
	with tqdm(total=len(test_dataset), desc=f"{backgroundColors.GREEN}GRID: {backgroundColors.CYAN}{x_split}x{y_split}{backgroundColors.GREEN}, Training Dataset Size: {backgroundColors.CYAN}{training_dataset_size}{backgroundColors.GREEN}, K: {backgroundColors.CYAN}{neighbours_value}{Style.RESET_ALL}") as progress_bar:
		# For every line in the test dataset
		for test_dataset_row in test_dataset.itertuples():
			# For every line in the training dataset
			for training_dataset_row in training_dataset.itertuples():
				squared_difference = 0 # Initialize the squared difference to 0
				# loop through from the fourth column to the last column
				for i in range(4, len(training_dataset_row)):
					squared_difference += (test_dataset_row[i] - training_dataset_row[i]) ** 2 # Calculate the squared difference
				distances[f"{math.sqrt(squared_difference)}"] = training_dataset_row[2] # Add the squared difference to the distances dictionary

			# Sort the distances dictionary by its keys
			sorted_distances = {key: distances[key] for key in sorted(distances.keys())}
			nearest_neighbours = [] # Initialize the nearest neighbours list
			# Get the first K values from the sorted distances dictionary
			for index, (key, value) in enumerate(sorted_distances.items()):
				if index < neighbours_value:
					nearest_neighbours.append(value)
			# Find the element with the maximum count
			most_common_neighbour = most_common_element(nearest_neighbours)
			# Validate the results
			validate_results(results, neighbours_value, x_split, y_split, training_dataset_size, test_dataset_row, most_common_neighbour)
			# Clear the distances dictionary
			distances.clear()
			# Update the progress bar
			progress_bar.update(1)

	# Calculate the accuracy
	results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size]["Accuracy"] = (results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size]["Correct Predictions"] / results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size]["Total Predictions"]) * 100

	# Return the results dictionary
	return results

# @brief: This function finds the most common element in a list
# @param: lst: The list
# @return: most_common_value: The most common element in the list
def most_common_element(nearest_neighbours):
	# Verify if the list is empty
	if not nearest_neighbours:
		return None # Return None for an empty list

	most_common_value = None # Initialize most_common_value to None
	max_count = 0 # Initialize max_count to 0

	# Loop through the nearest neighbours list
	for item in nearest_neighbours:
		count = nearest_neighbours.count(item) # Count occurrences of the current item
		# Verify if the current count is greater than the max_count
		if count > max_count:
			max_count = count # Update max_count
			most_common_value = item # Update most_common_value

	# Verify if there is a tie, return the first value that appears the most
	if max_count == 1:
		most_common_value = nearest_neighbours[0] # If there is a tie, it will return the first value that appears the most.

	return most_common_value # Return most_common_value

# @brief: This function validates the results
# @param: results: The results dictionary
# @param: neighbours_value: The K value for the KNN algorithm
# @param: x_split: The x split for the feature extractor
# @param: y_split: The y split for the feature extractor
# @param: training_dataset_size: The size of the training dataset
# @param: test_dataset_row: The current test dataset row
# @param: most_frequent_label: The most frequent label from the K nearest neighbours
# @return: results: The results dictionary
def validate_results(results, neighbours_value, x_split, y_split, training_dataset_size, test_dataset_row, most_frequent_label):
	# Verify if the most frequent label is equal to the actual label (Digit Class) column
	if most_frequent_label == test_dataset_row[2]:
		# Add 1 to the correct predictions column
		results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size]["Correct Predictions"] += 1
	# Add 1 to the total predictions column
	results[neighbours_value][f"{x_split}x{y_split}"][training_dataset_size]["Total Predictions"] += 1

# @brief: This function loops through the results dictionary and call the write_results_to_csv function
# @param: results: The results dictionary
# @return: output_file_path: The path for the output file
def write_results(results):
	output_file_path = initialize_output_file() # Initialize the output file
	for neighbours_value in NEIGHBOURS_VALUES: # Loop through the neighbours values: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19
		for x_split, y_split in SPLITS.items(): # Loop through the splits: 1x1, 2x2, 3x3 and 5x5.
			for training_dataset_size in TRAINING_DATASET_SIZE: # Loop through the training dataset sizes
				write_results_to_csv(results, neighbours_value, x_split, y_split, training_dataset_size, output_file_path) # Write the results to a csv file

	# return the output file path
	return output_file_path

# @brief: This function initializes the output file (creates the output file and writes the headers)
# @param: None
# @return: output_file_path: The path for the output file
def initialize_output_file():
	# The path for the output file
	output_file_path = f"{OUTPUT_DIRECTORY}/K-NN-Digits-Classification{OUTPUT_FILE_FORMAT}"

	# Create the output file
	with open(output_file_path, "w") as output_file:
		# Write the headers to the output file
		output_file.write(f"Grid,Training Dataset %,K Value,Correct Predictions,Total Predictions,Accuracy %\n")

	return output_file_path # Return the output file path

# @brief: This function appends the results to a csv file
# @param: results: The results dictionary
# @param: neighbours_value: The K value for the KNN algorithm
# @param: x_split: The x split for the feature extractor
# @param: y_split: The y split for the feature extractor
# @param: training_dataset_size: The size of the training dataset
# @param: output_file_path: The path for the output file
# @return: None
def write_results_to_csv(results, neighbours_value, x_split, y_split, training_dataset_size, output_file_path):
	# Append the results to the output file
	with open(output_file_path, "a") as output_file:
		# Write the results to the output file
		output_file.write(f"{x_split}x{y_split},{training_dataset_size},{neighbours_value},{results[neighbours_value][f'{x_split}x{y_split}'][training_dataset_size]['Correct Predictions']},{results[neighbours_value][f'{x_split}x{y_split}'][training_dataset_size]['Total Predictions']},{results[neighbours_value][f'{x_split}x{y_split}'][training_dataset_size]['Accuracy']}\n")

# @brief: This function sorts the output file by the accuracy column
# @param: output_file_path: The path for the output file
# @return: None
def sort_output_file(output_file_path):
	# Read the output file
	output_file = pd.read_csv(output_file_path)
	# Sort the output file by the accuracy column
	output_file = output_file.sort_values(by=["Accuracy %"], ascending=False)
	# Save the output file
	output_file.to_csv(output_file_path, index=False)

# @brief: This function defines the command to play a sound when the program finishes
# @param: None
# @return: None
def play_sound():
	if os.path.exists(SOUND_FILE):
		if platform.system() in SOUND_COMMANDS: # if the platform.system() is in the SOUND_COMMANDS dictionary
			os.system(f"{SOUND_COMMANDS[platform.system()]} {SOUND_FILE}")
		else: # if the platform.system() is not in the SOUND_COMMANDS dictionary
			print(f"{backgroundColors.RED}The {backgroundColors.CYAN}platform.system(){backgroundColors.RED} is not in the {backgroundColors.CYAN}SOUND_COMMANDS dictionary{backgroundColors.RED}. Please add it!{Style.RESET_ALL}")
	else: # if the sound file does not exist
		print(f"{backgroundColors.RED}Sound file {backgroundColors.CYAN}{SOUND_FILE}{backgroundColors.RED} not found. Make sure the file exists.{Style.RESET_ALL}")

# Register the function to play a sound when the program finishes
atexit.register(play_sound)

# @brief: This is the main function
# @param: None
# @return: None
def main():
	# Verify if the test and training dataset exists
	if not verify_datasets():
		return # If the datasets does not exists, exit the program

	# Verify if the output directory exists, if not, it creates the output directory
	verify_output_directory(OUTPUT_DIRECTORY)

	results = initialize_results() # Initialize the results dictionary

	# Process the datasets
	results = process_datasets(results)

	# Write the results to a csv file
	output_file_path = write_results(results)

	# Sort the output file by the accuracy column
	sort_output_file(output_file_path)

# @brief: The entry point of the program
# @param: None
# @return: None
if __name__ == '__main__':
	main() # Call the main function

Artificial Intelligence/Work 02 - K-NN Digits Classification/main.py


usage_line = \
"Usage:    CMD    <simulation_executable>  <arch_string>  <root-dir-for-ISA-tests>  <logs_dir>  <optional_verbosity>\n"

help_lines = \
"  Runs the RISC-V simulation executable with ELF files from root-dir and its sub-directories.\n" \
"  Only runs it on those ELF files that are relevant to the provided arch_string." \
"  For each ELF file FOO, saves simulation output in <logs_dir>/FOO.log. \n" \
"  The optional verbosity flag is:\n" \
"      v1:    Print instruction trace during simulation\n" \
"      v2:    Print pipeline stage state during simulation\n" \
"\n" \
"  Example:    $ CMD ../sim_verilator/exe_HW_sim  RV32IMU  ./isa  ./Logs  v1\n" \
"      will run the verilator simulation executable on the following RISC-V ISA tests\n" \
"            isa/rv32ui-p*\n"    \
"            isa/rv32mi-p*\n"    \
"            isa/rv32um-p*\n"    \
"  and leave a transcript of each test's simulation output in files like ./Logs/rv32ui-p-add.log\n" \
"  Each log will contain an instruction trace (because of the 'v1' arg).\n"

import sys
import os
import stat
import subprocess

# ================================================================
# Ignores files with the following in their names

ignore_list = [".",                   # Files with extensions (e.g., foo.dump)
               "rv32uc", "rv64uc",    # C (compressed) not yet implemented
               "rv32uf", "rv64uf",    # Single precision floating point not yet implemented
               "rv32ud", "rv64ud"]    # Double precision floating point not yet implemented

# ================================================================

elf_to_hex_exe = "./elf_to_hex/elf_to_hex"

num_executed = 0
num_passed   = 0

# ================================================================

def main (argv = None):
    print ("Use flag --help  or --h for a help message")
    if ((len (argv) <= 1) or
        (argv [1] == '-h') or (argv [1] == '--help') or
        ((len (argv) != 5) and (len (argv) != 6))):

        sys.stdout.write (usage_line.replace ("CMD", argv [0]))
        sys.stdout.write ("\n")
        sys.stdout.write (help_lines.replace ("CMD", argv [0]))
        sys.stdout.write ("\n")
        return 0

    sim_path = os.path.abspath (os.path.normpath (argv [1]))

    test_families = select_test_families (argv [2])
    print ("Testing the following families of ISA tests")
    for tf in test_families:
        print ("    " + tf)

    elfs_path = os.path.abspath (os.path.normpath (argv [3]))

    logs_path = os.path.abspath (os.path.normpath (argv [4]))
    if not (os.path.exists (logs_path) and os.path.isdir (logs_path)):
        print ("Creating dir: " + logs_path)
        os.mkdir (logs_path)

    verbosity = 0
    if (len (argv) == 6):
        if (argv [5] == "v1"):
            verbosity = 1
        elif (argv [6] == "v2"):
            verbosity = 2
        else:
            sys.stdout.write ("Unknown command-line argument: {0}\n".format (argv [5]))
            print ("Use flag --help  or --h for a help message")
            return -1

    # Perform the recursive traversal
    max_level = 20
    traverse (max_level, 0, sim_path, test_families, elfs_path, logs_path, verbosity)

    # Write final statistics
    sys.stdout.write ("Executed: {0} tests\n".format (num_executed))
    sys.stdout.write ("PASS:     {0} tests\n".format (num_passed))

# ================================================================
# Select ISA test families based on provided arch string

def select_test_families (arch):
    arch = arch.lower ()
    families = []

    if arch.find ("32") != -1:
        rv = 32
        families = ["rv32ui-p", "rv32mi-p"]
    else:
        rv = 64
        families = ["rv64ui-p", "rv64mi-p"]

    if (arch.find ("s") != -1):
        s = True
        if rv == 32:
            families.extend (["rv32ui-v", "rv32si-p"])
        else:
            families.extend (["rv64ui-v", "rv64si-p"])
    else:
        s = False

    def add_family (extension):
        if (arch.find (extension) != -1):
            if rv == 32:
                families.append ("rv32u" + extension + "-p")
                if s:
                    families.append ("rv32u" + extension + "-v")
            else:
                families.append ("rv64u" + extension + "-p")
                if s:
                    families.append ("rv64u" + extension + "-v")

    add_family ("m")
    add_family ("a")
    add_family ("f")
    add_family ("d")
    add_family ("c")

    return families

# ================================================================
# Recursively traverse the dir tree below elf_path and process each file

def traverse (max_level, level, sim_path, test_families, elfs_path, logs_path, verbosity):
    st = os.stat (elfs_path)
    is_dir = stat.S_ISDIR (st.st_mode)
    is_regular = stat.S_ISREG (st.st_mode)
    do_foreachfile_function (level, is_dir, is_regular, sim_path, test_families, elfs_path, logs_path, verbosity)
    if is_dir and level < max_level:
        for entry in os.listdir (elfs_path):
            elfs_path1 = os.path.join (elfs_path, entry)
            traverse (max_level, level + 1, sim_path, test_families, elfs_path1, logs_path, verbosity)
    return 0

# ================================================================
# This function is applied to every path in the
# recursive traversal

def do_foreachfile_function (level, is_dir, is_regular, sim_path, test_families, elfs_path, logs_path, verbosity):
    prefix = ""
    for j in range (level): prefix = "  " + prefix

    # directories
    if is_dir:
        print ("%s%d dir %s" % (prefix, level, elfs_path))

    # regular files
    elif is_regular:
        dirname  = os.path.dirname (elfs_path)
        basename = os.path.basename (elfs_path)
        # print ("%s%d %s" % (prefix, level, elfs_path))
        do_regular_file_function (level, dirname, basename, sim_path, test_families, logs_path, verbosity)

    # other files
    else:
        print ("%s%d Unknown file type: %s" % (prefix, level, os.path.basename (elfs_path)))

# ================================================================
# For each ELF file, execute it in the RISC-V simulator

def do_regular_file_function (level, dirname, basename, sim_path, test_families, logs_path, verbosity):
    global num_executed
    global num_passed

    full_filename = os.path.join (dirname, basename)

    # Ignore filename if has .dump extension (not an ELF file)
    if basename.find (".dump") != -1: return

    # Ignore filename if does not match test_families
    ignore = True
    for x in test_families:
        if basename.find (x) != -1: ignore = False
    if ignore:
        # print ("Ignoring file: " + full_filename)
        return

    # For debugging only
    # prefix = ""
    # for j in range (level): prefix = "  " + prefix
    # sys.stdout.write ("{0}{1} ACTION:    {2}\n".format (prefix, level, full_filename))

    # Construct the commands for sub-process execution
    command1 = [elf_to_hex_exe, full_filename, "Mem.hex"]

    command2 = [sim_path,  "+tohost"]
    if (verbosity == 1): command2.append ("+v1")
    elif (verbosity == 2): command2.append ("+v2")

    sys.stdout.write ("Test {0}\n".format (basename))

    sys.stdout.write ("    Exec:")
    for x in command1:
        sys.stdout.write (" {0}".format (x))
    sys.stdout.write ("\n")

    sys.stdout.write ("    Exec:")
    for x in command2:
        sys.stdout.write (" {0}".format (x))
    sys.stdout.write ("\n")

    # Run command as a sub-process
    completed_process1 = run_command (command1)
    completed_process2 = run_command (command2)
    num_executed = num_executed + 1
    passed = completed_process2.stdout.find ("PASS") != -1
    if passed:
        sys.stdout.write ("    PASS")
        num_passed = num_passed + 1
    else:
        sys.stdout.write ("    FAIL")

    log_filename = os.path.join (logs_path, basename + ".log")
    sys.stdout.write ("      Writing log: {0}.log\n".format (basename))

    fd = open (log_filename, 'w')
    fd.write (completed_process1.stdout)
    fd.write (completed_process2.stdout)
    fd.close ()

    return

# ================================================================
# This is a wrapper around 'subprocess.run' because of an annoying
# incompatible change in moving from Python 3.5 to 3.6

def run_command (command):
    python_minor_version = sys.version_info [1]
    if python_minor_version < 6:
        # Python 3.5 and earlier
        result = subprocess.run (args = command,
                                 bufsize = 0,
                                 stdout = subprocess.PIPE,
                                 stderr = subprocess.STDOUT,
                                 universal_newlines = True)
    else:
        # Python 3.6 and later
        result = subprocess.run (args = command,
                                 bufsize = 0,
                                 stdout = subprocess.PIPE,
                                 stderr = subprocess.STDOUT,
                                 encoding='utf-8')
    return result

# ================================================================
# For non-interactive invocations, call main() and use its return value
# as the exit code.
if __name__ == '__main__':
  sys.exit (main (sys.argv))


__author__ = 'lybin'
__date__ = '2018/11/25 12:13'

class BookViewModel:
    def __init__(self, book):
        self.title = book['title']
        self.publisher = book['publisher']
        self.isbn = book['isbn']
        self.author = book['author']
        self.pages = book['pages'] or ''
        self.price = book['price']
        self.summary = book['summary'] or ''
        self.image = book['image']  # 豆瓣源需要改变
        self.pubdate = book['pubdate']
        self.binding = book['binding']

    @property
    def intro(self):
        intros = filter(lambda x: True if x else False, [self.author, self.publisher, self.price])
        return ' / '.join(intros)

class BookCollection:
    def __init__(self):
        self.total = 0
        self.books = []
        self.keyword = ''

    def fill(self, ruyanBook, keyword):
        self.total = ruyanBook.total
        self.books = [BookViewModel(book) for book in ruyanBook.books]
        self.keyword = keyword

class _BookViewModel:
    '''
    面向过程的伪类
    只有方法，没有数据，而对象=数据+操作数据的方法
    '''
    @classmethod
    def packageSingle(cls, data, keyWord):
        '''isbn搜索返回单条数据'''
        res = {
            'books': [],
            'total': 0,
            'keyword': keyWord
        }
        if data:
            res['total'] = 1
            res['books'] = [cls.__cutBookData(data)]

        return res

    @classmethod
    def packageCollection(cls, data, keyWord):
        '''关键字搜索返回集合'''
        res = {
            'books': [],
            'total': 0,
            'keyword': keyWord
        }
        if data:
            res['total'] = data['total']
            res['books'] = [cls.__cutBookData(book) for book in data['books']]

        return res

    @classmethod
    def __cutBookData(cls, data):
        '''对原始模型数据单条数据进行裁剪处理'''
        book = {
            'title': data['title'],
            'publisher': data['publisher'],
            'author': data['author'],
            'pages': data['pages'] or '',
            'price': data['price'],
            'summary': data['summary'] or '',
            'image': data['image']  # 豆瓣源需要改变
        }
        return book


from abc import ABCMeta, abstractmethod
import numpy as np
import ipdb

class Agent(metaclass=ABCMeta):
    """Abstract Agent Class"""

    def __init__(self, alpha=None, policy=None):
        """
        :param alpha:
        :param policy:
        """
        self.alpha = alpha
        self.policy = policy
        self.rewards = []

    @abstractmethod
    def act(self):
        pass

    @abstractmethod
    def get_reward(self, reward):
        pass

class WoLFAgent(Agent):
    """
        Win or Learn Fast-PHC(WoLF-PHC)
        http://www.cs.cmu.edu/~mmv/papers/01ijcai-mike.pdf
    """
    def __init__(self, delta=0.0001, action_list=None, **kwargs):
        super().__init__(**kwargs)
        self.action_list = action_list  # 選択肢
        self.last_action_id = None
        self.q_values = self._init_q_values()   # 期待報酬値の初期化
        self.conter = 0
        self.pi = [(1.0/len(action_list)) for idx in range(len(action_list))]
        self.pi_a = [(1.0/len(action_list)) for idx in range(len(action_list))]
        self.pi_history = [self.pi[0]]
        self.high_delta = 0.0004
        self.row_delta = 0.0002

    def _init_q_values(self):
        q_values = {}
        q_values = np.repeat(0.0, len(self.action_list))
        return q_values

    def act(self, q_values=None):
        action_id = self.policy.select_action(self.pi)    # 行動選択
        self.last_action_id = action_id
        action = self.action_list[action_id]
        return action

    def get_reward(self, reward):
        self.rewards.append(reward)
        self.q_values[self.last_action_id] = self._update_q_value(reward)   # 期待報酬値の更新
        self._update_pi_a()
        self._update_pi()

    def _update_q_value(self, reward):
        return ((1.0 - self.alpha) * self.q_values[self.last_action_id]) + (self.alpha * reward) # 通常の指数移動平均で更新

    def _update_pi_a(self):
       self.conter += 1
       for aidx, _ in enumerate(self.pi):
           self.pi_a[aidx] = self.pi_a[aidx] + (1/self.conter)*(self.pi[aidx]-self.pi_a[aidx])
           if self.pi_a[aidx] > 1: self.pi_a[aidx] = 1
           if self.pi_a[aidx] < 0: self.pi_a[aidx] = 0

    def _update_pi(self):
       delta = self.decide_delta()
       max_action_id = np.argmax(self.q_values)
       for aidx, _ in enumerate(self.pi):
           if aidx == max_action_id:
               update_amount = delta
           else:
               update_amount = ((-delta)/(len(self.action_list)-1))
           self.pi[aidx] = self.pi[aidx] + update_amount
           if self.pi[aidx] > 1: self.pi[aidx] = 1
           if self.pi[aidx] < 0: self.pi[aidx] = 0
       self.pi_history.append(self.pi[0])

    def decide_delta(self):
        expected_value = 0
        expected_value_average = 0
        for aidx, _ in enumerate(self.pi):
            expected_value += self.pi[aidx]*self.q_values[aidx]
            expected_value_average += self.pi_a[aidx]*self.q_values[aidx]

        if expected_value > expected_value_average: # win
            return self.row_delta
        else:   # row
            return self.high_delta


from Module import AbstractModule

class Module(AbstractModule):
    def __init__(self):
        AbstractModule.__init__(self)

    def run(
        self, network, antecedents, out_attributes, user_options, num_cores,
        out_path):
        from genomicode import filelib

        ref_dict, ref_sam, ref_bowtie1, ref_bowtie2, ref_bwa = antecedents

        all_ref_genomes = ref_dict, ref_sam, ref_bowtie1, ref_bowtie2, ref_bwa
        for ref in all_ref_genomes:
            # Symlink the files for each of the individual indexes.
            filelib.symlink_file_or_path_to_path(
                ref.identifier, out_path, overwrite_outpath=False)

    def name_outfile(self, antecedents, user_options):
        return "ref.index"


import requests
import json

send_url = "http://api.ipstack.com/check?access_key=d12f72d834c71d8c72ca5face5f22bac&security=1"
#secure key
geo_req = requests.get(send_url)
geo_json = json.loads(geo_req.text)

latitude = geo_json['latitude']
longitude = geo_json['longitude']
city = geo_json['city']
country = geo_json['country_name']

print("I've always wanted to go to " + city + ", " + country)


from rdkit import Chem
from rdkit.Chem import AllChem
from rdkit.Chem import Draw

# load the SDF file
suppl = Chem.SDMolSupplier('input.sdf')

# loop over the molecules and convert to PDB format
for mol in suppl:
    # generate a 3D conformation for the molecule
    AllChem.EmbedMolecule(mol)
    # optimize the conformation
    AllChem.UFFOptimizeMolecule(mol)
    # write the molecule to a PDB file
    writer = Chem.PDBWriter(f'{mol.GetProp("_Name")}.pdb')
    writer.write(mol)
    writer.close()


def solution(answers):
    answer = [0] * 3
    res = []
    a1 = [1,2,3,4,5]
    a2 = [2,1,2,3,2,4,2,5]
    a3 = [3,3,1,1,2,2,4,4,5,5]

    for i in range(len(answers)):
        if answers[i] == a1[i % len(a1)]:
            answer[0] += 1
        if answers[i] == a2[i % len(a2)]:
            answer[1] += 1
        if answers[i] == a3[i % len(a3)]:
            answer[2] += 1
    for k, v in enumerate(answer):
        if v == max(answer):
            res.append(k+1)
    return res


from fileinput import filename
from flask import jsonify, request, current_app, url_for, g
from sqlalchemy import true
from . import api
from ..models import User, Problem, Code, Comment, Log, Room, Regist, TA, Video
import os
from werkzeug.utils import secure_filename
from flask import send_file, send_from_directory, flash
import shutil
from flask_login import current_user, login_required
from .decorators import admin_required_vs, permission_required_vs, prof_required_vs, moderator_required_vs
import subprocess
from .. import db
from io import BytesIO
from collections import OrderedDict

path = os.path.dirname(os.path.abspath(__file__))  # /home/codelab/ver1/app/api
# /home/codelab/ver1/app/api/problems
problems_path = os.path.join(path, "problems")
codes_path = os.path.join(path, "codes")  # /home/codelab/ver1/app/api/codes
grading_path = os.path.join(path, "grading")
videos_path = os.path.join(path, 'videos')

@api.route('/temp', methods=['GET'])  # 수정바람
def grading():
    filepath = os.path.join(path, "grading/")
    username = g.current_user.username
    id = g.current_user.id
    problem_id = Problem.query.filter_by(title='B001')  # 수정바람
    error = None

    sourcecode = 1  # 수정바람
    if not sourcecode:
        error = 'Sourcecode is required'

    if error is not None:
        flash(error)
    else:
        filename = 'bracket'

        subprocess.call(filepath + "compile.sh " +
                        filename + " " + str(id), shell=True)
        # resf = open(filepath + "results/result_" + filename + ".txt", 'r')
        # result = resf.readline().strip()
        # print(result + "Aa")

    return '', 200

@api.route('/users/<int:id>')
def get_user(id):
    user = User.query.get_or_404(id)
    print(path)
    return jsonify(user.to_json())

@api.route('problems/<lab>/<id>', methods=['GET'])  # 문제 file list 반납
def get_filenames(lab, id):
    problem_path = os.path.join(problems_path, lab, id, '')

    file_list = os.listdir(problem_path)

    if len(file_list) >= 1:
        return {'file_list': file_list}, 200
    else:
        return '', 404

# 문제 파일 다운로드
@api.route('problems/<labname>/<id>/<filename>', methods=['GET'])
def get_problem(id, filename, labname):
    problem_path = os.path.join(problems_path, labname, id)

    file = os.path.join(problems_path, labname, id, secure_filename(filename))

    if file:
        return send_file(file, download_name=filename, as_attachment=True, attachment_filename=filename)
    else:
        return '', 404

## pdf 다운로드
@api.route('problems/<lab>/<id>/<filename>.pdf', methods=['GET'])
def get_problem2(lab, id, filename):
    problem_path = os.path.join(problems_path, lab, id)

    file = os.path.join(problems_path, lab, id, secure_filename(filename))

    if file:
        return send_file(file, download_name=filename, as_attachment=True, attachment_filename=filename, mimetype="application/pdf")
    else:
        return '', 404

## 비디오 다운로드
@api.route('video/<lab>/<video_name>', methods=['GET'])
def get_video(lab, video_name):

    room = Room.query.filter_by(room_name=lab).first()

    student_id = str(Video.query.filter_by(video_name=video_name, room_id=room.id).first().id)

    video = Video.query.filter_by(video_name=video_name, room_id=room.id).first()

    problem_path = os.path.join(videos_path, lab)

    file = os.path.join(problem_path, secure_filename(video_name))

    is_ta = TA.query.filter_by(user_id=g.current_user.id, room_id=room.id).first()

    if file and is_ta is not None:
        video.flag = 1
        db.session.add(video)
        db.session.commit()
        return send_file(file, download_name=video_name, as_attachment=True, attachment_filename=video_name, mimetype="video/mp4")
    elif file and is_ta is None:
        video.flag = 2
        db.session.add(video)
        db.session.commit()
        return send_file(file, download_name=video_name, as_attachment=True, attachment_filename=video_name, mimetype="video/mp4")
    else:
        return '', 404

@api.route('video/<lab>', methods=['GET'])
def get_studentVideoList(lab):

    room_id = str(Room.query.filter_by(room_name=lab).first().id)

    video_path = os.path.join(videos_path, lab)

    file_list = os.listdir(video_path)

    print('file_list: ')
    print(file_list)

    if len(file_list) >= 1:
        return {'file_list': file_list}, 200
    else:
        return '', 404

# @api.route('video/<lab>/<id>', methods=['GET'])  # 문제 file list 반납
# def get_studentsVideo(lab, id):

#     code_path = os.path.join(videos_path, lab, id, '')

#     dir_list = os.listdir(code_path)

#     email_list = []

#     for i in range(len(dir_list)):
#         email = User.query.filter_by(id=int(dir_list[i])).first().email
#         email_list.append(email)

#     if len(dir_list) >= 1:
#         return {'dir_list': dir_list, 'email_list': email_list}, 200
#     else:
#         return '', 404

ALLOWED_EXTENSIONS = set(
    ['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'c', 'md', 'h'])

STUDENT_ALLOWED_EXTENSIONS = set(['c', 'h'])

def allowed_file(filename):
    return ('.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS) or 'Makefile'
def student_allowed_file(filename):
    return ('.' in filename and filename.rsplit('.', 1)[1].lower() in STUDENT_ALLOWED_EXTENSIONS)

# 교수 문제 제출
@api.route('problems/<labname>/<problem_title>', methods=['POST'])
@prof_required_vs
def upload_problem(labname, problem_title):
    problem_path = os.path.join(problems_path, labname, problem_title)
    grading_problem_path = os.path.join(grading_path, labname, problem_title)
    data = request.get_json()

    room = Room.query.filter_by(room_name=labname).first().id

    filenames = data['files']['filename'] # file명
    filedatas = data['files']['file'] # file 데이터

    for idx, filename in enumerate(filenames):
        filenames[idx] = secure_filename(filename)

    if not os.path.isdir(os.path.join(problems_path, labname)):
        resp.status_code = 404
        return resp

    if not os.path.isdir(problem_path):
        os.mkdir(problem_path)
        os.chmod(problem_path, 0o777)

        os.mkdir(grading_problem_path)
        os.mkdir(os.path.join(grading_problem_path, 'cases'))
        os.mkdir(os.path.join(grading_problem_path, 'results'))
        os.mkdir(os.path.join(grading_problem_path, 'src'))
        os.mkdir(os.path.join(grading_problem_path, 'cases', 'programs'))

    prof_filelist = ['input.txt', 'output.txt', 'makefile', problem_title.lower()] # 교수가 제출하면 grading으로 갈 파일리스트

    flag = False
    for filename, filedata in zip(filenames, filedatas):
        txtfilename = None

        if allowed_file(filename):
            if filename.lower() in prof_filelist:
                if filename == 'input.txt':
                    txtfilename = os.path.join(grading_problem_path, 'cases', 'input.txt')
                elif filename == 'Makefile':
                    # 학생도 받을 수 있도록
                    txtfilename = os.path.join(problem_path, filename)
                    f = open(txtfilename, "w+", encoding='utf-8')
                    f.write(filedata)
                    f.close()

                    txtfilename = os.path.join(grading_problem_path, 'src', 'Makefile')
                elif filename.lower() == problem_title.lower() or 'output.file':
                    txtfilename = os.path.join(grading_problem_path, 'cases', 'programs', filename.lower())
            else: # 학생에게 줄 파일들
                txtfilename = os.path.join(problem_path, filename)

            f = open(txtfilename, "w+", encoding='utf-8')
            f.write(filedata)
            f.close()
            flag = True

            if filename.lower() == problem_title.lower(): # 실행파일 권한 주기
                os.chmod(txtfilename, 0o777)

    if flag:
        # db 문제 등록
        if Problem.query.filter_by(title=problem_title, room_id=room).first() is not None:
            db.session.delete(Problem.query.filter_by(title=problem_title, room_id=room).first())
            db.session.commit()

        problem = Problem(title=problem_title, room_id=room)
        db.session.add(problem)
        db.session.commit()

        problem_id = Problem.query.filter_by(title=problem_title, room_id=room).first().id
        code = Code(problem_id = problem_id, user_id=g.current_user.id)
        db.session.add(code)
        db.session.commit()
        # users = User.query.all()
        # for user in users:
        #     code = Code(problem_id=problem_id, user_id=user.id)
        #     db.session.add(code)
        # db.session.commit()

        resp = jsonify({'message': 'Problem successfully uploaded'})
        resp.status_code = 201
    else:
        resp = jsonify(
            {'message': 'Allowed file types are txt, pdf, png, jpg, jpeg, gif, c, md'})
        resp.status_code = 400
    return resp

ALLOWED_PDF_EXTENSIONS = ['pdf']
def allowed_pdf(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_PDF_EXTENSIONS

## pdf 올리기
@api.route('problems/<labname>/<problem_title>/pdf', methods=['POST'])
@prof_required_vs
def upload_pdf(labname, problem_title):
    user_id = str(g.current_user.id)

    problem_path = os.path.join(problems_path, labname, problem_title)
    # student_path = os.path.join(problem_path, labname, user_id)

    if 'file' not in request.files:
        resp = jsonify({'message': 'Not video file'})
        resp.status_code = 404
        return resp

    if not os.path.isdir(problem_path):
        os.mkdir(problem_path)
        os.chmod(problem_path, 0o777)
    # if not os.path.isdir(student_path):
    #     os.mkdir(student_path)
    #     os.chmod(student_path, 0o777)

    file = request.files['file']

    if file.filename == '':
        resp = jsonify({'message': 'Not video filename'})
        resp.status_code = 404
        return resp

    if file and allowed_pdf(file.filename):
        filename = secure_filename(file.filename)
        file.save(os.path.join(problem_path, filename))

    resp = jsonify({'message': 'Success upload Pdf'})
    resp.status_code = 200
    return resp

# 교수 문제 삭제
@api.route('problems/<lab>/<problem_title>', methods=['DELETE'])
@prof_required_vs
def delete_problem(lab, problem_title):
    print('delete problem')
    problem_path = os.path.join(problems_path, lab, problem_title)
    grading_problem_path = os.path.join(grading_path, lab, problem_title)

    problem_code_path = os.path.join(codes_path, lab, problem_title)
    print(problem_code_path)

    room_id = Room.query.filter_by(room_name=lab).first().id
    # db 문제 삭제, problem
    problem = Problem.query.filter_by(title=problem_title, room_id=room_id).first()
    # print(problem.code) ## 이걸 해야지 삭제가 된다.... 중요!!!
    if problem:
        db.session.delete(problem)
        db.session.commit()

    if os.path.isdir(problem_code_path):
        shutil.rmtree(problem_code_path)
        codes = Code.query.filter_by(problem_id=problem.id).all()
        for code in codes:
            db.session.delete(code)
        db.session.commit()

    if os.path.isdir(problem_path):
        shutil.rmtree(problem_path)
        shutil.rmtree(grading_problem_path)

        resp = jsonify({'message': 'Problem successfully delete'})
        resp.status_code = 200
        return resp
    else:
        resp = jsonify({'message': 'Not exist problem ID'})
        resp.status_code = 200
        return resp

# 학생코드 삭제
@api.route('student_codes/<username>/<problem_title>', methods=['DELETE'])
@moderator_required_vs
def delete_code(username, problem_title):
    user_id = str(g.current_user.id)
    problem_path = os.path.join(codes_path, problem_title)
    student_code_path = os.path.join(problem_path, user_id)
    grading_src_path = os.path.join(path, "grading", problem_title, "src")

    problem_id = Problem.query.filter_by(title=problem_title).first().id

    code = Code.query.filter_by(problem_id=problem_id, user_id=g.current_user.id).first()

    if os.path.isdir(student_code_path):
        shutil.rmtree(student_code_path)

    if code:
        db.session.delete(code)
        db.session.commit()

        if os.path.isdir(grading_src_path):
            grading_src_list = os.listdir(grading_src_path)
            for file in grading_src_list:
                if file != 'Makefile':
                    os.remove(os.path.join(grading_src_path, file))

        resp = jsonify({'message': 'Code successfully delete'})
        resp.status_code = 200
        return resp
    else:
        resp = jsonify({'message': 'Not exist Code'})
        resp.status_code = 200
        return resp

# 학생코드 제출
@api.route('student_codes/<lab>/<problem_title>', methods=['POST'])
def upload_code(lab, problem_title):
    data = request.get_json()
    filenames = data['files']['filename'] # file명
    filedatas = data['files']['file'] # file 데이터
    user_id = str(g.current_user.id)
    username = g.current_user.username
    executable_file = None

    room_id = Room.query.filter_by(room_name=lab).first().id

    # /home/codelab/ver1/app/api/codes/<lab>/<problem_title>
    problem_path = os.path.join(codes_path, lab, problem_title)
    # /home/codelab/ver1/app/api/codes/<lab>/<problem_title>/<username>
    student_code_path = os.path.join(problem_path, user_id)
    grading_src_path = os.path.join(path, "grading", lab, problem_title, "src")

    problem_id = Problem.query.filter_by(title=problem_title).first().id

    code = Code.query.filter_by(problem_id=problem_id, user_id=g.current_user.id).first()
    if code is None:
        code = Code(problem_id=problem_id, user_id=g.current_user.id)
        db.session.add(code)
        db.session.commit()

    problem_first_path = os.path.join(codes_path, lab)
    student_first_code_path = os.path.join(problem_first_path, lab)

    if not os.path.isdir(problem_first_path):
        os.mkdir(problem_first_path)
        os.chmod(problem_first_path, 0o777)

    # dir없으면 생성
    if not os.path.isdir(problem_path):
        os.mkdir(problem_path)
        os.chmod(problem_path, 0o777)
    if not os.path.isdir(student_code_path):
        os.mkdir(student_code_path)
        os.chmod(student_code_path, 0o777)

    for filename, filedata in zip(filenames, filedatas):
        if allowed_file(filename):
            if student_allowed_file(filename):
                # grading에 저장
                txtfilename = os.path.join(grading_src_path, filename)
                f = open(txtfilename, "w+", encoding='utf-8')
                f.write(filedata)
                f.close()

                # code에 저장
                txtfilename = os.path.join(student_code_path, filename)
                f = open(txtfilename, "w+", encoding='utf-8')
                f.write(filedata)
                f.close()

        else:
            resp = jsonify(
                {'message': 'Allowed file types are txt, pdf, png, jpg, jpeg, gif, c, h'})
            resp.status_code = 400
            return resp

    # 채점
    filepath = os.path.join(path, "grading/")

    error = None
    sourcecode = 1  # 수정바람
    if not sourcecode:
        error = 'Sourcecode is required'

    if error is not None:
        flash(error)
    else:
        executable_file = problem_title.lower() + '_' + user_id
        print(grading_src_path, executable_file) ## /home/codelab/ver1/app/api/grading/DS/Bracket/src  bracket_1
        subprocess.call("make -C " + grading_src_path, shell=True) # 학생 코드 makefile 실행
        os.rename(os.path.join(grading_src_path, problem_title.lower()), os.path.join(grading_src_path, problem_title.lower()) + '_' + user_id)
        subprocess.call(filepath + "compile.sh " +
                        executable_file + " " + user_id + " " + problem_title + " " + lab, shell=True)

    out = os.system("diff -bZ {} {}".format(os.path.join(grading_path, lab, problem_title, "results", "result_" + user_id + ".txt"), os.path.join(grading_path, lab, problem_title, "cases", "programs", "output.txt")))

    message = None
    if out != 0:
        print("Wrong Answer\n")
        message = "Wrong Answer"
        body = g.current_user.email + '
' + problem_title + '
'  + message
        # comment_chat = Comment(username='Chat Bot', body=body)
        # db.session.add(comment_chat)
        # db.session.commit()
        code = Code.query.filter_by(problem_id=problem_id, user_id=g.current_user.id).first()
        code.pf = False
    else:
        print("맞았습니다\n")
        message = "Correct Answer"
        body = g.current_user.email + '
' + problem_title + '
' + message
        # comment_chat = Comment(username='Chat Bot', body=body)
        # db.session.add(comment_chat)
        # db.session.commit()
        code = Code.query.filter_by(problem_id=problem_id, user_id=g.current_user.id).first()
        code.pf = True
    db.session.commit()

    resp = jsonify({'message': message})
    resp.status_code = 200
    return resp

# 문제 리스트 가져오기
@api.route('info', methods=['GET'])
def problem_list():
    # return '',200 # 임시
    labs = []
    roles = []

    ## Regist에서 유저아이디가 current_user.id인거 다 가져와
    ## 그 중에서 룸 아이디 다 가져와
    ## 가져온 룸 아이디와 매칭된 룸 네임 다 가져와 -> lab이라는 리스트에 저장

    isRegist_all = Regist.query.filter_by(user_id=g.current_user.id).all()
    for i, room in enumerate(isRegist_all):
        room_name = Room.query.filter_by(id=room.room_id).first().room_name
        labs.append({"lab": room_name, "problems": [], "members": [], "videos": []})
        ## lab => DS
        # labs_lab.append(room_name)
        ## problem에서 룸 네임이 room_name인거 다 가져와 (일단 그냥 등록하자)
        problem_in_lab = Problem.query.filter_by(room_id=room.room_id).all()
        for j, problem in enumerate(problem_in_lab):
            ## title => Bracket
            labs[i]["problems"].append({"title":problem.title})

            code = Code.query.filter_by(problem_id=problem.id, user_id=g.current_user.id).first()
            if code is not None:
                if code.pf == True:
                    ## evaluation => correct
                    labs[i]["problems"][j]["evaluation"] = "correct"
                else:
                    labs[i]["problems"][j]["evaluation"] = "wrong"
            else:
                labs[i]["problems"][j]["evaluation"] = "not yet"

            ## 제출한놈들 가져오기
            code_all = Code.query.filter_by(problem_id=problem.id).all()
            # regist_all = Regist.query.filter_by(room_id=room.room_id).all()
            labs[i]["problems"][j]["submission"] = []
            for k, code_name in enumerate(code_all):
                user_name = User.query.filter_by(id=code_name.user_id).first().username
                print(user_name)
                labs[i]["problems"][j]["submission"].append({"name": user_name})
                code_submission = Code.query.filter_by(problem_id=problem.id, user_id=User.query.filter_by(id=code_name.user_id).first().id).first()
                if code_submission is not None:
                    if code_submission.pf == True:
                        labs[i]["problems"][j]["submission"][k]['evaluation'] = "correct"
                    elif code_submission.pf == False:
                        labs[i]["problems"][j]["submission"][k]['evaluation'] = "wrong"
                else:
                    labs[i]["problems"][j]["submission"][k]['evaluation'] = "not yet"

        ## member
        ## 이 방에 속한 아이들 전부 가져와야함
        ## 내가 들어있는 지금 이 방
        isRegist_all_members = Regist.query.filter_by(room_id=room.room_id).all()
        # isMember = []
        # isMember.append(Regist.query.filter_by(room_id=isRegist_all_members.room_id).first())
        for j, member in enumerate(isRegist_all_members):
            user_name = User.query.filter_by(id=member.user_id).first().username
            labs[i]["members"].append({"name": user_name})
            if User.query.filter_by(id=member.user_id).first().role_id == 3:
                labs[i]["members"][j]["role"] = "Professor"
            elif TA.query.filter_by(room_id=member.room_id, user_id=member.user_id).first():
                labs[i]["members"][j]["role"] = "TA"
            else:
                labs[i]["members"][j]["role"] = "Student"

        ## 비디오 목록 가져오기 (현재 내가 등록된 방에서)
        videos = Video.query.filter_by(room_id=room.room_id).all()
        ## 현재 내가 ta로 등록된 방
        tas = TA.query.filter_by(room_id=room.room_id, user_id=g.current_user.id).first()

        for j, video in enumerate(videos):
            if tas is not None:
                if video is not None and video.room_id == tas.room_id:
                    ## 비디오가 현재 ta로 등록된 방에 있으면 다 가져와
                    print(video.video_name)
                    labs[i]["videos"].append({"name": video.video_name})
                    if video.flag == 0:
                        labs[i]["videos"][j]["status"] = "Waiting"
                    elif video.flag == 1:
                        labs[i]["videos"][j]["status"] = "Processing"
                    elif video.flag == 2:
                        labs[i]["videos"][j]["status"] = "Done"
            else:
                if video is not None and (video.user_id == g.current_user.id or video.target_id == g.current_user.id):
                    ## 내가 ta로 등록은 안되있는데 그 비디오 주인이 나거나 그 비디오 target_id가 나면 다 가져와
                    labs[i]["videos"].append({"name": video.video_name})
                    if video.flag == 0:
                        labs[i]["videos"][j]["status"] = "Waiting"
                    elif video.flag == 1:
                        labs[i]["videos"][j]["status"] = "Processing"
                    elif video.flag == 2:
                        labs[i]["videos"][j]["status"] = "Done"

    regists = Regist.query.filter_by(user_id=g.current_user.id).all()
    for regist in regists:
        room_id = regist.room_id
        if TA.query.filter_by(user_id=g.current_user.id, room_id=room_id).first():
            roles.append('admin')
        else:
            roles.append('student')

    return jsonify({"labs": labs, "roles": roles}), 200

    # codes = Code.query.filter_by(user_id=g.current_user.id).all()

    # all_list = []
    # unresolved_list = []
    # resolved_list = []
    # print(g.current_user.id)
    # for code in codes:
    #     title = Problem.query.filter_by(id=code.problem_id).first().title
    #     question = Problem.query.filter_by(id=code.problem_id).first()

    #     if g.current_user.role.name == 'Administrator' or g.current_user.role.name == 'Prof':
    #         all_list.append(title)
    #     elif question.permission == True:
    #         all_list.append(title)

    #     if code.pf == False and question.permission == True:
    #         unresolved_list.append(title)
    #     elif code.pf == True and question.permission == True:
    #         resolved_list.append(title)

    # return jsonify({"All_Problems": all_list, "Solved_Problems": unresolved_list, "Resolved_Problems": resolved_list}), 200

ALLOWED_VIDEO_EXTENSIONS = ['mp4', 'zip']
def allowed_video_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_VIDEO_EXTENSIONS

# video 업로드 학생
@api.route('video/<lab>', methods=['POST'])
def upload_video(lab):
    user_id = str(g.current_user.id)

    problem_video_path = os.path.join(videos_path, lab)
    # student_video_path = os.path.join(problem_video_path, user_id)

    room_id = Room.query.filter_by(room_name=lab).first().id

    if 'file' not in request.files:
        resp = jsonify({'message': 'Not video file'})
        resp.status_code = 404
        return resp

    if not os.path.isdir(problem_video_path):
        os.mkdir(problem_video_path)
        os.chmod(problem_video_path, 0o777)
    # if not os.path.isdir(student_video_path):
    #     os.mkdir(student_video_path)
    #     os.chmod(student_video_path, 0o777)

    file = request.files['file']

    if file.filename == '':
        resp = jsonify({'message': 'Not video filename'})
        resp.status_code = 404
        return resp

    if file and allowed_video_file(file.filename):
        filename = secure_filename(file.filename)
        file.save(os.path.join(problem_video_path, filename))
        video = Video(user_id=g.current_user.id, video_name=filename, room_id=room_id, flag = 0)
        db.session.add(video)
        db.session.commit()

    resp = jsonify({'message': 'Success upload video'})
    resp.status_code = 200
    return resp

# video 업로드 TA
@api.route('video/<lab>/<video_name>', methods=['POST'])
def upload_video_ta(lab, video_name):
    # user_id = str(User.query.filter_by(username=username).first().id)

    video_id = str(Video.query.filter_by(video_name=video_name).first().id)

    video_student = Video.query.filter_by(video_name=video_name).first()

    problem_video_path = os.path.join(videos_path, lab)
    # student_video_path = os.path.join(problem_video_path, user_id)

    room_id = Room.query.filter_by(room_name=lab).first().id
    user_id = str(User.query.filter_by(id=video_student.user_id).first().id)

    if 'file' not in request.files:
        resp = jsonify({'message': 'Not video file'})
        resp.status_code = 404
        return resp

    if not os.path.isdir(problem_video_path):
        os.mkdir(problem_video_path)
        os.chmod(problem_video_path, 0o777)
    # if not os.path.isdir(student_video_path):
    #     os.mkdir(student_video_path)
    #     os.chmod(student_video_path, 0o777)

    file = request.files['file']

    if file.filename == '':
        resp = jsonify({'message': 'Not video filename'})
        resp.status_code = 404
        return resp

    if file and allowed_video_file(file.filename):
        filename = secure_filename(file.filename)
        print(filename)
        file.save(os.path.join(problem_video_path, filename))
        video = Video(user_id=g.current_user.id, video_name=filename, room_id=room_id, target_id=user_id, flag=0)
        db.session.add(video)
        db.session.commit()

    video_student = Video.query.filter_by(video_name=video_name, room_id=room_id).first()
    video_student.flag = 2
    db.session.commit()

    # video_student = Video.query.filter_by()

    resp = jsonify({'message': 'Success upload video'})
    resp.status_code = 200
    return resp

# video delete
@api.route('video/<lab>/<video_name>', methods=['DELETE'])
def delete_video(lab, video_name):

    user_id = str(User.query.filter_by(id=g.current_user.id).first().id)

    user_id_int = User.query.filter_by(id=g.current_user.id).first().id

    problem_video_path = os.path.join(videos_path, lab)
    student_video_path = os.path.join(problem_video_path, video_name)

    room_id = Room.query.filter_by(room_name=lab).first().id

    video = Video.query.filter_by(room_id=room_id, video_name=video_name).first()

    is_ta = TA.query.filter_by(user_id=g.current_user.id, room_id=room_id).first()

    if os.path.isfile(student_video_path) and (video.user_id == g.current_user.id or is_ta.user_id is not None):
        os.remove(student_video_path)

    if video.user_id == g.current_user.id or is_ta.user_id is not None:
        db.session.delete(video)
        db.session.commit()

    resp = jsonify({'message': 'Success delete video'})
    resp.status_code = 200
    return resp

#학생 코드 받는거
@api.route('student_codes/<lab>/<id>/<student_id>/<filename>', methods=['GET'])
@prof_required_vs
def get_student_code(lab, id, student_id, filename):

    print(lab)
    print(id)
    print(student_id)
    print(filename)

    code_path = os.path.join(codes_path, lab, id, student_id)

    file = os.path.join(code_path, secure_filename(filename))

    if file:
        return send_file(file, download_name=filename, as_attachment=True, attachment_filename=filename)
    else:
        return '', 404

@api.route('student_codes/<lab>/<id>', methods=['GET'])
def get_student_all(lab, id):
    code_path = os.path.join(codes_path, lab, id, '')

    dir_list = os.listdir(code_path)

    print(dir_list)

    email_list = []

    for i in range(len(dir_list)):
        email = User.query.filter_by(id=int(dir_list[i])).first().username
        email_list.append(email)

    if len(dir_list) >= 1:
        return {'dir_list': dir_list, 'email_list': email_list}, 200
    else:
        return '', 404

@api.route('student_codes/<lab>/<id>/<student_id>', methods=['GET'])  # 문제 file list 반납
def get_student_filelist(lab, id, student_id):
    code_path = os.path.join(codes_path, lab, id, student_id)

    file_list = os.listdir(code_path)

    if len(file_list) >= 1:
        return {'file_list': file_list}, 200
    else:
        return '', 404

# log 초기화
@api.route('logs/<lab>', methods=['DELETE'])
@prof_required_vs
def initialize_logs(lab):
    room_id = Room.query.filter_by(room_name=lab).first().id

    logs = Log.query.filter_by(room_id=room_id).all()

    for log in logs:
        db.session.delete(log)
    db.session.commit()

    resp = jsonify({'message': "success"})
    resp.status_code = 200
    return resp

# log 보내기
@api.route('logs/<lab>', methods=['POST'])
def post_logs(lab):
    student_id = str(g.current_user.id)
    data = request.get_json()
    flag = True if data['flag'] == 1 else False
    room = Room.query.filter_by(room_name=lab).first()
    code = data['code']
    length = data['length'] // 2
    username = User.query.filter_by(id=student_id).first().username

    log = Log(user_id=student_id, code=code, flag=flag, length=length, username=username, room_id=room.id)
    db.session.add(log)
    db.session.commit()
    print('-----------------------------------------------')
    print(log.length)
    print('-----------------------------------------------')

    resp = jsonify({'message': "success"})
    resp.status_code = 200
    return resp

# log 받기
@api.route('logs/<lab>', methods=['GET'])
@prof_required_vs
def get_logs(lab):
    users = Log.query.group_by(Log.user_id).all()
    user_list = []
    log = []
    for user in users:
        user_list.append(user.user_id)

## 랩 이름 받아서 등록
@api.route('labs', methods=['POST'])
@prof_required_vs
def makeLab():
    user_id = User.query.filter_by(id=g.current_user.id).first().id
    data = request.get_json()
    labName = data['labName']
    if Room.query.filter_by(room_name=labName).first():
        return 'The same name lab is exist', 404

    lab_name = Room(room_name=labName, host_id=user_id)
    db.session.add(lab_name)
    db.session.commit()
    ## 룸 등록

    room_id = Room.query.filter_by(room_name=labName).first().id
    host_id = User.query.filter_by(id=g.current_user.id).first().id

    ta = TA(user_id=g.current_user.id, room_id=room_id)

    regist_room = Regist(room_id=room_id, user_id=host_id)
    db.session.add(regist_room)
    db.session.add(ta)
    db.session.commit()

    user = User.query.filter_by(id=g.current_user.id).first()

    log_init = Log(user_id=g.current_user.id, username=user.username, code='Init Log', length=0, total_length=0, room_id=room_id)

    problem_path = os.path.join(problems_path, labName)
    if not os.path.isdir(problem_path):
        os.mkdir(problem_path)
        os.chmod(problem_path, 0o777)

    grading_problem_path = os.path.join(grading_path, labName)
    if not os.path.isdir(grading_problem_path):
        os.mkdir(grading_problem_path)
        os.chmod(grading_problem_path, 0o777)

    resp = jsonify({'lab_name': labName})
    resp.status_code = 200
    return resp

## 등록된 랩 이름 보내주기, 전부 보내주면 될듯
@api.route('labs', methods=['GET'])
def postLab():

    user_id = g.current_user.id

    ## room id 전부
    room_ids = [regists.room_id for regists in  Regist.query.filter_by(user_id=user_id).all()]

    ## room_id 로 찾아야함
    labName = [Room.query.filter_by(id=room_id).first().room_name for room_id in room_ids]

    resp = jsonify({'lab_name': labName})
    resp.status_code = 200
    return resp

## 지울 랩이름 받기
@api.route('labs/delete', methods=['POST'])
@prof_required_vs
def get_deleteLab():

    user_id = User.query.filter_by(id=g.current_user.id).first().id
    data = request.get_json()
    labName = data['deleteLab']

    problem_path = os.path.join(problems_path, labName)
    grading_problem_path = os.path.join(grading_path, labName)

    video_path = os.path.join(videos_path, labName)
    code_path = os.path.join(codes_path, labName)

    room = Room.query.filter_by(room_name=labName).first()
    regists = Regist.query.filter_by(room_id=room.id).all()
    tas = TA.query.filter_by(room_id=room.id).all()
    problems = Problem.query.filter_by(room_id=room.id).all()

    comments = Comment.query.filter_by(room_id=room.id).all()
    for comment in comments:
        db.session.delete(comment)
    db.session.commit()

    if os.path.isdir(video_path):
        shutil.rmtree(video_path)

    if os.path.isdir(code_path):
        shutil.rmtree(code_path)

    # db 문제 삭제, problem
    if room:
        db.session.delete(room)
        for regist in regists:
            db.session.delete(regist)
        for ta in tas:
            db.session.delete(ta)
        for problem in problems:
            db.session.delete(problem)
            problem_code_path = os.path.join(codes_path, labName)
            if os.path.isdir(problem_code_path):
                shutil.rmtree(problem_path)
            codes = Code.query.filter_by(problem_id=problem.id).all()
            for code in codes:
                db.session.delete(code)
        db.session.commit()

    if os.path.isdir(problem_path):
        shutil.rmtree(problem_path)

        if os.path.isdir(grading_problem_path):
            shutil.rmtree(grading_problem_path)

        resp = jsonify({'message': 'Problem successfully delete'})
        resp.status_code = 200
        return resp
    else:
        resp = jsonify({'message': 'Not exist problem ID'})
        resp.status_code = 200
        return resp

## 학생 이메일 받아서 랩에 초대
@api.route('invite', methods=['POST'])
def inviteStudent():
    data = request.get_json()
    email = data['email']
    lab = data['lab']

    addStudent = User.query.filter_by(email=email).first().id
    addRoom = Room.query.filter_by(room_name=lab).first().id
    student = User.query.filter_by(email=email).first()

    ## Regist에 추가
    addStudent2Lab = Regist(room_id=addRoom, user_id=addStudent)
    db.session.add(addStudent2Lab)
    db.session.commit()

    addStudent2Log = Log(user_id=addStudent, username=student.username, code='', length=0, total_length=0, room_id=addRoom)
    db.session.add(addStudent2Log)
    db.session.commit()

    resp = jsonify({'Success': 'Success'})
    resp.status_code = 200
    return resp

## 학생 이메일 받아서 TA권한 주기 (랩에도 바로 추가)
@api.route('inviteTA', methods=['POST'])
def inviteTA():
    data = request.get_json()
    email = data['email']
    lab = data['lab']

    addStudent = User.query.filter_by(email=email).first().id
    addRoom = Room.query.filter_by(room_name=lab).first().id

    ## Regist에 추가
    if Regist.query.filter_by(room_id=addRoom, user_id=addStudent).first() is None:
        addStudent2Lab = Regist(room_id=addRoom, user_id=addStudent)
        db.session.add(addStudent2Lab)
        db.session.commit()

    addTA = TA(user_id=addStudent, room_id=addRoom)
    db.session.add(addTA)
    db.session.commit()

    resp = jsonify({'Success': 'Success'})
    resp.status_code = 200
    return resp

## 학생 이메일 받아서 랩에서 지우기
@api.route('deleteStudentFromLab', methods=['POST'])
def deleteStudentFromLab():
    data = request.get_json()
    username = data['username']
    lab = data['lab']

    ## 지울 학생 아이디
    deleteStudent = User.query.filter_by(username=username).first().id
    ## 지울 랩 아이디
    deleteRoom = Room.query.filter_by(room_name=lab).first().id
    ## 지울 학생 쿼리
    student = User.query.filter_by(username=username).first()

    ## Regist에 있는 거 지움
    ## 지울 학생의 regist (룸 아이디는 지울 랩 아이디, 유저 아이디는 지울 학생 아이디 => 지울 학생이 해당룸에 속해있다.)
    if Room.query.filter_by(room_name=deleteRoom, host_id=g.current_user.id).first():
        return 'He is Professor'

    if Regist.query.filter_by(room_id=deleteRoom, user_id=deleteStudent).first():
        deleteStudent2Lab = Regist.query.filter_by(room_id=deleteRoom, user_id=deleteStudent).first()
        db.session.delete(deleteStudent2Lab)
        db.session.commit()

    ## 해당 학생이 TA라면
    if TA.query.filter_by(user_id=deleteStudent, room_id=deleteRoom).first():
        deleteTA = TA.query.filter_by(user_id=deleteStudent, room_id=deleteRoom).first()
        db.session.delete(deleteTA)
        db.session.commit()

    deleteStudent2Log = Log.query.filter_by(user_id=deleteStudent, username=student.username, room_id=deleteRoom).first()
    if deleteStudent2Log is not None:
        db.session.delete(deleteStudent2Log)
        db.session.commit()

    resp = jsonify({'Success': 'Success'})
    resp.status_code = 200
    return resp


#_*_ coding:utf-8_*_
"""

@Time:2020/8/12 0:19
@Author:Power5Bin
@File:selenium.py
@IDE:PyCharm
@Email:75806318@qq.com

"""
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
#from selenium.webdriver.support import expected_conditions as EC
#from selenium.webdriver.support.wait import WebDriverWait

res = webdriver.Chrome()
header = {"user-agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"}
res.get('https://data.leisu.com/index-9021')  # 通过get(url)
print(res.title)
time.sleep(5)
search = []
search = res.find_elements_by_class_name("data pd-8")
print(search[1])
#for x in search:
 #   header = x.find_element_by_class_name("v-a-m w-95 display-i-b")
 #   print(header)
#search.send_keys("test")
#search.send_keys(Keys.RETURN)

#print(search)
time.sleep(5)

res.close()


"""
  radiation code
  ______________

  Functions to calculate flux and radiance
"""

import numpy as np
import pytest
from scipy.constants import c, h, k

#
# get Stull's c_1 and c_2 from fundamental constants
#
# c=2.99792458e+08  #m/s -- speed of light in vacuum
# h=6.62606876e-34  #J s  -- Planck's constant
# k=1.3806503e-23  # J/K  -- Boltzman's constant

c1 = 2. * h * c**2.
c2 = h * c / k
sigma = 2. * np.pi**5. * k**4. / (15 * h**3. * c**2.)

def Elambda(wavel, Temp):
    """
    Calculate the blackbody radiant exitence (Stull 2.13)

    Parameters
    ----------

      wavel: float or array
           wavelength (meters)

      Temp: float
           temperature (K)

    Returns
    -------

    Elambda:  float or arr
           monochromatic radiant exitence (W/m^2/m)
    """
    Elambda_val = c1 * np.pi / (wavel**5. * (np.exp(c2 / (wavel * Temp)) - 1))
    return Elambda_val

def calc_radiance(wavel, Temp):
    """
    Calculate the blackbody radiance

    Parameters
    ----------

      wavel: float or array
           wavelength (meters)

      Temp: float
           temperature (K)

    Returns
    -------

    Llambda:  float or arr
           monochromatic radiance (W/m^2/m/sr)
    """
    Llambda_val = c1 / (wavel**5. * (np.exp(c2 / (wavel * Temp)) - 1))
    return Llambda_val

def radiance_invert(wavel, L):
    """
    Calculate the brightness temperature

    Parameters
    ----------
      wavel: float
           wavelength (meters)
      L: float or array
           radiance (W/m^2/m/sr)

    Returns
    -------
    Tbright:  float or arr
           brightness temperature (K)
    """
    c, h, k = 299792458.0, 6.62607004e-34, 1.38064852e-23
    c1 = 2.0 * h * c ** 2.0
    c2 = h * c / k
    sigma = 2.0 * np.pi ** 5.0 * k ** 4.0 / (15 * h ** 3.0 * c ** 2.0)
    Tbright = c2 / (wavel * np.log(c1 / (wavel ** 5.0 * L) + 1.0))
    return Tbright

def test_planck_wavelen():
    """
       test planck function for several wavelengths
       and Temps
    """
    #
    # need Temp in K and wavelen in m
    #
    the_temps = [200., 250., 350.]
    the_wavelens = np.array([8., 10., 12.]) * 1.e-6
    out = []
    for a_temp in the_temps:
        for a_wavelen in the_wavelens:
            #
            # convert to W/m^2/micron/sr
            #
            the_bbr = calc_radiance(a_wavelen, a_temp) * 1.e-6
            out.append(the_bbr)
    answer = [0.4521,   0.8954,   1.1955,   2.7324,   3.7835,   3.9883,
              21.4495,  19.8525,  16.0931]
    np.testing.assert_array_almost_equal(out, answer, decimal=4)
    return None

if __name__ == "__main__":
    #
    # the variable __file__ contains the name of this file
    # so the result of the following line will be the same as if
    # you typed:
    #
    # pytest a301/radiation.py -q
    #
    # in a terminal  (the -q means 'suppress most of output')
    #
    print('testing {}'.format(__file__))
    pytest.main([__file__, '-q'])


from random import sample
import sqlite3

from settings import DATABASE_NAME

class DBHelper:
    def __init__(self, dbname=DATABASE_NAME):
        self.dbname = dbname
        self.conn = sqlite3.connect(dbname, check_same_thread=False)
        self.cur = self.conn.cursor()

    def setup(self):
        group_table = '''CREATE TABLE IF NOT EXISTS group_table(
                    chat_id INTEGER PRIMARY KEY,
                    group_name VARCHAR(100),
                    group_proc VARCHAR(1)
                    )'''
        user_table = '''CREATE TABLE IF NOT EXISTS user_table(
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    user_id INTEGER,
                    chat_id INTEGER,
                    user_neme VARCHAR(100)
                    )'''
        self.cur.execute(group_table)
        self.cur.execute(user_table)
        self.conn.commit()

    def add_group(self, id, name):
        stmt = '''INSERT INTO group_table(chat_id, group_name, group_proc)
                VALUES("{}","{}",{})'''
        stmt = stmt.format(id, name, '0')
        self.cur.execute(stmt)
        self.conn.commit()

    def check_group(self, id):
        stmt = 'SELECT * FROM group_table WHERE chat_id={}'
        stmt = stmt.format(id)
        self.cur.execute(stmt)
        return len(self.cur.fetchall())

    def check_game(self, id):
        stmt = 'SELECT * FROM group_table WHERE chat_id={}'
        stmt = stmt.format(id)
        self.cur.execute(stmt)
        return int(self.cur.fetchone()[2])

    def start_game(self, id):
        stmt = 'UPDATE group_table SET group_proc=1 WHERE chat_id = "{}"'
        stmt = stmt.format(id)
        self.cur.execute(stmt)
        self.conn.commit()

    def end_game(self, id):
        stmt = 'UPDATE group_table SET group_proc=0 WHERE chat_id = "{}"'
        stmt = stmt.format(id)
        self.cur.execute(stmt)
        self.conn.commit()

    def add_player(self, chat_id, user_id, user_neme):
        stmt = '''INSERT INTO user_table(chat_id, user_id, user_neme)
                VALUES("{}","{}","{}")'''
        stmt = stmt.format(chat_id, user_id, user_neme)
        self.cur.execute(stmt)
        self.conn.commit()

    def check_player(self, chat_id, user_id):
        stmt = 'SELECT * FROM user_table WHERE chat_id={} and user_id={}'
        stmt = stmt.format(chat_id, user_id)
        self.cur.execute(stmt)
        return len(self.cur.fetchall())

    def count_player(self, chat_id):
        stmt = 'SELECT * FROM user_table WHERE chat_id={}'
        stmt = stmt.format(chat_id)
        self.cur.execute(stmt)
        return len(self.cur.fetchall())

    def delete_all(self, chat_id):
        stmt = 'DELETE FROM user_table WHERE chat_id={}'
        stmt = stmt.format(chat_id)
        self.cur.execute(stmt)
        return len(self.cur.fetchall())

    def get_player(self, chat_id):
        stmt = 'SELECT * FROM user_table WHERE chat_id={}'
        stmt = stmt.format(chat_id)
        self.cur.execute(stmt)
        players = self.cur.fetchall()
        return sample(players, 2)

    def get_all_players(self, chat_id):
        stmt = 'SELECT * FROM user_table WHERE chat_id={}'
        stmt = stmt.format(chat_id)
        self.cur.execute(stmt)
        players = self.cur.fetchall()
        return players

    def delete_player(self, user_id, chat_id):
        stmt = 'DELETE FROM user_table WHERE chat_id={} and user_id={}'
        stmt = stmt.format(chat_id, user_id)
        self.cur.execute(stmt)


import numpy as np

def is_collinear(p1, p2, p3):
    # make vectors out of the points
    vec1 = p2-p1
    vec2 = p3-p1
    # transform the vec1 to matrix (for the cross product between the two vectors)
    # so vec1 X vec2 => vec1x dot vec2
    vec1x = np.array([[0, -vec1[2], vec1[1]], [vec1[2], 0, -vec1[0]], [-vec1[1], vec1[0], 0]])
    line = vec1x.dot(vec2)
    # the cross product of two collinear vector is 0 (sin(0))
    return np.sum(np.abs(line))

def point_input():
    print('put 3 numbers to set the 3d point')
    point = list()
    for j in range(3):
        n = input('')
        point.append(int(n))
    return np.array(point)

if __name__ == '__main__':
    point1 = point_input()
    point2 = point_input()
    point3 = point_input()
    if is_collinear(point1, point2, point3) == 0:
        print('the points are collinear')
    else:
        print('the point are not collinear')