import os
import re
import time
import sys

flag_quick = False
#flag_test = True

def get_forward_time(filename : str):
	time = -1.0
	try:
		f = open(filename, "r")
		f_str = f.read()
		f.close()
		time = float(re.search("Kernel \d (\d*.\d*) sec",f_str).group(1))
	except Exception:
		pass
	return time

#calls the make file build_for_test function
def build_main(runname : str,extra : str,is_test = False):
	command = "make runname='{}' EXTRA='{}' build_for_test".format(runname,extra)
	print(command)
	if is_test:
		return
	os.popen(command).read()
	#os.remove("./cuda_temp.cu")

def measure(runname : str,n=1,is_test = False):
	if is_test:
		return -1
	time = 0.0
	temp_file_name = "{}_out.log".format(runname)
	for i in range(n):
		os.popen("timeout 10s {} > {} 2>&1".format(runname,temp_file_name) ).read()
		time += float(get_forward_time(temp_file_name))
	#os.remove("./bin/run")
	return str(time/n)

def create_test_cases(type):
	cases=[]
	areas = [800]
	space_orders = [2,4,8,16]
	block_threads = [-1]
	if type == "cuda":
		block_threads = [-1] # for cuda thread limit is defined by x*y*z
		block_parts = [2,4,8,16,32,64]

	if type == "cuda_tile":
		block_parts = [2,4,8,16,32,64]
		tile_parts = [1,2,4]
		for area in areas:
			for so in space_orders:
				for bx in block_parts:
					for by in block_parts:
						for bz in block_parts:
							if bx == by and by == bz:
								continue
							for tx in tile_parts:
								for ty in tile_parts:
									for tz in tile_parts:
										Ax,Ay,Az = (bx*tx,by*ty,bz*tz)
										size = Ax*Ay*Az
										if Ax == Ay and Ay == Az:
											continue
										if tx == ty and ty == tz:
											continue
										if size <= 512 and size >= 128:
											cases.append((area,so,bx,by,bz,tx,ty,tz,Ax,Ay,Az,size))
		return cases

	if type == "FORBLOCKTILLED":
		count_num = 0
		block_parts = [2,4,8,16,32,64]
		tile_parts = [1,2,4,8]
		block_threads = [128,256,512,1024]
		for area in areas:
			for so in space_orders:

				for bx in block_parts:
					for by in block_parts:
						for bz in block_parts:

							if bx == by and by == bz:
							#	continue
								pass

							for tx in tile_parts:
								for ty in tile_parts:
									for tz in tile_parts:
										if 1 == tx and 1 == ty and 1 == tz: # cubes are no good
											continue

										if bx < tx or by < ty or bz < tz: # cant be smaler than the tile
											continue
											pass

										for t in block_threads:

											block_size = bx*by*bz

											size = t*tx*ty*tz
											if size > 1024:
												continue

											if size != block_size:
												#print("wrong")
												continue
												pass
											#if Ax == Ay and Ay == Az:
											#	continue
											#if tx == ty and ty == tz:
											#	continue

											#if size <= 512 and size >= 128:
											#print((area,so,bx,by,bz,tx,ty,tz,size))
											#cases.append((area,so,bx,by,bz,tx,ty,tz,size))
											count_num+=1
											if count_num % 5 == 0:
												cases.append(("-D{} -DF{}_{} -DTHREADLIMIT={} -Dblocksize_x={} -Dblocksize_y={} -Dblocksize_z={} -Dtilesize_x={} -Dtilesize_y={} -Dtilesize_z={}".format(type,area,so,size,bx,by,bz,tx,ty,tz),area,so,size,bx,by,bz,tx,ty,tz))
												#cases.append((area,so,bx,by,bz,tx,ty,tz,size))

		#print("len",len(cases))
		#quit()
		return cases

	if type == "FORNAIV":
		threads = 128
		for area in areas:
			for so in space_orders:
				cases.append(("-DFORNAIV -DF{}_{} -DTHREADLIMIT={}".format(area,so,threads),area,so,threads))
		return cases

	if type == "FORBLOCKED":
		#this case we need the default cases
		block_threads = [128,256,512,1024]
		block_parts = [2,4,8,16,32,64]
		for area in areas:
			for so in space_orders:

				for t in block_threads:

					for x in block_parts:
						for y in block_parts:
							for z in block_parts:

								if x*y*z <= 2 * t:
									#cases.append((area,so,x,y,z,t))
									#count_num+=1
									#if count_num % 5 == 0:
									cases.append(("-D{} -DF{}_{} -DTHREADLIMIT={} -Dblocksize_x={} -Dblocksize_y={} -Dblocksize_z={}".format(type,area,so,t,x,y,z),area,so,t,x,y,z,x*y*z))

									#print(x,y,z,"=",x*y*z,t)

		return cases

	if type == "FORTILLED":
		#this case we need the default cases
		block_threads = [128,256,512,1024]
		block_parts = [1,2,4,8,16,32,64]
		count_num = 0
		for area in areas:
			for so in space_orders:

				for t in block_threads:

					for x in block_parts:
						for y in block_parts:
							for z in block_parts:

								if x*y*z*t <= 2048:
									#cases.append((area,so,x,y,z,t))
									#count_num+=1
									#if count_num % 5 == 0:
									cases.append(("-D{} -DF{}_{} -DTHREADLIMIT={} -Dblocksize_x={} -Dblocksize_y={} -Dblocksize_z={}".format(type,area,so,t,x,y,z),area,so,t,x,y,z,x*y*z*t))
								else:
									pass
									#print(("-D{} -DF{}_{} -DTHREADLIMIT={} -Dblocksize_x={} -Dblocksize_y={} -Dblocksize_z={}".format(type,area,so,t,x,y,z),area,so,t,x,y,z,x*y*z*t))

		return cases

def export_cases(cases,path = "./cases.csv"):
	f = open(path,'w')
	for case in cases:
		#print(case)
		case = list(case)
		line = ""
		for p in case:
			line+=str(p)+","
		line = line[0:-1]
		f.write(line+"\n")
	f.flush()
	f.close()

def import_cases(path = "./cases.csv"):
	f = open(path,'r')
	lines = f.readlines()
	f.close()
	cases = []
	for line in lines:
		#print(line)
		line = line.replace("[","").replace("]","").replace("'","")
		#print(line)
		#quit()
		line = line.strip()
		params = line.split(',')
		#case = [int(p) for p in params]
		case = tuple(params)
		#case = (int(params[0]),int(params[1]),int(params[2]),int(params[3]),int(params[4]),int(params[5]))
		cases.append(case)
	return cases

import os
import sys

class Case:
	def __init__(self,s):
		#print(len(s))
		self.list = s
		self.param = s[0]
		#self.param = s[1]
		self.so = int(s[2])
		self.threads = int(s[3])
		self.time = float(s[4])
		if len(s) > 5:
			self.x = int(s[4])
			self.y = int(s[5])
			self.z = int(s[6])
			self.size = int(s[7])
			self.time = float(s[8])
		if len(s) > 9:
			self.time = float(s[11])

	def __str__(self):
		val = ""
		for i in range(0,len(self.list)):
			val += str(self.list[i]) + ","
		val = val[0:-1]
		return val
		return self.param + "," + str(self.time)

if __name__ == "__main__":
	print("generate case files")

	results_folder = sys.argv[1]
	print(results_folder)

	N = 5

	#s = import_cases(results_folder + "/fornaiv.csv")
	#so = {2:[],4:[],8:[],16:[]}
	#for i in s:
	#	so[int(i[2])].append(Case(i))
	#
	#naiv = so
	#for soi in [2,4,8,16]:
	#	for c in naiv[soi]:
	#		print(c)

	try:
		s = import_cases(results_folder + "/cuda.csv")
		so = {2:[],4:[],8:[],16:[]}
		for i in s:
			so[int(i[2])].append(Case(i))

		for soi in [2,4,8,16]:
			so[soi] = [ s for s in so[soi] if s.time >= 0]

			so[soi].sort(key=lambda a : a.time)

			so[soi] = [ so[soi][i] for i in range(N)]

		cuda = so
		for soi in [2,4,8,16]:
			for i,c in enumerate(cuda[soi]):
				print(str(c)+",cuda"+str(i+1))
	except:
		pass

	#quit()
	try:
		s = import_cases(results_folder + "/forblocked.csv")
		so = {2:[],4:[],8:[],16:[]}
		for i in s:
			so[int(i[2])].append(Case(i))

		for soi in [2,4,8,16]:
			so[soi] = [ s for s in so[soi] if s.time >= 0]

			so[soi].sort(key=lambda a : a.time)

			so[soi] = [ so[soi][i] for i in range(N)]

		block = so
		for soi in [2,4,8,16]:
			for i,c in enumerate(block[soi]):
				print(str(c)+",B"+str(i+1))
	except:
		pass

	try:
		s = import_cases(results_folder + "/fortilled.csv")
		so = {2:[],4:[],8:[],16:[]}
		for i in s:
			so[int(i[2])].append(Case(i))

		for soi in [2,4,8,16]:
			so[soi] = [ s for s in so[soi] if s.time >= 0]

			so[soi].sort(key=lambda a : a.time)

			so[soi] = [ so[soi][i] for i in range(5)]

		tilled = so

		for soi in [2,4,8,16]:
			for i,c in enumerate(tilled[soi]):
				print(str(c)+",T"+str(i+1))
	except:
		pass

	try:
		s = import_cases(results_folder + "/forblocktilled.csv")
		so = {2:[],4:[],8:[],16:[]}
		for i in s:
			so[int(i[2])].append(Case(i))

		for soi in [2,4,8,16]:
			so[soi] = [ s for s in so[soi] if s.time >= 0]

			so[soi].sort(key=lambda a : a.time)

			so[soi] = [ so[soi][i] for i in range(5)]

		combined = so

		for soi in [2,4,8,16]:
			for i,c in enumerate(combined[soi]):
				print(str(c)+",C"+str(i+1))
	except:
		pass


import datetime

import elasticsearch

from core.auth.models import LoggedUser
from core.auth.utils import get_current_user, user_has_permission, verify_logged_in, verify_existing_users
from core.helpers.converters import get_parsed_folder
from core.helpers.db_client import ElasticManager
from core.models.database import DBFolder
from . import *

router = APIRouter(
    prefix="/folders",
    tags=["folders"],
    responses={
        401: {'description': 'User must be logged in to perform this action'},
        404: {"description": "Folder not found"}
    }
)

tag_metadata = {
        'name': 'folders',
        'description': 'Operations with document folders'
}

elastic = ElasticManager.get_instance()

folders_page_size = 10
folders_db = MongoManager.get_instance().BD2.Folder
users_db = MongoManager.get_instance().BD2.User

@router.get(
    "",
    response_model=List[Folder],
    status_code=status.HTTP_200_OK,
    responses={
        200: {'description': 'Found documents list'},
        400: {'description': 'Sent wrong query param'}
    }
)
def get_folders(request: Request, response: Response, page: int = 1,
                title: Union[str, None] = None, owner: Union[str, None] = None,
                current_user: LoggedUser = Depends(get_current_user)):
    if page < 1:
        raise HTTPException(status_code=400, detail='Page number must be a positive integer')

    folder_filter = {}
    if title is not None:
        folder_filter["title"] = {'$regex': ".*" + str(title) + ".*"}
    if owner is not None:
        try:
            folder_filter["createdBy"] = {'$regex': ".*" + str(owner) + ".*"}
        except bson.errors.InvalidId:
            return []
    if current_user is None:
        folder_filter["$or"] = [
            {"allCanRead": True},
            {"allCanWrite": True}
        ]
    else:
        folder_filter["$or"] = [
            {"allCanRead": True},
            {"allCanWrite": True},
            {"readers": current_user.username},
            {"writers": current_user.username},
            {"createdBy": current_user.username}
        ]
    result = folders_db.find(folder_filter).skip((page - 1) * folders_page_size).limit(folders_page_size)
    folder_count = folders_db.count_documents({})
    folders = list()
    for folder in result:
        folders.append(Folder(
            self=str(request.url.remove_query_params(["title", "author", "page"])) + "/" + str(folder['_id']),
            id=str(folder['_id']),
            createdBy=folder['createdBy'],
            lastEditedBy=folder['lastEditedBy'],
            createdOn=str(folder['createdOn']),
            lastEdited=str(folder['lastEdited']),
            title=folder['title'],
            description=folder['description'],
            content=folder['content'],
            writers=folder['writers'],
            readers=folder['readers'],
            allCanWrite=folder['allCanWrite'],
            allCanRead=folder['allCanRead'],
        ))
    response.headers.append("first", str(request.url.remove_query_params(["page"]).include_query_params(page=1)))
    response.headers.append("last", str(request.url.remove_query_params(["page"]).include_query_params(
                page=str(int((folder_count - 1) / folders_page_size) + 1))))
    return folders

