from lib_scoring import *
#from lib_scoring import sentencesFromSegmentations, SummaryGraph, buildSCUcandidateList, filename, getsegsCount
#from lib_scoring import getScore, getLayerSizes, processResults, scusBySentences, maxRawScore, readPyramid, new_getlayersize
from scipy.stats import pearsonr as pearson
from scipy.stats import spearmanr as spearman
#from printEsumLog import printEsumLogWrapper
from printEsumLog import *
from time import time
import optparse
import glob
import copy
import csv
import os
import collections
import sys
import pandas as pd
import pickle
import threading
import json

#Wasih (02-21-20) results.csv not generating
PYTHON_VERSION = 2
if sys.version_info[0] == 2:
    import ConfigParser as configparser
else:
    import configparser
    PYTHON_VERSION = 3

#Wasih (02-21-20) Use termcolor to display colored text; user-friendly
from termcolor import colored

"""
============================ Input==============================
"""
#dir1 = sys.argv[1]

#dataset_ind = sys.argv[1]
#Wasih (02-21-20) results.csv not generating

timer = time()

config = configparser.ConfigParser()
config.read('../parameters.ini')

#Puru (11-03-21) Fixed bugs with -l -t -a

parser = optparse.OptionParser()
parser.add_option('-a', '--all', action="store_true", dest="a", default=False)
parser.add_option('-t', '--table', action="store_true", dest="t", default=False)
parser.add_option('-p', '--pyramid', action="store", dest="pyramid", default="pyrs/pyramids")
#parser.add_option('-o', '--output', action="store", dest='output', default='../results.csv')
#Wasih (02-21-20) results.csv not generating
parser.add_option('-o', '--output', action="store", dest='output', default=config.get('Paths', 'OutputFile'))

parser.add_option('-l', '--log', action='store', dest='log', default=True)
parser.add_option('-m', '--model', action='store', dest='model', default=1)
parser.add_option('-n', '--numsmodel', action='store', dest='numsmodel', default=False)
#Wasih 04-13-21 Add flag for return type data structure for notebook
parser.add_option('-r', '--returnflag', action='store', dest='returnflag', default=False)

options, args = parser.parse_args()

print_all = options.a
print("Print All booleanb value:", print_all)
print_table = options.t
pyramid_path = options.pyramid
results_file = options.output
log = options.log

#Wasih 04-07-21: If log folder is not there create it
if log or print_all:
    if not os.path.exists('../log'):
        os.makedirs('../log')

model = options.model
#pyramids = list(glob.iglob(pyramid_path + '*.pyr'))
pyramids = list(glob.iglob(pyramid_path + '/*.pyr'))
#pyramids = list(glob.iglob(dir1+"/*.pyr"))
summaries = list(glob.iglob('../Preprocess/peer_summaries/*'))
numsmodel = len(list(glob.iglob('../Preprocess/wise_crowd_summaries/*.xml')))
#Wasih (07-15-21) If ABCD is used, then instead of xml, '.out' files will be there
if numsmodel == 0:
    numsmodel = len(list(glob.iglob('../Preprocess/wise_crowd_summaries/*.out')))

#Wasih 07-04-21 Override numsmodel with parser if present
if options.numsmodel:
    numsmodel = options.numsmodel
    numsmodel = int(numsmodel)

numsmodel = 5
print ("Numbers of contributors: ", numsmodel)
# See pyrmaid from "Scoring/pyrs/pyramids/" folder
#pyramid = sys.argv[1]
#for testing
# pyramids = list(glob.iglob('pyrs/pyramids/*'))
#pyramids = list(glob.iglob('pyrs/pyramids/*'))
# for pyr in pyramids:
    # print (pyr)

"""
================ Scoring Mechanisms ======================
"""
score_tables = ['raw', 'quality', 'coverage', 'Comprehensive']

"""
==== What is Matter Test Data Set ====
"""

"""
Raw scores from scores.csv, a column
"""

"""
=== DUC Test Data Sets ====
"""

def getName(name):
    num = name.rfind('.')
    name = name[num+1:]
    return name

"""
=== Dictionary data-structure used to return to notebook after evaluating a summary. {Segment-Id:{'text':<Text corresponding to Segment-Id>, 'SCU':SCU-Id},...}
"""

def getDictionary(segList, pyramid, results, scores):
    #closely follows printSegments() in printEsumLog.py
    answer = {}
    for s in segList:
        for seg_index, text in s.text.items():
            if seg_index in s.scu_text_pairs.keys():
                segment_id = str(s.sentence_id) + '&' + str(s.segment_id) + '&' + str(seg_index)
                value = {}
                value['text'] = text.strip()
                value['SCU'] = s.scu_text_pairs[seg_index]
                answer[segment_id] = value
            else:
                segment_id = str(s.sentence_id) + '&' + str(s.segment_id) + '&' + str(seg_index)
                value = {}
                value['text'] = text.strip()
                value['SCU'] = None
                answer[segment_id] = value
    #now put scores in answer
    for (key, value) in scores[0].items():
        answer['raw'] = value
    for (key, value) in scores[1].items():
        answer['quality'] = value
    for (key, value) in scores[2].items():
        answer['coverage'] = value
    for (key, value) in scores[3].items():
        answer['comprehensive'] = value
    return answer

"""
====================== Scoring Pipeline ========================
"""

#Puru (11-03-21) Implemented Threading. Commented out since did not improve performance

for pyramid in pyramids:
    raw_scores = {}
    quality_scores = {}
    coverage_scores = {}
    comprehension_scores = {}
    pyramid_name = pyramid[pyramid.rfind('/') + 1:pyramid.rfind('.')]
    #print "test"
    scus_og, scu_labels = readPyramid(pyramid)
    x = []
    # threads = []
    # Puru 02/17/22 Extension for Notebook Input generation and descriptive spreadsheets
    cu_matches = {}
    group_matches = {}

    for summary in summaries:
        if os.path.isdir(summary):
            summ = glob.iglob(summary+'/*')
            #fn is the summary name
            for fn in summ:
                if fn.endswith('.ls'):
                    fn_name = fn.split('/')[-1].rsplit('.', 1)[0]
                    print ("Scoring File: ", fn_name)
                    # if print_all:
                        # print("Printing output is disabled with multithreading")
                        # print_all = False
                    # threads.append(threading.Thread(target = score, args= (copy.deepcopy(scus_og), fn, raw_scores, quality_scores, coverage_scores, comprehension_scores, pyramid, pyramid_name, scu_labels, numsmodel, print_all, log, options.returnflag)))
                    x.append(fn_name)
                    score(copy.deepcopy(scus_og), fn, raw_scores, quality_scores, coverage_scores, comprehension_scores, pyramid, pyramid_name, scu_labels, numsmodel, print_all, log, options.returnflag, cu_matches, group_matches)
                    # threads[-1].start()

    # for i in range(len(threads)):
    #     threads[i].join()
    # if print_table:
        #results_f =
        ### For DUC05

    # Puru 02/17/22 Extension for Notebook Input generation and descriptive spreadsheets
    with open('cu_vectors.json', 'w') as f:
        json.dump(cu_matches, f)
    with open('groupings_vectors.json', 'w') as f:
        json.dump(group_matches, f)
    # Take input from file for the grouping names once file is decided
    cu_df = pd.DataFrame.from_dict(cu_matches, orient='index')
    cu_df = cu_df.sort_index()
    with open('cu_vectors.csv', 'w') as f:
        cu_df.to_csv(f)
    gp_df = pd.DataFrame.from_dict(group_matches, orient='index', columns = ['A', 'B', 'C', 'D'])
    gp_df = gp_df.sort_index()
    with open('group_vectors.csv', 'w') as f:
        gp_df.to_csv(f)

    # print(cu_matches)
    # print(group_matches)
    ## FOr Duc 05
    #results_file = "results-raw.csv"
    print ("Will write into results file!! ", results_file)
    f = open(results_file, 'w')
    f.close()
    # 07/05/21 Puru changes to sorting of results
    # x = [summ for summ in summaries if not summ.split('.')[-1] == 'xml']
    x = sorted(x)
    # print(x)
    #Puru (11-03-21) Fixed Output bugs

    with open(results_file, 'a') as f:
        w = csv.writer(f)
        w.writerow([pyramid_name])
        if print_table:
            print (pyramid_name)
        w.writerow(['Summary'] + score_tables)
        if print_table:
            print ('{} | {:^9} | {:^9} | {:^9} | {}'.format("Summary Name", "Raw Rcore", "Quality", "Coverage", "Comprehensive"))
        for summary_name in x:
            #w.writerow([filename(summary)] + [s[n] for s in scores])
            # if os.path.isdir(summary):
            #     summ = glob.iglob(summary+'/*')
            #     for fn in summ:
            #         #if fn[:-5] == '.segs':
            #          if fn.endswith('.ls'):
            # summary_slash= summary.rfind('/') + 1
            # summary_dot = summary.rfind('.')
            # summary_name = summary[summary_slash:summary_dot]
            #             # print ("Raw score for summary ", summary_name, ": ", raw_scores[summary_name])
            output = [summary_name, raw_scores[summary_name],quality_scores[summary_name],coverage_scores[summary_name],comprehension_scores[summary_name]]
            w.writerow(output)
            if print_table:
                print ('{:<12} | {:^9} | {:^9.3f} | {:^9.3f} | {:^13.3f}'.format(summary_name, raw_scores[summary_name], quality_scores[summary_name],coverage_scores[summary_name],comprehension_scores[summary_name]))

print ('\n')
text = colored('Results written to %s' % results_file, 'blue')
print (text)
done = time()
text = colored(('Time: {}'.format(str(done - timer))), 'blue')
print (text)
#print 'Results written to %s' % results_file
print ('\n')


import datetime

class ProcessTxns:
	def __init__(self, transactionsList):
		self.transactionsList = transactionsList

	def getAmountByCategoryInPeriod(self, category, startTime, endTime):
		amount = 0
		for txns in self.transactionsList:
			if txns['category'] == category and txns['time'] >= startTime and txns['time'] < endTime:
				amount += txns['amount']

		return amount
	def get_list_of_dupe_txns(self):
		dupe_txns_list = []
		for txns_o in self.transactionsList:
			for txns_i in self.transactionsList:
				if txns_o['amount'] == txns_i['amount'] and txns_o['category'] == txns_i['category'] and txns_o['id'] != txns_i['id']:
					dupe_txns_list.append(txns_o)
		return self.get_sorted_list(dupe_txns_list)

	@staticmethod
	def get_sorted_list(unsorted_list):
		sorted_list = []
		#print(datetime.datetime.strptime(unsorted_list['time'], '%Y-%m-%dT%H:%M:%SZ')))
		print('1 -', unsorted_list)
		#print(datetime.datetime.strptime(unsorted_list[0]['time'], '%Y-%m-%dT%H:%M:%SZ'))
		while unsorted_list:
			minimum = datetime.datetime.strptime(unsorted_list[0]['time'], '%Y-%m-%dT%H:%M:%SZ')
			y = unsorted_list[0]
			for txns in unsorted_list:
				x = datetime.datetime.strptime(txns['time'], '%Y-%m-%dT%H:%M:%SZ')
				if x < minimum:
					print(x, minimum)
					minimum = x
					y = txns
			sorted_list.append(y)
			unsorted_list.remove(y)
		print('2 -', sorted_list)
		return sorted_list


from cs50 import get_string

x=get_string('Text: ')
y=len(x)
words=1;
sentences=0;
letters=0;

for character in x:
    if character==' ':
        words=words+1;
    if character=='.' or character=='?' or character=='!':
        sentences=sentences+1
    if (character>='a' and character<='z') or (character>="A" and character<='z'):
        letters=letters+1;
L=(letters/words)*100
S=(sentences/words)*100
CLI=(0.0588*L)-(0.296*S)-15.8
roundedCLI=round(CLI)
if roundedCLI>=16:
    print('Grade 16+')