@router.post(
    "",
    status_code=status.HTTP_201_CREATED,
    responses={
        201: {'description': 'Document successfully created'},
        400: {'description': 'Sent wrong param'}
    }
)
def create_folder(doc: NewFolder, request: Request, response: Response,
                  current_user: LoggedUser = Depends(get_current_user)):
    verify_logged_in(current_user)
    are_writers = doc.writers is not None
    are_readers = doc.readers is not None
    are_docs = doc.content is not None
    verify_existing_users(doc.writers, doc.readers)
    if are_docs and docs_exist(doc.content) is False:
        raise HTTPException(status_code=400, detail='Document to include on folder does not exist')
    if are_docs and is_docs_owner(doc.content, current_user) is False:
        raise HTTPException(status_code=400, detail='User is not owner of document included in folder')
    now = datetime.datetime.now()
    result = folders_db.insert_one({
        'createdBy': current_user.username,
        'lastEditedBy': current_user.username,
        'createdOn': now,
        'lastEdited': now,
        'title': doc.title,
        'description': doc.description,
        'content': doc.content if are_docs else [],
        'writers': doc.writers if are_writers else [],
        'allCanWrite': doc.allCanWrite if doc.allCanWrite is not None else False,
        'readers': doc.readers if are_readers else [],
        'allCanRead': doc.allCanRead if doc.allCanRead is not None else False
    })
    users_db.update_one({"_id": ObjectId(current_user.id)}, {
        "$addToSet": {
            "folders": str(result.inserted_id)
        }
    })
    response.headers.append("Location", str(request.url) + "/" + str(result.inserted_id))
    return {}

@router.get(
    "/{id}",
    response_model=Folder,
    status_code=status.HTTP_200_OK,
    responses={
        200: {'description': 'Found folder'},
        404: {'description': 'Folder not found for id sent'},
    }
)
def get_folder(id: str, request: Request, current_user: LoggedUser = Depends(get_current_user)):
    folder_obj = get_parsed_folder(id, folders_db, None if current_user is None else current_user.username)       # Filtro complejo para que no se devuelva una carpeta con 1000 lectores o escritores
    if folder_obj is None:
        raise HTTPException(status_code=404, detail='Folder not found')
    folder = DBFolder(
        id=str(folder_obj['id']),
        createdBy=folder_obj['createdBy'],
        lastEditedBy=folder_obj['lastEditedBy'],
        createdOn=str(folder_obj['createdOn']),
        lastEdited=str(folder_obj['lastEdited']),
        title=folder_obj['title'],
        description=folder_obj['description'],
        content=folder_obj['content'],
        writers=folder_obj['writers'],
        readers=folder_obj['readers'],
        allCanWrite=folder_obj['allCanWrite'],
        allCanRead=folder_obj['allCanRead'],
    )
    if not user_has_permission(folder, current_user, request.method.title()):
        raise HTTPException(status_code=403, detail='User has no permission to access this folder')
    return Folder(
        self=str(request.url),
        id=str(folder.id),
        createdBy=folder.createdBy,
        lastEditedBy=folder.lastEditedBy,
        createdOn=str(folder.createdOn),
        lastEdited=str(folder.lastEdited),
        title=folder.title,
        description=folder.description,
        content=folder.content,
        writers=folder.writers,
        readers=folder.readers,
        allCanWrite=folder.allCanWrite,
        allCanRead=folder.allCanRead,
    )

@router.patch(
    "/{id}",
    status_code=status.HTTP_204_NO_CONTENT,
    responses={
        204: {'description': 'Modified Folder'},
        400: {'description': 'Invalid param sent'},
        403: {'description': 'User has no permission for attempted action'},
        404: {'description': 'Folder not found'}
    }
)
def modify_folder(id: str, update_folder: UpdateFolder,
                  current_user: LoggedUser = Depends(get_current_user)):
    verify_logged_in(current_user)
    folder_obj = get_parsed_folder(id, folders_db, current_user.username)
    if folder_obj is None:
        raise HTTPException(status_code=404, detail="Folder not found")
    folder = DBFolder(
        id=str(folder_obj['id']),
        createdBy=folder_obj['createdBy'],
        lastEditedBy=folder_obj['lastEditedBy'],
        createdOn=str(folder_obj['createdOn']),
        lastEdited=str(folder_obj['lastEdited']),
        title=folder_obj['title'],
        description=folder_obj['description'],
        content=folder_obj['content'],
        writers=folder_obj['writers'],
        readers=folder_obj['readers'],
        allCanWrite=folder_obj['allCanWrite'],
        allCanRead=folder_obj['allCanRead'],
    )
    are_writers = update_folder.writers is not None
    are_readers = update_folder.readers is not None
    are_docs = update_folder.content is not None

    verify_existing_users(update_folder.writers, update_folder.readers)
    if are_docs and is_docs_owner(update_folder.content, current_user) is False:
        raise HTTPException(status_code=400, detail='Document to include on folder does not exist or User is not owner')
    if current_user.username != folder.createdBy:
        if update_folder.writers is not None:
            raise HTTPException(status_code=403, detail="User has no permission to edit writers")
        if update_folder.readers is not None:
            raise HTTPException(status_code=403, detail="User has no permission to edit readers")

    folders_db.update_one({"_id": ObjectId(id)}, {
        "$set": {
            "lastEditedBy": current_user.username,
            "lastEdited": datetime.datetime.now(),
            "title": folder.title if update_folder.title is None else update_folder.title,
            "description": folder.description if update_folder.description is None else update_folder.description,
            "content": folder.content if update_folder.content is None else update_folder.content,
            "writers": folder.writers if update_folder.writers is None else update_folder.writers,
            "readers": folder.readers if update_folder.readers is None else update_folder.readers,
            "allCanWrite": folder.allCanWrite if update_folder.allCanWrite is None else update_folder.allCanWrite,
            "allCanRead": folder.allCanRead if update_folder.allCanRead is None else update_folder.allCanRead,
        }
    })

@router.delete(
    "/{id}",
    status_code=status.HTTP_204_NO_CONTENT,
    responses={
        204: {'description': 'Deleted document'},
        403: {'description': 'User has no permission to delete the folder'}
    }
)
def delete_folder(id: str, request: Request, current_user: LoggedUser = Depends(get_current_user)):
    verify_logged_in(current_user)
    folder_obj = get_parsed_folder(id, folders_db, current_user.username)
    if folder_obj is None:
        return
    folder = DBFolder(
        id=folder_obj['id'],
        createdBy=folder_obj['createdBy'],
        createdOn=str(folder_obj['createdOn']),
        lastEditedBy=folder_obj['lastEditedBy'],
        lastEdited=str(folder_obj['lastEdited']),
        title=folder_obj['title'],
        description=folder_obj['description'],
        content=folder_obj['content'],
        writers=folder_obj['writers'],
        readers=folder_obj['readers'],
        allCanRead=folder_obj['allCanRead'],
        allCanWrite=folder_obj['allCanWrite'],
    )
    if user_has_permission(folder, current_user, request.method.title()) is False:
        raise HTTPException(status_code=403, detail="User has no permission to modify this folder")
    if len(folder.content) > 0:
        elastic.delete_by_query(index="documents", query={
            "bool": {
                "must": [
                    {
                        "match": {"createdBy": folder['content']}
                    }
                ]
            }
        })
    folders_db.delete_one({"_id": id})

# TODO: Check for more optimized way of doing it (one request for all)
def users_exist(user_list: List[str]):
    return len(list(users_db.find({'username': {'$in': user_list}}))) == len(user_list)

def docs_exist(doc_list: List[str]):
    try:
        for doc in doc_list:
            elastic.get(index="documents", id=doc)
    except elasticsearch.NotFoundError:
        return False
    return True

def is_docs_owner(doc_list: List[str], user: LoggedUser):
    try:
        for doc in doc_list:
            aux_doc = elastic.get(index="documents", id=doc)['_source']
            if aux_doc['createdBy'] != user.username:
                return False
    except elasticsearch.NotFoundError:
        return False
    return True


import pandas as pd
import numpy as np
import glob
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from xgboost import XGBRegressor
import time
from sklearn.metrics import mean_absolute_error, r2_score

path = 'c:/study/_data/AIFac_pollution/'
save_path = 'c:/study/_save/AIFac_pollution/'
submission = pd.read_csv(path + 'answer_sample.csv')

train_files = glob.glob(path + "TRAIN/*.csv")
test_input_files = glob.glob(path + 'test_input/*.csv')

################## train folder ##########################
li = []
for filename in train_files:
    df = pd.read_csv(filename, index_col=None, header=0, encoding='utf-8-sig')
    li.append(df)

train_dataset = pd.concat(li, axis=0, ignore_index=True)

################## test folder #################################
li = []
for filename in test_input_files:
    df = pd.read_csv(filename, index_col=None, header=0, encoding='utf-8-sig')
    li.append(df)

test_input_dataset = pd.concat(li, axis=0, ignore_index=True)

################# 측정소 라벨 인코더 #########################
le = LabelEncoder()
train_dataset['locate'] = le.fit_transform(train_dataset['측정소'])
test_input_dataset['locate'] = le.transform(test_input_dataset['측정소'])
train_dataset = train_dataset.drop(['측정소'], axis=1)
test_input_dataset = test_input_dataset.drop(['측정소'], axis=1)

################### 일시-> 월, 일, 시간 으로 분리 !! #######################
train_dataset['month'] = train_dataset['일시'].str[:2]
train_dataset['hour'] = train_dataset['일시'].str[6:8]
train_dataset = train_dataset.drop(['일시'], axis=1)

test_input_dataset['month'] = test_input_dataset['일시'].str[:2]
test_input_dataset['hour'] = test_input_dataset['일시'].str[6:8]
test_input_dataset = test_input_dataset.drop(['일시'], axis=1)

train_dataset['month'] = train_dataset['month'].astype('int8')
train_dataset['hour'] = train_dataset['hour'].astype('int8')

test_input_dataset['month'] = test_input_dataset['month'].astype('int8')
test_input_dataset['hour'] = test_input_dataset['hour'].astype('int8')

train_dataset = train_dataset.dropna()

##### 시즌 -파생피쳐도 생각!!!

# Perform one-hot encoding on categorical features
train_dataset = pd.get_dummies(train_dataset, columns=['month', 'hour', 'locate'])
test_input_dataset = pd.get_dummies(test_input_dataset, columns=['month', 'hour', 'locate'])

y = train_dataset['PM2.5']
x = train_dataset.drop(['PM2.5'], axis=1)

x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.1, random_state=1, shuffle=True)

parameter = {'n_estimators': 20000,
              'learning_rate': 0.7,
              'max_depth': 3,
              'n_jobs': -1
              }

# 2. 모델
model = XGBRegressor()

# 3. 컴파일, 훈련
model.set_params(**parameter,
                 eval_metric='mae',
                 early_stopping_rounds=200
                 )

start_time = time.time()
model.fit(x_train, y_train,
          eval_set=[(x_train, y_train), (x_test, y_test)],
          verbose=True
          )
end_time = time.time()

print("걸린시간:", round(end_time - start_time, 2), "초")

# 4. 평가 예측
y_predict = model.predict(x_test)

result = model.score(x_test, y_test)
print("model.score:", result)

r2 = r2_score(y_test, y_predict)
print("r2 스코어:", r2)

mae = mean_absolute_error(y_test, y_predict)
print("mae 스코어:", mae)

# 제출 파일 만들기
x_submit = test_input_dataset[test_input_dataset.isna().any(axis=1)]
x_submit = x_submit.drop(['PM2.5'], axis=1)

y_submit = model.predict(x_submit)

answer_sample_csv = pd.read_csv(path + 'answer_sample.csv', index_col=None, header=0)
answer_sample_csv['PM2.5'] = y_submit
answer_sample_csv.to_csv(path + '004.csv', index=None)


import time
import gmpy2
import math
import random

user_num = 10  ####参与解密的人数
thre = int(user_num/2) ##解密的阈值
deta = math.factorial(user_num)