else:
    print('Grade: ',roundedCLI)


from botorch.models import SingleTaskGP
from gpytorch.mlls import ExactMarginalLogLikelihood
from botorch.fit import fit_gpytorch_model
import torch
import pytest
from greattunes._best_response import _find_max_response_value, _update_max_response_value

def test_find_max_response_value_unit(custom_models_simple_training_data_4elements,
                                      tmp_best_response_class):
    """
    test finding of max response value
    """

    # data -- max at 4th element
    train_X = custom_models_simple_training_data_4elements[0]
    train_Y = custom_models_simple_training_data_4elements[1]

    # test class for all methods from greattunes._best_response --- only an infrastructure ease for
    # _find_max_reponse_value since it's a static method
    cls = tmp_best_response_class

    max_X, max_Y = cls._find_max_response_value(train_X, train_Y)

    # assert that max value is at index 3 (4th element)
    maxit = 3
    assert max_X[0].item() == train_X[maxit].item()
    assert max_Y[0].item() == train_Y[maxit].item()

def test_find_max_response_value_multivariate(training_data_covar_complex, tmp_best_response_class):
    """
    test that the right covariate row tensor is returned when train_X is multivariate
    """

    # data
    train_X = training_data_covar_complex[1]
    train_Y = training_data_covar_complex[2]

    # test class for all methods from greattunes._best_response --- only an infrastructure ease for
    # _find_max_reponse_value since it's a static method
    cls = tmp_best_response_class

    max_X, max_Y = cls._find_max_response_value(train_X, train_Y)

    # assert that max value is at index 1 (2nd element)
    maxit = 1
    for it in range(train_X.shape[1]):
        assert max_X[0,it].item() == train_X[maxit, it].item()
    assert max_Y[0].item() == train_Y[maxit].item()

def test_update_max_response_value_unit(custom_models_simple_training_data_4elements, tmp_best_response_class,
                                        custom_models_simple_training_data_4elements_covar_details, monkeypatch):
    """
    test that _update_max_response_value works for univariate data
    """

    # data -- max at 4th element
    train_X = custom_models_simple_training_data_4elements[0]
    train_Y = custom_models_simple_training_data_4elements[1]
    covar_details = custom_models_simple_training_data_4elements_covar_details[0]
    covar_mapped_names = custom_models_simple_training_data_4elements_covar_details[1]

    # test class
    cls = tmp_best_response_class

    # set some attributes
    cls.train_X = train_X
    cls.proposed_X = train_X
    cls.train_Y = train_Y
    cls.covar_details = covar_details
    cls.covar_mapped_names = covar_mapped_names

    # monkeypatch
    max_X = 1.0
    max_Y = 2.0
    def mock_find_max_response_value(train_X, train_Y):
        mX = torch.tensor([[max_X]], dtype=torch.double,
                          device=torch.device("cuda" if torch.cuda.is_available() else "cpu"))
        mY = torch.tensor([[max_Y]], dtype=torch.double,
                          device=torch.device("cuda" if torch.cuda.is_available() else "cpu"))
        return mX, mY
    monkeypatch.setattr(
        cls, "_find_max_response_value", mock_find_max_response_value
    )

    # test that it initializes storage of best results when none present
    cls._update_max_response_value()

    assert cls.covars_best_response_value[0].item() == max_X
    assert cls.best_response_value[0].item() == max_Y

@pytest.mark.parametrize(
    "response_sampled_iter, covars_best, response_best",
    [
        [3, [1.1], [2.2]],
        [10, [3.5, 12.2], [1.7]]
    ]
)
def test_current_best_univariate_unit(tmp_best_response_class, response_sampled_iter, covars_best, response_best):
    """
    test that current_best works for univariate and multivariate covariate data
    """

    # class used for test
    cls = tmp_best_response_class

    # set attribute
    cls.model = {"response_sampled_iter": response_sampled_iter}
    cls.covar_details = {}
    for i in range(len(covars_best)):
        tmp_key = "covar" + str(i)
        cls.covar_details[tmp_key] = {"guess": covars_best[i],
                                      "min": covars_best[i]-1,
                                      "max": covars_best[i]+1,
                                      "type": float,
                                      "columns": i,
                                      "pandas_column": i}
    cls.total_num_covars = len(covars_best)

    # set best response variables
    cls.covars_best_response_value = torch.tensor([covars_best], dtype=torch.double)
    cls.best_response_value = torch.tensor([response_best], dtype=torch.double)

    # run method
    cls.current_best()

    # assert
    for it in range(len(covars_best)):
        assert cls.best["covars"].values[0][it] == covars_best[it]
    assert cls.best["response"].values[0][0] == response_best[0]
    assert cls.best["iteration_when_recorded"] == response_sampled_iter

@pytest.mark.parametrize(
    "candidate, proposed_X, covars_sampled_iter",
    [
        [torch.tensor([[1]], dtype=torch.double), torch.tensor([[0.9]], dtype=torch.double), 1],  # univariate
        [torch.tensor([[1, 2, 3]], dtype=torch.double), torch.tensor([[0.9, 1.1, 200]], dtype=torch.double), 1],  # multivariate
        [torch.tensor([[1, 2, 3]], dtype=torch.double), torch.tensor([[0.9, 1.1, 200], [0, 1, 2]], dtype=torch.double), 2]  # multivariate and several historical entries
    ]
)
def test_update_proposed_data_works(tmp_best_response_class, candidate, proposed_X, covars_sampled_iter):
    """
    positive tests for the cases where "_update_proposed_data" works
    :param: tmp_best_response_class (test class defined in conftest.py)
    """

    # initialize temp class for running test
    cls = tmp_best_response_class

    # update attributes to run test
    cls.model = {
        "covars_sampled_iter": covars_sampled_iter,
        "covars_proposed_iter": 0,  # can initialize at any value, is updated relative to "covars_sampled_iter"
    }
    cls.proposed_X = proposed_X

    # run the test
    cls._update_proposed_data(candidate=candidate)

    # assert that cls.proposed_X has grown by one row
    assert cls.proposed_X.size()[0] == proposed_X.size()[0] + 1

    # assert content of that last row of cls.proposed_X
    for i in range(cls.proposed_X.size()[1]):
        assert cls.proposed_X[-1, i].item() == candidate[0, i].item()

@pytest.mark.parametrize(
    "candidate, proposed_X, covars_sampled_iter",
    [
        [torch.tensor([[1]], dtype=torch.double), torch.tensor([[0.9], [1.1]], dtype=torch.double), 1],
        [torch.tensor([[1, 2, 3]], dtype=torch.double), torch.tensor([[0.9, 1.1, 200], [1.1, 2.2, 4.3]], dtype=torch.double), 1],
        [torch.tensor([[1, 2, 3]], dtype=torch.double), torch.tensor([[0.9, 1.1, 200], [1.1, 2.2, 4.3], [0, 1, 2]], dtype=torch.double), 2]
    ]
)
def test_update_proposed_data_overwrite(tmp_best_response_class, candidate, proposed_X, covars_sampled_iter):
    """
    positive tests for the cases where "_update_proposed_data" overwrites last entry in self.proposed_X
    :param: tmp_best_response_class (test class defined in conftest.py)
    """

    # initialize temp class for running test
    cls = tmp_best_response_class

    # update attributes to run test
    cls.model = {
        "covars_sampled_iter": covars_sampled_iter,
        "covars_proposed_iter": 0,  # can initialize at any value, is updated relative to "covars_sampled_iter"
    }
    cls.proposed_X = proposed_X

    # run the test
    cls._update_proposed_data(candidate=candidate)

    # assert that cls.proposed_X has NOT grown
    assert cls.proposed_X.size()[0] == proposed_X.size()[0]

    # assert content of that last row of cls.proposed_X
    for i in range(cls.proposed_X.size()[1]):
        assert cls.proposed_X[-1, i].item() == candidate[0, i].item()

@pytest.mark.parametrize(
    "candidate", [torch.tensor([[1]], dtype=torch.double), torch.tensor([[1, 2, 3]], dtype=torch.double)]
)
def test_update_proposed_data_works_firs_entry(tmp_best_response_class, candidate):
    """
    positive tests for the cases where "_update_proposed_data" stores first set of candidate datapoints
    :param: tmp_best_response_class (test class defined in conftest.py)
    """

    # initialize temp class for running test
    cls = tmp_best_response_class

    # update attributes to run test. self.proposed_X is initialized as 'None' in conftest.py
    cls.model = {
        "covars_sampled_iter": 0,  # initialize at 0 for the test to work (no data points sampled yet)
        "covars_proposed_iter": 1,  # initialize at 1 since one datapoint has been proposed (can actually initialize at any value for _update_proposed_data to work)
    }

    # run the test
    cls._update_proposed_data(candidate=candidate)

    # assert that only a single candidate datapoint has been added
    assert cls.proposed_X.size()[0] == 1

    # assert that it's the right datapoint by comparing to 'candidate'
    for i in range(cls.proposed_X.size()[1]):
        assert cls.proposed_X[-1, i].item() == candidate[0, i].item()

@pytest.mark.parametrize(
    "candidate, proposed_X, error_msg",
    [
        [None, torch.tensor([[0.9], [1.1]], dtype=torch.double), "greattunes._best_response._update_proposed_data: provided variable is not 'candidate' of type torch.DoubleTensor (type of 'candidate' is " + str(type(None)) + ")"],
        [[1.1], torch.tensor([[0.9], [1.1]], dtype=torch.double), "greattunes._best_response._update_proposed_data: provided variable is not 'candidate' of type torch.DoubleTensor (type of 'candidate' is " + str(type([1.1])) + ")"],
        [torch.tensor([[1, 2]], dtype=torch.double), torch.tensor([[0.9], [1.1]], dtype=torch.double), "greattunes._best_response._update_proposed_data: wrong number of covariates provided in 'candidate'. Expected 1, but got 2"],
        [torch.tensor([[1, 2]], dtype=torch.double), torch.tensor([[0.9, 1.1, 200], [1.1, 2.2, 4.3], [0, 1, 2]], dtype=torch.double), "greattunes._best_response._update_proposed_data: wrong number of covariates provided in 'candidate'. Expected 3, but got 2"]
    ]
)
def test_update_proposed_data_fails(tmp_best_response_class, candidate, proposed_X, error_msg):
    """
    negative tests for "_update_proposed_data": wrong data types, wrong number of candidates
    :param: tmp_best_response_class (test class defined in conftest.py)
    """

    # initialize temp class for running test
    cls = tmp_best_response_class

    # update attributes to run test. self.proposed_X is initialized as 'None' in conftest.py
    cls.model = {
        "covars_sampled_iter": 0,  # initialize at 0 for the test to work (no data points sampled yet)
        "covars_proposed_iter": 1,
        # initialize at 1 since one datapoint has been proposed (can actually initialize at any value for _update_proposed_data to work)
    }
    cls.proposed_X = proposed_X

    # run the test
    with pytest.raises(AssertionError) as e:
        cls._update_proposed_data(candidate=candidate)
    assert str(e.value) == error_msg

@pytest.mark.parametrize(
    "maximize, result",
    [
        [True, 1],
        [False, 0],
    ]
)
def test_find_best_predicted_1d(tmp_best_response_class, monkeypatch, maximize, result):
    """"
    tests that the optimizing method indeed finds the maximum. Monkeypatching the function evaluation step
    """

    # defines temporary class
    tmp = tmp_best_response_class

    # add some attributes to tmp
    tmp.dtype = torch.double
    tmp.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    # add function to maximize
    def f(type, x):
        return torch.sin(x**2)

    monkeypatch.setattr(tmp, "_evaluate_model", f)

    # initialize x and type (ignore type in this test)
    #x_init = torch.rand(1).requires_grad_(True)
    x_init = torch.rand(1, 1, dtype=torch.double)
    type = "mean"

    # run the method
    y, x = tmp._find_best_predicted(x_init, type, maximize=maximize, max_iter=20)

    # assert
    assert abs(y-result) < 1e-3

@pytest.mark.parametrize(
    "maximize, result",
    [
        [True, 1],
        [False, 0],
    ]
)
def test_find_best_predicted_2d(tmp_best_response_class, monkeypatch, maximize, result):
    """"
    tests that the optimizing method indeed finds the maximum. Monkeypatching the function evaluation step
    """

    # defines temporary class
    tmp = tmp_best_response_class

    # add some attributes to tmp
    tmp.dtype = torch.double
    tmp.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    # add function to maximize
    def f(type, x):
        return (torch.sin(x[:,0]**2)*torch.sin(x[:,1]**2)).unsqueeze(1)

    monkeypatch.setattr(tmp, "_evaluate_model", f)

    # initialize x and type (ignore type in this test)
    #x_init = torch.rand(1, 2).requires_grad_(True)
    x_init = torch.rand(1, 2, dtype=torch.double)
    type = "mean"

    # run the method
    y,x = tmp._find_best_predicted(x_init, type, maximize=maximize, max_iter=20)

    # assert
    assert abs(y-result) < 1e-3

@pytest.mark.parametrize(
    "type, result",
    [
        ["mean", 1.2500295534805428],
        ["lower_conf", -2.440432203804888],
    ]
)
def test_evaluate_model(type, result):
    """
    test that method '_evaluate_model' works
    """

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    dtype = torch.double

    # define training data
    train_X = torch.tensor([[1, 2, 3], [1, 2, 3]], dtype=dtype, device=device)
    train_Y = torch.tensor([[1], [1.5]], dtype=dtype, device=device)

    # define and train model
    mymodel = SingleTaskGP(train_X=train_X, train_Y=train_Y)
    ll = ExactMarginalLogLikelihood(mymodel.likelihood, mymodel)
    fit_gpytorch_model(ll)

    # construct temporary class
    class Tmp:
        def __init__(self, mymodel):
            self.model = {"model": mymodel}

        from greattunes._best_response import _evaluate_model

    cls = Tmp(mymodel)

    # data point to investigate
    x = torch.tensor([[2, 3, 4]], dtype=dtype, device=device)

    # run method
    y = cls._evaluate_model(type=type, x=x)

    # assert
    assert isinstance(y, torch.DoubleTensor)

    ERROR_LIM = 1e-8
    assert abs(y.item()-result) <= ERROR_LIM


import requests
import tqdm
import os
from bs4 import BeautifulSoup
base = input('Enter Album URL code: ')
url = 'https://freeallmusic.top/track/' + base + '/'
i = 1
first = 1
last = int(input('Enter total number of tracks: '))
inf = {'Title': 0}
albumUrl = 'https://freeallmusic.top/album/' + base
a = requests.get(albumUrl)
soup = BeautifulSoup(a.text, features="html.parser")
a = soup.findAll ('meta', {'property': 'og:title'})
print(a)
b = str(a[0])
# b.encode(encoding='UTF-8',errors='strict')
start = b.find('content') + 9
c = b[start:]
end = c.find('property') - 8
album = b[start:start+end+6]
os.makedirs('downloads/' + album + '/', exist_ok=True)

# Download Function

def download(i = first):
    if(i < 10):
        song_url = url + '10' + str(i)
    else:
        song_url = url + '1' + str(i)

    a = requests.get(song_url)
    soup = BeautifulSoup(a.text, features="html.parser")
    a = soup.findAll ('a', {'class': 'text-danger'})
    b = str(a[0])
    # b.encode(encoding='UTF-8',errors='strict')
    start = b.find('href') + 6
    c = b[start:]
    end = c.find('"') - 6
    url_next = b[start:start+end+6]
    # url_next = b[start:end]

    s = requests.Session()
    a = requests.get(url_next)
    soup = BeautifulSoup(a.text, features="html.parser")
    title = soup.findAll ('a', {'class': 'text-sm text-muted'})
    print(title)
    title = str(title[0])
    print(title[0])
    start = title.find('>') + 1
    c = title[start:]
    end = c.find('<') - 1
    title = title[start:start+end+1]
    a = soup.findAll ('a', {'class': 'btn-outline-success'})
    b = str(a[0])
    b = str(b)
    start = b.find('href') + 6
    c = b[start:]
    end = c.find('"') - 6
    url_dl = b[start:start+end+6]
    s.headers.update({'referer': url_next}) #url_next needs to be passed as the referer header for the get request
    p = s.get(url_dl)

    # Sanitize Special Characters while writing file
    set = '<>:"/\|?*'
    for c in set:
        title = title.replace(c, ';')

    open('downloads/'+album + '/'+title+'.mp3', 'wb').write(p.content)
    inf[title] = i

# Download Function Ends Here

print('Downloading...\n')
for i in tqdm.tqdm(range(first, last +1), unit='song'):
    download(i)

print('\nVerifying...\n')
i = 0
for filename in tqdm.tqdm(os.listdir('downloads/'+album + '/'), unit='song'):

    info = os.stat('./downloads/'+ album + '/'+  filename)
    if info.st_size < 500000:
        print('Error in ' + filename + '. Trying again.')
        os.remove('./downloads/' + album + '/'+ filename)
        download(inf[filename[:-4]])
        if info.st_size < 500000:
            print('Error in ' + filename + ' again. Try again after a few minutes.')
            os.remove('./downloads/' + album + '/'+ filename)

print('Finished Downloading!')


from TwitterSearch import *
import dictionary
import keys
from tweepy import *

def find_keywords(data):
    words = data.split()
    query = []

    for word in words:
        if word.lower() in dictionary.computer_science:
            query.append("#" + word)

    return query

def search_results(words):

    #auth = OAuthHandler(keys.consumer_key, keys.consumer_secret)
    #auth.set_access_token(keys.access_token, keys.access_token_secret)

    try:

        tso = TwitterSearchOrder()
        tso.set_keywords(words)

        rilo_twitter = TwitterSearch(
            consumer_key = keys.consumer_key,
            consumer_secret = keys.consumer_secret,
            access_token = keys.access_token,
            access_token_secret = keys.access_token_secret
            )

        for tweet in rilo_twitter.search_tweets_iterable(tso):
            if  tweet['retweet_count'] > 150:
                #API.retweet(tweet['id'])
                print('@%s tweeted:  %s' % (tweet['user']['screen_name'], tweet['text']))
                print('\n\n\n')

    except TwitterSearchException as e:
        print (e)

def run_app(q):
    x = find_keywords(q)
    return search_results(x)
#print x


import sys
from collections import deque
inp = lambda : sys.stdin.readline().split()
n, m = map(int, inp())
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]
q = deque()
maps = []
res = [[-1] * m for _ in range(n)]
for i in range(n):
    line = list(map(int, inp()))
    maps.append(line)
    for j in range(m):
        if line[j] == 2:
            q.append((i, j))
            res[i][j] = 0
        elif not line[j]:
            # 0인 좌표는 어차피 못 가는 곳
            res[i][j] = 0
while q:
    x, y = q.popleft()
    for i in range(4):
        nx, ny = x + dx[i], y + dy[i]
        if nx < 0 or nx >= n or ny < 0 or ny >= m: continue
        ## 아직 방문하지 않은 좌표
        if res[nx][ny] == -1:
            if maps[nx][ny]:
                res[nx][ny] = res[x][y] + 1
                q.append((nx, ny))
for r in res:
    print(*r)


def reverse_GGGGotate(movebit):
    # Reverse the GGGGotate function to recover the original value (lol)
    if movebit & 1:
        movebit &= 254  # Clear the last bit if it is set
        lol = (movebit >> 1) + 128
    else:
        lol = movebit >> 1
    return lol

def reverse_code(ListMoveBit):
    ORD_value = []
    Index_Value = 0

    for i in range(1, len(ListMoveBit)):
        Index_Value += 1

    # Reversing the loop to reconstruct the original ORD_value
    for i in range(len(ListMoveBit) - 1, 0, -1):
        lol = reverse_GGGGotate(ListMoveBit[i]) ^ int(ListMoveBit[Index_Value - 1])
        ORD_value.insert(0, lol)
        Index_Value -= 1

    return ORD_value, Index_Value

# Provided final value
ListMoveBit = [42, 158, 219, 95]

# Run the reverse code to recover the initial ORD_value and set Index_Value
recovered_ORD_value, recovered_Index_Value = reverse_code(ListMoveBit.copy())

# Check if the recovered ORD_value matches the provided ORD_value
print("Recovered ORD_value:", recovered_ORD_value)
# Output: [116, 101, 115, 116]

# Check if the recovered Index_Value matches the provided Index_Value
print("Recovered Index_Value:", recovered_Index_Value)
# Output: 0


from rest_framework import status
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet

from film.models import Film, Comment
from film.serializers import FilmsSerializer, CommentsSerializer
from film.tasks import populate_with_swapi

# class AccountViewsSet(ViewSet):
#     login_serializer_class = AuthTokenSerializer
#     signup_serializer_class = SignupSerializer
#