####以下两个函数不用管，是生成密钥时keygen()调用的
def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        g, y, x = egcd(b % a, a)
        return (g, x - (b // a) * y, y)
def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        raise Exception('modular inverse does not exist')
    else:
        return x % m

def get_prime(rs):
    p = gmpy2.mpz_urandomb(rs, 256)
    while not (gmpy2.is_prime(p) and gmpy2.is_prime(2 * p + 1)):
        p = p + 1
    return p, (2*p + 1)
def LL(x, n):
    return (x - 1) // n

def keygen():
    rs = gmpy2.random_state(int(time.time()))
    _p, p = get_prime(rs)
    _q, q = get_prime(rs)

    m = _p * _q
    n = p * q
    lmd = (p - 1) * (q - 1)
    g = n + 1

    pk = [n, g]
    sk = lmd

    d = m * modinv(m, n)

    return pk, sk, m, d

def encipher(plaintext, pk):
    m = plaintext
    n, g = pk
    r = random.randint(1, n ** 2)
    c = gmpy2.powmod(g, int(m), n ** 2) * gmpy2.powmod(r, int(n), n ** 2) % (n ** 2)
    return c

####生成部分私钥
def share_private_key(s, t, pk, d, m):  ###一共s个人，阈值为t
    coffe = []
    n = pk[0]
    nm = n*m
    coffe.append(d)
    for i in range(t-1):
        coffe.append(random.randint(0, nm-1))

    share_pri = []
    for user in range(1, s+1):
        total = 0
        for j in range(t):
            total = (total + pow(user, j) * coffe[j])
        share_pri.append(total % nm)

    return share_pri

###部分解密，i_share_pri代表用户i的部分私钥
def partial_decryption(i_share_pri, ciphertext, n):
    pa_de = gmpy2.powmod(int(ciphertext), int(2 * deta * i_share_pri), n ** 2) % (n ** 2)
    return pa_de

####联合解密，arr_pa_de是解密出来的部分密文的数组
def combining(arr_pa_de, pk):
    length = thre
    lam = []
    c = 1
    n, g = pk

    for i in range(1, length+1):
        temp_com = 1
        temp_com1 = 1
        for j in range(1, length+1):
            if(i != j):
                temp_com = temp_com * (-j)
                temp_com1 = temp_com1 * (i - j)
        lam.append(temp_com // temp_com1)

    c = 1
    for i in range(length):
        if lam[i] > 0:
            temp = gmpy2.powmod(int(arr_pa_de[i]), int(lam[i] * 2 * deta), n ** 2)
           # print('c_[',i,'] = ', temp, '\n')
            c = c * temp % (n ** 2)
        elif lam[i] == 0:
            continue
        elif lam[i] < 0:
            temp = gmpy2.powmod(int(arr_pa_de[i]), int(-lam[i] * 2*deta), n ** 2)
          #print('c_[',i,'] = ', temp, '\n')
            c = c * gmpy2.invert(temp, n ** 2) % (n ** 2)

    c = c % (n ** 2)
    u = gmpy2.invert(LL(gmpy2.powmod(g, int(4 * (deta ** 2)), n ** 2), n), n) % (n ** 2)
    c_u = LL(c, n)
    plaintext = c_u * u % n

    return plaintext

##用于单个解密的函数
def decipher(c, pk, sk):
    [n, g] = pk
    lmd = sk
    u = gmpy2.invert(LL(gmpy2.powmod(g, lmd, n ** 2), n), n) % n
    m = LL(gmpy2.powmod(c, lmd, n ** 2), n) * u % n
    plaintext = m
    return plaintext

#### sk是用于单个用户解密时的私钥，d是阈值解密的私钥
#####keygen生成公钥，d，sk等参数
pk, sk, m, d = keygen()

####生成部分私钥
share_key = share_private_key(user_num, thre, pk, d, m)

def test():
    plaintext = 11
    c_text = encipher(plaintext, pk)  ###加密

    pa_c = []

    #####部分解密
    for user in range(user_num):
        pa_c.append(partial_decryption(share_key[user], c_text, pk[0]))

    p1_1 = combining(pa_c, pk)  ###联合解密，不需要d以及sk
    p1_2 = decipher(c_text, pk, sk)  ####单独解密，用到了私钥sk

    print('联合解密解密出来的密文是：', p1_1)
    print('单独解密解密出来的密文是：', p1_2)

test()


# -*- coding: utf-8 -*-
"""
Created on Wed Jan 13 16:25:09 2019

@author: Nils
"""
#Attēli:Attels1 Attels2 Attels3 Attels4 Attels5

#Tiek import modeļi
import cv2
import matplotlib.pyplot as plt
import time

#Sāk laiku skaitīt
l1 = time.time()

def sejas_atrast_img(lbp_face_cascade, colored_img, scaleFactor = 1.2):
    img_copy = colored_img.copy()

    gray = cv2.cvtColor(img_copy, cv2.COLOR_BGR2GRAY)

    faces = lbp_face_cascade.detectMultiScale(gray, scaleFactor=scaleFactor, minNeighbors=4);

    for (x, y, w, h) in faces:
        cv2.rectangle(img_copy, (x, y), (x+w, y+h), (0, 255, 0), 2)

    return img_copy

#Ielādē uztrenetu kaskadesanas klasifikatoru
lbp_face_cascade = cv2.CascadeClassifier('lbpcascade_frontalface_improved.xml')

#ielādēt attēlu
test2 = cv2.imread('Attels5.jpg')

#call our function to detect faces
detect_faces = sejas_atrast_img(lbp_face_cascade, test2)

#convert image to RGB and show image
plt.imshow(detect_faces)

#beidz laiku skaitīt
l2 = time.time()
#laika diference
ld1 = l2 - l1
#izvada laika diferenci
print("LBP: "+str(ld1))


from typing import List
import re

def valid_triangle(sides: List[int]):
    a, b, c = sorted(sides)
    return a + b > c

def number_valid_triange_col(values: List[int]):
    chunks = [values[i : i + 3] for i in range(0, len(values), 3)]
    return len([1 for n in chunks if valid_triangle(n)])

def solution_1(puzzle_input: str):
    values = []
    for line in puzzle_input.splitlines():
        values.append([int(n) for n in re.findall(r"\d+", line)])

    return len([1 for n in values if valid_triangle(n)])

def solution_2(puzzle_input: str):
    values = [int(n) for n in re.findall(r"\d+", puzzle_input)]
    return number_valid_triange_col(
        [n for n in values[0::3]]
        + [n for n in values[1::3]]
        + [n for n in values[2::3]]
    )


# filename = 'programming.txt';
# with open(filename, 'w') as file_object:
#     file_object.write("I'm study python programming.");

# filename = 'programming.txt';
# with open(filename, 'w') as file_object:
#     file_object.write("I'm study python programming.\n");
#     file_object.write("I'm working with java\n");

# filename = 'programming.txt';
# with open(filename, 'a') as file_object:
#     file_object.write("I also love finding meaning in large datasets.\n");
#     file_object.write("I love creating apps that can run in a browser.\n");

# 练习1
# filename = 'guest.txt'
# with open(filename, 'w') as file_object:
#     name = input("please input your name: ");
#     file_object.write(name+"\n");

# 练习2
filename = 'guest_book.txt'
with open(filename, 'a') as file_object:
    name = input("please input your name: ");
    while name!='exit':
        file_object.write(name+"\n");
        name = input("please input your name: ");


from snake_con import snake
from trainer import Trainer
from cnn import pdqn
import os
import json
import numpy as np
import sys
import tensorflow as tf
tf.enable_eager_execution()
tf.executing_eagerly()
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
tf.keras.backend.set_session(sess)

# os.chdir(r"C:\Users\devar\Documents\EngProj\SSPlayer\\")

with open("meta.json", "r") as params_file:
    data = json.load(params_file)
    # print(data)

LOGDIR = data["logdir"] if data["pc"] == 1 else data["plogdir"]
save_steps = data["save_steps"]

# network params
batch_size = data["batchsize"]
seq_len = data["seq_len"]
conv_k_size = [i["l"+str(idx+1)] for i, idx in zip(data["conv_k_size"],
                                                   range(0, len(data["conv_k_size"])))]
conv_stride = [i["l"+str(idx+1)] for i, idx in zip(data["conv_stride"],
                                                   range(0, len(data["conv_stride"])))]
conv = [i["l"+str(idx+1)]
        for i, idx in zip(data["conv"], range(0, len(data["conv"])))]
fclyr = [i["l"+str(idx+1)]
         for i, idx in zip(data["fclyr"], range(0, len(data["fclyr"])))]
learning_rate = data["learing_rate"]
gamma = np.array([data["gamma"]]).astype(np.float16)
load_weights = True if data["load_weights"] == 1 else False

net = pdqn(seq_len, conv, fclyr, conv_k_size, conv_stride, LOGDIR,
           gamma=gamma, batch_size=batch_size, learning_rate=learning_rate)

if (load_weights):
    weights_dir = data["weightsdir"]
    T1 = np.zeros(shape=(1, 84, 84, seq_len))
    infer_dummy = [T1]
    train_dummy = [np.vstack([T1, T1]),
                   np.asarray([[1], [0]]),
                   np.asarray([.5, -1.0]).reshape((2, 1)),
                   np.vstack([T1, T1])]
    net.infer(infer_dummy)
    net.train(inputs=train_dummy, IS_weights=np.ones(shape=(2, 1)), r=[0, 0])
    net.set_model_weights(weights_dir)
game = snake(data["pc"])

run_type = input("Run type?(r=run, t=testing,p=play): ")
if (run_type == "p"):
    num_times = int(input("Play_times?: "))
    game_trainer = Trainer(1)
    game_trainer.play(net, game, seq_len, num_times,
                      TSNE=False, TSNE_size=10000)
elif (run_type == "r"):
    num_times = 1000000
    greed_frames = 200000
    max_exp_len = 1000000
    min_exp_len_train = 25000  # 30000
    n = 5000
    game_trainer = Trainer(1)
    game_trainer.play_train(net, game, learning_rate, seq_len, batch_size,
                            num_times, greed_frames, max_exp_len, min_exp_len_train, 1, n, 15, LOGDIR)
elif (run_type == "t"):
    num_times = 20000
    greed_frames = 5000
    max_exp_len = 100
    min_exp_len_train = 10
    n = 5000
    game_trainer = Trainer(1)
    game_trainer.play_train(net, game, learning_rate, seq_len, batch_size,
                            num_times, greed_frames, max_exp_len, min_exp_len_train, 1, n, 15, LOGDIR)
else:
    print("INVALID PLAY OPTION")

game.kill()
exit()


from __future__ import annotations
from typing import TYPE_CHECKING, Tuple, Dict, Type, Union, Optional
from ...http import Route

from . import models

if TYPE_CHECKING:
    from .server import EventSubClient
    from .models import EventData, Subscription

__all__ = ("EventSubHTTP",)

class EventSubHTTP:
    def __init__(self, client: EventSubClient, token: Optional[str]):
        self._client = client
        self._http = client.client._http
        self._token = token

    async def create_subscription(self, event_type: Tuple[str, int, Type[EventData]], condition: Dict[str, str]):
        payload = {
            "type": event_type[0],
            "version": str(event_type[1]),
            "condition": condition,
            "transport": {"method": "webhook", "callback": self._client.route, "secret": self._client.secret},
        }
        route = Route("POST", "eventsub/subscriptions", body=payload, token=self._token)
        return await self._http.request(route, paginate=False, force_app_token=True)

    async def delete_subscription(self, substription: Union[str, Subscription]):
        if isinstance(substription, models.Subscription):
            return await self._http.request(
                Route("DELETE", "eventsub/subscriptions", query=[("id", substription.id)]), paginate=False
            )
        return await self._http.request(
            Route("DELETE", "eventsub/subscriptions", query=[("id", substription)]), paginate=False
        )

    async def get_subscriptions(self, status: str = None):
        qs = []
        if status:
            qs.append(("status", status))

        return [
            models.Subscription(d)
            for d in await self._http.request(Route("GET", "eventsub/subscriptions", query=qs), paginate=False)
        ]

    async def get_status(self, status: str = None):
        qs = []
        if status:
            qs.append(("status", status))

        v = await self._http.request(Route("GET", "eventsub/subscriptions", query=qs), paginate=False, full_body=True)
        del v["data"]
        del v["pagination"]
        return v


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jul 13 10:38:12 2020

@author: dvasilkova
"""

import numpy as np

def centre(x,y,r,theta):
    #x,y of decay point, find centre of tangent circle
    N = np.sqrt(x**2+y**2)
    vect = (-x/N,-y/N)
    newx = x + r*vect[0]
    newy = y + r*vect[1]
    return rotate((x,y),(newx,newy),theta)

def track(x,y,r,theta):
    #calculate the circle of a track from a decay at x,y
    #x,y of tangent point, r radius of curvature
    angles = np.linspace(-np.pi,np.pi,1000)
    sx, sy = centre(x,y,r,theta)

    xp = np.cos(-angles)*r+sx
    yp = np.sin(-angles)*r+sy

    return xp,yp,sx,sy

def r_c(P):
    #calculate radius of curvature in m, P = positron momentum in MeV
    B = 1.45
    e = 0.303
    return (P*1e-3)/(B*e)

def hit_tracker(decays,trackerx_min,trackerx_max,trackery_min,trackery_max):
    #check if the track hits the tracker, defined to exist between xmin-xmax, ymin-ymax
    #decays should be a list of muon decay-style objects with attributes for ring position and momentum
    passed = []

    for d in decays:
        rad = r_c(d.P)
        circx, circy, cx, cy = track(d.x,d.y,rad,d.angle)

        hitcount = 0

        for i in range(len(circx)):
            xpos = circx[i]
            ypos = circy[i]
            #print(xpos,ypos)

            if xpos > trackerx_min and xpos < trackerx_max and ypos < trackery_max and ypos > trackery_min:
                  #print('hit!')

                  d.nhits += 1
                  d.hits.append((xpos,ypos))

                  if hitcount == 0:

                      passed.append(d)

                      d.hitTracker = True

                      xh = xpos
                      yh = ypos

                      x1 = d.x
                      y1 = d.y

                      a = np.sqrt((x1-xh)**2+(y1-yh)**2)
                      b = np.sqrt((x1-cx)**2+(y1-cy)**2)
                      c = np.sqrt((cx-xh)**2+(cy-yh)**2)

                      angle = np.arccos((b**2+c**2-a**2)/(2*b*c))

                      d.arclength = angle*rad

                      d.xhit = xh
                      d.yhit = yh

                      hitcount = 1

    return passed, circx,circy, cx, cy

def rotate(origin, point, angle):
    #helper function to rotate tracks by the azimuthal decay angle
    ox, oy = origin
    px, py = point

    qx = np.cos(angle)*(px-ox) - np.sin(angle)*(py-oy) + ox
    qy = np.sin(angle)*(px-ox) + np.cos(angle)*(py-oy) + oy

    return qx,qy

if __name__ == "__main__":

    import matplotlib.pyplot as plt
    from scipy.interpolate import interp1d

    plt.style.use('gm2.mplstyle')
    plt.ion()

    #these functions are copies of the main MC ones to allow this module to be run solo

    def angleSpectrum(E,theta,Pu=1):
        muonM = 105.66

        Emax = muonM/2

        x = E/Emax

        a = (Pu*np.cos(theta))*(1-2*x)
        b = 3-2*x
        return x*x*(b-a)

    def sample_angle(n,E):

        samples = []

        while len(samples) < n:
            z = np.random.uniform(-np.pi, np.pi)
            u = np.random.uniform(0, 5.)

            if u <= angleSpectrum(E,z,1):
                samples.append(z)

        if len(samples) ==1:
            return samples[0]
        else:
            return samples

    def acc_filter(data,function,xs):

        scan = [function(i) for i in xs]
        maxfn = max(scan)

        samples = []

        for d in data:
            u = np.random.uniform(0, maxfn)
            if u <= momAcceptanceFunction(d.P):
                samples.append(d)
        return samples

    def mom_acc_cut(data):
        output = acc_filter(data,momAcceptanceFunction,np.linspace(0.511,3094,50))

        return output

    def momAcceptanceFunction(x):
        #applies the volumes hit momentum cut
        xs = np.linspace(0.511,3094,10)
        y = [0,0,14,23,26,25,23,18,10,0]

        fit = interp1d(xs, y,kind='linear')

        return fit(x)

    class decay:

        def __init__(self):
            radius = 7.1
            self.ringAngle = np.random.uniform(-np.pi,np.pi)
            self.x = np.cos(self.ringAngle)*radius
            self.y = np.sin(self.ringAngle)*radius
            self.P = np.random.uniform(0.511,3094)
            self.E = np.sqrt(self.P**2+0.51**2)
            self.arclength = radius*self.ringAngle
            self.hitTracker = False
            self.nhits = 0
            self.angle = sample_angle(1,self.P)

            self.xhit = 0
            self.yhit = 0

            self.hits = []

        def boost(self):
        #method to boost the muon into the detector frame
            gamma = 29.3
            muonM = 105.66
            mu_momentum = 3.094e3 #3.094 GeV/c
            mu_v = -mu_momentum/(gamma*muonM) #-tive because boosting back into lab frame

            Px = self.P*np.sin(self.angle)
            Pz = self.P*np.cos(self.angle)

            boostedPz = gamma*(Pz-mu_v*self.E)
            #boostedE = gamma*(self.E-mu_v*Pz)

            #self.P = np.sqrt(boostedPz**2+Px**2+Py**2)
            #self.E = boostedE
            self.angle = np.arctan(Px/boostedPz)

    decays = []

    for i in range(100000):
        d = decay()
        d.boost()
        decays.append(d)

    x = []
    y = []
    p = []
    arcs = []
    for i in decays:
        x.append(i.x)
        y.append(i.y)

    fig, ax = plt.subplots(figsize=(6, 6))

    #define tracker position and boundaries
    x_max = 6.9
    x_min = 6.7
    y_min = -1
    y_max = 0

    nplanes = 32
    plane_cut = 5

    cutdist = plane_cut/nplanes

    plane = 1/32

    ring = plt.Circle((0,0),radius=7.1,alpha=0.5,fill=False)
    hits, circx,circy, cx, cy= hit_tracker(decays,x_min,x_max,y_min,y_max)

    nocuthits = hits #all hits

    hits = mom_acc_cut(hits) #hits with acceptance cuts

    pos_track = []

    for i,j in zip(circx,circy):
        pos_track.append((i,j))

    arcs = []
    col = 'r'
    if len(hits) > 0:
        col = 'green'

    nohits = []

    xhits = []
    yhits = []

    momp = []
    ang = []
    vert = []

    nocutp = []

    for i in nocuthits:
        nocutp.append(i.P)

    for i in hits:

        x.append(i.x)
        y.append(i.y)
        xhits.append(i.xhit)
        yhits.append(i.yhit)
        p.append(i.P)

        ang.append(i.angle)

        #perform the nHits cut - compare yin/yout to see how many planes hit
        y_first = i.hits[0][1]
        y_last = i.hits[-1][1]

        xhit = i.hits[0][0]

        ydiff = abs(y_last-y_first)

        if ydiff >= 11*plane and i.P > 400:
            nohits.append(np.floor(ydiff/plane))
            momp.append(i.P)
            arcs.append(i.arclength)
        elif ydiff >= 5*plane and ydiff < 11*plane and i.P > 400:

            ran = np.random.uniform(5,11)

            if np.floor(ydiff/plane) >= ran:

                nohits.append(np.floor(ydiff/plane))
                momp.append(i.P)
                arcs.append(i.arclength)

    '''
    plt.figure(1)
    #this plots the actual vertices and tracks
    #for unknown reasons it can't handle plotting more than a few tracks at once

    ax.add_artist(ring)
    ax.scatter(x,y)
    ax.plot([i[0] for i in pos_track],[i[1] for i in pos_track],color=col)

    plt.scatter(xhits,yhits,marker='x')

    plt.plot(np.linspace(x_min,x_max,3),[y_max,y_max,y_max],color='k')
    plt.plot([x_max,x_max,x_max],np.linspace(y_min,y_max,3),color='k')
    plt.plot([x_min,x_min,x_min],np.linspace(y_min,y_max,3),color='k')
    plt.plot(np.linspace(x_min,x_max,3),[y_min,y_min,y_min],color='k')

    plt.xlabel("x position [m]",horizontalalignment='right', x=1.0, verticalalignment='bottom', y=0.0)
    plt.ylabel("y position [m]",horizontalalignment='right', y=1.0, verticalalignment='bottom', x=0.0,labelpad=20)

    plt.xlim(-8,8)
    plt.ylim(-8,8)
    '''
    plt.figure(2)
    bins = np.linspace(0,3090,30)

    plt.hist(p,bins,histtype='step', label='All hits')
    plt.hist(momp,bins,histtype='step', label = 'Trackable hits')

    pre = np.histogram(nocutp,bins)[0]
    post = np.histogram(momp,bins)[0]
    ratio = post/pre

    plt.xlabel("Momentum [MeV]",horizontalalignment='right', x=1.0, verticalalignment='bottom', y=0.0)
    plt.ylabel("Counts/bin",horizontalalignment='right', y=1.0, verticalalignment='bottom', x=0.0,labelpad=20)
    plt.legend()

    plt.figure(3)
    plt.hist(arcs,bins=50,histtype='step')
    #plt.hist2d(p,ang,bins=(20,np.linspace(-0.01,0.01,20)))
    plt.xlabel("Arc length [m]",horizontalalignment='right', x=1.0, verticalalignment='bottom', y=0.0)
    plt.ylabel("Counts/bin",horizontalalignment='right', y=1.0, verticalalignment='bottom', x=0.0,labelpad=20)

    plt.figure(4)
    binz = np.linspace(0,3100,10)
    binz = np.insert(binz,1,300)
    corr = np.array([ 0.        ,  0, 0.14418263,  0.6452906 ,  0.92512741,  0.99520434,
    0.97328187,  0.880436  ,  0.72599633,  0.62138323,  0.        ])
    plt.scatter(binz,corr/1.5,label='Gas gun correction')
    plt.scatter(bins[:-1],ratio, label='nHits + high P correction')
    plt.xlabel("Momentum [MeV]",horizontalalignment='right', x=1.0, verticalalignment='bottom', y=0.0)
    plt.ylabel("Efficiency",horizontalalignment='right', y=1.0, verticalalignment='bottom', x=0.0,labelpad=20)

    plt.legend()


import os
import csv

# Define all the variables
votes = []
candidates = []
county = []
Khan = []
Correy = []
Li = []
Otooley = []

#Enter path to collect data from the Recources folder
election_csv = os.path.join("Resources", "election_data.csv")

# Open and read the csv file
with open(election_csv, 'r') as csvfile:

    # Split up the data on commas
    csvreader = csv.reader(csvfile, delimiter=',')

    next(csvreader)

    #Loop through the data
    for row in csvreader:
        votes.append(int(row[0]))
        county.append(row[1])
        candidates.append(row[2])
    for candidate in candidates:
        if candidate == "Khan":
            Khan.append(candidates)
            Khan_votes = len(Khan)
        elif candidate == "Correy":
            Correy.append(candidates)
            Correy_votes = len(Correy)
        elif candidate == "Li":
            Li.append(candidates)
            Li_votes = len(Li)
        else:
            Otooley.append(candidates)
            Otooley_votes = len(Otooley)

    #Calculate the total number of votes
    total_votes = (len(votes))

    #Calculate the percentages
    KP = round((Khan_votes / total_votes) * 100, 2)
    CP = round((Correy_votes / total_votes) * 100, 2)
    LP = round((Li_votes / total_votes) * 100, 2)
    OP = round((Otooley_votes / total_votes) * 100, 2)

    # To find the winner
    winner = [KP, CP, LP, OP]
    Election_winner = max(winner)

    if Election_winner == KP:
        winner_name = "Khan"

    elif Election_winner == CP:
        winner_name = "Correy"

    elif Election_winner == LP:
        winner_name = "Li"

    else:
        winner_name = "O'Tooley"

    #Print the results
    print("Election Results")
    print("----------------------")
    print(f"Total Votes: {total_votes}")
    print("-----------------------")
    print(f"Khan: {KP}% ({Khan_votes})")
    print(f"Correy: {CP}% ({Correy_votes})")
    print(f"Li: {LP}% ({Li_votes})")
    print(f"O'Tooley: {OP}% ({Otooley_votes})")
    print("------------------------")
    print(f"Winner: {winner_name}")
    print("-------------------------")

    #Export the output to a text file
    file = open("pypolloutput.txt", "w")
    data = ["Election Results \n",
    "--------------------- \n",
    "Total Votes: {} \n".format(total_votes),
    "--------------------- \n",
    "Khan: {}% ({}) \n".format(KP, Khan_votes),
    "Correy: {}% ({}) \n".format(CP, Correy_votes),
    "Li: {}% ({}) \n".format(LP, Li_votes),
    "O'Tooley: {}% ({}) \n".format(OP, Otooley_votes),
    "--------------------- \n",
    "Winner: {} \n".format(winner_name),
     "--------------------- \n"]

    file.writelines(data)
    file.close()


# coding: UTF-8
import os
import torch
import numpy as np
import pickle as pkl
from tqdm import tqdm
import time
from datetime import timedelta
import jieba
import re
from random import random

MAX_VOCAB_SIZE = 10000  # 词表长度限制
UNK, PAD = '<UNK>', '<PAD>'  # 未知字，padding符号

def build_vocab(file_path, tokenizer, max_size, min_freq):
    vocab_dic = {}
    with open(file_path, 'r', encoding='UTF-8') as f:
        for line in tqdm(f):
            lin = line.strip()
            if not lin:
                continue
            name = lin.split('\t')[4]
            text = eval(lin.split('\t')[5])
            text1 = [key for key in text.keys()]
            text2 = [value for value in text.values()]
            content = name + '|' + '|'.join(text1 + text2)
            content = ' '.join(jieba.lcut(content))
            for word in tokenizer(content):
                vocab_dic[word] = vocab_dic.get(word, 0) + 1
        vocab_list = sorted([_ for _ in vocab_dic.items() if _[1] >= min_freq], key=lambda x: x[1], reverse=True)[
                     :max_size]
        vocab_dic = {word_count[0]: idx for idx, word_count in enumerate(vocab_list)}
        vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1})
    return vocab_dic

def build_dataset(config, ues_word, feature_map):
    if ues_word:
        tokenizer = lambda x: x.split(' ')  # 以空格隔开，word-level
    else:
        tokenizer = lambda x: [y for y in x]  # char-level
    if os.path.exists(config.vocab_path):
        vocab = pkl.load(open(config.vocab_path, 'rb'))
        print(vocab)
    else:
        vocab = build_vocab(config.train_path, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)
        pkl.dump(vocab, open(config.vocab_path, 'wb'))
    print(f"Vocab size: {len(vocab)}")

    def load_dataset(path, feature_map, class_list, gather_class_list, pad_size=32, feature_number=2):
        contents = []
        with open(path, 'r', encoding='UTF-8') as f:
            for line in tqdm(f):
                lin = line.strip()
                if not lin:
                    continue
                # 正常操作
                # name = lin.split('\t')[4]
                # text = eval(lin.split('\t')[5])
                # text = [value for value in text.values()]
                # content = name + '|' + '|'.join(text)
                # content = ' '.join(jieba.lcut(content))

                # bertplus_data要素内容和要素名称分开读取
                name = lin.split('\t')[4]
                text = eval(lin.split('\t')[5])
                content1 = ['商品名称'] + [key for key in text.keys()]  # 要素名称
                content2 = [name] + [value for value in text.values()]  # 要素内容

                gather_label = lin.split('\t')[3]
                if gather_label in feature_map.keys():
                    feature_id = feature_map[gather_label]
                    feature_name = []
                    feature_text = []
                    try:
                        # 按照feature_map选前两位
                        feature_name += [content1[_] for _ in feature_id[:feature_number]]
                        feature_text += [content2[_] for _ in feature_id[:feature_number]]
                    except:
                        # print(content1)
                        # print(content2)
                        # print(gather_label)
                        feature_name = [content1[0]] + [content1[3]]
                        feature_text = [content2[0]] + [content2[3]]
                else:
                    try:
                        feature_name = [content1[0]] + [content1[3]]
                        feature_text = [content2[0]] + [content2[3]]
                    except:
                        feature_name = [content1[0]]
                        feature_text = [content2[0]]

                feature_content = ''
                for name, text in zip(feature_name, feature_text):
                    feature_content += name + text + '|'
                feature_content = feature_content[:-1]
                feature_content = ' '.join(jieba.lcut(feature_content))

                content1 = '|'.join(content1)

                content2_1 = '|'.join(content2)
                content2_2 = '||'.join(content2)
                content2_3 = '|||'.join(content2)
                content2 = '|'.join(content2)

                content1 = jieba.lcut(content1)

                content2 = jieba.lcut(content2)
                content2_1 = jieba.lcut(content2_1)
                content2_2 = jieba.lcut(content2_2)
                content2_3 = jieba.lcut(content2_3)

                index_list = []
                for index, word in enumerate(content2):  # 定位要素信息'|'的位置，获得要素分割地址
                    if word == '|':
                        index_list.append(index)

                content1 = ' '.join(content1)

                content2 = ' '.join(content2)
                content2_1 = ' '.join(content2_1)
                content2_2 = ' '.join(content2_2)
                content2_3 = ' '.join(content2_3)

                content2_1 = re.sub('\|', PAD, content2_1)  # 不做pading
                content2_2 = re.sub('\|', PAD, content2_2)
                content2_3 = re.sub('\|', PAD, content2_3)

                # bertplus_data只加载要素名称
                # content = eval(content)
                # content = [keys for keys in content.keys()]
                # content = '商品名称|'+'|'.join(content)

                # 正常
                label = lin.split('\t')[2]
                if label in class_list:
                    label = class_list.index(label)
                else:
                    print('sth wrong')
                    print(line)
                    continue

                # 大税号分类
                # label = lin.split('\t')[3]
                # label = class_list.index(label)

                gather_label = lin.split('\t')[3]
                if gather_label in gather_class_list:
                    gather_label = gather_class_list.index(gather_label)
                else:
                    print('sth wrong')
                    print(line)
                    continue

                words_line = []

                # 正常2id
                # token = tokenizer(content)
                # seq_len = len(token)

                """
                # 用两个token做2id
                token1 = tokenizer(content1)
                token2 = tokenizer(content2)
                seq_len1 = len(token1)
                seq_len2 = len(token2)

                # 分别对两个token进行pad操作
                for i, token in enumerate([token1, token2]):
                    if pad_size:
                        if len(token) < pad_size:
                            seq_len = len(token)
                            token.extend([PAD] * (pad_size - len(token)))
                        else:
                            token = token[:pad_size]
                            seq_len = pad_size
                        if i == 0:
                            token1 = token
                            seq_len1 = seq_len
                        elif 1 == 1:
                            token2 = token
                            seq_len2 = seq_len

                index_list.append(seq_len2)  # 加一个最后长度，防止把pad算入, 并填充至20
                if len(index_list) < 20:
                    index_list.extend([-1] * (20 - len(index_list)))
                else:
                    print('this sentense index over')
                token = token1 + token2
                """

                """
                # 正常操作：
                if pad_size:
                    if len(token) < pad_size:
                        token.extend([PAD] * (pad_size - len(token)))
                    else:
                        token = token[:pad_size]
                        seq_len = len(token)
                """
                # """
                # 4组不同的pading
                token1 = tokenizer(content1)
                token2_1 = tokenizer(content2_1)
                token2_2 = tokenizer(content2_2)
                token2_3 = tokenizer(content2_3)
                token3 = tokenizer(feature_content)

                seq_len1 = len(token1)
                seq_len2_1 = len(token2_1)
                seq_len2_2 = len(token2_2)
                seq_len2_3 = len(token2_3)
                seq_len3 = len(token3)

                # 分别对4个token进行pad操作
                for i, token in enumerate([token1, token2_1, token2_2, token2_3, token3]):
                    if pad_size:
                        if len(token) < pad_size:
                            seq_len = len(token)
                            token.extend([PAD] * (pad_size - len(token)))
                        else:
                            token = token[:pad_size]
                            seq_len = pad_size
                        if i == 0:
                            token1 = token
                            seq_len1 = seq_len
                        elif i == 1:
                            token2_1 = token
                            seq_len2_1 = seq_len
                        elif i == 2:
                            token2_2 = token
                            seq_len2_2 = seq_len
                        elif i == 3:
                            token2_3 = token
                            seq_len2_3 = seq_len
                        elif i == 4:
                            token3 = token
                            seq_len3 = seq_len

                token = token1 + token2_1 + token2_2 + token2_3 + token3
                # """

                # word to id
                for word in token:
                    words_line.append(vocab.get(word, vocab.get(UNK)))
                # contents.append((words_line, int(label), seq_len, int(gather_label)))  # 正常的2id
                contents.append((words_line, int(label), seq_len1, seq_len2_1, seq_len2_2, seq_len2_3, int(gather_label)))  # 两条语句的2id
        return contents  # [([...], 0, 32, 32，'8400'), ([...], 1), ...]

    train = load_dataset(config.train_path, feature_map, config.class_list, config.gather_class_list, config.pad_size)
    dev = load_dataset(config.dev_path, feature_map, config.class_list, config.gather_class_list, config.pad_size)
    test = load_dataset(config.test_path, feature_map, config.class_list, config.gather_class_list, config.pad_size)
    return vocab, train, dev, test

class DatasetIterater(object):
    def __init__(self, batches, batch_size, device):
        self.batch_size = batch_size
        self.batches = batches
        self.n_batches = len(batches) // batch_size
        self.residue = False  # 记录batch数量是否为整数
        if len(batches) % self.n_batches != 0:
            self.residue = True
        self.index = 0
        self.device = device

    def _to_tensor(self, datas):
        x = torch.LongTensor([_[0] for _ in datas]).to(self.device)  # 文本id
        y = torch.LongTensor([_[1] for _ in datas]).to(self.device)  # label
        z = torch.LongTensor([_[6] for _ in datas]).to(self.device)  # gather_label  3或者4或者6

        """
        # 正常操作
        # pad前的长度(超过pad_size的设为pad_size)
        seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)
        return (x, seq_len), y, z

        # """
        # 两层token转tensor
        seq_len1 = torch.LongTensor([_[2] for _ in datas]).to(self.device)
        seq_len2_1 = torch.LongTensor([_[3] for _ in datas]).to(self.device)
        seq_len2_2 = torch.LongTensor([_[4] for _ in datas]).to(self.device)
        seq_len2_3 = torch.LongTensor([_[5] for _ in datas]).to(self.device)
        # index_list = torch.LongTensor([_[5] for _ in datas]).to(self.device)
        return (x, seq_len1, seq_len2_1, seq_len2_2, seq_len2_3), y, z
        # """

    def __next__(self):
        if self.residue and self.index == self.n_batches:
            batches = self.batches[self.index * self.batch_size: len(self.batches)]
            self.index += 1
            batches = self._to_tensor(batches)
            return batches

        elif self.index >= self.n_batches:
            self.index = 0
            raise StopIteration
        else:
            batches = self.batches[self.index * self.batch_size: (self.index + 1) * self.batch_size]
            self.index += 1
            batches = self._to_tensor(batches)
            return batches

    def __iter__(self):
        return self

    def __len__(self):
        if self.residue:
            return self.n_batches + 1
        else:
            return self.n_batches

def build_iterator(dataset, config):
    iter = DatasetIterater(dataset, config.batch_size, config.device)
    return iter

def get_time_dif(start_time):
    """获取已使用时间"""
    end_time = time.time()
    time_dif = end_time - start_time
    return timedelta(seconds=int(round(time_dif)))

if __name__ == "__main__":
    '''提取预训练词向量'''
    # 下面的目录、文件名按需更改。
    train_dir = "./THUCNews/data/train.txt"
    vocab_dir = "./THUCNews/data/vocab.pkl"
    pretrain_dir = "./THUCNews/data/sgns.sogou.char"
    emb_dim = 300
    filename_trimmed_dir = "./THUCNews/data/embedding_SougouNews"
    if os.path.exists(vocab_dir):
        word_to_id = pkl.load(open(vocab_dir, 'rb'))
    else:
        # tokenizer = lambda x: x.split(' ')  # 以词为单位构建词表(数据集中词之间以空格隔开)
        tokenizer = lambda x: [y for y in x]  # 以字为单位构建词表
        word_to_id = build_vocab(train_dir, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)
        pkl.dump(word_to_id, open(vocab_dir, 'wb'))

    embeddings = np.random.rand(len(word_to_id), emb_dim)
    f = open(pretrain_dir, "r", encoding='UTF-8')
    for i, line in enumerate(f.readlines()):
        # if i == 0:  # 若第一行是标题，则跳过
        #     continue
        lin = line.strip().split(" ")
        if lin[0] in word_to_id:
            idx = word_to_id[lin[0]]
            emb = [float(x) for x in lin[1:301]]
            embeddings[idx] = np.asarray(emb, dtype='float32')
    f.close()
    np.savez_compressed(filename_trimmed_dir, embeddings=embeddings)


import json

def Read_JSON (filename):
    with open (filename) as infile:
        output = json.load(infile)
    return output

def Write_JSON (filename, object):
    with open( filename, 'w') as outfile:
        json.dump(object, outfile)

def Calc_Centroid (coordinates, multiPolygon):
    max_lat=-180
    max_lon=-180
    min_lat=180
    min_lon=180
    for l1 in coordinates:
        for l2 in l1:
            if multiPolygon:
                for l3 in l2:
                    max_lat=max(l3[0], max_lat)
                    min_lat=min(l3[0], min_lat)
                    max_lon=max(l3[1], max_lon)
                    min_lon=min(l3[1], min_lon)
            else:
                max_lat=max(l2[0], max_lat)
                min_lat=min(l2[0], min_lat)
                max_lon=max(l2[1], max_lon)
                min_lon=min(l2[1], min_lon)
    return [(max_lat+min_lat)/2 , (max_lon+min_lon)/2]

def Calc_All_Centroids (geojsonObject, propertiesId):
    features=geojsonObject['features']
    centroids={}
    for feature in features:
        id=feature['properties'][propertiesId]
        if feature['geometry'] != None:
            coordinates=feature['geometry']['coordinates']
            multiPolygon= True if feature['geometry']['type']=='MultiPolygon' else False
            centroid=Calc_Centroid(coordinates, multiPolygon)
            centroids[id]=centroid
    return centroids

def Centroid_Calculator (infile, outfile, propertiesId):
    geojsonObject=Read_JSON(infile)
    centroids=Calc_All_Centroids(geojsonObject, propertiesId)
    Write_JSON(outfile, centroids)


# При заданном целом числе n посчитайте n + nn + nnn.

n = 123

nn = int(str(n) + str(n))

nnn = int(str(nn) + str(n))

result = n + nn + nnn

print(result)
print(123 + 123123 + 123123123)

def solve(n):
    n1 = n
    n2 = int(str(n) * 2)
    n3 = int(str(n) * 3)
    print(n1 + n2 + n3)

solve(123)


import sys
sys.setrecursionlimit(10 ** 9)

n, K = map(int, input().split())
p = list(map(int, input().split()))
for i in range(n):
    p[i] -= 1
c = list(map(int, input().split()))

g = [[] for _ in range(n)]
for i in range(n):
    g[i].append(p[i])
    #g[p[i]].append(i)
#print(g)

def dfs(g, v):
    seen[v] = True
    for next_v in g[v]:
        if seen[next_v]:
            continue
        lis.append(next_v)
        dfs(g, next_v)
    return lis

seen = [False] * n
count = 0
cycle_lis = []
for v in range(n):
    if seen[v]:
        continue
    lis = [v]
    dfs(g, v)
    cycle_lis.append(lis)
    count += 1
#print("count =  " + str(count))
#print(cycle_lis)

INF = 10 ** 18
ans = -INF
for i in range(count):
    cycle_lis_i = cycle_lis[i] * 2; #print("cycle_lis_i = " + str(cycle_lis_i))
    l = len(cycle_lis_i); #print("l = " + str(l))
    cycle_sum = 0
    for j in range(l // 2):
        cycle_sum += c[cycle_lis_i[j]]
    #print("cycle_sum = " + str(cycle_sum))
    rest = K % (l // 2)
    if rest == 0:
        rest = l // 2
    #print("rest = " + str(rest))
    tmp_max = -INF; tmp_max_loop = -INF
    for j in range(l // 2):
        tmp = 0;
        for k in range(j, j + rest):
            tmp += c[cycle_lis_i[k]]
            #print("c = " + str(c[cycle_lis_i[k]]))
            #print("tmp = " + str(tmp))
            tmp_max = max(tmp_max, tmp)
        tmp2 = 0
        for k in range(j, j + l // 2):
            tmp2 += c[cycle_lis_i[k]]
            tmp_max_loop = max(tmp_max_loop, tmp2)
    #print("tmp_max = " + str(tmp_max))
    if cycle_sum > 0 and rest != l // 2:
        ans = max(cycle_sum * (K // (l // 2)) + tmp_max, ans)
    elif cycle_sum > 0 and rest == l // 2:
        ans = max(cycle_sum * (K // (l // 2) - 1) + tmp_max, ans)
    else:
        if K <= l // 2:
            ans = max(tmp_max, ans)
        else:
            ans = max(tmp_max_loop, ans)
print(ans)


import json
import pandas as pd
import numpy as np
from sklearn import preprocessing
from spherecluster import SphericalKMeans

types=['cid','genres','language','starCast']

#df.drop(['_id'], axis = 1, inplace = True)
def handle_non_numerical_data(df):
    columns = df.columns.values
    for column in columns:
        text_digit_vals = {}
        def convert_to_int(val):
            return text_digit_vals[val]

        if df[column].dtype != np.int64 and df[column].dtype != np.float64:
            column_contents = df[column].values.tolist()
            unique_elements = set(column_contents)
            x = 0
            for unique in unique_elements:
                if unique not in text_digit_vals:
                    text_digit_vals[unique] = x
                    x+=1

            df[column] = list(map(convert_to_int, df[column]))

    return df

def preprocessdata(df,type):
    df = handle_non_numerical_data(df)
    #df.drop(['_id',type],axis=1)
    df.drop(['_id'],axis=1)

    X=np.array(df.astype(float))
    X= preprocessing.scale(X)

    return X

for type in types:
    df=pd.read_csv(type+'.csv', index_col=0)
    X=preprocessdata(df, type)

    skm = SphericalKMeans(n_clusters=2)
    skm.fit(X)

    df=pd.read_csv(type+'.csv', index_col=0)
    df['cluster_id']=skm.labels_
    print(df)


import sys, os

sys.path.append(os.pardir)
import numpy as np
import matplotlib.pylab as plt
from dataset.mnist import load_mnist

(x_train, t_train), (x_test, t_test) = \
    load_mnist(normalize=True, one_hot_label=True)

print(x_train.shape)
print(t_train.shape)

train_size = x_train.shape[0]
batch_size = 10
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]

print(np.random.choice(60000, 10))  # 10개의 인덱스를 랜덤으로 뽑음

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

### 4.3.1 미분~~~

# 나쁜 구현 예
def numerical_diff(f, x):
    h = 10e-50
    return (f(x + h) - f(x)) / h

print(np.float32(1e-50))

def numerical_diff(f, x):
    h = 1e-4  # 0.0001
    return (f(x + h) - f(x - h)) / (2 * h)

def function_1(x):
    return 0.01 * x ** 2 + 0.1 * x

'''
x = np.arange(0.0, 20.0, 0.1)
y = function_1(x)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.plot(x, y)
plt.show()
'''

print(numerical_diff(function_1, 5))
print(numerical_diff(function_1, 10))

def function_2(x):
    return x[0] ** 2 + x[1] ** 2  # 또는 return np.sum(x**2)

def function_tmp1(x0):
    return x0 * x0 + 4.0 ** 2.0

print(numerical_diff(function_tmp1, 3.0))

def function_tmp2(x1):
    return 3.0 ** 2.0 + x1 * x1

print(numerical_diff(function_tmp2, 4.0))

def numerical_gradient(f, x):
    h = 1e-4
    grad = np.zeros_like(x)       # x 와 형상이 같은 배열을 생성

    for idx in range(x.size):
        tmp_val = x[idx]

        # f(x+h) 계산
        x[idx] = tmp_val + h
        fxh1 = f(x)

        # f(x-h) 계산
        x[idx] = tmp_val - h
        fxh2 = f(x)

        grad[idx] = (fxh1 - fxh2) / (2*h)
        x[idx] = tmp_val # 값 복원

    return grad

print(numerical_gradient(function_2, np.array([3.0, 4.0])))
print(numerical_gradient(function_2, np.array([0.0, 2.0])))
print(numerical_gradient(function_2, np.array([3.0, 0.0])))

### 4.4.1

def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x

    for i in range(step_num):
        grad = numerical_gradient(f, x)
        x -= lr * grad
    return x

def function_2(x):
    return x[0]**2 + x[1]**2

init_x = np.array([-3.0, 4.0])
print(gradient_descent(function_2, init_x = init_x, lr=0.1, step_num=100))

# 학습률이 너무 큰 예 : lr=10.0
init_x = np.array([-3.0, 4.0])
print(gradient_descent(function_2, init_x=init_x, lr=10.0, step_num=100))

# 학습률이 너무 작은 예 : lr=1e-10
init_x = np.array([-3.0, 4.0])
print(gradient_descent(function_2, init_x=init_x, lr=1e-10, step_num=100))


import os
from setuptools import setup, find_packages

# Note: setup() has access to cmd arguments of the setup.py script via sys.argv

# Utility function to read the README file.
def read(fname):
    return open(os.path.join(os.path.dirname(__file__), fname)).read()

install_requires = [
    "pickle5",
    "matplotlib",
    "tqdm",
    "tensorboard",
    "torch>=1.8",
    "torch-geometric>=1.7.2",
    "torch-scatter",
    "torch-sparse",
]
test_requires = ["black", "pytest", "pytest-mpi"]

setup(
    name="HydraGNN",
    version="1.0",
    package_dir={"hydragnn": "hydragnn"},
    packages=find_packages(),
    install_requires=install_requires,
    extras_require={"test": test_requires},
    description="Distributed PyTorch implementation of multi-headed graph convolutional neural networks",
    license="BSD-3",
    long_description=read("README.md"),
    url="https://github.com/ORNL/HydraGNN",
    author="Massimiliano Lupo Pasini, Samuel Temple Reeve, Pei Zhang, Jong Youl Choi",
    author_email="lupopasinim@ornl.gov",
)


class Solution:
    def reductionOperations(self, nums: List[int]) -> int:
        n = len(nums)
        nums.sort(reverse = True)
        res = 0
        prev, ctr = None, 0
        for i in range(n):
            if prev == None:
                prev, ctr = nums[i], 1
            elif nums[i] == prev:
                ctr += 1
            else:
                res += ctr
                prev = nums[i]
                ctr += 1
        return res


import cv2
import dlib
import os
import numpy as np
import joblib
import sklearn
import torch
from utils.eye_sample import EyeSample
from utils.eye_prediction import EyePrediction
from models.PupilNet import PupilNet_v2
import torch.nn as nn

model_x = joblib.load('models/model_x.pkl') # model for predicting x-coordinate of gaze vector
model_y = joblib.load('models/model_y.pkl') # model for predicting y-coordinate of gaze vector
model = PupilNet_v2()                # model for predicting pupil center
model.load_state_dict(torch.load('models/pupilnet_v5.pt'))

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = model.to(device)
print(device)

def shape_to_np(shape, dtype="int"):
    # initialize the list of (x, y)-coordinates
    coords = np.zeros((68, 2), dtype=dtype)
    # loop over the 68 facial landmarks and convert them
    # to a 2-tuple of (x, y)-coordinates
    for i in range(0, 68):
        coords[i] = (shape.part(i).x, shape.part(i).y)
    # return the list of (x, y)-coordinates
    return coords

def predict_pupil(eyes, ow=160, oh=96):
    result = []
    for eye in eyes:
        with torch.no_grad():
            x = torch.tensor([eye.img/255.0], dtype=torch.float32).to(device)
            pupil = model(x.view(1, 1, 96, 160))
            pupil = np.asarray(pupil.cpu().numpy())
            assert pupil.shape == (1, 2)
            tmp = pupil[0][0]
            pupil[0][0] = pupil[0][1] / 2
            pupil[0][1] = tmp / 2
            pupil = pupil * np.array([oh/48, ow/80])
            temp = np.zeros((1, 3))
            if eye.is_left:
                temp[:, 0] = ow - pupil[:, 1]
            else:
                temp[:, 0] = pupil[:, 1]
            temp[:, 1] = pupil[:, 0]
            temp[:, 2] = 1.0
            pupil = temp
            assert pupil.shape == (1, 3)
            pupil = np.asarray(np.matmul(pupil, eye.transform_inv.T))[:, :2]
            assert pupil.shape == (1, 2)
            result.append(EyePrediction(eye_sample=eye, landmarks=pupil, gaze=None))

    return result

def segment_eyes(frame, landmarks, ow=160, oh=96):
    eyes = []

    # Segment eyes
    for corner1, corner2, is_left in [(42, 45, True), (36, 39, False)]:
        x1, y1 = landmarks[corner1, :]
        x2, y2 = landmarks[corner2, :]
        eye_width = 1.5 * np.linalg.norm(landmarks[corner1, :] - landmarks[corner2, :])
        if eye_width == 0.0:
            return eyes

        cx, cy = 0.5 * (x1 + x2), 0.5 * (y1 + y2)

        # center image on middle of eye
        translate_mat = np.asmatrix(np.eye(3))
        translate_mat[:2, 2] = [[-cx], [-cy]]
        inv_translate_mat = np.asmatrix(np.eye(3))
        inv_translate_mat[:2, 2] = -translate_mat[:2, 2]

        # Scale
        scale = ow / eye_width
        scale_mat = np.asmatrix(np.eye(3))
        scale_mat[0, 0] = scale_mat[1, 1] = scale
        inv_scale = 1.0 / scale
        inv_scale_mat = np.asmatrix(np.eye(3))
        inv_scale_mat[0, 0] = inv_scale_mat[1, 1] = inv_scale

        estimated_radius = 0.5 * eye_width * scale

        # center image
        center_mat = np.asmatrix(np.eye(3))
        center_mat[:2, 2] = [[0.5 * ow], [0.5 * oh]]
        inv_center_mat = np.asmatrix(np.eye(3))
        inv_center_mat[:2, 2] = -center_mat[:2, 2]

        # Get rotated and scaled, and segmented image
        transform_mat = center_mat * scale_mat * translate_mat
        inv_transform_mat = (inv_translate_mat * inv_scale_mat * inv_center_mat)

        eye_image = cv2.warpAffine(frame, transform_mat[:2, :], (ow, oh))
        eye_image = cv2.equalizeHist(eye_image)

        if is_left:
            eye_image = np.fliplr(eye_image)

        eyes.append(EyeSample(orig_img=frame.copy(),
                              img=eye_image,
                              transform_inv=inv_transform_mat,
                              is_left=is_left,
                              estimated_radius=estimated_radius))
    return eyes

detector = dlib.get_frontal_face_detector() # face detector
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # pretrained facial landmarks detector

left = [36, 37, 38, 39, 40, 41] # choosing only eye`s landmarks
right = [42, 43, 44, 45, 46, 47]

cap = cv2.VideoCapture(0) # initializing webcam
ret, img = cap.read()
shape = None

while True:
    ret, img = cap.read()
    orig_frame = img.copy()
    frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    rects = detector(gray, 1)

    for rect in rects:
        shape = predictor(gray, rect)
        shape = shape_to_np(shape)

        eye_samples = segment_eyes(gray, shape)
        pupil_predicts = predict_pupil(eye_samples)

        left_eyes = list(filter(lambda x: x.eye_sample.is_left, pupil_predicts))
        right_eyes = list(filter(lambda x: not x.eye_sample.is_left, pupil_predicts))

        center_left = int(round(left_eyes[0].landmarks[0][0])), int(round(left_eyes[0].landmarks[0][1]))
        center_right = int(round(right_eyes[0].landmarks[0][0])), int(round(right_eyes[0].landmarks[0][1]))

        cv2.circle(img, center_left, 2, (0, 0, 255), -1)
        cv2.circle(img, center_right, 2, (0, 0, 255), -1)

        for (x, y) in shape[36:48]:
            cv2.circle(img, (x, y), 2, (255, 0, 0), -1)

        norm_right = np.sqrt(np.sum((np.array([shape[36][0], shape[36][1]]) - \
                                         np.array([shape[39][0], shape[39][1]])) ** 2))
        norm_left = np.sqrt(np.sum((np.array([shape[42][0], shape[42][1]]) - \
                                         np.array([shape[45][0], shape[45][1]])) ** 2))
        try:
            ldmks_right = (np.array([[shape[36][0], shape[36][1]],
                          [shape[37][0], shape[37][1]],
                          [shape[38][0], shape[38][1]],
                          [shape[39][0], shape[39][1]],
                          [shape[40][0], shape[40][1]],
                          [shape[41][0], shape[41][1]],
                          list(center_right)]) - [shape[36][0], shape[36][1]]) / norm_right
            ldmks_left = (np.array([[shape[42][0], shape[42][1]],
                          [shape[43][0], shape[43][1]],
                          [shape[44][0], shape[44][1]],
                          [shape[45][0], shape[45][1]],
                          [shape[46][0], shape[46][1]],
                          [shape[47][0], shape[47][1]],
                          list(center_left)]) - [shape[42][0], shape[42][1]]) / norm_left

            lookpt_right_x = model_x.predict(ldmks_right.reshape(1, -1))
            temp = np.append(ldmks_right.reshape(1, -1), lookpt_right_x)
            lookpt_right_y = model_y.predict(temp.reshape(1, -1))

            lookpt_left_x = model_x.predict(ldmks_left.reshape(1, -1))
            temp = np.append(ldmks_left.reshape(1, -1), lookpt_left_x)
            lookpt_left_y = model_y.predict(temp.reshape(1, -1))

            cv2.line(img, center_right, tuple([int(lookpt_right_x * norm_right * 1.5 + shape[36][0]+3),
                     int(lookpt_right_y * norm_right + shape[36][1])]), (0,255,0), 2)
            cv2.line(img, center_left, tuple([int(lookpt_left_x * norm_left * 1.5 + shape[42][0]+3),
                     int(lookpt_left_y * norm_left + shape[42][1])]), (0,255,0), 2)
        except:
            pass

    cv2.imshow('eyes', img)
    if cv2.waitKey(1) & 0xFF == ord('q'): # press q to stop the program
        break

cv2.destroyAllWindows()
cap.release()


import argparse
import pusion as p
import numpy as np
from sklearn.neural_network import MLPClassifier
import csv
import sys
sys.path.insert(0, '/home/khen_proj_1/yuvaltuval/MicroExpressionsFaceRecognition/')
from model.utils import *

eval_metrics = [
    p.PerformanceMetric.ACCURACY,
    p.PerformanceMetric.MICRO_F1_SCORE,
    p.PerformanceMetric.MICRO_PRECISION,

    # p.PerformanceMetric.MICRO_RECALL,
    # p.PerformanceMetric.MICRO_F2_SCORE,
    # p.PerformanceMetric.MICRO_JACCARD_SCORE,
    # p.PerformanceMetric.MACRO_PRECISION,
    # p.PerformanceMetric.MACRO_RECALL,
    # p.PerformanceMetric.MACRO_F1_SCORE,
    # p.PerformanceMetric.MACRO_F2_SCORE,
    # p.PerformanceMetric.MACRO_JACCARD_SCORE,
    # p.PerformanceMetric.MEAN_MULTILABEL_ACCURACY,
    # p.PerformanceMetric.MEAN_CONFIDENCE,
    # p.PerformanceMetric.BALANCED_MULTICLASS_ACCURACY_SCORE
]

def fusion(dataset, y_true_path, y_lgbp_dir_path, y_slowfast_dir_path, output_path, slowfast_duplications):
    # get csv files paths
    if y_lgbp_dir_path is not None:
        # svm saves the csv files in one folder (for example: /SAMM/y_prob/C_1.0__kernel_rbf.csv)
        y_lgbp_paths_list = list(paths.list_files(y_lgbp_dir_path))
    # slowfast saves the csv files in one folder (for example: /<date>/SLOWFAST-ALPHA_4/y_prob_output)
    y_slowfast_paths_list = list(paths.list_files(y_slowfast_dir_path))
    y_slowfast_paths_list = [path for path in y_slowfast_paths_list if "y_prob_output.csv" in path]

    # create dictionary of paths
    fusion_paths = dict()
    fusion_paths['y_true_path'] = [y_true_path]
    if y_lgbp_dir_path is not None:
        fusion_paths['y_lgbp_path'] = y_lgbp_paths_list

    # create empty list for permutations
    permutations_dicts = []

    for i in range(slowfast_duplications):
        fusion_paths[f'y_slowfast_{i}_path'] = y_slowfast_paths_list

        # add permutations for the path so far, so if the requestd slowfasts is n, we'll have also n-1, n-2 etc
        permutations_dicts += create_permutations_from_dict(fusion_paths)

    # for each permutation, load the csv, get predictions and perform fusion
    for perm in tqdm(permutations_dicts):
        # default None for lgbp
        y_lgbp = None

        # load predictions
        if y_lgbp_dir_path is not None:
            y_test, y_lgbp, y_slowfasts_dict = load_lgbp_slowfast_and_labels(**perm)
        else:
            y_test, y_slowfasts_dict = load_slowfast_and_labels(**perm)

        # fuse predictions
        generic_matrix, ensemble_matrix = perform_fusion(y_test, y_lgbp, y_slowfasts_dict)

        # save report
        is_lgbp_exists = y_lgbp is not None
        save_report(output_path, generic_matrix, ensemble_matrix, slowfast_duplications, is_lgbp_exists=is_lgbp_exists, **perm)

def load_lgbp_slowfast_and_labels(y_true_path, y_lgbp_path, **y_slowfast_paths):
    # load predictions
    y_lgbp = load_lgbp(y_lgbp_path)
    y_slowfasts_dict = load_slowfast(**y_slowfast_paths)
    y_test = load_labels(y_true_path, y_lgbp)

    return y_test, y_lgbp, y_slowfasts_dict

def load_slowfast_and_labels(y_true_path, **y_slowfast_paths):
    # load predictions
    y_slowfasts_dict = load_slowfast(**y_slowfast_paths)
    random_y_of_slowfast = list(y_slowfasts_dict.values())[0]
    y_test = load_labels(y_true_path, random_y_of_slowfast)

    return y_test, y_slowfasts_dict

def load_lgbp(y_lgbp_path):
    y_lgbp = load_results_and_predict(y_lgbp_path, header='infer', index_col=0)
    return y_lgbp

def load_slowfast(**y_slowfast_paths):
    y_slowfasts_dict = {}

    for slowfast_i, y_path in y_slowfast_paths.items():
        y_slowfast_i = load_results_and_predict(y_path, header=None, index_col=None)
        y_slowfasts_dict[slowfast_i] = y_slowfast_i

    return y_slowfasts_dict

def load_labels(y_true_path, y):
    y_test = load_dataset_csv_and_get_labels(y_true_path, y.shape)

    return y_test

def perform_fusion(y_test, y_lgbp, y_slowfasts_dict):
    # create instances with names
    # y_lgbp =  "LGBP Predictions using SVM"
    # y_slowfast.name = "SlowFast Predictions"

    # create instances. first is LGBP, the rest are SlowFast according to dict length
    if y_lgbp is not None:
        instances = ["LGBP"] + [f"SlowFast_{i}" for i in range(len(y_slowfasts_dict.keys()))]
    else:
        instances = [f"SlowFast_{i}" for i in range(len(y_slowfasts_dict.keys()))]

    # Create a numpy tensor
    y_ensemble = []
    if y_lgbp is not None:
        y_ensemble += [y_lgbp]
    y_ensemble += [y_slowfast for slowfast_i, y_slowfast in y_slowfasts_dict.items()]
    y_ensemble = np.array(y_ensemble)

    # perform generic fusion to get some statistics
    generic_matrix, ensemble_matrix = generic_fusion(y_test, y_ensemble, instances)

    # perform borda count off fusion
    # borda_matrix = borda_fusion(y_test, y_ensemble)

    return generic_matrix, ensemble_matrix

def save_report(output_path, generic_matrix, ensemble_matrix, total_number_of_slowfasts, is_lgbp_exists=False, **paths):
    # get names
    if is_lgbp_exists:
        lgbp_run = os.path.splitext(os.path.basename(paths['y_lgbp_path']))[0]
    slowfast_runs = [os.path.basename(os.path.dirname(os.path.normpath(paths[f'y_slowfast_{i}_path']))) if f'y_slowfast_{i}_path' in paths else None for i in range(total_number_of_slowfasts)]

    # create names columns
    slowfasts_names_dict = {f'SlowFast_{i}_name': slowfast_runs[i] for i in range(total_number_of_slowfasts)}
    if is_lgbp_exists:
        names_dict = {'LGBP_name': lgbp_run, **slowfasts_names_dict}
    else:
        names_dict = {**slowfasts_names_dict}

    # get LGBP and SlowFast accuracy
    ensemble_records = {x.replace(' ', ''): v for x, v in ensemble_matrix.records.items()}
    if is_lgbp_exists:
        LGBP_accuracy = ensemble_records['LGBP'][0]
    SlowFast_accuracies = [ensemble_records[f'SlowFast_{i}'][0] if f'SlowFast_{i}' in ensemble_records else None for i in range(total_number_of_slowfasts)]

    #build accuracies list
    accuracies = []
    if is_lgbp_exists:
        accuracies += [LGBP_accuracy]
    accuracies += SlowFast_accuracies
    accuracies = list(filter(None, accuracies))

    # create accuracies columns
    slowfasts_acc_dict = {f'SlowFast_{i}_accuracy': SlowFast_accuracies[i] for i in range(total_number_of_slowfasts)}
    if is_lgbp_exists:
        acc_dict = {'LGBP_accuracy': LGBP_accuracy, **slowfasts_acc_dict}
    else:
        acc_dict = {**slowfasts_acc_dict}

    # merge
    row_data = {**names_dict, **acc_dict}

    # add Number_Of_Winning_Fusions
    row_data['Number_Of_Winning_Fusions'] = 0

    # there are too much trailing white spaces at these strings
    generic_records = {x.replace(' ', ''): v for x, v in generic_matrix.records.items()}

    for i in range(len(generic_matrix.instance_names)):
        name = generic_matrix.instance_names[i].strip()
        accuracy = generic_records[name][0]
        row_data[f'{name}_accuracy'] = accuracy

        # check if the current fusion score is higher than the models scores
        if all(accuracy > x for x in accuracies):
            row_data['Number_Of_Winning_Fusions'] += 1

    # create accuracy report csv file
    create_accuracy_file_at_runtime(output_path, row_data, print_log=False)

def generic_fusion(y_test, y_ensemble, instances):
    # Initialize the general framework interface
    conf = p.Configuration(
        method=p.Method.GENERIC
    )

    # Initialize the general framework interface
    dp = p.DecisionProcessor(conf)

    # Fuse the ensemble classification outputs (test dataset)
    dp.combine(y_ensemble)

    # print metrics
    generic_matrix, ensemble_matrix = print_generic_fusion_metrics(dp, y_test, y_ensemble, instances)

    return generic_matrix, ensemble_matrix

def borda_fusion(y_test, y_ensemble):
    # User defined configuration
    conf = p.Configuration(
        method=p.Method.BORDA_COUNT,
        problem=p.Problem.MULTI_CLASS,
        assignment_type=p.AssignmentType.CONTINUOUS,
        coverage_type=p.CoverageType.COMPLEMENTARY_REDUNDANT
    )

    # Initialize the general framework interface
    dp = p.DecisionProcessor(conf)

    # Fuse the ensemble classification outputs (test dataset)
    y_comb = dp.combine(y_ensemble)

    # print metrics
    borda_matrix = print_single_fusion_metrics(dp, y_test, y_comb)

    return borda_matrix

def print_generic_fusion_metrics(dp, y_test, y_ensemble, instances):
    # print("============= Ensemble ===============")
    # print("ndarray[0] is LGBP, ndarray[1] is Slowfast")
    eval_classifiers = p.Evaluation(*eval_metrics)
    eval_classifiers.set_instances(instances)
    eval_classifiers.evaluate(y_test, y_ensemble)
    # print(eval_classifiers.get_report())
    ensemble_matrix = eval_classifiers.get_report()

    # print()
    eval_combiner = p.Evaluation(*eval_metrics)
    eval_combiner.set_instances(dp.get_combiners())
    eval_combiner.evaluate(y_test, dp.get_multi_combiner_decision_output())
    dp.set_evaluation(eval_combiner)
    # print(dp.report())
    generic_matrix = dp.evaluation.get_report()

    return generic_matrix, ensemble_matrix

def print_single_fusion_metrics(dp, y_test, y_comb):
    print("============== Borda Count Combiner ==============")
    eval_combiner = p.Evaluation(*eval_metrics)
    eval_combiner.set_instances(dp.get_combiner())
    eval_combiner.evaluate(y_test, y_comb)
    print(eval_combiner.get_report())
    borda_matrix = eval_combiner.performance_matrix

    return borda_matrix

if __name__ == '__main__':
    parser = argparse.ArgumentParser()

    # Path arguments
    parser.add_argument('--dataset', type=str,  # required=True,
                        default="SMIC",
                        help='Name of dataset.')
    parser.add_argument('--y_true_path', type=str, required=True,
                        # default="/home/khen_proj_1/yuvaltuval/MicroExpressionsFaceRecognition/output/classes/2022-08-17_08:00_SMIC_Split/SMIC/test.csv",
                        help='Path to load true labels.')
    parser.add_argument('--y_lgbp_dir_path', type=str, # required=True,
                        default=None,
                        # default="/home/khen_proj_1/yuvaltuval/MicroExpressionsFaceRecognition/output/SVM/2022-06-23_13:00/SAMM/y_prob/",
                        help='Path to a directory with lgbp predictions csv files.')
    parser.add_argument('--y_slowfast_dir_path', type=str, required=True,
                        # default="/home/khen_proj_1/yuvaltuval/MicroExpressionsFaceRecognition/output/SlowFast/2022-08-23_10:00_SMIC/",
                        help='Path to a directory with SlowFast predictions directories.')
    parser.add_argument('--output_path', type=str,  required=True,
                        # default="/home/khen_proj_1/yuvaltuval/MicroExpressionsFaceRecognition/output/Fusion/2022-08-23_10:00_SMIC/",
                        help='Path to save the fusion results')
    parser.add_argument('--slowfast_duplications', type=int,  # required=True,
                        default=1,
                        help='fuse LGBP with number of slowfasts')
    # parser.add_argument('--weights', type=str,  # required=True,
    #                     default="80/10/10",
    #                     help='How to divide wieghts between models first weight is LGBP, the rest are slowfast. 80/10/10 or 80/10/5/5')

    # parse arguments
    args = parser.parse_args()

    # create parameters for data making
    fusion_params = {
        'dataset': args.dataset,
        'y_true_path': args.y_true_path,
        'y_lgbp_dir_path': args.y_lgbp_dir_path,
        'y_slowfast_dir_path': args.y_slowfast_dir_path,
        'output_path': args.output_path,
        'slowfast_duplications': args.slowfast_duplications,
        # 'weights_list': args.weights,
    }

    # run functions
    fusion(**fusion_params)


# /usr/bin/python
# coding: utf-8
import math

class Solution:
    def findMin(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        left_minimum = nums[0]
        length = len(nums)
        while nums[-1] == left_minimum and length > 1:
            nums.pop()
            length -= 1
        if length <= 2:
            return min(nums)
        if left_minimum < nums[-1]:
            return left_minimum
        left, right = 0, length - 1
        while right > left + 1:
            medium = math.floor((left + right) / 2)
            if nums[medium] >= left_minimum:
                left = medium + 1
            else:
                right = medium
        return min(nums[left], nums[right])

print(Solution().findMin([1,3,5]))
print(Solution().findMin([2,2,2,0,1]))
print(Solution().findMin([2, 2, 2, 0, 2]))
print(Solution().findMin([2, 0, 2, 2, 2]))

154/Find Minimum in Rotated Sorted Array II.py


from common_func import *
from tqdm import tqdm

def sub_simrank(am, a, b, c=0.8):
    if a == b:
        return 1
    # id_matrix = np.identity(len(am))
    column_a = am[:, a]
    column_b = am[:, b]
    temp = column_a.sum() * column_b.sum()
    if temp == 0:
        return 0
    else:
        front_func = c / temp

    end_func = 0
    # 非常耗時
    # for i, i_tf in enumerate(column_a):
    #     for j, j_tf in enumerate(column_b):
    #         if i_tf and j_tf and i == j:
    #             end_func += 1

    # for i, i_tf in enumerate(column_a):
    #     if i_tf:
    #         for j, j_tf in enumerate(column_b):
    #             if j_tf and i == j:
    #                 end_func += 1

    a_1 = np.argwhere(column_a == 1)
    b_1 = np.argwhere(column_b == 1)
    if len(a_1) < len(b_1):
        for i in a_1:
            if i in b_1:
                end_func += 1
    else:
        for i in b_1:
            if i in a_1:
                end_func += 1
    return front_func * end_func

def simrank(am, c=0.8):
    n = len(am)
    sim_matrix = np.identity(n)
    for i in tqdm(range(n)):
        # print()
        for j in range(n):
            sim_matrix[i, j] = sub_simrank(am, i, j, c)
            # print(i, j, end='\r')
    return sim_matrix

if __name__ == '__main__':
    # lecture
    a1 = [[0, 0, 1, 0, 1],
         [0, 0, 1, 0, 1],
         [0, 0, 0, 1, 0],
         [1, 0, 1, 0, 0],
         [0, 0, 0, 0, 0]]
    a1 = np.array(a1)
    print(simrank(a1))

    from time import time
    t = time()
    items, am = list_to_adjacent_matrix(load_txt(g6))
    s = simrank(am)
    print(time() - t)
    #
    # t = time()
    # items, am = list_to_adjacent_matrix(load_IBM_text(i1))
    # s = simrank(am)
    # print(time() - t)

    # from time import time
    #
    # print()
    # tesk = [g1, g2, g3, g4, g5, g6]
    # tt = time()
    # for i in tesk:
    #     t = time()
    #     items, adjacent_matrix = list_to_adjacent_matrix(load_txt(i))
    #     s = simrank(adjacent_matrix)
    #     print('%.8f' % (time() - t))
    # print('%.8f' % (time() - tt))

# a = [[0] * 3] * 3
# a = [[0 for _ in range(3)] for _ in range(3)]
# a[0][1] = 1
# print(a)
#
# a1 = [[1, 2], [2, 3], [3, 4]]
# a2 = zip(*a1)
# print(list(a2))


from vpython import *

class Grafico:
    def __init__(self):
        self.graficos()

    def graficos(self):
        # Criando o gráfico para mostrar os sinais
        self.grafico = graph(width=700, height=400, align='right',
                             title='Resposta do sistema a um sinal de referência',
                             xtitle='Tempo (s)', ytitle='Posição (mm)', fast=False,
                             scroll=True, xmin=0, xmax=5)
        # Curva da posição real
        self.yplot = gdots(color=color.red, size=2, label='Sistema')
        # Curva do sinal de referência
        self.rplot = gcurve(color=color.blue, label='Referência')

        # %% Criação da legenda flutuante

        self.legenda_1 = label(pos=vec(0, 11.5e-2, 0),
                               text="<b>O cilindro está na posição inicial!</b>",
                               font="Verdana")


import pandas as pd
import xml.etree.ElementTree as ET
import urllib

from datetime import datetime

class Speeches:

    URL = (
        'http://www.camara.leg.br/SitCamaraWS/SessoesReunioes.asmx/ListarDiscursosPlenario'
        '?dataIni={dataIni}'
        '&dataFim={dataFim}'
        '&codigoSessao=&parteNomeParlamentar=&siglaPartido=&siglaUF='
    )

    CSV_PARAMS = {
        'compression': 'xz',
        'encoding': 'utf-8',
        'index': False
    }

    def fetch(self, range_start, range_end):
        """
        Fetches speeches from the ListarDiscursosPlenario endpoint of the
        SessoesReunioes (SessionsReunions) API.

        The date range provided should be specified as a string using the
        format supported by the API (%d/%m/%Y)
        """
        range = {'dataIni': range_start, 'dataFim': range_end}
        url = self.URL.format(**range)
        file=urllib.request.urlopen(url)

        t = ET.ElementTree(file=file)
        root = t.getroot()
        records = self.__parse_speeches(root)

        return pd.DataFrame(records, columns=[
            'session_code',
            'session_date',
            'session_num',
            'phase_code',
            'phase_desc',
            'speech_speaker_num',
            'speech_speaker_name',
            'speech_speaker_party',
            'speech_speaker_state',
            'speech_started_at',
            'speech_room_num',
            'speech_insertion_num'
        ])

    def write_file(self, filepath, df):
        """Save a compressed CSV file with the given df to the path specified as filepath"""
        print('Writing it to file…')
        df.to_csv(filepath, **self.CSV_PARAMS)

        print('Done.')

    def __parse_speeches(self, root):
        for session in root:
            session_code = self.__extract_text(session, 'codigo')
            session_date = self.__extract_date(session, 'data')
            session_num  = self.__extract_text(session, 'numero')
            for phase in session.find('fasesSessao'):
                phase_code = self.__extract_text(phase, 'codigo')
                phase_desc = self.__extract_text(phase, 'descricao')
                for speech in phase.find('discursos'):
                    speech_speaker_num   = self.__extract_text(speech, 'orador/numero')
                    speech_speaker_name  = self.__extract_text(speech, 'orador/nome')
                    speech_speaker_party = self.__extract_text(speech, 'orador/partido')
                    speech_speaker_state = self.__extract_text(speech, 'orador/uf')
                    speech_started_at    = self.__extract_datetime(speech, 'horaInicioDiscurso')
                    speech_room_num      = self.__extract_text(speech, 'numeroQuarto')
                    speech_insertion_num = self.__extract_text(speech, 'numeroInsercao')

                    yield [
                        session_code,
                        session_date,
                        session_num,
                        phase_code,
                        phase_desc,
                        speech_speaker_num,
                        speech_speaker_name,
                        speech_speaker_party,
                        speech_speaker_state,
                        speech_started_at,
                        speech_room_num,
                        speech_insertion_num
                    ]

    @staticmethod
    def __extract_date(node, xpath):
        return datetime.strptime(Speeches.__extract_text(node, xpath), "%d/%m/%Y")

    @staticmethod
    def __extract_datetime(node, xpath):
        return datetime.strptime(Speeches.__extract_text(node, xpath), "%d/%m/%Y %H:%M:%S")

    @staticmethod
    def __extract_text(node, xpath):
        return node.find(xpath).text.strip()

def fetch_speeches(output, range_start, range_end):
    """
    :param output: (str) directory in which the output file will be saved
    :param range_start: (str) date in the format dd/mm/yyyy
    :param range_end: (str) date in the format dd/mm/yyyy
    """
    speeches = Speeches()
    df = speeches.fetch(range_start, range_end)
    speeches.write_file(output, df)