class FilmsViewSet(ViewSet):
    film_serializer_class = FilmsSerializer
    comment_serializer_class = CommentsSerializer
    pagination_class = PageNumberPagination

    @property
    def paginator(self):
        """
        The paginator instance associated with the view, or `None`.
        """
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        return self._paginator

    def paginate_queryset(self, queryset):
        """
        Return a single page of results, or `None` if pagination is disabled.
        """
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)

    def get_paginated_response(self, data):
        """
        Return a paginated style `Response` object for the given output data.
        """
        assert self.paginator is not None
        return self.paginator.get_paginated_response(data)

    @action(methods=['GET'], detail=False, )
    def films(self, request):
        """get list of films"""
        data = Film.objects.all().order_by('-release_date').values()
        page = self.paginate_queryset(data)
        if page is not None:
            serializer = self.film_serializer_class(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.film_serializer_class(data, many=True)
        return Response(serializer.data)

    @action(methods=['GET'], detail=False, )
    def comments(self, request):
        """get list of comments"""
        self.name = "Comment"
        self.description = "List of comments"
        """get list comments for a film"""
        data = Comment.objects.all().order_by('-created')
        page = self.paginate_queryset(data)
        if page is not None:
            serializer = self.comment_serializer_class(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.comment_serializer_class(data, many=True)
        return Response(serializer.data)

    @action(methods=['POST'], detail=False, )
    def comment_add(self, request):
        """add a comment to a film"""
        self.name = "Add Comment"
        self.description = "Post comments"
        data = request.data
        serializer = self.comment_serializer_class(data=data)
        if serializer.is_valid():
            serializer.save()
        else:
            return Response({'message', 'comment not created'}, status=status.HTTP_400_BAD_REQUEST)
        return Response({'message', 'comment created'}, status=status.HTTP_201_CREATED)

    @action(methods=['PUT'], detail=True)  # PUT for updating a film
    def film_update(self, request, pk):
        try:
            film = Film.objects.get(pk=pk)
        except Film.DoesNotExist:
            return Response({'message': 'Film not found'}, status=status.HTTP_404_NOT_FOUND)

        serializer = self.film_serializer_class(film, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'message': 'Film updated'}, status=status.HTTP_200_OK)
        else:
            return Response({'message': 'Invalid data for updating film'}, status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['DELETE'], detail=True)  # DELETE for deleting a film
    def film_delete(self, request, pk):
        try:
            film = Film.objects.get(pk=pk)
        except Film.DoesNotExist:
            return Response({'message': 'Film not found'}, status=status.HTTP_404_NOT_FOUND)

        film.delete()
        return Response({'message': 'Film deleted'}, status=status.HTTP_204_NO_CONTENT)

    @action(methods=['PUT'], detail=True)  # PUT for updating a comment
    def comment_update(self, request, pk):
        try:
            comment = Comment.objects.get(pk=pk)
        except Comment.DoesNotExist:
            return Response({'message': 'Comment not found'}, status=status.HTTP_404_NOT_FOUND)

        serializer = self.comment_serializer_class(comment, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'message': 'Comment updated'}, status=status.HTTP_200_OK)
        else:
            return Response({'message': 'Invalid data for updating comment'}, status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['DELETE'], detail=True)  # DELETE for deleting a comment
    def comment_delete(self, request, pk):
        try:
            comment = Comment.objects.get(pk=pk)
        except Comment.DoesNotExist:
            return Response({'message': 'Comment not found'}, status=status.HTTP_404_NOT_FOUND)

        comment.delete()
        return Response({'message': 'Comment deleted'}, status=status.HTTP_204_NO_CONTENT)

    @action(detail=True, methods=['GET'])
    def comments_for_film(self, request, pk=None):
        try:
            film = Film.objects.get(pk=pk)
        except Film.DoesNotExist:
            return Response({'message': 'Film not found'}, status=status.HTTP_404_NOT_FOUND)

        data = Comment.objects.filter(film=film).order_by('created')
        page = self.paginate_queryset(data)
        if page is not None:
            serializer = self.comment_serializer_class(data, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.comment_serializer_class(data, many=True)

        return Response(serializer.data)

    @action(methods=['POST'], detail=False, )
    def swapi_callback(self, request):
        """webhook to get updates"""
        data = request.data

        if data.get("event", None) == "update":
            # run update on the database
            populate_with_swapi.delay()
            return Response({'message', 'update received'}, status=status.HTTP_200_OK)
        else:
            # ignore
            return Response({'message', 'event received'}, status=status.HTTP_200_OK)


from math import sqrt
from kin_emg_plot import planes

import pandas as pd
import statsmodels.api as sm

def find_cmc(data1, data2, data3, joint):

    df = pd.DataFrame([data1[joint],  data2[joint],  data3[joint]]).transpose()
    df.columns =  ['X1', 'X2', 'X3']
    cmc_v = []
    for run in range(df.shape[1]):
        if run == 2:
            X, y = df[df.columns[run]], df[df.columns[run - 2]]
        else:
            X, y = df[df.columns[run]], df[df.columns[run + 1]]
        X1 = sm.add_constant(X)
        model = sm.OLS(y, X1).fit()
        rsa = model.rsquared_adj
        cmc_v.append(sqrt(abs(rsa)))
    # print(cmc_v, cmc_avg)
    cmc_v = [round(cmc_v[_], 3) for _ in range(len(cmc_v))]
    return cmc_v

def cmc(df1, df2, df3, runs):
    cmc_total = []
    cmc_avg_total = []
    index = []
    planes_dict = planes()
    planes_v = planes_dict['sagittal'] + planes_dict['frontal'] + planes_dict['transverse']
    joints = ['ac' + joint for joints in planes_v for joint in joints]

    for joint in joints:
        cmc_v = find_cmc(df1, df2, df3, joint)
        cmc_avg = round(sum(cmc_v) / len(cmc_v), 3)
        cmc_total.append(cmc_v)
        cmc_avg_total.append(cmc_avg)
        index.append(joint)

    planes_titles =  planes_dict['sagittal_titles'] + planes_dict['frontal_titles'] + planes_dict['transverse_titles']
    index_2d = [[title + ' Derecha', title + ' Izquierda'] for title in planes_titles]
    index = [title for titles in index_2d for title in titles]      #flatten vector
    columns = [f'{runs[0]}-{runs[1]}', f'{runs[1]}-{runs[2]}', f'{runs[0]}-{runs[2]}']

    df = pd.DataFrame(cmc_total, columns=columns, index=index)
    df2 = pd.DataFrame(cmc_avg_total, columns=['Total'], index=index)
    df2save = pd.concat([df, df2], axis=1)

    return df2save


# -*- coding: UTF-8 -*-
"""
title: 寻找峰值
A peak element is an element that is strictly greater than its neighbors.
Given an integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.
You may imagine that nums[-1] = nums[n] = -∞.
You must write an algorithm that runs in O(log n) time.

Example 1:
Input: nums = [1,2,3,1]
Output: 2
Explanation: 3 is a peak element and your function should return the index number 2.

Example 2:
Input: nums = [1,2,1,3,5,6,4]
Output: 5
Explanation: Your function can return either index number 1 where the peak element is 2, or index number 5 where the peak element is 6.

Constraints:
1 <= nums.length <= 1000
-2^31 <= nums[i] <= 2^31 - 1
nums[i] != nums[i + 1] for all valid i.
"""
from typing import List

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        """
        二分查找。若nums[0] > nums[1]，则nums[0]也是峰值；同理，若nums[n-1] > nums[n-2]，则nums[n-1]也是峰值。
        若 nums[mid - 1] < nums[mid] > nums[mid + 1]，则nums[mid]就是要找的峰值；
        若 nums[mid - 1] > nums[mid] > nums[mid + 1]，则nums[mid - 1]可能为峰值，因此向左走；
        若 nums[mid - 1] < nums[mid] < nums[mid + 1]，则nums[mid + 1]可能为峰值，因此向右走；
        若 nums[mid - 1] > nums[mid] < nums[mid + 1]，则nums[mid - 1]、nums[mid + 1]都有可能为峰值，因此可以随机一个方向，假定为向右走。
        因此，若 nums[mid] < nums[mid + 1]，则向右走；否则向左走。
        """
        left, right = 0, len(nums) - 1
        # 退出循环时，left == right，也就确定了最终的峰值所在列
        while left < right:
            mid = (left + right) // 2
            # mid 取不到 right，即 mid < len(nums) - 1，所以 mid+1 < len(nums)
            if nums[mid] < nums[mid + 1]:
                # 此时的mid不可能是峰值所在列
                left = mid + 1
            else:
                # 此时 nums[mid] > nums[mid + 1]，因为 nums[i] != nums[i + 1] for all valid i.
                # 此时的mid有可能是峰值所在列
                right = mid
        # 注意：是返回下标，而不是返回元素值
        return left

if __name__ == '__main__':
    print(Solution().findPeakElement([1, 2, 1, 3, 5, 6, 4]))


import sys
from unittest import TestCase

from xsdata.codegen.models import Restrictions

class RestrictionsTests(TestCase):
    def setUp(self) -> None:
        self.restrictions = Restrictions(
            min_occurs=1,
            max_occurs=1,
            min_exclusive="1.1",
            min_inclusive="1",
            min_length=1,
            max_exclusive="1",
            max_inclusive="1.1",
            max_length=10,
            total_digits=333,
            fraction_digits=2,
            length=5,
            white_space="collapse",
            pattern=r"[A-Z]",
            explicit_timezone="+1",
            nillable=True,
            path=[("s", 0, 1, 1)],
            process_contents="skip",
        )

    def test_property_is_list(self):
        restrictions = Restrictions()
        self.assertFalse(restrictions.is_list)

        restrictions.max_occurs = 1
        self.assertFalse(restrictions.is_list)

        restrictions.max_occurs = 2
        self.assertTrue(restrictions.is_list)

    def test_property_is_prohibited(self):
        self.assertFalse(Restrictions().is_prohibited)
        self.assertTrue(Restrictions(max_occurs=0).is_prohibited)

    def test_merge(self):
        source = Restrictions(min_length=2, max_length=10, format="base16")
        target = Restrictions(min_length=1, pattern=r"[A-Z]")

        target.merge(source)

        self.assertEqual(2, target.min_length)
        self.assertEqual(10, target.max_length)
        self.assertEqual(r"[A-Z]", target.pattern)
        self.assertEqual("base16", target.format)

    def test_merge_ignore_nillable(self):
        parent = Restrictions(nillable=True)
        child = Restrictions()

        child.merge(parent)
        self.assertIsNone(child.nillable)

        child.nillable = False
        child.merge(parent)
        self.assertFalse(child.nillable)

    def test_merge_occurs(self):
        a = Restrictions()
        b = Restrictions()

        a.merge(b)

        self.assertIsNone(a.min_occurs)
        self.assertIsNone(a.max_occurs)

        b.min_occurs = 0
        b.max_occurs = 1
        a.merge(b)
        self.assertEqual(0, a.min_occurs)
        self.assertEqual(1, a.max_occurs)

    def test_asdict(self):
        expected = {
            "explicit_timezone": "+1",
            "fraction_digits": 2,
            "length": 5,
            "max_exclusive": "1",
            "max_inclusive": "1.1",
            "max_length": 10,
            "min_exclusive": "1.1",
            "min_inclusive": "1",
            "min_length": 1,
            "nillable": True,
            "pattern": "[A-Z]",
            "process_contents": "skip",
            "total_digits": 333,
            "white_space": "collapse",
        }
        self.assertEqual(expected, self.restrictions.asdict())

        self.restrictions.nillable = None

        del expected["nillable"]
        expected["required"] = True
        self.assertEqual(expected, self.restrictions.asdict())

    def test_asdict_with_types(self):
        expected = {
            "explicit_timezone": "+1",
            "fraction_digits": 2,
            "length": 5,
            "max_exclusive": 1.0,  # str -> float
            "max_inclusive": 1.1,  # str -> float
            "max_length": 10,
            "min_exclusive": 1.1,  # str -> float
            "min_inclusive": 1.0,  # str -> float
            "min_length": 1,
            "nillable": True,
            "pattern": "[A-Z]",
            "process_contents": "skip",
            "total_digits": 333,
            "white_space": "collapse",
        }
        self.assertEqual(expected, self.restrictions.asdict(types=[float]))

    def test_asdict_with_implied_types(self):
        restrictions = Restrictions(min_occurs=1, max_occurs=4)
        self.assertEqual({"max_occurs": 4, "min_occurs": 1}, restrictions.asdict())

        restrictions.min_occurs = 0
        self.assertEqual({"max_occurs": 4}, restrictions.asdict())

        restrictions.max_occurs = sys.maxsize
        self.assertEqual({}, restrictions.asdict())

    def test_clone(self):
        restrictions = Restrictions(max_occurs=2)
        clone = restrictions.clone()

        self.assertEqual(clone, restrictions)
        self.assertIsNot(clone, restrictions)


import time
import random

class SeedManager:
    # 初始化
    def __init__(self):
        self.seed_file = "seed"  # 种子文件名称
        self.entropy_file = "entropy"  # 熵源文件名称
        self.accumulator = None  # 初始化累加器
        self.seed_itv = 600  # 重新产生种子文件的时间间隔
        self.last_seed_time = time.time()  # 上一次重新产生种子的时间
        self.source = 0   # 源编号
        self.index = 0   # 熵池编号

    # 写入种子文件
    def write_seed_file(self):
        with open(self.seed_file, 'wb') as f:
            f.write(self.accumulator.pseudo_random_data(64))

    # 更新种子文件
    def update_seed_file(self, accumulator):
        self.accumulator = accumulator
        self.write_seed_file()
        # 超过时间间隔，则重新产生一次种子文件
        if time.time() - self.last_seed_time >= self.seed_itv:
            with open(self.seed_file, 'rb+') as f:
                s = f.read()
                assert len(s) == 64
                self.accumulator.generator.reseed(s)
                f.seek(0)  # 文件指针移到开头
                f.truncate()  # 清空文件
                f.write(self.accumulator.pseudo_random_data(64))   # 重新写入文件
            self.last_seed_time = time.time()   # 更新时间

        # 向累加器中添加随机事件
        with open(self.entropy_file, 'rb') as random_event_source:
            max_rand = len(random_event_source.read()) // 32
            random_event_source.seek(random.randint(1, max_rand), 0)
            event = random_event_source.read(random.randint(1, 32))  # 随机读取熵源，作为随机事件
            self.accumulator.add_random_event(s=self.source, i=self.index, e=event)
            self.source = (self.source + 1) % 256
            self.index = (self.index + 1) % 32   # 编号都自增


import asyncio
import aiohttp

from typing import List, Tuple, Dict

async def get_answer(context: List[Dict[str, str]]) -> str:
    api_url = "https://patient-buck-weekly.ngrok-free.app/get_answer"
    payload = {
        "context": context
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(api_url, json=payload) as response:
            answer = await response.json()
            return answer

async def get_rand_question() -> Tuple[str, str]:
    api_url = "https://patient-buck-weekly.ngrok-free.app/get_rand_question"
    async with aiohttp.ClientSession() as session:
        async with session.get(api_url) as response:
            response_json = await response.json()
            question_id = response_json["question_id"]
            question = response_json["question"]
            return question_id, question

async def check_answer(question_id: str, answer: str) -> Tuple[float, str]:
    api_url = "https://patient-buck-weekly.ngrok-free.app/check_answer"
    payload = {
        "question_id": question_id,
        "answer": answer,
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(api_url, json=payload) as response:
            response_json = await response.json()
            return response_json["answer_coef"], response_json["expected_answer"]


with open("_input/day6.txt", encoding='utf8') as f:
    input = f.read()

def check(items):
    sortedItems = sorted(items)
    for i in range(1, len(sortedItems)):
        if sortedItems[i-1] == sortedItems[i]: return False
    return True

def findMarker(length):
    for i in range(length, len(input)):
        result = check(list(input[i-length:i]))
        if (result == True):
            return i

print(f'part 1 is {findMarker(4)}, part 2 is {findMarker(14)}')


import numpy as np

class HMM(object):
    """
    Training for Hidden Markov Model (HMM).

    Methods:
    --------------------------------------------------------
    learn_initial: learn the initial probality for the sequence
    learn_transition: learn the transition probality matrix for the sequence
    """

    def __init__(self, sequence, state):

        """
        Parameters:
        -------------------------------
        sequence: np.array, a time series
        state: int, the number of state
        """
        self.sequence = sequence
        self.state = state

    def learn_initial(self):

        """
        learn the initial probality for the sequence
        """

        ini_pro = np.zeros((self.state))

        unique, counts = np.unique(self.sequence, return_counts=True)
        unique = unique.astype('int64')
        ini_pro[unique] = counts

        return ini_pro/ini_pro.sum()

    def learn_transfer(self):

        """
        learn the transition probality matrix for the sequence
        """

        trans_pro = np.zeros((self.state, self.state))

        for time in range(len(self.sequence)-1):
            trans_pro[int(self.sequence[time])][int(self.sequence[time+1])]+=1

        for column in xrange(self.state):
            if trans_pro[:,column].any()==0:
                trans_pro[:,column] = np.ones((self.state))

        return trans_pro.T/np.sum(trans_pro, axis =1)


#!/usr/bin/env python3

import sys
import os

filename = os.path.basename(__file__).split(".")[0][:-1] + ".txt"
if len(sys.argv) > 1:
    filename = sys.argv[1]

with open(filename) as f:
    points = set()
    line = f.readline()
    while "," in line:
        x, y = line.strip("\n").split(",")
        points.add((int(x), int(y)))
        line = f.readline()
    folds = f.readlines()
    for fold in folds:
        axis = fold[11]
        c = int(fold[13:].strip("\n"))
        _points = set()
        for (x, y) in points:
            if axis == "x":
                if x > c:
                    x = 2 * c - x
                _points.add((x, y))
            if axis == "y":
                if y > c:
                    y = 2 * c - y
                _points.add((x, y))
        points = _points
    max_x = max(points, key=lambda p: p[0])[0]
    max_y = max(points, key=lambda p: p[1])[1]
    _points = []
    for i in range(max_y + 1):
        _points.append(["."] * (max_x + 1))
    for (x, y) in points:
        _points[y][x] = "#"
    for line in _points:
        print("".join(line))


#!/usr/bin/python

from math import sqrt
import sys
import argparse
from collections import deque
from struct import pack, unpack
import numpy as np

from osgeo import gdal
import math
import decimal

from concavehull import ConcaveHull

gdal.UseExceptions()
gdal.TermProgress = gdal.TermProgress_nocb

#
# NormalVector
#
# Calculate the normal vector of a triangle. (Unit vector perpendicular to
# triangle surface, pointing away from the "outer" face of the surface.)
# Computed using 32-bit float operations for consistency with other tools.
#
# Parameters:
#  triangle vertices (nested x y z tuples)
#
# Returns:
#  normal vector (x y z tuple)
#
def NormalVector(t):
    (ax, ay, az) = t[0]
    (bx, by, bz) = t[1]
    (cx, cy, cz) = t[2]

    # first edge
    e1x = np.float32(ax) - np.float32(bx)
    e1y = np.float32(ay) - np.float32(by)
    e1z = np.float32(az) - np.float32(bz)

    # second edge
    e2x = np.float32(bx) - np.float32(cx)
    e2y = np.float32(by) - np.float32(cy)
    e2z = np.float32(bz) - np.float32(cz)

    # cross product
    cpx = np.float32(e1y * e2z) - np.float32(e1z * e2y)
    cpy = np.float32(e1z * e2x) - np.float32(e1x * e2z)
    cpz = np.float32(e1x * e2y) - np.float32(e1y * e2x)

    # return cross product vector normalized to unit length
    mag = np.sqrt(np.power(cpx, 2) + np.power(cpy, 2) + np.power(cpz, 2))
    return cpx / mag, cpy / mag, cpz / mag

def cal_ang(point_1, point_2, point_3):
    """
    根据三点坐标计算夹角
    :param point_1: 点1坐标
    :param point_2: 点2坐标
    :param point_3: 点3坐标
    :return: 返回任意角的夹角值，这里只是返回点2的夹角
    """
    a = decimal.Decimal(math.sqrt(
        (point_2[0] - point_3[0]) * (point_2[0] - point_3[0]) + (point_2[1] - point_3[1]) * (point_2[1] - point_3[1])))
    b = decimal.Decimal(math.sqrt(
        (point_1[0] - point_3[0]) * (point_1[0] - point_3[0]) + (point_1[1] - point_3[1]) * (point_1[1] - point_3[1])))
    c = decimal.Decimal(math.sqrt(
        (point_1[0] - point_2[0]) * (point_1[0] - point_2[0]) + (point_1[1] - point_2[1]) * (point_1[1] - point_2[1])))
    # print(point_1, point_2, point_3, a, b, c)
    A = math.degrees(math.acos(decimal.Decimal((a * a - b * b - c * c) / (-2 * b * c))))
    B = math.degrees(math.acos(decimal.Decimal((b * b - a * a - c * c) / (-2 * a * c))))
    # print((c * c - a * a - b * b) / (-2 * a * b))
    C = math.degrees(math.acos(decimal.Decimal((c * c - a * a - b * b) / (-2 * a * b))))

    return [A, B, C]

# stlwriter is a simple class for writing binary STL meshes.
# Class instances are constructed with a predicted face count.
# The output file header is overwritten upon completion with
# the actual face count.
class stlwriter():

    # path: output binary stl file path
    # facet_count: predicted number of facets
    def __init__(self, path, facet_count=0):
        self.f = open(path, 'wb')

        # track number of facets actually written
        self.written = 0

        # write binary stl header with predicted facet count
        self.f.write(str.encode('\0' * 80))
        # (facet count is little endian 4 byte unsigned int)
        self.f.write(pack('<I', facet_count))

    # t: ((ax, ay, az), (bx, by, bz), (cx, cy, cz))
    def add_facet(self, t):
        # facet normals and vectors are little endian 4 byte float triplets
        # strictly speaking, we don't need to compute NormalVector,
        # as other tools could be used to update the output mesh.
        self.f.write(pack('<3f', *NormalVector(t)))
        for vertex in t:
            self.f.write(pack('<3f', *vertex))
        # facet records conclude with two null bytes (unused "attributes")
        self.f.write(str.encode('\0\0'))
        self.written += 1

    def done(self):
        # update final facet count in header before closing file
        self.f.seek(80)
        self.f.write(pack('<I', self.written))
        self.f.close()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.done()

def fail(msg):
    print(msg)
    exit(1)

def log(msg):
    if args.verbose:
        print(msg)

ap = argparse.ArgumentParser(description='Convert a GDAL raster (like a GeoTIFF heightmap) to an STL terrain surface.')
ap.add_argument('-x', action='store', default=0.0, type=float, help='Fit output x to extent (mm)')
ap.add_argument('-y', action='store', default=0.0, type=float, help='Fit output y to extent (mm)')
optg_z = ap.add_mutually_exclusive_group()
optg_z.add_argument('-z', action='store', default=None, type=float,
                    help='Z scale expressed as a vertical scale factor (1)')
optg_z.add_argument('-s', action='store', default=None, type=float,
                    help='Z scale expressed as a ratio of vertical units per horizontal unit (1)')
ap.add_argument('-b', '--base', action='store', default=0.0, type=float, help='Base height (0)')
ap.add_argument('-c', '--clip', action='store_true', default=False, help='Clip z to minimum elevation')
ap.add_argument('-v', '--verbose', action='store_true', default=False, help='Print log messages')
ap.add_argument('--band', action='store', default=1, type=int, help='Raster data band (1)')
ap.add_argument('-m', '--minimum', action='store', default=None, type=float,
                help='Omit vertices below minimum elevation')
ap.add_argument('-M', '--maximum', action='store', default=None, type=float,
                help='Omit vertices above maximum elevation')
optg_region = ap.add_mutually_exclusive_group()
optg_region.add_argument('-w', '--window', action='store', default=None, type=float, nargs=4,
                         help='Opposing corner coordinates in geographic CRS')
optg_region.add_argument('-p', '--pixels', action='store', default=None, type=float, nargs=4,
                         help='Opposing corner coordinates in pixel coordinates')
ap.add_argument('RASTER', help='Input heightmap image')
ap.add_argument('STL', help='Output STL path')
args = ap.parse_args()

try:
    img = gdal.Open(args.RASTER)
except RuntimeError as e:
    fail(str(e).strip())

# input raster dimensions
w = img.RasterXSize
h = img.RasterYSize
log("raster dimensions = (%s, %s)" % (str(w), str(h)))

# get default transformation from image coordinates to world coordinates
# note that since we obtain this transformation before making any region
# selection, and since this transformation is used for output, subset
# window regions will be aligned correctly in output stl coordinates.
t = img.GetGeoTransform()

git = gdal.InvGeoTransform(t)[1]
log("geo->pixel transform: %s" % str(git))

if args.window is not None:
    # if a geographic window is specified, convert it to a pixel window in input raster coordinates

    # apply inverse geo transform to window points
    px0, py0 = gdal.ApplyGeoTransform(git, args.window[0], args.window[1])
    px1, py1 = gdal.ApplyGeoTransform(git, args.window[2], args.window[3])

    # set arg.pixels to obtained pixel points
    args.pixels = [px0, py0, px1, py1]

if args.pixels is None:
    # if no pixel extent window is specified, use whole input raster.
    xmin = 0
    ymin = 0
    ww = w
    wh = h
else:
    # if a pixel extent window is specified (either directly with --pixels or
    # derived from a geographic --window), clip it to the input raster extent.

    xmin = int(round(min(args.pixels[0], args.pixels[2])))
    ymin = int(round(min(args.pixels[1], args.pixels[3])))

    xmax = int(round(max(args.pixels[0], args.pixels[2])))
    ymax = int(round(max(args.pixels[1], args.pixels[3])))

    if xmin >= w:
        fail("Region of interest lies entirely outside raster (xmin)")

    if ymin >= h:
        fail("Region of interest lies entirely outside raster (ymin")

    if xmax <= 0:
        fail("Region of interest lies entirely outside raster (xmax)")

    if ymax <= 0:
        fail("Region of interest lies entirely outside raster (ymax)")

    # if we passed those tests, at least part of the window overlaps the raster,
    # so we can safely clip to the raster extent and still have something

    if xmin < 0:
        xmin = 0

    if ymin < 0:
        ymin = 0

    if xmax > w:
        xmax = w

    if ymax > h:
        ymax = h

    ww = xmax - xmin
    wh = ymax - ymin

log("xmin, ymin = %d, %d" % (xmin, ymin))
log("ww, wh = %d, %d" % (ww, wh))

# output mesh dimensions are one row and column less than raster window
mw = ww - 1
mh = wh - 1

# save x pixel size if needed for scaling
xyres = abs(t[1])

# Apply z scale factor, if any
if args.z is not None:
    zscale = args.z
elif args.s is not None:
    zscale = 1.0 / args.s
else:
    zscale = 1.0

# recalculate z scale and xy transform if different dimensions are requested
if args.x != 0.0 or args.y != 0.0:

    # recaculate xy scale based on requested x or y dimension
    # if both x and y dimension are set, select smaller scale
    if args.x != 0.0 and args.y != 0.0:
        pixel_scale = min(args.x / mw, args.y / mh)
    elif args.x != 0.0:
        pixel_scale = args.x / mw
    elif args.y != 0.0:
        pixel_scale = args.y / mh

    # adjust z scale to maintain proportions with new xy scale
    zscale *= pixel_scale / xyres

    # revise transformation matrix
    # image: 0,0 at top left corner of top left pixel (0.5,0.5 at pixel center)
    t = (
        -pixel_scale * mw / 2.0,  # 0 left edge of top left pixel
        pixel_scale,  # 1 pixel width
        0,  # 2
        pixel_scale * mh / 2.0,  # 3 top edge of top left pixel
        0,  # 4
        -pixel_scale  # 5 pixel height
    )

log("transform = %s" % str(t))

band = img.GetRasterBand(args.band)
nd = band.GetNoDataValue()

# map GDAL pixel data type to corresponding struct format character
typemap = {
    gdal.GDT_Byte: 'B',
    gdal.GDT_UInt16: 'H',
    gdal.GDT_Int16: 'h',
    gdal.GDT_UInt32: 'I',
    gdal.GDT_Int32: 'i',
    gdal.GDT_Float32: 'f',
    gdal.GDT_Float64: 'd'
}

typeName = gdal.GetDataTypeName(band.DataType)
if band.DataType not in typemap:
    fail('Unsupported data type: %s' % typeName)

# rowformat is used to unpack a row of raw image data to numeric form
rowformat = typemap.get(band.DataType) * ww
log("data type = %s" % typeName)
log("type format = %s" % typemap.get(band.DataType))

# min, max, mean, sd; min used for z clipping
stats = band.GetStatistics(True, True)
log("min, max, mean, sd = %s" % str(stats))

# zmin is subtracted from elevation values
if args.clip == True:
    zmin = stats[0]
    zmax = stats[1]
else:
    zmin = stats[0]
    zmax = stats[1]
log("zmin = %s, zmax= %s" % (str(zmin), str(zmax)))

# Rolling pixel buffer has space for two rows of image data.
# Old data is automatically discarded as new data is loaded.
pixels = deque(maxlen=(2 * ww))
log("buffer size = %s" % str(pixels.maxlen))

# Initialize pixel buffer with first row of data from the image window.
pixels.extend(unpack(rowformat, band.ReadRaster(xmin, ymin, ww, 1, ww, 1, band.DataType)))

# Precalculate output mesh size (STL is 50 bytes/facet + 84 byte header)
# Actual facet count and file size may differ (be less) if pixels are skipped as nodata or out of range.
facetcount = mw * mh * 2
filesize = (facetcount * 50) + 84
log("predicted (max) facet count = %s" % str(facetcount))
log("predicted (max) STL file size = %s bytes" % str(filesize))

# skip(v) tests if elevation value v should be omitted from output.
# It returns True if v matches the nodata value, if v is less than
# the minimum allowed elevation, or if v is greater than the
# maximum allowed elevation. Otherwise it returns False.
def skip(v):
    global nd
    global args
    if v == nd:
        return True
    if args.minimum is not None and v < args.minimum:
        return True
    if args.maximum is not None and v > args.maximum:
        return True
    return False

points_3d = []

for y in range(mh):
    pixels.extend(unpack(rowformat, band.ReadRaster(xmin, ymin + y + 1, ww, 1, ww, 1, band.DataType)))
    for x in range(mw):
        av = pixels[x]

        if skip(av):
            continue

        points_3d.append([t[0] + ((xmin + x) * t[1]) + ((ymin + y) * t[2]),
                          t[3] + ((xmin + x) * t[4]) + ((ymin + y) * t[5]),
                          zscale * float(av)])

points_3d = np.asarray(points_3d)
points_2d = points_3d[:, :2]

from scipy.spatial import Delaunay

tri = Delaunay(points_2d)

mask = []
for simple in tri.simplices:
    in_degrees = cal_ang(points_2d[simple[0]], points_2d[simple[1]], points_2d[simple[2]])
    dmax = max(in_degrees)
    # dind = in_degrees.index(dmax)
    mask.append(dmax <= 90.0001)

with stlwriter(args.STL, facetcount) as mesh:
    for simple in tri.simplices[mask]:
        a = points_3d[simple[0]]
        b = points_3d[simple[1]]
        c = points_3d[simple[2]]
        mesh.add_facet((a, b, c))
        # print(a, b, c)

    for simple in tri.simplices[mask]:
        a1 = [points_3d[simple[0]][0], points_3d[simple[0]][1], points_3d[simple[0]][2]]
        a1[2] = zscale * zmin + args.base
        b1 = [points_3d[simple[1]][0], points_3d[simple[1]][1], points_3d[simple[1]][2]]
        b1[2] = zscale * zmin + args.base
        c1 = [points_3d[simple[2]][0], points_3d[simple[2]][1], points_3d[simple[2]][2]]
        c1[2] = zscale * zmin + args.base
        mesh.add_facet((a1, b1, c1))
        # print(a1, b1, c1)

    tri.simplices = tri.simplices[mask]

    ch = ConcaveHull()

    ch.loadpoints(points_2d)
    ch.calculatehull()
    hull_points = np.vstack(ch.boundary.exterior.coords.xy).T.tolist()
    # print(hull_points[:2])

    points_2d = points_2d.tolist()
    # print(points_2d[:2])
    for i, hp in enumerate(hull_points):
        if i == len(hull_points)-1:
            continue
        # print(hp)
        ind = points_2d.index(hp)
        a = (hp[0], hp[1], points_3d[ind][2])
        a1 = (hp[0], hp[1], zscale * zmin + args.base)
        hp_1 = hull_points[i+1]
        ind = points_2d.index(hp_1)
        b = (hp_1[0], hp_1[1], points_3d[ind][2])
        b1 = (hp_1[0], hp_1[1], zscale * zmin + args.base)

        # print(a, a1, b, b1)
        mesh.add_facet((a, a1, b))
        mesh.add_facet((b, b1, a1))
    # log("actual facet count: %s" % str(mesh.written))


import os

from flask import Flask, redirect, url_for
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

PORT = 443
HOST = "127.0.0.1"
DEBUG = True

# Use SSH. Set a context with crt and key files and path it to app.run()
parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
                                          os.path.pardir))
crt_path = os.path.join(parent_dir, 'ssl', 'nginx.crt')
key_path = os.path.join(parent_dir, 'ssl', 'nginx.key')
context = (crt_path, key_path)

if not os.path.exists(crt_path) or not os.path.exists(crt_path):
    raise ValueError("Missing files for SSL context %s and/or %s."
                     % (crt_path, key_path))

@app.route('/', methods=['GET'])
def main():
    return redirect(url_for('static', filename='index.html'))

if __name__ == "__main__":
    app.run(HOST, PORT, DEBUG, ssl_context=context)


from logging import Logger
from pathlib import Path
from typing import Optional

import numpy as np
import torch
import torch.nn as nn
from torch.utils.tensorboard import SummaryWriter  # type: ignore

from .batch_generator import BatchGenerator
from .metrics import Metrics
from .misc import clean_print

AcceptedConfigTypes = int | float | str | bool | torch.Tensor

class TensorBoard:
    def __init__(self,
                 model: nn.Module,
                 tb_dir: Path,
                 train_dataloader: BatchGenerator,
                 val_dataloader: BatchGenerator,
                 logger: Logger,
                 metrics: Optional[Metrics] = None,
                 write_graph: bool = True):
        """Class with TensorBoard utility functions for classification-like tasks.

        Args:
            model (nn.Module): Pytorch model whose performance are to be recorded
            tb_dir (Path): Path to where the tensorboard files will be saved
            train_dataloader (BatchGenerator): DataLoader with a PyTorch DataLoader like interface, contains train data
            val_dataloader (BatchGenerator): DataLoader containing  validation data
            logger (Logger): Used to print things.
            metrics (Metrics, optional): Instance of the Metrics class, used to compute classification metrics
            write_graph (bool): If True, add the network graph to the TensorBoard
        """
        super().__init__()
        self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        self.tb_dir = tb_dir
        self.model = model
        self.train_dataloader = train_dataloader
        self.val_dataloader = val_dataloader
        self.logger = logger
        self.metrics = metrics

        self.weights_warning_printed: bool = False  # Prints a warning if the network cannot give its weights

        self.train_tb_writer = SummaryWriter(tb_dir / "Train")
        self.val_tb_writer = SummaryWriter(tb_dir / "Validation")
        if write_graph:
            self.logger.info("Adding network graph to TensorBoard")
            dummy_input = (torch.empty(2, *self.train_dataloader.data_shape, device=self.device), )
            self.train_tb_writer.add_graph(model, dummy_input)
            self.train_tb_writer.flush()

    def close_writers(self) -> None:
        self.train_tb_writer.close()
        self.val_tb_writer.close()

    def write_metrics(self, epoch: int, mode: str = "Train") -> None:
        """Writes metrics in TensorBoard.

        Args:
            epoch (int): Current epoch
            mode (str): Either "Train" or "Validation"

        Raises:
            TypeError: No Metrics instance
        """
        if not isinstance(self.metrics, Metrics):
            raise TypeError("Trying to write metrics, but did not get a Metrics instance during initialization")

        tb_writer = self.train_tb_writer if mode == "Train" else self.val_tb_writer
        metrics = self.metrics.get_metrics(mode)

        clean_print("Adding scalars to TensorBoard", end="\r")
        for scalar_metric_name, scalar_metric_value in metrics["scalars"].items():
            tb_writer.add_scalar(scalar_metric_name, scalar_metric_value, epoch)

        clean_print("Adding images to TensorBoard", end="\r")
        for img_metric_name, img_metric_value in metrics["imgs"].items():
            tb_writer.add_image(img_metric_name, img_metric_value, global_step=epoch, dataformats="HWC")

    def write_weights_grad(self, epoch: int):
        """Writes the model's weights and gradients to tensorboard, if the model can provide them.

        Args:
            epoch (int): Current epoch
        """
        try:
            for tag, (weight, grad) in self.model.get_weight_and_grads().items():  # type: ignore
                self.train_tb_writer.add_histogram(f"{tag}/weights", weight, epoch)
                self.train_tb_writer.add_histogram(f"{tag}/gradients", grad, epoch)
        except AttributeError:  # torch.nn.modules.module.ModuleAttributeError:
            if not self.weights_warning_printed:
                print(f"Warning: The model {self.model.__class__.__name__}"
                      f" does not support recording weights and gradients.")
                self.weights_warning_printed = True

    def write_loss(self, epoch: int, loss: float, mode: str = "Train"):
        """Writes loss metric in TensorBoard.

        Args:
            epoch (int): Current epoch
            loss (float): Epoch loss that will be added to the TensorBoard
            mode (str): Either "Train" or "Validation"
        """
        tb_writer = self.train_tb_writer if mode == "Train" else self.val_tb_writer
        tb_writer.add_scalar("Loss", loss, epoch)
        self.train_tb_writer.flush()

    def write_lr(self, epoch: int, lr: float):
        """Writes learning rate in the TensorBoard.

        Args:
            epoch (int): Current epoch
            lr (float): Learning rate for the given epoch
        """
        self.train_tb_writer.add_scalar("Learning Rate", lr, epoch)

    def write_config(self,
                     config: dict[str, AcceptedConfigTypes | list[float | int] | tuple[float | int, ...]],
                     metrics: Optional[dict[str, float]] = None):
        """Writes the config (and optionally metrics) to the TensorBoard.

        Args:
            config: The config to add to the TensorBoard.
                    The config's values should be "simple" values.
                    If a tuple/list is given, it will either be split up into several values or transformed into an str.
            metrics: The metrics for this run.
        """
        fixed_config: dict[str, AcceptedConfigTypes] = {}
        for key, value in config.items():
            if isinstance(value, (tuple, list, np.ndarray)):
                if len(value) < 3:
                    if isinstance(value, np.ndarray):
                        value = value.tolist()  # Convert from numpy types to python ones
                    for i in range(len(value)):
                        fixed_config[key + f"[{i}]"] = float(value[i])
                else:
                    fixed_config[key] = str(value)
            elif isinstance(value, int | float | str | bool | torch.Tensor):
                fixed_config[key] = value
            else:  # For things like None or other random types
                fixed_config[key] = str(value)

        config_tb_writer = SummaryWriter(self.tb_dir)
        config_tb_writer.add_hparams(fixed_config, metrics if metrics is not None else {"None": 0}, run_name="Config")
        config_tb_writer.close()

if __name__ == "__main__":
    def _main():
        import argparse

        from .logger import create_logger
        parser = argparse.ArgumentParser(description=("Script to test the Tensorboard template. "
                                                      "Run with 'python -m utils.tensorboard_template'."),
                                         formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        parser.add_argument("--output_path", "-o", type=Path, default=Path("tb_temp"),
                            help="Path to where the TB file will be saved")
        parser.add_argument("--verbose_level", "-v", choices=["debug", "info", "error"], default="info", type=str,
                            help="Logger level.")
        args = parser.parse_args()

        output_path: Path = args.output_path

        logger = create_logger("Test TB", verbose_level=args.verbose_level)

        def _test_config():
            config = {"lr": 4e-3, "Batch Size": 32, "image_sizes": (224, 224)}
            metrics = {"Final/Accuracy": 0.99, "Final/counter": 3}
            tensorboard = TensorBoard(None, output_path, None, None, None, write_graph=False)  # type: ignore
            tensorboard.write_config(config, metrics)  # type: ignore
            logger.info(f"Tested the config writing part. TB can be found at {output_path}")
        _test_config()
    _main()


# telescope_device.py - A virtual device to serve as an intermediate layer between SEO and
# MaxIm DL.  We only need to implement methods relevant to pulse guide, with everything else
# already managed.

from threading import Timer
from threading import Lock
from logging import Logger
import subprocess
import time

class TelescopeDevice:
    def __init__(self, logger: Logger):
        self._lock = Lock()
        self.name: str = 'SEO Telescope v2'
        self.logger = logger
        #
        # Telescope Constants
        #
        self._alignment_mode = 0  # Alt/Az alignment
        self._aperture_area = 0.196  # Area of the SEO Telescope mirror
        self._aperture_diameter = 0.5  # Aperture diameter of SEO telescope
        self._can_find_home = False  # Not implemented in this driver
        self._can_park = False  # Not implemented in this driver
        self._can_pulse_guide = True  # To be implemented by us
        self._can_set_declination_rate = False  # Not implemented in this driver
        self._can_set_guide_rates = True  # To be implemented by us
        self._can_set_park = False  # TODO: Check with Marc and Dick
        self._can_set_pier_side = False  # Not implemented in this driver
        # TODO: Check if we can actually set the RA rate
        self._can_set_right_ascension_rate = False
        self._can_set_tracking = False  # Not implemented by us
        self._can_slew = True
        self._can_slew_alt_az = False
        self._can_slew_alt_az_async = False
        self._can_slew_async = True
        self._can_sync = True
        self._can_unpark = False  # Not implemented in this driver
        self._declination_rate = 0  # Always 0 due to cansetdeclinationrate being False
        # SEO does not do atmospheric refraction to coordinates
        self._does_refraction = False
        self._equatorial_system = 2  # J2000
        self._focal_length = 2  # TODO: Check for SEO
        self._right_ascension_rate = 0  # 0 because canSetRightAscensionRate is False
        self._side_of_pier = 0  # Cannot be changed
        self._site_elevation = 144  # TODO: Get this from Marc
        self._site_latitude = 50  # TODO: Get real value
        self._site_longitude = 70  # TODO: Get real value
        self._slew_settling_time = 0.5  # TODO: Chose what value to set this to
        self._tracking_rate = 0  # Sidereal Tracking (15.041 arcs/s)
        self._tracking_rates = [0]  # We only have 1 rate
        #
        # Telescope state variables
        #
        self._altitude = 0
        self._at_home = True
        self._at_park = True
        self._azimuth = 0
        self._connected = False
        self._declination = 0
        self._guide_rate_declination = 0.005
        self._guide_rate_right_ascension = 0.005
        self._is_pulse_guiding = False
        self._right_ascension = 0
        self._sidereal_time = 0.1
        self._slewing = False
        self._tracking = True
        self._target_declination = 0
        self._target_right_ascension = 0
        self._utc_date = None

    # Connector methods
    @property
    def connected(self) -> bool:
        self._lock.acquire()
        res = self._connected
        self._lock.release()
        return res

    @connected.setter
    def connected(self, connected: bool):
        self._lock.acquire()
        if (not connected) and self._connected and self._slewing:
            self._lock.release()
            # Yes you could call Halt() but this is for illustration
            raise RuntimeError('Cannot disconnect while telescope is moving')
        elif (not connected) and self._connected and self._is_pulse_guiding:
            raise RuntimeError('Cannot disconnect while guider is tracking')
        self._connected = connected
        self._lock.release()
        if connected:
            self.logger.info('[connected]')
        else:
            self.logger.info('[disconnected]')

    #
    # Guarded properties
    #

    @property
    def alignment_mode(self) -> int:
        self._lock.acquire()
        res = self._alignment_mode
        self._lock.release()
        return res

    @property
    def aperture_area(self) -> float:
        self._lock.acquire()
        res = self._aperture_area
        self._lock.release()
        return res

    @property
    def aperture_diameter(self) -> float:
        self._lock.acquire()
        res = self._aperture_diameter
        self._lock.release()
        return res

    @property
    def can_find_home(self) -> bool:
        self._lock.acquire()
        res = self._can_find_home
        self._lock.release()
        return res

    @property
    def can_park(self) -> bool:
        self._lock.acquire()
        res = self._can_park
        self._lock.release()
        return res

    @property
    def can_pulse_guide(self) -> bool:
        self._lock.acquire()
        res = self._can_pulse_guide
        self._lock.release()
        return res

    @property
    def can_set_declination_rate(self) -> bool:
        self._lock.acquire()
        res = self._can_set_declination_rate
        self._lock.release()
        return res

    @property
    def can_set_guide_rates(self) -> bool:
        self._lock.acquire()
        res = self._can_set_guide_rates
        self._lock.release()
        return res

    @property
    def can_set_park(self) -> bool:
        self._lock.acquire()
        res = self._can_set_park
        self._lock.release()
        return res

    @property
    def can_set_pier_side(self) -> bool:
        self._lock.acquire()
        res = self._can_set_pier_side
        self._lock.release()
        return res

    @property
    def can_set_right_ascension_rate(self) -> bool:
        self._lock.acquire()
        res = self._can_set_right_ascension_rate
        self._lock.release()
        return res

    @property
    def can_set_tracking(self) -> bool:
        self._lock.acquire()
        res = self._can_set_tracking
        self._lock.release()
        return res

    @property
    def can_slew(self) -> bool:
        self._lock.acquire()
        res = self._can_slew
        self._lock.release()
        return res

    @property
    def can_slew_alt_az(self) -> bool:
        self._lock.acquire()
        res = self._can_slew_alt_az
        self._lock.release()
        return res

    @property
    def can_slew_alt_az_async(self) -> bool:
        self._lock.acquire()
        res = self._can_slew_alt_az_async
        self._lock.release()
        return res

    @property
    def can_slew_async(self) -> bool:
        self._lock.acquire()
        res = self._can_slew_async
        self._lock.release()
        return res

    @property
    def can_sync(self) -> bool:
        self._lock.acquire()
        res = self._can_sync
        self._lock.release()
        return res

    @property
    def can_unpark(self) -> bool:
        self._lock.acquire()
        res = self._can_unpark
        self._lock.release()
        return res

    @property
    def declination_rate(self) -> float:
        self._lock.acquire()
        res = self._declination_rate
        self._lock.release()
        return res

    @property
    def does_refraction(self) -> bool:
        self._lock.acquire()
        res = self._does_refraction
        self._lock.release()
        return res

    @property
    def equatorial_system(self) -> int:
        self._lock.acquire()
        res = self._equatorial_system
        self._lock.release()
        return res

    @property
    def focal_length(self) -> float:
        self._lock.acquire()
        res = self._focal_length
        self._lock.release()
        return res

    @property
    def right_ascension_rate(self) -> float:
        self._lock.acquire()
        res = self._right_ascension_rate
        self._lock.release()
        return res

    @property
    def side_of_pier(self) -> int:
        self._lock.acquire()
        res = self._side_of_pier
        self._lock.release()
        return res

    @property
    def site_elevation(self) -> float:
        self._lock.acquire()
        res = self._site_elevation
        self._lock.release()
        return res

    @property
    def site_latitude(self) -> float:
        self._lock.acquire()
        res = self._site_latitude
        self._lock.release()
        return res

    @property
    def site_longitude(self) -> float:
        self._lock.acquire()
        res = self._site_longitude
        self._lock.release()
        return res

    @property
    def slew_settling_time(self) -> float:
        self._lock.acquire()
        res = self._slew_settling_time
        self._lock.release()
        return res

    @property
    def tracking_rate(self) -> int:
        self._lock.acquire()
        res = self._tracking_rate
        self._lock.release()
        return res

    @property
    def tracking_rates(self) -> list:
        self._lock.acquire()
        res = self._tracking_rates
        self._lock.release()
        return res

    #
    # State properties
    #

    @property
    def altitude(self) -> float:
        self._lock.acquire()
        # Make a call to aster to get the altitude
        command = 'tx where'
        process = subprocess.run(command.split(), stdout=subprocess.PIPE)
        output = process.stdout.decode('utf-8')
        # Parse the output

        self._lock.release()
        return res

    @altitude.setter
    def altitude(self, altitude: float):
        self._lock.acquire()
        self._altitude = altitude
        self._lock.release()

    @property
    def at_home(self) -> bool:
        self._lock.acquire()
        res = self._at_home
        self._lock.release()
        return res

    @at_home.setter
    def at_home(self, at_home: bool):
        self._lock.acquire()
        self._at_home = at_home
        self._lock.release()

    @property
    def azimuth(self) -> float:
        self._lock.acquire()
        res = self._azimuth
        self._lock.release()
        return res

    @azimuth.setter
    def azimuth(self, azimuth: float):
        self._lock.acquire()
        self._azimuth = azimuth
        self._lock.release()

    @property
    def at_park(self) -> bool:
        self._lock.acquire()
        res = self._at_park
        self._lock.release()
        return res

    @at_park.setter
    def at_park(self, at_park: bool):
        self._lock.acquire()
        self._at_park = at_park
        self._lock.release()

    @property
    def declination(self) -> float:
        self._lock.acquire()
        res = self._declination
        self._lock.release()
        return res

    @declination.setter
    def declination(self, declination: float):
        self._lock.acquire()
        self._declination = declination
        self._lock.release()

    @property
    def guide_rate_declination(self) -> float:
        self._lock.acquire()
        res = self._guide_rate_declination
        self._lock.release()
        return res

    @guide_rate_declination.setter
    def guide_rate_declination(self, guide_rate_declination: float):
        self._lock.acquire()
        self._guide_rate_declination = guide_rate_declination
        self._lock.release()

    @property
    def guide_rate_right_ascension(self) -> float:
        self._lock.acquire()
        res = self._guide_rate_right_ascension
        self._lock.release()
        return res

    @guide_rate_right_ascension.setter
    def guide_rate_right_ascension(self, guide_rate_right_ascension: float):
        self._lock.acquire()
        self._guide_rate_right_ascension = guide_rate_right_ascension
        self._lock.release()

    @property
    def is_pulse_guiding(self) -> bool:
        self._lock.acquire()
        res = self._is_pulse_guiding
        self._lock.release()
        return res

    @is_pulse_guiding.setter
    def is_pulse_guiding(self, ispulseguiding: bool):
        self._lock.acquire()
        self._is_pulse_guiding = ispulseguiding
        self._lock.release()

    @property
    def right_ascension(self) -> float:
        self._lock.acquire()
        res = self._right_ascension
        self._lock.release()
        return res

    @right_ascension.setter
    def right_ascension(self, right_ascension: float):
        self._lock.acquire()
        self._right_ascension = right_ascension
        self._lock.release()

    @property
    def sidereal_time(self) -> float:
        self._lock.acquire()
        res = self._sidereal_time
        self._lock.release()
        return res

    @sidereal_time.setter
    def sidereal_time(self, sidereal_time: float):
        self._lock.acquire()
        self._sidereal_time = sidereal_time
        self._lock.release()

    @property
    def slewing(self) -> bool:
        self._lock.acquire()
        res = self._slewing
        self._lock.release()
        return res

    @slewing.setter
    def slewing(self, slewing: bool):
        self._lock.acquire()
        self._slewing = slewing
        self._lock.release()

    @property
    def tracking(self) -> bool:
        self._lock.acquire()
        res = self._tracking
        self._lock.release()
        return res

    @tracking.setter
    def tracking(self, tracking: bool):
        self._lock.acquire()
        self._tracking = tracking
        self._lock.release()

    @property
    def target_declination(self) -> float:
        self._lock.acquire()
        res = self._target_declination
        self._lock.release()
        return res

    @target_declination.setter
    def target_declination(self, target_declination: float):
        self._lock.acquire()
        self._target_declination = target_declination
        self._lock.release()

    @property
    def target_right_ascension(self) -> float:
        self._lock.acquire()
        res = self._target_right_ascension
        self._lock.release()
        return res

    @target_right_ascension.setter
    def target_right_ascension(self, target_right_ascension: float):
        self._lock.acquire()
        self._target_right_ascension = target_right_ascension
        self._lock.release()

    @property
    def utc_date(self) -> str:
        self._lock.acquire()
        res = self._utc_date
        self._lock.release()
        return res

    #
    # Methods
    #

    def abort_slew(self):
        pass

    def action(self, action: str, parameters: list):
        pass

    def axis_rates(self, axis: int) -> list:
        pass

    def can_move_axis(self, axis: int) -> bool:
        pass

    def pulse_guide(self, direction: int, duration: int):
        self._is_pulse_guiding = True
        if direction == 0:
            self.logger.info("Pulse guide: N")
        elif direction == 1:
            self.logger.info("Pulse guide: S")
        elif direction == 2:
            self.logger.info("Pulse guide: E")
        elif direction == 3:
            self.logger.info("Pulse guide: W")
        self.logger.info("Pulse guide: {} ms".format(duration))
        time.sleep(duration / 1000)
        self._is_pulse_guiding = False


from words import words

# this function is for animation for sliding the "welcome to Tying Speed Game"
def sliders():
    global count, sliderwords
    text = "welcome to Typing Speed Game"
    if count >= len(text):
        count = 0
        sliderwords = ''
    sliderwords += text[count]
    count += 1
    fontlabel.configure(text=sliderwords)
    fontlabel.after(150, sliders)

def for_getting_time():
    global timer, score, miss
    if timer > 11:
        pass
    else:
        timerlabelcount.configure(fg='red')
    if timer > 0:
        timer -= 1
        timerlabelcount.configure(text=timer)
        timerlabelcount.after(1000, for_getting_time)
    else:
        gameinstructions.configure(text=f'Hit = {score} | Miss = {miss} | Total Score = {score - miss}')
        rr = messagebox.askretrycancel('Notification', 'Wanna Play Again!!!')
        if rr:
            score = 0
            miss = 0
            timer = 60
            timerlabelcount.configure(text=timer)
            wordlabel.configure(text=words[0])
            scorelabelcount.configure(text=score)
            wordentry.delete(0, END)

def startgame(event):
    global score, miss
    if timer == 60:
        for_getting_time()
    gameinstructions.configure(text='')
    startlabel.configure(text='')
    if wordentry.get() == wordlabel['text']:
        score += 1
        scorelabelcount.configure(text=score)
    else:
        miss += 1
    random.shuffle(words)
    wordlabel.configure(text=words[0])
    wordentry.delete(0, END)

from tkinter import *
import random
from tkinter import messagebox

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

window = Tk()
window.geometry('800x600+400+100')
window.config(bg='black')
window.title('Typing Speed Game')
window.iconbitmap('logo.ico')

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

score = 0
miss = 0
timer = 60
count = 0
sliderwords = ''

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

fontlabel = Label(window, text='Lets begin!!!', font='airal 25 italic bold', bg='black', fg='purple', width=40)
fontlabel.place(x=10, y=10)
sliders()

startlabel = Label(window, text="Lets begin!!!", font='airal 30 italic bold', bg='black', fg='green')
startlabel.place(x=275, y=50)

random.shuffle(words)

wordlabel = Label(window, text=words[0], font='airal 45 italic bold', bg='black', fg='green')
wordlabel.place(x=350, y=240)

scorelabel = Label(window, text='your Score:', font='arial 25 italic bold', bg='black', fg='red')
scorelabel.place(x=10, y=100)

scorelabelcount = Label(window, text=score, font='arial 25 italic bold', bg='black', fg='red')
scorelabelcount.place(x=150, y=180)

timerlabel = Label(window, text='Time Left', font='arial 25 italic bold', bg='black', fg='red')
timerlabel.place(x=600, y=100)

timerlabelcount = Label(window, text=timer, font='arial 25 italic bold', bg='black', fg='blue')
timerlabelcount.place(x=600, y=180)

gameinstructions = Label(window, text='Type the word and hit enter button', font='arial 25 italic bold', bg='black',
                         fg='green')
gameinstructions.place(x=150, y=500)

####################################
wordentry = Entry(window, font='airal 25 italic bold', bd=10, justify='center')
wordentry.place(x=250, y=330)
wordentry.focus_set()

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

window.bind('<Return>', startgame)

window.mainloop()


import argparse
import os
import requests
import zipfile

MOVIELEN_DOMAIN = 'http://files.grouplens.org/datasets/movielens'
MOVIELEN_SMALL_DS = 'ml-latest-small.zip'
MOVIELEN_FULL_DS = 'ml-latest.zip'

def download_file(url, outputdir, chunk_size=8192):
    '''
    Download file and write it into outputdir

    Args:
        url (str): link to download
        outputdir (str): where to place new file
        chunk_size (int): size of chunks to write on disk default: 4Kb
    Return:
        (str) Name of downloaded File
    '''

    local_filename = url.split('/')[-1]
    local_filename = f'{outputdir}/{local_filename}'
    with requests.get(url, stream=True) as r:
        r.raise_for_status()
        with open(local_filename, 'wb') as f:
            for chunk in r.iter_content(chunk_size=8192):
                f.write(chunk)
    return local_filename

def unzip_file(filename, outputdir, delete=True):
    '''
    Unzip file and delete it if necessary

    Args:
        filename (str): file to unzip
        outputdir (str): where to unpack
        delete (bool): whatever delete or not after unziping [default: True]

    Return:
        None
    '''
    with zipfile.ZipFile(filename, 'r') as zip_ref:
        zip_ref.extractall(outputdir)
    if delete:
        os.remove(filename)

def main():
    parser = argparse.ArgumentParser(
        description='Downloads dataset with movies ratings')
    parser.add_argument('outdir', type=str, help='Output dir for dataset')
    parser.add_argument('--small',
                        action='store_true',
                        help='Download small version of dataset')
    args = parser.parse_args()
    if args.small:
        download_link = f'{MOVIELEN_DOMAIN}/{MOVIELEN_SMALL_DS}'
    else:
        download_link = f'{MOVIELEN_DOMAIN}/{MOVIELEN_FULL_DS}'

    archive_filename = download_file(download_link, outputdir=args.outdir)
    unzip_file(archive_filename, args.outdir)

if __name__ == '__main__':
    main()


import datetime

from django.contrib import admin

from aerolinksma.shuttle.models import Place, Client, Reservation

@admin.register(Place)
class PlaceAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'get_display_time', 'display_price', 'enabled')
    list_filter = ('enabled',)
    actions = ('make_enabled', 'make_disabled')

    def get_display_time(self, obj):
        """Display time readibly."""
        return '{} ({})'.format(datetime.timedelta(hours=obj.time),
                                obj.time)
    get_display_time.short_description = 'Time (h:m:s)'
    get_display_time.admin_order_field = 'time'

    def make_enabled(self, request, queryset):
        rows_updated = queryset.update(enabled=True)

        if rows_updated == 1:
            message_bit = '1 place was'
        else:
            message_bit = '{} places were'.format(rows_updated)
        self.message_user(request, '{} enabled'.format(message_bit))
    make_enabled.short_description = 'Enable selected places'
    make_enabled.allowed_permissions = ('change',)

    def make_disabled(self, request, queryset):
        rows_updated = queryset.update(enabled=False)

        if rows_updated == 1:
            message_bit = '1 place was'
        else:
            message_bit = '{} places were'.format(rows_updated)
        self.message_user(request, '{} disabled'.format(message_bit))
    make_disabled.short_description = 'Disable selected places'
    make_disabled.allowed_permissions = ('change',)

@admin.register(Reservation)
class ReservationAdmin(admin.ModelAdmin):
    list_display = ('id', 'place', 'direction', 'fare_type',
                    'paid', 'pickup_date', 'created_at')

@admin.register(Client)
class ClientAdmin(admin.ModelAdmin):
    list_display = ('id', 'first_name', 'last_name', 'email',
                    'phone_number')


""" syndat.py """
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

np.random.seed(1234)
X=np.pi*(2* np.random.random (size =(400 ,2)) -1)
y=(np.cos(X[: ,0])*np.sin(X[: ,1]) >=0)
X_train , X_test , y_train , y_test = train_test_split(X, y, test_size =0.5)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter( X_train [ y_train ==0 ,0] , X_train [ y_train ==0 ,1] , c='g',
marker ='o',alpha =0.5)
ax.scatter ( X_train [ y_train ==1 ,0] , X_train [ y_train ==1 ,1] , c='b',
marker ='o',alpha =0.5)
ax.scatter ( X_test [ y_test ==0 ,0] , X_test [ y_test ==0 ,1] , c='g',
marker ='s',alpha =0.5)
ax.scatter ( X_test [ y_test ==1 ,0] , X_test [ y_test ==1 ,1] , c='b',
marker ='s',alpha =0.5)

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
plt.savefig('sklearntraintest.pdf ',format ='pdf')
plt.show()
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%