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

# In[2]:

from torch import log
from underthesea import word_tokenize
from underthesea import pos_tag
from underthesea import sent_tokenize
from underthesea import dependency_parse
from underthesea import ner
from underthesea import classify
from underthesea import chunk

import random
import sys
import os

# In[3]:

import re
# Bỏ khoảng trắng trước PUNCT
def removeSpaceFrontPunct(s):
    s = re.sub(r'\s([?.!"](?:\s|$))', r'\1', s)
    s = s.replace(' ,', ',')
    return s

# In[103]:

def dp_tree(s):
    s_ner = ner(s)
    s_dp = dependency_parse(s)
    s_dp_tree = []
    for i in range(len(s_dp)):
        tmp = []
        for j in range(6):
            if j < 3:
                if j == 1:
                    tmp.append(s_dp[i][j]-1)
                else:
                    tmp.append(s_dp[i][j])
            else:
                tmp.append(s_ner[i][j-2])
        s_dp_tree.append(tmp)

    # Tìm các nhánh con
    for i in range(len(s_dp_tree)):
        tmp_tree = []
        for j in range(len(s_dp_tree)):
            if i == j:
                tmp_tree.append(j)
            if s_dp[j][1]-1 == i:
                tmp_tree.append(j)
        s_dp_tree[i].append(tmp_tree)

    # Chuyển thành tuple
    for i in range(len(s_dp_tree)):
        s_dp_tree[i] = tuple(s_dp_tree[i])

    return s_dp_tree

# Kiểm tra trong Tiếng Việt có trường hợp nào đặc biệt (có nút a và bé hơn cha nó, kiểm tra xem con lớn của nút a có lớn hơn cha của a không)
def duyet_cay(s_dp_tree, index):
    # Tìm các index con
    childs_index = s_dp_tree[index][-1]
    if len(childs_index) == 1:
        return str(index)

    cum = ''
    for i in childs_index:
        if i != index:
            cum += ' ' + duyet_cay(s_dp_tree, i)
        else:
            cum += ' ' + str(index)

    # Xoá các khoảng trắng dư thừa
    cum = " ".join(cum.split())
    return cum

def check_special_case(s_dp_tree, index):
    os = duyet_cay(s_dp_tree, index)
    os = os.split()
    for i in range(len(os)):
        os[i] = int(os[i])
    for i in range(len(os)-1):
        for j in range(i+1, len(os)):
            # Special case
            if i > j:
                return True

    for i in range(len(os)-1):
        if os[i+1]-os[i] > 1:
            return True
    return False

# Xác định cụm từ bằng đệ quy và DP-Tree
def xd_ct(s_dp_tree, index):
    if check_special_case(s_dp_tree, index):
        return "TRƯỜNG HỢP ĐẶC BIỆT"

    order_cum = duyet_cay(s_dp_tree, index)
    order_cum = order_cum.split()
    cum = ''
    for i in order_cum:
        index = int(i)
        cum += ' ' + s_dp_tree[index][0]

    cum = cum.strip()
    # Xoá khoảng trắng trước dấu
    cum = removeSpaceFrontPunct(cum)
    cum = cum.replace("' ", "'", 1)
    cum = cum.replace(" ' ", "' ", 1)
    return cum

con = 'con trai, con gái, con nuôi, con tàu, con thuyền, con sông, con nước, con kênh, con ngươi, con mắt'
def xd_nguoi_vat(subj):
    set_daitu = daitu.split(', ')
    set_con = con.split(', ')
    for i in subj.split(' '):
        if i.lower() in set_daitu:
            return 0
    for i in subj.split(' '):
        if i.lower() == 'con':
            for j in set_con:
                if j in subj.lower():
                    if j == 'con trai' or j == 'con gái' or j == 'con nuôi':
                        return 0
                    else:
                        return 2
            return 1
    return 2

def vhccd(s):
    s = s.strip()
    return s[0].upper() + s[1:]

def xvhccd(s):
    s = s.strip()
    return s[0].lower() + s[1:]

def xdccc(s):
    s = s.strip()
    if s[-3:] == '...':
        s = s[:-3]
    if s[-1] == '.':
        s = s[:-1]
    return s

# In[6]:

dongtu_ymuon = 'toan, định, dám, chịu, buồn, nỡ, dự định, muốn, mong, chúc'
dongtu_batdau_tiepdien_ketthuc = 'bắt đầu, tiếp tục, hết, thôi, chuẩn bị'
daitu = 'tôi, tao, ta, tớ, mình, chúng tôi, chúng ta, chúng tớ, chúng tao, chúng mình, bọn tao, bạn, các bạn, đằng ấy, mày, bọn mày, tên kia, anh, cậu, ông, gã, y, hắn, thằng, cô, chị, bà, ả, thị, cổ, bả, chúng nó, họ, bọn họ, bọn chúng, nó, bác, chú, mợ, dì, thím, nhân, dân, chủ, người, thầy, công, vợ, chồng, mẹ, cha, ba, tía, má, u, bầm, nữ, bố, trai, gái'
gioitu_noichon = 'ở, tại, trong, ngoài, trên, dưới, giữa'
gioitu_cachthuc = 'bằng'
gioitu_thoigian = 'vào, lúc, khi'

def bongu_mieuta(s, s_dp):
    ns = s
    if s[-1] == '.':
        ns = s[:-1]
    #s_dp = dp_tree(s)
    root_index = None
    # Tìm vị trí root
    for i in range(len(s_dp)):
        if s_dp[i][2] == 'root':
            root_index = i
            break

    # Đặt câu hỏi cho bổ ngữ miêu tả (trả lời cho câu hỏi cách thức, trạng thái, tính chất, mục đích, nơi chốn)
    qa = []
    list_obl = []
    for i in s_dp[root_index][6]:
        if i <= root_index:
            continue
        if 'obl' in s_dp[i][2] and s_dp[i][1] == root_index:
            list_obl.append(i)
            cum_tn = xd_ct(s_dp, i)
            list_gt = []
            for j in s_dp[i][6]:
                if s_dp[j][4] == 'B-PP':
                    list_gt.append(j)
            if len(list_gt) >= 1:
                # Trường hợp có giới từ
                # Giới từ chỉ cách thức
                for i in list_gt:
                    if s_dp[i][0].lower() == 'bằng':
                        qa.append(['Bằng cách nào ' + xvhccd(s[:-1].replace(' ' + cum_tn, '')) + '?', vhccd(cum_tn)])

                # Giới từ chỉ nơi chốn
                set_gioitu_noichon = gioitu_noichon.split(', ')
                for i in list_gt:
                    if s_dp[i][0].lower() in set_gioitu_noichon:
                        qa.append([ns.replace(' ' + cum_tn, '') + ' ở đâu?', vhccd(cum_tn)])
                # Giới từ chỉ thời gian
                set_gioitu_thoigian = gioitu_thoigian.split(', ')
                for i in list_gt:
                    if s_dp[i][0].lower() in set_gioitu_thoigian:
                        qa.append(['Khi nào ' + xvhccd(ns.replace(' ' + cum_tn, '')) + '?', vhccd(cum_tn)])

            else:
                if 'tmod' in s_dp[i][2]:
                    for i in s_dp[i][6]:
                        if s_dp[i][0].lower() == 'ngày':
                            qa.append(['Vào ngày mấy ' + xvhccd(ns.replace(' ' + cum_tn, '')) + '?', vhccd(cum_tn)])
                            return qa
                    qa.append(['Khi nào ' + xvhccd(ns.replace(' ' + cum_tn, '')) + '?', vhccd(cum_tn)])
    return qa
# In[250]:

### TEMPLATE Chủ ngữ + là + danh từ

### TEMPLATE Chủ ngữ + là + danh từ
def temp_cn_la_danhtu(s, s_dp):
    #s_dp = dp_tree(s)
    root_index = None
    # Tìm vị trí root
    for i in range(len(s_dp)):
        if s_dp[i][2] == 'root':
            if s_dp[i][4] != 'B-NP':
                return 'SAI FORMAT'
            if root_index is None:
                root_index = i
            else:
                return 'SAI FORMAT'
    if root_index is None:
        return 'SAI FORMAT'

    # Check format: Chủ ngữ phải xuất hiện đầu câu, không thành phần phụ
    cn_index = s_dp[root_index][6][0]
    if 'subj' not in s_dp[cn_index][2]:
        return 'SAI FORMAT'

    # Check nhiều chủ ngữ
    for i in range(cn_index+1, root_index):
        if 'subj' in s_dp[i][2]:
            return 'SAI FORMAT'

    # Check vị trí từ "là"
    la_index = None
    for i in range(s_dp[cn_index][6][-1] + 1, root_index):
        if s_dp[i][2] == 'cop' and s_dp[i][0] == 'là' and len(s_dp[i][6]) == 1:
            if la_index is None:
                la_index = i
            else:
                return 'SAI FORMAT'

    if la_index is None:
        for i in range(s_dp[cn_index][6][-1] + 1, root_index):
            if 'NP' not in s_dp[i][4]:
                return 'SAI FORMAT'
        s = s.replace(vhccd(xd_ct(s_dp, cn_index)), vhccd(xd_ct(s_dp, cn_index)) + ' có')
        s_dp = dp_tree(s)
        return temp_cn_dongtu(s, s_dp)

    # Check format: Danh từ xuất hiện cuối câu, chỉ có danh từ là root.
    for i in range(la_index + 1, len(s_dp)-1):
        mqh = s_dp[i][2]
        if mqh == 'advcl' or mqh == 'parataxis' \
            or mqh == 'mark' or mqh == 'ccomp':
            return 'SAI FORMAT'
        # Nếu có trường hợp conj và cc thì kiểm tra có phải là mệnh đề không (kiểm tra kiểu chunking)
        if mqh == 'conj':
            for j in s_dp[i][6]:
                if s_dp[j][4] != 'B-NP' and s_dp[j][4] != 'B-PP' and s_dp[j][2] != 'cc' and s_dp[j][2] != 'punct':
                    print(s_dp[j][4])
                    return 'SAI FORMAT'

    qa = []
    # Trường hợp ccn = 0: Chủ ngữ là trường hợp khác
    ccn = 0
    subj = xd_ct(s_dp, cn_index)
    danhtu = ''
    for i in range(la_index + 1, len(s_dp)-1):
        if s_dp[i][2] == 'punct':
            danhtu += s_dp[i][0]
        else:
            danhtu += ' ' + s_dp[i][0]
    danhtu = danhtu.strip()
    # Trường hợp ccn = 4: Chủ ngữ là cụm tính từ
    if 'asubj' in s_dp[cn_index][2]:
        ccn = 4
        qa.append([subj + ' là gì?', vhccd(xdccc(danhtu))])
        qa.append([vhccd(xdccc(danhtu)) + ' là gì?', subj])

    # Trường hợp ccn = 3: Chủ ngữ là cụm động từ
    if 'vsubj' in s_dp[cn_index][2]:
        ccn = 3
        qa.append([subj + ' là gì?', vhccd(xdccc(danhtu))])
        qa.append(['Hành động nào là ' + xdccc(danhtu) + '?', subj])

    loc = False
    if 'nsubj' in s_dp[cn_index][2] and s_dp[cn_index][4] == 'B-NP':
        # Trường hợp ccn = 2: Chủ ngữ là cụm danh từ
        ccn = 2
        for i in s_dp[cn_index][6]:
            if 'NP' not in s_dp[i][4]:
                if s_dp[i][2] != 'amod' or s_dp[i][2] != 'case' or s_dp[i][2] != 'compound:vmod' or s_dp[i][2] != 'acl:subj':
                    # Trường hợp ccn = 1: Chủ ngữ là mệnh đề chủ ngữ và vị ngữ --> không đặt câu hỏi chủ ngữ cho trường hợp này
                    ccn = 1
                    break

        # ĐẶT CÂU HỎI CHO CHỦ NGỮ
        if ccn == 2:
            for i in s_dp[cn_index][6]:
                # Trường hợp chủ ngữ là tên riêng PER (NER)
                if ('PER' in s_dp[i][5]):
                    qa.append([vhccd(xdccc(danhtu)) + ' có tên là gì?', subj])
                    break
                # Trường hợp chủ ngữ là tên địa danh LOC (NER)
                elif ('LOC' in s_dp[i][5]):
                    qa.append(['Đâu là ' + xdccc(danhtu) + '?', subj])
                    loc = True
                    break

            if len(qa) == 0:
                # Trường hợp chủ ngữ là đại từ nhân xưng
                set_daitu = daitu.split(', ')
                for i in subj.split(' '):
                    if i.lower() in set_daitu:
                        qa.append([vhccd(xdccc(danhtu)) + ' là ai?', subj])
                        break

            if len(qa) == 0:
                for i in s_dp[cn_index][6]:
                    # Trường hợp chủ ngữ là con vật
                    if s_dp[i][0].lower() == 'con' and 'clf' in s_dp[i][2] and 'con gái' not in subj.lower() and 'con trai' not in subj.lower():
                        qa.append([vhccd(xdccc(danhtu)) + ' là con gì?', subj])
                        break

            # Trường hợp chủ ngữ là vật
            if len(qa) == 0:
                qa.append([vhccd(xdccc(danhtu)) + ' là gì?', subj])

    # ĐẶT CÂU HỎI CHO VỊ NGỮ
    if len(qa) <= 1:
        generate = True

        # Trường hợp vị ngữ là tên riêng PER (NER)
        if (s_dp[root_index][5] == 'B-PER'):
            qa.append([subj + ' có tên là gì?', vhccd(xdccc(danhtu))])
            generate = False

        # Trường hợp vị ngữ là tên địa danh LOC (NER)
        if (s_dp[root_index][5] == 'B-LOC') and loc:
            qa.append([subj + ' là đâu?', vhccd(xdccc(danhtu))])
            generate = False

        if generate:
            # Trường hợp vị ngữ là đại từ nhân xưng
            set_daitu = daitu.split(', ')

            for i in s_dp[root_index][0].split(' '):
                if i.lower() in set_daitu:
                    qa.append([subj + ' là ai?', vhccd(xdccc(danhtu))])
                    generate = False
                    break

        if generate:
            for i in s_dp[root_index][6][la_index+1:root_index]:
                # Trường hợp vị ngữ là con vật
                if s_dp[i][0].lower() == 'con' and 'clf' in s_dp[i][2] and 'con gái' not in subj.lower() and 'con trai' not in subj.lower():
                    qa.append([subj + ' là con gì?', vhccd(xdccc(danhtu))])
                    generate = False
                    break

        # Trường hợp vị ngữ là vật
        if generate:
            qa.append([subj + ' là gì?', vhccd(xdccc(danhtu))])
    qa.extend(bongu_mieuta(s, s_dp))
    return qa

# In[251]:

### TEMPLATE Chủ ngữ + (là) + tính từ
### TEMPLATE Chủ ngữ + (là) + tính từ
### TEMPLATE Chủ ngữ + (là) + tính từ
def temp_cn_tinhtu(s, s_dp):
    #s_dp = dp_tree(s)
    root_index = None
    # Tìm vị trí root
    for i in range(len(s_dp)):
        if s_dp[i][2] == 'root':
            if s_dp[i][4] != 'B-AP':
                return 'SAI FORMAT'
            if root_index is None:
                root_index = i
            else:
                return 'SAI FORMAT'
    if root_index is None:
        return 'SAI FORMAT'

    # Check format: Chủ ngữ phải xuất hiện đầu câu, không thành phần phụ
    cn_index = s_dp[root_index][6][0]
    if 'subj' not in s_dp[cn_index][2]:
        return 'SAI FORMAT'

    # Check nhiều chủ ngữ
    for i in range(cn_index+1, root_index):
        if 'subj' in s_dp[i][2]:
            return 'SAI FORMAT'

    # Check format: Tính từ xuất hiện cuối câu, chỉ có tính từ là root.
    last_cn_index = s_dp[cn_index][6][-1]
    for i in range(last_cn_index + 1, len(s_dp)-1):
        mqh = s_dp[i][2]
        if mqh == 'advcl' or mqh == 'parataxis' \
            or mqh == 'mark' or mqh == 'ccomp':
            return 'SAI FORMAT'
        # Nếu có trường hợp conj và cc thì kiểm tra có phải là mệnh đề không (kiểm tra kiểu chunking)
        if mqh == 'conj':
            for j in s_dp[i][6]:
                if s_dp[j][4] != 'B-AP' and s_dp[j][2] != 'cc' and s_dp[j][2] != 'punct':
                    return 'SAI FORMAT'

    qa = []
    # Trường hợp ccn = 0: Chủ ngữ là trường hợp khác
    ccn = 0
    subj = xd_ct(s_dp, cn_index)
    tinhtu = s.replace(subj + ' ', '')
    # Bỏ các thành phần phụ sau của tính từ
    for i in s_dp[root_index][6]:
        if i > root_index and s_dp[i][1] == root_index and (s_dp[i][2] == 'advmod' or s_dp[i][3] == 'R'):
            tinhtu = tinhtu.replace(' ' + s_dp[i][0], '')

    # Trường hợp ccn = 4: Chủ ngữ là cụm tính từ
    if 'asubj' in s_dp[cn_index][2]:
        ccn = 4
        return []

    # Trường hợp ccn = 3: Chủ ngữ là cụm động từ
    if 'vsubj' in s_dp[cn_index][2]:
        ccn = 3
        qa.append([subj + ' có đặc điểm gì?', vhccd(xdccc(tinhtu))])
        qa.append(['Hành động nào có đặc điểm ' + xdccc(tinhtu) + '?', subj])

    if 'nsubj' in s_dp[cn_index][2] and s_dp[cn_index][4] == 'B-NP':
        # Trường hợp ccn = 2: Chủ ngữ là cụm danh từ
        ccn = 2
        for i in s_dp[cn_index][6]:
            if 'NP' not in s_dp[i][4]:
                if s_dp[i][2] != 'amod' or s_dp[i][2] != 'case' or s_dp[i][2] != 'compound:vmod' or s_dp[i][2] != 'acl:subj':
                    # Trường hợp ccn = 1: Chủ ngữ là mệnh đề chủ ngữ và vị ngữ --> không đặt câu hỏi chủ ngữ cho trường hợp này
                    ccn = 1
                    break

        # ĐẶT CÂU HỎI CHO CHỦ NGỮ
        if ccn == 2:
            # Trường hợp chủ ngữ là tên riêng PER (NER)
            if (s_dp[cn_index][5] == 'B-PER'):
                qa.append(['Ai ' + xdccc(tinhtu) + '?', subj])

            # Trường hợp chủ ngữ là tên địa danh LOC (NER)
            elif (s_dp[cn_index][5] == 'B-LOC'):
                qa.append(['Đâu là nơi ' + xdccc(tinhtu) + '?', subj])

            if len(qa) == 0:
                # Trường hợp chủ ngữ là đại từ nhân xưng
                set_daitu = daitu.split(', ')
                for i in subj.split(' '):
                    if i.lower() in set_daitu:
                        qa.append(['Ai ' + xdccc(tinhtu) + '?', subj])
                        break

            if len(qa) == 0:
                for i in s_dp[cn_index][6]:
                    # Trường hợp chủ ngữ là con vật
                    if s_dp[i][0].lower() == 'con' and 'clf' in s_dp[i][2] and 'con gái' not in subj.lower() and 'con trai' not in subj.lower():
                        qa.append(['Con gì ' + xdccc(tinhtu) + '?', subj])
                        break

            # Trường hợp chủ ngữ là vật
            if len(qa) == 0:
                qa.append(['Cái gì ' + xdccc(tinhtu) + '?', subj])
    # ĐẶT CÂU HỎI CHO VỊ NGỮ
    if len(qa) <= 1:
        qa.append([subj + ' có đặc điểm gì?', vhccd(xdccc(tinhtu))])
    qa.extend(bongu_mieuta(s, s_dp))
    return qa

# In[301]:

### TEMPLATE Chủ ngữ + động từ
### TEMPLATE Chủ ngữ + động từ
def temp_cn_dongtu(s, s_dp):
    #s_dp = dp_tree(s)
    root_index = None
    # Tìm vị trí root
    for i in range(len(s_dp)):
        if s_dp[i][2] == 'root':
            if s_dp[i][4] != 'B-VP':
                return 'SAI FORMAT'
            if root_index is None:
                root_index = i
            else:
                return 'SAI FORMAT'

    if root_index is None:
        return 'SAI FORMAT'

    # Check format: Chủ ngữ phải xuất hiện đầu câu, không thành phần phụ
    cn_index = s_dp[root_index][6][0]
    if 'subj' not in s_dp[cn_index][2]:
        return 'SAI FORMAT'

    # Check nhiều chủ ngữ
    for i in range(cn_index+1, root_index):
        if 'subj' in s_dp[i][2]:
            return 'SAI FORMAT'

    # Check format: Động từ xuất hiện cuối câu, chỉ có động từ là root.
    last_cn_index = s_dp[cn_index][6][-1]
    for i in range(last_cn_index + 1, len(s_dp)-1):
        mqh = s_dp[i][2]
        if mqh == 'advcl' or mqh == 'parataxis' or mqh == 'mark':
            return 'SAI FORMAT'
        # Nếu có trường hợp conj và cc thì kiểm tra có phải là mệnh đề không (kiểm tra kiểu chunking)
        if mqh == 'conj':
            for j in s_dp[i][6]:
                if s_dp[j][4] != 'B-VP' and s_dp[j][2] != 'cc' and s_dp[j][2] != 'punct':
                    return 'SAI FORMAT'

    # Loại bỏ tất cả trường hợp phủ định
    for i in range(last_cn_index + 1, root_index):
        if 'neg' in s_dp[i][2]:
            return 'SAI FORMAT'

    # Lấy thành phần phụ đầu của vị ngữ
    phutruoc_dongtu = ''
    for i in range(last_cn_index + 1, root_index):
        phutruoc_dongtu += s_dp[i][0] + ' '
    phutruoc_dongtu = phutruoc_dongtu.strip()

    qa = []
    vn_dongtu = 0
    subj = xd_ct(s_dp, cn_index)
    dongtu = s.replace(subj + ' ', '')
    set_dongtu_ymuon = dongtu_ymuon.split(', ')
    set_dongtu_batdau_tiepdien_ketthuc = dongtu_batdau_tiepdien_ketthuc.split(', ')

    # ĐẶT CÂU HỎI CHO CHỦ NGỮ
    if 'nsubj' in s_dp[cn_index][2] and s_dp[cn_index][4] == 'B-NP':
        # Trường hợp ccn = 2: Chủ ngữ là cụm danh từ
        ccn = 2
        for i in s_dp[cn_index][6]:
            if 'NP' not in s_dp[i][4]:
                if s_dp[i][2] != 'amod' or s_dp[i][2] != 'case' or s_dp[i][2] != 'compound:vmod' or s_dp[i][2] != 'acl:subj':
                    # Trường hợp ccn = 1: Chủ ngữ là mệnh đề chủ ngữ và vị ngữ --> không đặt câu hỏi chủ ngữ cho trường hợp này
                    ccn = 1
                    break

        # ĐẶT CÂU HỎI CHO CHỦ NGỮ
        if ccn == 2:

            # Trường hợp chủ ngữ là tên riêng PER (NER)
            if (s_dp[cn_index][5] == 'B-PER'):
                qa.append(['Ai ' + xdccc(dongtu) + '?', subj])

            # Trường hợp chủ ngữ là tên địa danh LOC (NER)
            elif (s_dp[cn_index][5] == 'B-LOC'):
                qa.append(['Đâu là nơi ' + xdccc(dongtu) + '?', subj])

            if len(qa) == 0:
                # Trường hợp chủ ngữ là đại từ nhân xưng
                set_daitu = daitu.split(', ')
                for i in subj.split(' '):
                    if i.lower() in set_daitu:
                        qa.append(['Ai ' + xdccc(dongtu) + '?', subj])
                        break

            if len(qa) == 0:
                for i in s_dp[cn_index][6]:
                    # Trường hợp chủ ngữ là con vật
                    if s_dp[i][0].lower() == 'con' and 'clf' in s_dp[i][2] and 'con gái' not in subj.lower() and 'con trai' not in subj.lower():
                        qa.append(['Con gì ' + xdccc(dongtu) + '?', subj])
                        break

            # Trường hợp chủ ngữ là vật
            if len(qa) == 0:
                qa.append(['Cái gì ' + xdccc(dongtu) + '?', subj])

    # Xác định thể bị động
    auxpass_index = None
    for i in range(last_cn_index + 1, root_index):
        if s_dp[i][2] == 'aux:pass':
            if auxpass_index is None:
                auxpass_index = i
            else:
                return 'SAI FORMAT'
    if auxpass_index is not None:
        agent_index = None
        for i in range(auxpass_index + 1, len(s_dp) - 1):
            if s_dp[i][1] == root_index and s_dp[i][2] == 'obl:agent':
                agent_index = i
                break

        ans_vn = ''
        for j in range(auxpass_index, len(s_dp) - 1):
            ans_vn += s_dp[j][0] + ' '
        qa.append([vhccd(xd_ct(s_dp, cn_index)) + ' ' + s_dp[auxpass_index][0] + ' gì?', vhccd(ans_vn.strip())])
        if agent_index is not None:
            theloai_agent = xd_nguoi_vat(xd_ct(s_dp, agent_index))
            loai = 'cái gì'
            if theloai_agent == 0:
                loai = 'ai'
            elif theloai_agent == 1:
                loai = 'con gì'
            qa.append([s[:-1].replace(xd_ct(s_dp, agent_index), loai) + '?', vhccd(xd_ct(s_dp, agent_index))])
    else:
        # Xác định template
        for i in range(root_index, len(s_dp)-1):
            mqh = s_dp[i][2]
            cn_index_ccomp = s_dp[i][6][0]
            # Trường hợp vn_dongtu = 11: Root là động từ có.
            if s_dp[root_index][0] == 'có':
                vn_dongtu = 11
                for i in range(root_index+1, len(s_dp)-1):
                    if s_dp[i][2] == 'acomp' and s_dp[i][6][-1] == len(s_dp)-2:
                        qa.append([s[:-1].replace(xd_ct(s_dp, i), 'như thế nào') + '?', vhccd(xd_ct(s_dp, i))])
                after_sent = ''
                for j in range(root_index, len(s_dp)-1):
                    after_sent += s_dp[j][0] + ' '
                qa.append([subj + ' có cái gì?', vhccd(after_sent.strip())])
                break

            # Truong hop vn_dongtu = 1: Subj + V(root) + Subj + (V/N/A)(ccomp) + (obj)
            elif s_dp[i][1] == root_index and mqh == 'ccomp' and 'subj' in s_dp[cn_index_ccomp][2]:
                vn_dongtu = 1
                bongu_ccomp = xd_ct(s_dp, i)
                bongu_ccomp_dp = dp_tree(bongu_ccomp)
                pre_sent = s.replace(bongu_ccomp, '')
                pre_sent = pre_sent[:-1].strip()
                cn_dongtu = temp_cn_dongtu(bongu_ccomp, bongu_ccomp_dp)
                cn_tinhtu = temp_cn_tinhtu(bongu_ccomp, bongu_ccomp_dp)
                cn_la_danhtu = temp_cn_la_danhtu(bongu_ccomp, bongu_ccomp_dp)
                if (cn_dongtu != 'SAI FORMAT'):
                    for j in range(len(cn_dongtu)):
                        qa.append([pre_sent + ' ' + xvhccd(cn_dongtu[j][0]), cn_dongtu[j][1]])
                elif (cn_tinhtu != 'SAI FORMAT'):
                    for j in range(len(cn_tinhtu)):
                        qa.append([pre_sent + ' ' + xvhccd(cn_tinhtu[j][0]), cn_tinhtu[j][1]])
                elif (cn_la_danhtu != 'SAI FORMAT'):
                    for j in range(len(cn_la_danhtu)):
                        qa.append([pre_sent + ' ' + xvhccd(cn_la_danhtu[j][0]), cn_la_danhtu[j][1]])

            # Truong hop vn_dongtu = 2: Subj + V(root)(ý muốn) + V(comp/compound) + (obj)
            elif s_dp[i][1] == root_index and 'comp' in mqh and mqh != 'ccomp' and s_dp[i][4] == 'B-VP' and s_dp[root_index][0].lower() in set_dongtu_ymuon:
                vn_dongtu = 2
                #after_sent = ''
                #for j in range(root_index+1, len(s_dp)-1):
                    #after_sent += s_dp[j][0] + ' '
                qa.append([subj + ' ' + phutruoc_dongtu + ' ' + s_dp[root_index][0].lower() + ' làm gì?', vhccd(xd_ct(s_dp, i))])
                break

            # Truong hop vn_dongtu = 3: Subj + V(root)(bắt đầu/kết thúc/tiếp diễn) + (V(comp/compound)/obj) + (obj)
            elif s_dp[root_index][0].lower() in set_dongtu_batdau_tiepdien_ketthuc and ('obj' in mqh or 'comp' in mqh) and s_dp[i][1] == root_index:
                vn_dongtu = 3
                if 'obj' in s_dp[i][2]:
                    qa.append([subj + ' ' + phutruoc_dongtu + ' ' + s_dp[root_index][0].lower() + ' điều gì?', vhccd(xd_ct(s_dp, i))])
                else:
                    qa.append([subj + ' ' + phutruoc_dongtu + ' ' + s_dp[root_index][0].lower() + ' làm gì?', vhccd(xd_ct(s_dp, i))])
                break

            # Trường hợp vn_dongtu = 4: Subj + V(root) + compound:dir + obj
            elif s_dp[i][1] == root_index and 'dir' in mqh and s_dp[i][4] == 'B-VP':
                vn_dongtu = 4
                after_sent = ''
                for j in range(root_index, len(s_dp)-1):
                    after_sent += s_dp[j][0] + ' '
                if s_dp[root_index][0] != 'đi':
                    qa.append([subj + ' ' + phutruoc_dongtu + ' ' + s_dp[root_index][0] + ' đi đâu?', vhccd(after_sent.strip())])
                else:
                    qa.append([subj + ' ' + phutruoc_dongtu + ' ' + s_dp[root_index][0] + ' đâu?', vhccd(after_sent.strip())])
                break

            # Trường hợp vn_dongtu = 5: Subj + V(root)(động từ mang ý nghĩa nối kết) + obj + (cùng/với) + obl:with
            elif s_dp[i][1] == root_index and 'obl:with' in mqh and s_dp[i][4] == 'B-NP':
                vn_dongtu = 5
                obj_index = None
                for j in range(root_index, s_dp[i][6][-1]):
                    if 'obj' in s_dp[j][2]:
                        obj_index = j
                        break
                if obj_index is not None:
                    qa.append([subj + ' ' + phutruoc_dongtu + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, obj_index) + ' với gì?', vhccd(xd_ct(s_dp, i))])
                break

            # Trường hợp vn_dongtu = 6: Sau root là 'từ'
            elif s_dp[i][1] == root_index and 'obl:' in s_dp[i][2] and 'comp' in s_dp[i][2] :
                vn_dongtu = 6
                if 'LOC' in s_dp[i][5]:
                    qa.append([s[:-1].replace(xd_ct(s_dp, i), 'đâu') + '?', vhccd(xd_ct(s_dp, i))])
                else:
                    qa.append([s[:-1].replace(xd_ct(s_dp, i), 'gì') + '?', vhccd(xd_ct(s_dp, i))])
                break

            elif s_dp[i][1] == root_index and mqh == 'obj':

                # Trường hợp vn_dongtu = 7: Sau root có obj và có động từ con của động từ. VD: Tôi mua hoa tặng cho mẹ.
                vn_dongtu = 7
                iobj = None
                for j in range(root_index+1, len(s_dp)-1):
                    if 'iobj' in s_dp[j][2]:
                        iobj = j
                if iobj is not None:
                    for j in range(root_index+1, len(s_dp)-1):
                        if 'obj' in s_dp[j][2]:
                            theloai_obj = xd_nguoi_vat(xd_ct(s_dp, j))
                            loai = 'cái gì'
                            if theloai_obj == 0:
                                loai = 'ai'
                            elif theloai_obj == 1:
                                loai = 'con gì'
                            if 'iobj' in s_dp[j][2]:
                                loai = 'cho ' + loai
                            qa.append([s[:-1].replace(xd_ct(s_dp, j), loai) + '?', vhccd(xd_ct(s_dp, j))])

                    if s_dp[iobj][1] != root_index:
                        parent = s_dp[iobj][1]
                        qa.append([s[:-1].replace(xd_ct(s_dp, parent), 'để làm gì') + '?', vhccd(xd_ct(s_dp, parent))])

                else:
                    for j in range(root_index+1, len(s_dp)-1):
                        if s_dp[j][2] == 'obj':
                            theloai_obj = xd_nguoi_vat(xd_ct(s_dp, j))
                            loai = 'cái gì'
                            if theloai_obj == 0:
                                loai = 'ai'
                            elif theloai_obj == 1:
                                loai = 'con gì'
                            parent = s_dp[j][1]

                            if parent == root_index:
                                quesobj = vhccd(xd_ct(s_dp, cn_index)) + ' ' + s_dp[root_index][0] + ' ' + xd_ct(s_dp, j) + '?'
                            else:
                                quesobj = vhccd(xd_ct(s_dp, cn_index)) + ' ' + xd_ct(s_dp, parent) + '?'
                            if s_dp[parent][0].lower() == 'đi' or s_dp[parent][0].lower() == 'về' or s_dp[parent][0].lower() == 'đến' or s_dp[parent][0].lower() == 'tới':
                                qa.append([quesobj.replace(xd_ct(s_dp, j), 'đâu'), vhccd(xd_ct(s_dp, j))])
                            else:
                                qa.append([quesobj.replace(xd_ct(s_dp, j), loai), vhccd(xd_ct(s_dp, j))])

            # Trường hợp vn_dongtu = 10: Sau root là một acomp bổ ngữ cho động từ.
            elif s_dp[i][1] == root_index and 'acomp' in mqh and s_dp[i][4] == 'B-AP':
                vn_dongtu = 10
                qa.append([subj + ' ' + s_dp[root_index][0] + ' như thế nào?', vhccd(xd_ct(s_dp, i))])
                break
            '''
            elif s_dp[i][1] == root_index and 'obj' in mqh:
                # Trường hợp vn_dongtu = 7: Sau root là 2 obj. VD: Tôi biếu thầy cái bánh.
                confirm_break = False
                for j in range(i+1, len(s_dp)-1):
                    if s_dp[j][1] == root_index and 'obj' in s_dp[j][2]:
                        vn_dongtu = 7
                        if 'iobj' in s_dp[i][2]:
                            qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, j) + ' cho ai?', vhccd(xd_ct(s_dp, i))])
                            qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, i) + ' cái gì?', vhccd(xd_ct(s_dp, j))])
                        elif 'iobj' in s_dp[j][2]:
                            qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, i) + ' cho ai?', vhccd(xd_ct(s_dp, j))])
                            qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, j) + ' cái gì?', vhccd(xd_ct(s_dp, i))])
                        elif s_dp[i][3] == 'Np' and s_dp[i][3] != 'Np':
                            qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, j) + ' cho ai?', vhccd(xd_ct(s_dp, i))])
                            qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' cho ' + xd_ct(s_dp, i) + ' cái gì?', vhccd(xd_ct(s_dp, j))])
                        else:
                            qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, i) + ' làm gì?', vhccd(xd_ct(s_dp, j))])
                            theloai_cn = xd_nguoi_vat(xd_ct(s_dp, i))
                            loai = 'cái gì'
                            if theloai_cn == 0:
                                loai = 'ai'
                            elif theloai_cn == 1:
                                loai = 'con gì'
                            qa.append([s[:-1].replace(xd_ct(s_dp, i), loai) + '?', vhccd(xd_ct(s_dp, i))])
                        confirm_break = True
                        break
                if confirm_break:
                    break

                # Trường hợp vn_dongtu = 8: Sau root là 1 obj của root và 1 obj của comp. VD: Tôi mua hoa tặng mẹ.
                for j in range(i+1, len(s_dp)-1):
                    if s_dp[j][1] == root_index and 'comp' in s_dp[j][2] and s_dp[j][2] != 'ccomp' and s_dp[j][4] == 'B-VP':
                        for z in range(j+1, len(s_dp)-1):
                            if s_dp[z][1] == j and 'obj' in s_dp[z][2]:
                                vn_dongtu = 8
                                qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, i) + ' làm gì?', vhccd(xd_ct(s_dp, j))])
                                theloai_cn = xd_nguoi_vat(xd_ct(s_dp, i))
                                loai = 'cái gì'
                                if theloai_cn == 0:
                                    loai = 'ai'
                                elif theloai_cn == 1:
                                    loai = 'con gì'
                                qa.append([s[:-1].replace(xd_ct(s_dp, i), loai) + '?', vhccd(xd_ct(s_dp, i))])
                                if s_dp[z][3] == 'Np' or s_dp[z][5] == 'B-PER':
                                    qa.append([subj + ' ' + s_dp[root_index][0].lower() + ' ' + xd_ct(s_dp, i) + ' ' + s_dp[j][0] + ' ai?', vhccd(xd_ct(s_dp, z))])
                                confirm_break = True
                                break
                    if confirm_break:
                        break
                if confirm_break:
                    break

            # Trường hợp vn_dongtu = 9: Sau root là 1 obj.
            elif s_dp[i][1] == root_index and 'obj' in mqh:
                vn_dongtu = 9
                if s_dp[i][3] == 'Np' or s_dp[i][5] == 'B-PER':
                    qa.append([s[:-1].replace(xd_ct(s_dp[i][0]), 'ai') + '?', vhccd(xd_ct(s_dp, i))])
                else:
                    theloai_cn = xd_nguoi_vat(xd_ct(s_dp, i))
                    loai = 'cái gì'
                    if theloai_cn == 0:
                        loai = 'ai'
                    elif theloai_cn == 1:
                        loai = 'con gì'
                    qa.append([s[:-1].replace(xd_ct(s_dp[i][0]), loai) + '?', vhccd(xd_ct(s_dp, i))])
                break
            '''

        # Trường hợp cơ bản
        if vn_dongtu == 0:
            for i in range(root_index + 1, -1):
                if s_dp[i][4] != 'B-VP':
                    return 'SAI FORMAT'
            qa.append([subj + ' làm gì?', vhccd(xdccc(dongtu))])
        qa.extend(bongu_mieuta(s, s_dp))
    return qa

def xuly_trangngu_daucau(s, s_dp):
    #s_dp = dp_tree(s)
    root_index = None
    # Tìm vị trí root
    for i in range(len(s_dp)):
        if s_dp[i][2] == 'root':
            if s_dp[i][4] != 'B-VP':
                return 'SAI FORMAT'
            if root_index is None:
                root_index = i
            else:
                return 'SAI FORMAT'

    if root_index is None:
        return 'SAI FORMAT'

    # Check format: Trạng ngữ phải xuất hiện đầu câu
    tn_index = s_dp[root_index][6][0]
    if 'obl' not in s_dp[tn_index][2] and 'advcl' not in s_dp[tn_index][2]:
        return 'SAI FORMAT'

    # Tìm vị trí chủ ngữ
    cn_index = None
    for i in s_dp[root_index][6]:
        if i == root_index:
            break
        if 'subj' in s_dp[i][2]:
            if cn_index is not None:
                return 'SAI FORMAT'
            cn_index = i

    if cn_index is None:
        return 'SAI FORMAT'
    qa = []

    cum_tn = xd_ct(s_dp, tn_index)
    cum_cn = xd_ct(s_dp, cn_index)
    cn_index_last = s_dp[cn_index][6][-1]
    cum_vn = ''

    for i in range(cn_index_last+1, len(s_dp)-1):
        if s_dp[i][2] == 'punct':
            cum_vn += s_dp[i][0]
        else:
            cum_vn += ' ' + s_dp[i][0]
    cum_vn = cum_vn.strip()
    cau = cum_cn + ' ' + cum_vn
    dau = ''
    cau = vhccd(cau)
    cau_dp = dp_tree(cau)
    if cau[0] == ',':
        cau = cau.replace(',', '', 1)
        dau = ','
    if 'obl' in s_dp[tn_index][2]:
        list_obl = []
        dauphay_root_index = []
        # Check thành phần phía trước vị ngữ chỉ có trạng ngữ và chủ ngữ
        for i in s_dp[root_index][6]:
            if i == root_index:
                break
            if s_dp[i][2] != 'punct' and 'obl' not in s_dp[i][2] and 'subj' not in s_dp[i][2]:
                return 'SAI FORMAT'
            if 'obl' in s_dp[i][2]:
                list_obl.append(i)
            if s_dp[i][2] == 'punct':
                dauphay_root_index.append(i)
        if len(list_obl) >= 2:
            for i in list_obl[1:]:
                obl = xd_ct(s_dp, i)
                if obl[-1] == ',':
                    obl = obl[:-1]
                s = s.replace(' ' + obl, '')
                if s[-3:] == '...':
                    s = s[:-3] + ' ' + obl + '...'
                else:
                    s = s[:-1] + ' ' + obl + '.'

            for i in range(len(s)):
                s = s.replace(',,', ',')
            s_dp = dp_tree(s)
            return xuly_trangngu_daucau(s, s_dp)

        # Phát sinh câu hỏi 'Khi nào, ở đâu'
        cau_cn_dongtu = temp_cn_dongtu(cau, cau_dp)
        cau_cn_tinhtu = temp_cn_tinhtu(cau, cau_dp)
        cau_cn_la_danhtu = temp_cn_la_danhtu(cau, cau_dp)
        if (cau_cn_dongtu != 'SAI FORMAT'):
            for j in range(len(cau_cn_dongtu)):
                qa.append([cum_tn + dau + ' ' + xvhccd(cau_cn_dongtu[j][0]), cau_cn_dongtu[j][1]])
        elif (cau_cn_tinhtu != 'SAI FORMAT'):
            for j in range(len(cau_cn_tinhtu)):
                qa.append([cum_tn + dau + ' ' + xvhccd(cau_cn_tinhtu[j][0]), cau_cn_tinhtu[j][1]])
        elif (cau_cn_la_danhtu != 'SAI FORMAT'):
            for j in range(len(cau_cn_la_danhtu)):
                qa.append([cum_tn + dau + ' ' + xvhccd(cau_cn_la_danhtu[j][0]), cau_cn_la_danhtu[j][1]])

        list_gt = []
        for i in range(tn_index):
            if s_dp[i][4] == 'B-PP':
                list_gt.append(i)
        if len(list_gt) >= 1:
            # Trường hợp có giới từ
            # Giới từ chỉ cách thức
            for i in list_gt:
                if s_dp[i][0].lower() == 'bằng':
                    qa.append(['Bằng cách nào ' + xvhccd(cau) + '?', cum_tn])

            # Giới từ chỉ nơi chốn
            set_gioitu_noichon = gioitu_noichon.split(', ')
            for i in list_gt:
                if s_dp[i][0].lower() in set_gioitu_noichon:
                    qa.append([cau + ' ở đâu?', cum_tn])
            # Giới từ chỉ thời gian
            set_gioitu_thoigian = gioitu_thoigian.split(', ')
            for i in list_gt:
                if s_dp[i][0].lower() in set_gioitu_thoigian:
                    qa.append(['Khi nào ' + xvhccd(cau) + '?', cum_tn])

        else:
            if 'tmod' in s_dp[tn_index][2]:
                for i in s_dp[tn_index][6]:
                    if s_dp[i][0].lower() == 'ngày':
                        qa.append(['Vào ngày mấy ' + xvhccd(cau) + '?', cum_tn])
                        return qa
                qa.append(['Khi nào ' + xvhccd(cau) + '?', cum_tn])
    else:
        cau_cn_dongtu = temp_cn_dongtu(cau, cau_dp)
        cau_cn_tinhtu = temp_cn_tinhtu(cau, cau_dp)
        cau_cn_la_danhtu = temp_cn_la_danhtu(cau, cau_dp)
        if (cau_cn_dongtu != 'SAI FORMAT'):
            for j in range(len(cau_cn_dongtu)):
                qa.append([cum_tn + dau + ' ' + xvhccd(cau_cn_dongtu[j][0]), cau_cn_dongtu[j][1]])
        elif (cau_cn_tinhtu != 'SAI FORMAT'):
            for j in range(len(cau_cn_tinhtu)):
                qa.append([cum_tn + dau + ' ' + xvhccd(cau_cn_tinhtu[j][0]), cau_cn_tinhtu[j][1]])
        elif (cau_cn_la_danhtu != 'SAI FORMAT'):
            for j in range(len(cau_cn_la_danhtu)):
                qa.append([cum_tn + dau + ' ' + xvhccd(cau_cn_la_danhtu[j][0]), cau_cn_la_danhtu[j][1]])
    return qa
# In[302]:

# temp_cn_dongtu('Tôi mua hoa tặng mẹ.')

# In[285]:

import string
# Tách câu ghép đẳng lập trong văn bản (quan hệ parataxis)
def tach_vecau(s):
    s_dp = dp_tree(s)
    root_index = None
    # Tìm vị trí root
    for i in range(len(s_dp)):
        if s_dp[i][2] == 'root':
            root_index = i
            break
    if root_index is None:
        return [s]
    kq = []
    for i in s_dp[root_index][6]:
        if s_dp[i][2] == 'parataxis' or s_dp[i][2] == 'conj':
            for j in s_dp[i][6]:
                if 'subj' in s_dp[j][2]:
                    vecau = xd_ct(s_dp, i)
                    s = s.replace(vecau, '')
                    vecau = vecau.strip() + '.'
                    vecau_dp = dp_tree(vecau)
                    while vecau_dp[0][2] == 'cc' or vecau_dp[0][2] == 'punct':
                        vecau = vecau.replace(vecau_dp[0][0], '')
                        vecau_dp = dp_tree(vecau)
                    kq.append(vhccd(vecau.strip()))
                    break

    kq.insert(0, removeSpaceFrontPunct(s))
    return kq

def tach_vecau_dauhaicham(s):
    s = s.split(':')
    for i in range(len(s)):
        s[i] = s[i].replace('\"', '')
        s[i] = s[i].replace("'", '')
        s[i] = s[i].replace("- ", '')
        s[i] = s[i].replace(".", '')
        if s[i] == '':
            s.pop(i)
        else:
            if s[i][-1] not in string.punctuation:
                s[i] = s[i].strip() + '.'
            s[i] = vhccd(s[i].strip())
    return s

# In[306]:

def loadFile(filename):
    lines = []
    count = 0
    with open(filename, 'r') as f:
        for para in f:
            st = sent_tokenize(para.strip())
            for s in st:
                if (s[-1] != '.'):
                    continue
                set_tach_hai_cham = tach_vecau_dauhaicham(s)
                for thc in set_tach_hai_cham:
                    thc = re.sub(r"\([^()]*\)", "", thc)
                    thc = thc.replace("(", "")
                    thc = thc.replace(")", "")
                    ve_cau = tach_vecau(thc)
                    lines.extend(ve_cau)
    return lines

# In[315]:

def loadTextarea(text):
    lines = []
    count = 0
    set_para = text.split('\n')
    for para in set_para:
        st = sent_tokenize(para.strip())
        for s in st:
            if (s[-1] != '.'):
                continue
            set_tach_hai_cham = tach_vecau_dauhaicham(s)
            for thc in set_tach_hai_cham:
                thc = re.sub(r"\([^()]*\)", "", thc)
                thc = thc.replace("(", "")
                thc = thc.replace(")", "")
                ve_cau = tach_vecau(thc)
                lines.extend(ve_cau)
    return lines

# In[316]:

def createQuestion(text):
    # lines = loadFile('textFile.txt')
    lines = loadTextarea(text)
    q = []
    loss = 0
    for l in lines:
        l_dp = dp_tree(l)
        kq = xuly_trangngu_daucau(l, l_dp)
        if kq != 'SAI FORMAT' and len(kq) > 0:
            q.append([l, kq])
            print(1)
        else:
            kq = temp_cn_dongtu(l, l_dp)
            if kq != 'SAI FORMAT' and len(kq) > 0:
                q.append([l, kq])
                print(2)
            else:
                kq = temp_cn_tinhtu(l, l_dp)
                if kq != 'SAI FORMAT' and len(kq) > 0:
                    q.append([l, kq])
                    print(3)
                else:
                    kq = temp_cn_la_danhtu(l, l_dp)
                    if kq != 'SAI FORMAT' and len(kq) > 0:
                        q.append([l, kq])
                    else:
                        loss += 1
    bad = 1
    if len(lines) > 0:
        bad = loss/len(lines)
    return (q, bad)

# In[317]:

if __name__ == '__main__':
    questions = createQuestion(sys.argv[1])
    # questions = createQuestion('')
    q = questions[0]
    bad = questions[1]

    print('__result__')

    # print(q)

    for i in q:
        # Selected sentence
        print('\n',i[0])
        # Generated questions
        for j in i[1]:
            print('\t', j[0], '\t', j[1])


from torch import nn
import torch
from utils.misc import Accumulator, Timer

def accuracy(y_hat, y):
    """
    计算训练正确的样本的个数
    :param y_hat: 预测值
    :param y: 真实值
    :return:
    """
    # 如果是二维的数据的话，就按行取最大值的索引
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        y_hat = y_hat.argmax(axis=1)
    # 按位运算，获取正确的个数
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())

def accuracy_gpu(net, data_iter, ae=None, device=None):
    """
    使用device计算精度
    :param ae:
    :param net:
    :param data_iter:
    :param device:
    :return:
    """
    if isinstance(net, nn.Module):
        net.eval()  # 设置为评估模式
        if not device:
            device = next(iter(net.parameters())).device
    # 正确预测的数量，总预测的数量
    metric = Accumulator(2)
    with torch.no_grad():
        if ae:
            for X, y in data_iter:
                X = X.to(device)
                X_rec = ae(X)
                y = y.to(device)
                metric.add(accuracy(net(X), y), y.numel())
                metric.add(accuracy(net(X_rec), y), y.numel())
        else:
            for X, y in data_iter:
                X = X.to(device)
                y = y.to(device)
                metric.add(accuracy(net(X), y), y.numel())
    return metric[0] / metric[1]

def loss_gpu(net, data_iter, loss_fn, device=None):
    """使用GPU计算自编器在数据集上的精度
    """
    if isinstance(net, nn.Module):
        net.eval()  # 设置为评估模式
        if not device:
            device = next(iter(net.parameters())).device

    # loss，总预测的数量
    metric = Accumulator(2)
    with torch.no_grad():
        for X, y in data_iter:
            X = X.to(device)
            X_R = net(X)
            metric.add(X.shape[0] * loss_fn(X_R, X).item(), y.numel())
    return metric[0] / metric[1]

def jenson_shannon_divergence(net_1_logit, net_2_logit):
    from torch.functional import F
    net_1_probs = F.softmax(net_1_logit, dim=1)
    net_2_probs = F.softmax(net_2_logit, dim=1)

    total_m = 0.5 * (net_1_probs + net_2_probs)
    loss = 0.0
    loss += F.kl_div(F.log_softmax(net_1_logit, dim=1), total_m, reduction="none")
    loss += F.kl_div(F.log_softmax(net_2_logit, dim=1), total_m, reduction="none")
    return 0.5 * loss.sum(dim=1)


"""fixture models

Revision ID: edf9d4b6cdea
Revises: bb02384217e4
Create Date: 2023-05-21 20:04:01.734393

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "edf9d4b6cdea"
down_revision = "bb02384217e4"
branch_labels = None
depends_on = None

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column("categories", "archive", nullable=False, new_column_name="is_archived")
    op.add_column("tasks", sa.Column("title", sa.String(), nullable=False))
    op.add_column("tasks", sa.Column("name_organization", sa.String(), nullable=True))
    op.add_column("tasks", sa.Column("deadline", sa.Date(), nullable=True))
    op.add_column("tasks", sa.Column("description", sa.String(), nullable=False))
    op.alter_column("tasks", "archive", nullable=False, new_column_name="is_archived")
    # ### end Alembic commands ###

def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column("tasks", "is_archived", nullable=False, new_column_name="archive")
    op.drop_column("tasks", "description")
    op.drop_column("tasks", "deadline")
    op.drop_column("tasks", "name_organization")
    op.drop_column("tasks", "title")
    op.alter_column("categories", "is_archived", nullable=False, new_column_name="archive")
    # ### end Alembic commands ###


"""Handle interactions with github."""
import logging
import os
import shutil

import requests
from github import Github
from provision.utils import chdir, run

LOG = logging.getLogger(__name__)

def git_clone(repo: str, dest_path: str = "", args: list = ["--recursive"]) -> None:
    """Clone git repo to dest path."""
    if not shutil.which("git"):
        LOG.error("Git not installed!")
        return
    if not repo[0:4] in ("git@", "http"):
        # Assume it's my repo
        repo = f"git@github.com:comfortablynick/{repo}.git"
    if dest_path is not None:
        args.append(os.path.expanduser(dest_path))
    cmd = ["git", "clone", repo, *args]
    LOG.debug("Cmd: %s", " ".join(cmd))
    with chdir(os.path.expanduser("~/git")):
        run(cmd)
    return

def github_token() -> str:
    """Retrieve secret access token from disk."""
    file = os.path.expanduser("~/.github_token")
    token = ""
    try:
        with open(file, "r") as f:
            token = f.read()
    except FileNotFoundError:
        LOG.error("GitHub token file not found: %s. Aborting!", file)
        return ""
    else:
        return token.strip("\n")

def clone_git_repos(args) -> None:
    """Clone repos from GitHub."""
    token = github_token()
    LOG.info("GitHub token found: %s", token)
    if token == "":
        return
    g = Github(token)
    for repo in g.get_user().get_repos():
        root_files = [content.name for content in repo.get_contents(".")]
        if ".provision_ignore" not in root_files:
            git_clone(repo.ssh_url)

def git_latest_tag() -> str:
    """Return first tag after reverse sort of available tags."""
    return run("git describe --tags --abbrev=0", capture_output=True).stdout.strip("\n")

def github_latest_release(args) -> int:
    """Get latest release binary."""
    token = github_token()
    if token == "":
        LOG.error("No GitHub token found!")
        return 1
    LOG.info("GitHub token found: %s", token)
    g = Github(token)
    r = g.get_repo(args.repo)
    name = r.name

    if shutil.which(name) and not args.force:
        LOG.warning("%s already exists. Skipping install!", name)
        return 1
    rel = r.get_releases()[0]  # latest
    assets = rel.get_assets()
    if assets.totalCount is None:
        LOG.error("Repo '%s' has no assets", args.repo)
        return 1
    print("Choose from the following packages:")
    for ctr, asset in enumerate(assets, 1):
        print(f"{str(ctr)}: {asset.name}")
    while True:
        choice = input("Enter number of choice: ")
        if choice == "":
            LOG.error("User input canceled!")
            return 1
        try:
            file = assets[int(choice) - 1]
        except IndexError:
            LOG.error("Choice '%s' out of range!", str(choice))
            continue
        except ValueError:
            LOG.error("Incorrect value: '%s'. Enter a number in range.", str(choice))
            continue
        else:
            break
    print(f"You chose to download {file.name}")
    r = requests.get(file.browser_download_url, stream=True)
    LOG.debug("Request response: %s", r.status_code)
    dest_path = os.path.join(os.path.expanduser(args.dest), file.name)
    print(f"Downloading to {dest_path}...")
    with open(dest_path, "wb") as f:
        for chunk in r.iter_content(chunk_size=128):
            f.write(chunk)
    return 0


class Student:
    def __init__(self, name, surname, gender):
        self.name = name
        self.surname = surname
        self.gender = gender
        self.finished_courses = []
        self.courses_in_progress = []
        self.grades = {}
        self.medium_value = []

    def rate_lec(self, lecturer, course, grade_lec):
        if isinstance(lecturer, Lecturer) and course in lecturer.courses_attached and course in self.courses_in_progress:
            if course in lecturer.grades_for_lectures:
                lecturer.grades_for_lectures[course] += [grade_lec]
            else:
                lecturer.grades_for_lectures[course] = [grade_lec]
        else:
            return 'Ошибка'

    def medium_student_grade(self, student_grades):
        for i in student_grades.values():
            medium_grade = sum(i) / len(i)
            self.medium_value = medium_grade

    def __str__(self):
        return f"Имя: {self.name}\nФамилия: {self.surname}\nСредняя оценка за домашние задания:{self.medium_value}\nКурсы в процессе изучения:{','.join(self.courses_in_progress)}\nЗавершенные курсы:{','.join(self.finished_courses)}"

    def __lt__(self, other):
        return self.medium_value < self.medium

class Mentor:
    def __init__(self, name, surname):
        self.name = name
        self.surname = surname
        self.courses_attached = []

    # def rate_hw(self, student, course, grade):
    #     if isinstance(student,
    #                   Student) and course in self.courses_attached and course in student.courses_in_progress:
    #         if course in student.grades:
    #             student.grades[course] += [grade]
    #         else:
    #             student.grades[course] = [grade]
    #     else:
    #         return 'Ошибка'

class Lecturer(Mentor):
    def __init__(self, name, surname):
        Mentor.__init__(self, name, surname)
        self.grades_for_lectures = {}
        self.medium = []

    def medium_grade_lec(self, lecturers_grades):
        for i in lecturers_grades.values():
            medium_grade = sum(i) / len(i)
            print(medium_grade)
            self.medium = medium_grade

    def __str__(self):
        return f"Имя: {self.name}\nФамилия: {self.surname}\nСредняя оценка за лекции: {self.medium}"

    def __lt__(self, other):
        return self.medium < other.medium_value

class Reviewer(Mentor):
    def __init__(self, name, surname):
        Mentor.__init__(self, name, surname)
        self.name = name
        self.surname = surname

    def rate_hw(self, student, course, grade):
        if isinstance(student,
                      Student) and course in self.courses_attached and course in student.courses_in_progress:
            if course in student.grades:
                student.grades[course] += [grade]
            else:
                student.grades[course] = [grade]
        else:
            return 'Ошибка'

    def __str__(self):
        return f"Имя: {self.name}\nФамилия: {self.surname}"

lecturer_1 = Lecturer('Nata', 'Mel')
lecturer_1.courses_attached += ['Python', 'Java']

lecturer_2 = Lecturer('Vasya', 'Ivanov')
lecturer_2.courses_attached += ['Java', 'Git']

student_1 = Student('Pasha', 'Dulin', 'm')
student_1.courses_in_progress += ['Java', 'Git', 'Python']
student_1.finished_courses += ['Git']

student_2 = Student('Ruoy', 'Eman', 'f')
student_2.courses_in_progress += ['Git', 'Java', 'Python']
student_2.finished_courses += ['Веб разработчик']

# student_3 = Student('Lena', 'Panina', 'f')
# student_3.courses_in_progress += ['Python']
# student_3.finished_courses += ['Основы программирования']

reviewer_1 = Reviewer('Some', 'Buddy')
reviewer_1.courses_attached += ['Python', 'Java']

reviewer_2 = Reviewer('Ivan', 'Kozlov')
reviewer_2.courses_attached += ['Git', 'Java']

student_1.rate_lec(lecturer_1, 'Java', 7)
student_1.rate_lec(lecturer_1, 'Java', 9)
student_1.rate_lec(lecturer_1, 'Python', 2)
student_1.rate_lec(lecturer_1, 'Python', 9)

student_2.rate_lec(lecturer_2, 'Java', 9)
student_2.rate_lec(lecturer_2, 'Java', 8)
student_2.rate_lec(lecturer_2, 'Python', 3)
student_2.rate_lec(lecturer_2, 'Python', 5)

student_1.rate_lec(lecturer_1, 'Java', 7)
student_1.rate_lec(lecturer_1, 'Java', 9)
student_1.rate_lec(lecturer_1, 'Python', 2)
student_1.rate_lec(lecturer_1, 'Python', 9)

student_2.rate_lec(lecturer_2, 'Git', 9)
student_2.rate_lec(lecturer_2, 'Git', 8)
student_2.rate_lec(lecturer_2, 'Git', 3)
student_2.rate_lec(lecturer_2, 'Git', 5)

print(lecturer_1.grades_for_lectures)
print(lecturer_2.grades_for_lectures)

reviewer_1.rate_hw(student_1, 'Python', 8)
reviewer_1.rate_hw(student_1, 'Python', 10)
reviewer_1.rate_hw(student_1, 'Python', 5)
reviewer_1.rate_hw(student_1, 'Python', 7)

reviewer_2.rate_hw(student_2, 'Java', 10)
reviewer_2.rate_hw(student_2, 'Java', 7)
reviewer_2.rate_hw(student_2, 'Java', 6)
reviewer_2.rate_hw(student_2, 'Java', 4)

print(student_1.grades)
print(student_2.grades)

student_1.medium_student_grade(student_1.grades)
student_2.medium_student_grade(student_2.grades)
lecturer_1.medium_grade_lec(lecturer_1.grades_for_lectures)
lecturer_2.medium_grade_lec(lecturer_2.grades_for_lectures)

# reviewer_1 = Reviewer('Rob', 'Toresh')
# reviewer_2 = Reviewer('Dasha', 'Sokolova')
# reviewer_1.courses_attached += ['Python', 'Java']
# reviewer_2.courses_attached += ['Python', 'Java']
print(reviewer_1)
print(reviewer_2)

print(lecturer_1)
print(lecturer_2)
# best_student = Student('Ruoy', 'Eman', 'your_gender')
# best_student.courses_in_progress += ['Python']

# cool_mentor = Mentor('Some', 'Buddy')
# cool_mentor.courses_attached += ['Python']
# cool_mentor.rate_hw(best_student, 'Python', 10)
# cool_mentor.rate_hw(best_student, 'Python', 10)
# cool_mentor.rate_hw(best_student, 'Python', 10)

# print(best_student.grades)
print(student_1)
print(student_2)

student_list = [student_1, student_2]
lecturer_list = [lecturer_1, lecturer_2]

def medium_mark_student(info, course):
    total = []
    for student in info:
        total.append(sum(student.grades[course])/len(student.grades[course]))
        print(f"Средняя оценка за домашние задания у студентов по {course}: {sum(total) / len(total)}")

def medium_mark_lecturer(info, course):
    total = []
    for lecturer in info:
        total.append(sum(lecturer.grades_for_lectures[course]) / len(lecturer.grades_for_lectures[course]))
    print(f"Средняя оценка у лекторов за лекции по курсу {course}: {sum(total) / len(total)}")

medium_mark_student(student_list, "Git")
medium_mark_student(student_list, "Java")

medium_mark_lecturer(lecturer_list, "Python")
medium_mark_lecturer(lecturer_list, "Java")

# def medium_mark_student(student_list, course):
#     total = 0
#     counter = 0
#     for student in student_list:
#         if course in student.courses_in_progress:
#             medium_course_student = sum(student.grades[course]) / len(student.grades[course])
#             total += medium_course_student
#             counter += 1
#     if counter == 0:
#         return "Такой курс никто не изучает"
#     else:
#         return f"Средний балл по курсу '{course}': {total /counter}"
#
# medium_mark_student(student_list, 'Git')


#!/usr/local/bin/python3
import numpy as np
import pandas as pd
pd.options.mode.chained_assignment = None
import geopandas as gpd

# pygeos sjoin gives widely inaccurate results, so force using rtree instead
#import pygeos
gpd.options.use_pygeos = False

from geopandas import GeoSeries
from geopandas.tools import sjoin
from shapely.geometry import Polygon

import argparse
argparser = argparse.ArgumentParser(description='generate contour polygons with prominence information from elevation-labelled contour lines')
argparser.add_argument('-o', '--out', default='prominence.shp', help='output filename')
argparser.add_argument('file', help='input file of elevation-labelled contour linestrings (any format supported by geopandas)')
#argparser.add_argument('--attribute', default='elevation', help='name of the elevation attribute')
args = argparser.parse_args()

ct = gpd.read_file(args.file)
ct['poly'] = GeoSeries([Polygon(g) for g in ct.geometry])
ct['area'] = ct.poly.area

# sorting by area as secondary is important for two reasons:
# 1. assume larger areas of the same elevation are actually a little higher, so are assigned prominence first
# 2. when selecting basin containers we want to stick to the smallest containing one,
# (so we aggregate using .max(), maybe .last() also ok)
ct.sort_values(['elevation', 'area'], ascending=[False, False], inplace=True, na_position='first')
ct.reset_index(drop=True, inplace=True)
ct.reset_index(inplace=True)

# now that contour lines have been re-sorted, make dedicated polygon dataframe for spatial joins
polys = gpd.GeoDataFrame(geometry=ct.poly)
# FIXME get proj from input file
polys = polys.set_crs(epsg=31297, inplace=True)
# and put in an appropriate projection
print("Reprojecting...")
#polys.to_crs('ESRI:102030', inplace=True)
polys.to_crs('EPSG:31297', inplace=True)

centroids = gpd.GeoDataFrame(geometry=polys.geometry.centroid)

els = list(ct.elevation.unique())
interval = els[0] - els[1]

# index of the 'parent' (containing) contour line
ct['parent'] = np.repeat(-1, len(ct))

for ele in els:
  left = sum(ct.elevation == ele)
  descentparents = sjoin(centroids[ct.elevation == ele], polys[ct.elevation == ele - interval], predicate='within', how='left') # or within or intersects
  # if there's no direct descent parent, maybe it is a basin within a
  # (usually much wider) contour line of the same elevation
  orphans = descentparents[np.isnan(descentparents.index_right)].index
  basins = 0
  if len(orphans):
    # TODO only keep polygons larger than the smallest orphan as candidates
#    largestorphan = max(ct.area)
    basinparents = sjoin(centroids.loc[orphans], polys[ct.elevation == ele], predicate='within', how='left')
    # FIXME drop multiple matches! also group by but select largest (=first/min)
    basinparents.dropna(inplace = True)
    basins = sum(basinparents.index != basinparents.index_right)

  # if there's multiple, only keep smallest (because that will be the direct parent)
  descentparents.dropna(inplace=True)
  groups = descentparents[['index_right']].groupby(descentparents.index, sort=False)
  # because we originally sorted like this, we know it's the highest index! yesss!
  descentparents = groups.max()

  # using pygeos' sjoin I found that I got many incorrect results, basd on this check:
  # p.geometry.within(polys.geometry[p.index_right])]
#  invalid = [i for i, p in descentparents.iterrows() if np.isnan(p.index_right)]
#  print(invalid)
#  descentparents.drop(invalid, inplace=True)

  # actual matches found
  print(ele)
  print(left)
  print(len(descentparents) + basins)
  ct.parent[descentparents.index] = descentparents.index_right
  # now that known parents have been assigned, we can use this information to correctly
  # assign the lower parent of basins
  if basins:
    print("found basin(s)")
    # FIXME there might be recursive basin-parenting happening here which would require a loop
    ct.parent[basinparents.index] = ct.parent[basinparents.index_right]
#    print(ct.parent[basinparents.index])
  print()

ct['prominence'] = np.repeat(None, len(ct))
for i in range(len(ct)):
  if ct.prominence[i] != None or ct.parent[i] == -1:
    continue
#  print(i)
  parent = ct.parent[i]
  print(f'{i} @ {ct.elevation[i]}: ', end = '')
  while ct.prominence[parent] == None:
    print('.', end = '')
    ct.prominence[parent] = 0
    if ct.parent[parent] == -1 or np.isnan(ct.parent[parent]):
      break
    parent = ct.parent[parent]
  # ok, compute prominence
  ct.prominence[i] = ct.elevation[i] - ct.elevation[parent]
  print(f'{parent} @ {ct.elevation[parent]}')

peaks = [i for i, p in enumerate(ct.prominence > 0) if p]
peaks = gpd.GeoDataFrame({ 'elevation': ct.elevation[peaks], 'prominence': pd.to_numeric(ct.prominence[peaks]), 'geometry': polys.geometry[peaks] }, crs='ESRI:102030')

# TODO filter only positive prominence
peaks.to_file(args.out)


import json
from database import ForumDB
import requests

TOKEN = "5466989984:AAHIwjOaHUMHPkMNlGqRtta_T8oWx9L_1bg"
URL = "https://api.telegram.org/bot{}/".format(TOKEN)

DB = ForumDB()
last_msg = 'none'

def send_msg(msg):
    url = URL + 'sendMessage?chat_id=224133650&text={}'.format(msg) + '&parse_mode=HTML&reply_markup='
    requests.post(url)

def send_photo(msg):
    try:
        url = URL + 'sendPhoto'
        requests.post(url, {'chat_id': '224133650', }, files = {'photo' : open('static/images/' + msg,"rb")})
    except:
        url = URL + 'sendPhoto'
        requests.post(url, {'chat_id': '224133650', }, files = {'photo' : open('default.png',"rb")})

# check for mistakes if ok add category
def add_category(msg):
    if msg.strip() == '' or len(msg) < 2 or len(msg) > 20 or msg.isalpha() != True:
        send_msg('This name is not valid!')
    else:
        result = DB.add_category(msg.lower())
        send_msg(result)

# check for mistakes if ok edit category
def edit_category(msg):
    try:
        msg = msg.split(',')
        msg[1] = msg[1].lower().strip()
    except:
        send_msg('Invalid input, Please check!')
        return 1

    if msg[0].isdigit() != True or msg[1].isalpha() != True or len(msg[1]) < 2 or len(msg[1]) > 20:
        print(msg[0].isdigit())
        print(msg[1].isalpha())
        print(len(msg[1]) < 2)
        print(len(msg[1]) > 20)
        send_msg('Invalid input, Please check!')
    else:
        result = DB.edit_categ(msg)
        send_msg(result)

# information about user
def user_info(msg):
    result = DB.info_user(msg)
    send_msg(result)
    send_photo(msg + '.png')

def get_updates(offset=None):
    url = URL + "getUpdates?timeout=100"
    if offset:
        url += "&offset={}".format(offset)

    response = requests.get(url)
    content = response.content.decode("utf8")
    return content

def parsing(updates):
    updates = json.loads(updates)
    global last_msg

    if 'entities' in updates['result'][-1]['message']:
        last_msg = updates['result'][-1]['message']['text']

        if updates['result'][-1]['message']['text'] == '/list':
            # selecting the list of all users
            users = DB.select_all_users()
            send_msg(users)

        elif updates['result'][-1]['message']['text'] == '/add':
            send_msg('Enter category name')

        elif updates['result'][-1]['message']['text'] == '/edit':
            category = DB.select_category()
            send_msg(category)
            send_msg('Send № and new name of category \nEx:  1, nature')

        elif updates['result'][-1]['message']['text'] == '/info':
            send_msg("Enter username of person")

    else:
        if last_msg == '/add':
            last_msg = updates['result'][-1]['message']['text']
            # check for mistakes if ok add category
            add_category(last_msg)

        elif last_msg == '/edit':
            last_msg = updates['result'][-1]['message']['text']
            # check for mistakes if ok edit category
            edit_category(last_msg)

        elif last_msg == '/info':
            last_msg = updates['result'][-1]['message']['text']
            # check for mistakes if ok edit category
            user_info(last_msg)

        else:
            last_msg = updates['result'][-1]['message']['text']
            send_msg('Choose command, Bro')

def main():
    last_update_id = None

    while True:
        updates = get_updates(last_update_id)
        if len(json.loads(updates)['result']) > 0:
           last_update_id = json.loads(updates)['result'][-1]['update_id'] + 1
           parsing(updates)

if __name__ == '__main__':
    main()


import matplotlib.pyplot as plt
import numpy as np
import cv2
import json
train_json = json.load(open('../../../SVHN-Data/mchar_train.json'))

# 数据标注处理
def parse_json(d):
    arr = np.array([
        d['top'], d['height'], d['left'],  d['width'], d['label']
    ])
    arr = arr.astype(int)
    return arr

img = cv2.imreasd('../../../SVHN-Data/mchar_train/000000.png')
arr = parse_json(train_json['000000.png'])

plt.figure(figsize=(10, 10))
plt.subplot(1, arr.shape[1]+1, 1)
plt.imshow(img)
plt.xticks([]); plt.yticks([])

for idx in range(arr.shape[1]):
    plt.subplot(1, arr.shape[1]+1, idx+2)
    plt.imshow(img[arr[0, idx]:arr[0, idx]+arr[1, idx],arr[2, idx]:arr[2, idx]+arr[3, idx]])
    plt.title(arr[4, idx])
    plt.xticks([]); plt.yticks([])


#!/usr/bin/env python3

import sys
from time import sleep
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from PIL import Image
from io import BytesIO
from xvfbwrapper import Xvfb

WEBCAMS = {
    "https://webcam.exdesign.ru/cds-polyustrovo-1": "webcam1.png",
    "https://webcam.exdesign.ru/cds-polyustrovo-2": "webcam2.png"}
VIDEO_CLASSNAME = "container"

def capture_photos():

    options = Options()
    options.headless = True
    driver = webdriver.Chrome(options=options)

    for url, pic in WEBCAMS.items():
        print("%s: capturing..." % url)
        driver.get(url)
        sleep(5)
        element = driver.find_element_by_class_name(VIDEO_CLASSNAME)
        location = element.location
        size = element.size
        png = driver.get_screenshot_as_png()

        im = Image.open(BytesIO(png))

        left = location['x']
        top = location['y']
        right = location['x'] + size['width']
        if url == "https://webcam.exdesign.ru/cds-polyustrovo-1":
            # the site lies about element size (850px)
            bottom = 700
        else:
            bottom = location['y'] + size['height']

        im = im.crop((left, top, right, bottom))
        im.save(pic)
        print("%s: captured as %s" % (url, pic))
    driver.quit()

def main():
    with Xvfb(width=1920, height=1080) as xvfb:
        capture_photos()

if __name__ == "__main__":
    main()


# for 语句语法:
#     for 变量列表 in 可迭代对象 :
#           语句块1
#     else:
#            语句块2

# s = "ABCDE"

# for ch in s :
#     print("ch绑定----->",ch)
# else:
#     print("for语句迭代访问结束")

# print("程序退出")

# 练习：
#     任意输入一段字符串
#     １）计算出这个字符串中空格的个数，并打印这个个数
#         （要求使用ｆｏｒ语句，　不允许使用s.count方法）
#     ２）计算出字符串中全部英文字母（a~z和Ａ～Ｚ）的个数，
#         并打印这个个数：
#     完成上题后思考：
#         能否用ｗｈｉｌｅ语句实现上述功能

s = input("请输入一段字符串：")

shu = 0
#遍历输入的字符串，当有字符为‘　’时，将ｓｈｕ做加１操作
for ch in s:
    if ch == " ":
        shu += 1
else:
    print("空格的个数有:",shu)

dzimu = 0
xzimu = 0
zgs = 0
for ch in s:
    if 65 <= ord(ch) <= 65+26:
        dzimu += 1
        zgs += 1
    if 97 <= ord(ch) <= 97+26:
        xzimu += 1
        zgs += 1
print("您输入的大写字母有:",dzimu,"个")
print("您输入的小写字母有:",xzimu,"个")
print("您输入的英文字母共有：",zgs,"个")


#
# Parse mapfile and dump all information collected.
# Requires https://github.com/pfalcon/pymapfile .
#
import sys
import logging
from pprint import pprint

from mapfile import GnuMapFile

logging.basicConfig(level=logging.DEBUG)

f = open(sys.argv[1])
m = GnuMapFile(f)
m.skip_till_memmap()
m.skip_while_lead_space()
m.parse_sections()
m.validate()

basename = sys.argv[1].replace("-", "_").replace(".", "_")

with open(basename + ".subareas", "w") as f:
    print("[subareas]", file=f)
    for k, addr, sz in m.section_order:
        #print("%08x %08x %s" % (addr, sz, k))
        for sec, addr, sz, obj, symbols in m.sections[k]["objects"]:
            if sec.endswith(".literal"):
                obj += ".literal"
            obj = obj.replace(" ", "_")
            print("%s 0x%08x(0x%08x)" % (obj, addr, sz), file=f)
        print(file=f)

with open(basename + "_script.py", "w") as f:
    print("""\
from idc import *

""", file=f)
    for k, addr, sz in m.section_order:
        #print("%08x %08x %s" % (addr, sz, k))
        for sec, addr, sz, obj, symbols in m.sections[k]["objects"]:
            if obj.endswith(".fill"):
                print("# %s 0x%08x(0x%08x)" % (obj, addr, sz), file=f)
                print("MakeAlign(0x%08x, 0x%08x, 0)" % (addr, sz), file=f)
        print(file=f)


'''
Train the highest number prediction with the rational extractor.
'''
import torch
from torch.utils.data import DataLoader
import pytorch_lightning as pl
from HighestNumber.HighestDataset import HighestDataset
from HighestNumber.reinforce_rational_extraction import ReinforceRationalExtractor, HighestNumberLSTM, ReinforceModelPL

max_epochs = 3

dataset_train = HighestDataset(n_examples=int(10e3))
dataloader_train = DataLoader(dataset_train, shuffle=True, batch_size=8)

dataset_test = HighestDataset(n_examples=int(10e2))
dataloader_test = DataLoader(dataset_test, shuffle=False, batch_size=8)

loss_module = torch.nn.CrossEntropyLoss()
model = HighestNumberLSTM()

RE = ReinforceRationalExtractor()

hparams = {
    "learning_rate": 1e-3
}

model_pl_pretrain = ReinforceModelPL(model, RE, loss_module, hparams=hparams, pretrain=True)
trainer = pl.Trainer(default_root_dir='logs',
                     checkpoint_callback=False,
                     # checkpoint_callback=ModelCheckpoint(save_weights_only=True, mode="min", monitor="val_loss"),
                     gpus=1 if torch.cuda.is_available() else 0,
                     max_epochs=5,
                     log_every_n_steps=1,
                     progress_bar_refresh_rate=1,
                     gradient_clip_val=2,
                     )
trainer.logger._default_hp_metric = None  # Optional logging argument that we don't need

trainer.fit(model_pl_pretrain, dataloader_train, dataloader_test)
loss_module = torch.nn.CrossEntropyLoss(reduce=False)
model_pl = ReinforceModelPL(model, RE, loss_module, hparams=hparams, pretrain=False)
trainer = pl.Trainer(default_root_dir='logs',
                     checkpoint_callback=False,
                     # checkpoint_callback=ModelCheckpoint(save_weights_only=True, mode="min", monitor="val_loss"),
                     gpus=1 if torch.cuda.is_available() else 0,
                     max_epochs=40,
                     log_every_n_steps=1,
                     progress_bar_refresh_rate=1,
                     gradient_clip_val=2,
                     )
trainer.logger._default_hp_metric = None  # Optional logging argument that we don't need

trainer.fit(model_pl, dataloader_train, dataloader_test)


import os, shutil, random
from glob import glob
from tqdm import tqdm

if __name__ == '__main__':
    in_bpath = '/data/datasets/godatasets/goboard_datasets/'
    train_bpath = in_bpath + 'train/yehu/'
    test_bpath = in_bpath +'test/yehu/'
    train_prop = 0.7
    label_file_postfix = '.schema'
    image_file_postfix = '.png'

    label_file_list = glob(train_bpath + '*/*' + label_file_postfix)
    # print(label_file_list[:3])
    random.shuffle(label_file_list)
    # print(label_file_list[:3])
    n = len(label_file_list)
    print(f"total instance: {n}")
    train_n = int(n * train_prop)
    for now_label_file in tqdm(label_file_list[train_n:]):
        now_image_file = now_label_file.replace(label_file_postfix, image_file_postfix)
        now_out_base_path = os.path.split(now_label_file)[0].replace(train_bpath, test_bpath) + '/'
        if not os.path.exists(now_out_base_path):
            os.makedirs(now_out_base_path)
        now_file_id  = os.path.split(now_label_file)[1].split('.')[0]
        shutil.move(now_label_file, now_out_base_path + now_file_id + label_file_postfix)
        shutil.move(now_image_file, now_out_base_path + now_file_id + image_file_postfix)


import logging

import azure.functions as func
import json
from random import randint
# from pathlib import Path

# calcola-somma function
def main(req: func.HttpRequest) -> func.HttpResponse:
        logging.info('Python HTTP trigger function processed a request.')
        users = {"1754462800": {"name": "John", "surname": "Doe", "email": "john.doe@email.com"}, "4659781230": {"name": "Mario", "surname": "Rossi", "email": "mario.rossi@email.com"}, "7845120036": {"name": "Mattia", "surname": "Di Nardo", "email": "mattia.di.nardo@email.com"}, "9956223017": {"name": "Angela", "surname": "Donadoni", "email": "angela.donadoni@email.com"}, "3328182950": {"name": "Maria", "surname": "Lorena", "email": "maria.lorena@email.com"}}

        # GET method
        if req.method == "GET":
                # read users file
                # with open(str(Path.cwd()) + "\\ServerPOST\\users.json", "r") as file:
                #         parsed = json.load(file)
                #         users = json.dumps(parsed, indent=4)

                # HTTP Response
                return func.HttpResponse(
                        f"This HTTP triggered function executed successfully.\nThe users are: {json.dumps(users, indent=4)}",
                        status_code=200
                )

        # POST method
        if req.method == "POST":
                # if there are params
                if len(req.params) >= 3:
                        # take data
                        id = randint(1000000000, 9999999999)
                        name = req.params.get("name")
                        surname = req.params.get("surname")
                        email = req.params.get("email")

                        # read users file
                        # with open(str(Path.cwd()) + "\\ServerPOST\\users.json", "r") as file:
                        #         users = json.load(file)

                        # append new user
                        # users[str(id)] = {
                        #                 "name": name,
                        #                 "surname": surname,
                        #                 "email": email
                        # }

                        user = {id: {
                                "name": name,
                                "surname": surname,
                                "email": email
                        }}

                        # insert new format file
                        # with open(str(Path.cwd()) + "\\ServerPOST\\users.json", "w") as file:
                        #         json.dump(users, file)

                        # HTTP Response
                        return func.HttpResponse(
                                f"This HTTP triggered function executed successfully.\nThe user has been added!\nDetails:{json.dumps(user, indent=4)}",
                                status_code=200
                        )
                # otherwise, check body
                else:
                        # take body
                        req_body = req.get_json()

                        # gen id
                        id = randint(1000000000, 9999999999)

                        # read file
                        # with open(str(Path.cwd()) + "\\ServerPOST\\users.json", "r") as file:
                        #         users = json.load(file)

                        # append new user
                        user = {
                                id:
                                {
                                        "name": req_body["name"],
                                        "surname": req_body["surname"],
                                        "email": req_body["email"]
                                }
                        }

                        # insert new format file
                        # with open(str(Path.cwd()) + "\\ServerPOST\\users.json", "w") as file:
                        #         json.dump(users, file)

                        # HTTP Response
                        return func.HttpResponse(
                                f"This HTTP triggered function executed successfully.\nThe user has been added!\nDetails:{json.dumps(user, indent=4)}",
                                status_code=200
                        )

        # DELETE method
        if req.method == "DELETE":
                # read users file
                # with open(str(Path.cwd()) + "\\ServerPOST\\users.json", "r") as file:
                #         users = json.load(file)

                # take id from params
                id_user = req.params.get("id")

                # deepcopy
                users_pre_delete = users.copy()

                # delete user
                users.pop(id_user)

                # insert new format file
                # with open(str(Path.cwd()) + "\\ServerPOST\\users.json", "w") as file:
                #         json.dump(users, file)

                # HTTP Response
                return func.HttpResponse(
                        f"This HTTP triggered function executed successfully.\nThe user has been deleted!\nUsers pre-delete:{json.dumps(users_pre_delete, indent=4)}\nUsers after-delete:{json.dumps(users, indent=4)}",
                        status_code=200
                )


import sys
from functools import partial
from defect.circuit import load_circuit
from defect import analysis
import defect.filetypes.internal as fileio
import networkx as nx

EATTR_CHANGE = 'delta'     # float - change in current
EATTR_SOURCE = 'src'       # node - positive-sign source for EATTR_CHANGE
EATTRS = [EATTR_CHANGE, EATTR_SOURCE]
VATTR_POS    = 'pos'       # (x,y) - position (for display)
VATTR_DEFECT = 'newdefect' # bool - was defect introduced between steps?
VATTRS = [VATTR_POS, VATTR_DEFECT]

def main():
	import argparse
	parser = argparse.ArgumentParser()
	add_modes(parser)
	args = parser.parse_args()

	if hasattr(args, 'func'): # workaround for Python 3.3+: http://bugs.python.org/issue16308
		args.func(args)
	else:
		parser.print_usage(file=sys.stderr)
		print('Error: No mode specified', file=sys.stderr)
		sys.exit(1)

def add_modes(parser):
	subparsers = parser.add_subparsers()
	add_generate_mode(subparsers, 'create')
	add_plot_mode(subparsers, 'plot')

def add_generate_mode(subparsers, cmd):
	sub = subparsers.add_parser(cmd, description='generate plot data')
	sub.add_argument('circuit', type=str, help='path to initial circuit')
	sub.add_argument('cyclebasis', type=str, help='path to initial cycles')
	sub.add_argument('gpos', type=str, help='path to gpos file')
	sub.add_argument('results', type=str, help='path to results.json from trial')
	sub.add_argument('trialid', type=int, help='trial index in results.json')
	sub.add_argument('step', type=int, help='trial step for which to compute currents')
	def callback(args):
		data = Data.from_trial_data(
			circuit = load_circuit(args.circuit),
			cycles = fileio.cycles.read_cycles(args.cyclebasis, repeatfirst=True),
			pos = fileio.gpos.read_gpos(args.gpos),
			resultinfo = analysis.read_info(args.results),
			trialid = args.trialid,
			step = args.step,
		)
		# FIXME -- TERRIBLE HACK for obvious reasons
		outpath = args.results[:-len('.results.json')]
		outpath += '-{}-{}-currents.dat'.format(args.trialid, args.step)

		print("Writing to '{}'...".format(outpath))
		data.save(outpath)

	sub.set_defaults(func = callback)

def add_plot_mode(subparsers, cmd):
	sub = subparsers.add_parser(cmd, description='display plot data')
	sub.add_argument('data', type=str, help='path to -currents.dat')
	sub.add_argument('--output', '-o', type=str, default='out.pdf', help='path to plot')
	sub.add_argument('--noshow', dest='show', action='store_false', help='no preview')
	def callback(args):
		data = Data.load(args.data)
		plot_data(data, args.output, args.show)

	sub.set_defaults(func = callback)

class Data:
	def __init__(self, g):
		self.g = g

	@classmethod
	def from_trial_data(cls, circuit, cycles, pos, resultinfo, trialid, step):
		# several parts of this script would require reconsideration to support trials
		# where the vertices weren't actually deleted
		if resultinfo['defect_mode']['mode'] != 'direct removal':
			raise RuntimeError('This script was only written with "remove" mode in mind')

		# Find change in currents
		before = analysis.trial_edge_currents_at_step(circuit, cycles, resultinfo, trialid, step)
		after  = analysis.trial_edge_currents_at_step(circuit, cycles, resultinfo, trialid, step+1)

		before = edict_remove_redundant_entries(before)
		delta  = {e: after.get(e, 0.0) - before[e] for e in before}

		# NOTE: this reconstruction will lack some isolated vertices
		defects = set(get_added_defects(resultinfo, trialid, step))
		defect_dict = {v:False for v in edict_vertices(delta)}
		defect_dict.update({v:True for v in defects})

		sources = {(s,t):s for (s,t) in delta}

		g = nx.Graph()
		g.add_edges_from(delta)
		g.add_nodes_from(defects) # in case any of the defects are isolated vertices

		# ``pos`` contains all vertices from the graph's initial state.  Limit it to those currently
		#  in the modified graph (because set_node_attributes crashes on nodes that don't exist)
		pos = {k:v for k,v in pos.items() if k in g}

		nx.set_edge_attributes(g, EATTR_CHANGE, delta)
		nx.set_edge_attributes(g, EATTR_SOURCE, sources)
		nx.set_node_attributes(g, VATTR_POS, pos)
		nx.set_node_attributes(g, VATTR_DEFECT, defect_dict)
		return cls(g)

	def save(self, path):
		fileio.graph.write_networkx(self.g, path)

	@classmethod
	def load(cls, path):
		g = fileio.graph.read_networkx(path)
		for attr in EATTRS:
			if len(nx.get_edge_attributes(g, attr)) == 0:
				raise RuntimeError('Graph is missing edge attribute {}.'.format(repr(attr)))
		for attr in VATTRS:
			if len(nx.get_node_attributes(g, attr)) == 0:
				raise RuntimeError('Graph is missing node attribute {}.'.format(repr(attr)))
		return cls(g)

# for a dict assigning attributes to an undirected graph, ensure each edge only appears once
def edict_remove_redundant_entries(d):
	d = dict(d)
	for (s,t) in list(d):
		if (s,t) in d and (t,s) in d:
			del d[(t,s)]
	return d

# flatten iterable
def flat(it):
	for x in it: yield from x

# get all vertices that appear in an edge dict
def edict_vertices(d):
	return set(flat(d))

# vertices deleted between step and step+1
def get_added_defects(resultinfo, trialid, step):
	trials = resultinfo['trials']
	trial = trials[trialid]
	arr = analysis.trial_array(trial)
	return arr['deleted'][step+1]

def remove_nodes(it, removed):
	return set(it) - set(removed)

def remove_edges(it, removed):
	it = set(it)
	for s,t in removed:
		it.discard((s,t))
		it.discard((t,s))
	return it

def plot_data(data, path, show):
	import matplotlib.pyplot as plt

	# position attributes
	g = data.g
	pos = nx.get_node_attributes(g, VATTR_POS)
	delta = nx.get_edge_attributes(g, EATTR_CHANGE)

	deleted_dict = nx.get_node_attributes(g, VATTR_DEFECT)

	# things to be used as nodelists and edgelists in draw_networkx
	# (use these when defining e.g. edge_color to ensure order is consistent)
	deleted_nodes = [v for v in g if deleted_dict[v]]
	deleted_edges = [e for e in delta if any(v in deleted_nodes for v in e)] # edges attached to deleted nodes
	remaining_nodes = list(remove_nodes(g, deleted_nodes))
	remaining_edges = list(remove_edges(delta, deleted_edges))

	draw_g = partial(nx.draw_networkx, g, pos=pos, with_labels=False)
	draw_remaining_nodes = partial(draw_g, edgelist=[], nodelist=remaining_nodes)
	draw_deleted_nodes   = partial(draw_g, edgelist=[], nodelist=deleted_nodes)
	draw_remaining_edges = partial(draw_g, nodelist=[], edgelist=remaining_edges)
	draw_deleted_edges   = partial(draw_g, nodelist=[], edgelist=deleted_edges)

	def edge_intensities(es):
		deltas = list(map(delta.__getitem__, es))
		deltas = list(map(abs, deltas))
		delta_max = max(deltas)
		return [max(x / delta_max * 5., 0.25) for x in deltas]

	fig, ax = plt.subplots()
	ax.set_xticks([])
	ax.set_yticks([])
	draw_remaining_edges(ax=ax,
#		edge_color = [abs(ecurrents[0][e] - ecurrents[1][e]) for e in remaining_edges],
#		edge_cmap = mpl.cm.get_cmap('gist_heat_r'),
		width=edge_intensities(remaining_edges),
	)
	draw_deleted_nodes(ax=ax, node_color='g', node_size=40)
	draw_deleted_edges(ax=ax, edge_color='r', width=5.)
#	draw_deleted_edges(ax=ax, edge_color='r', width=list(range(len(deleted_edges))))
	fig.savefig(path)
	if show:
		plt.show()

if __name__ == '__main__':
	main()


import os
import sys
import time
WIDTH = 79
message = "4396"
printedMessage = ["", "", "", "", "", "", ""]
characters = {
    " ": [	" ",
           " ",
           " ",
           " ",
           " ",
           " ",
           " "],
    "4": [	"*    *",
           "*    *",
           "*    *",
           "******",
           "     *",
           "     *",
           "     *"],
    "3": [	"******",
           "     *",
           "     *",
           "******",
           "     *",
           "     *",
           "******"],
    "9": [	"******",
           "*    *",
           "*    *",
           "******",
           "     *",
           "     *",
           "******"],
    "6": [	"******",
           "*     ",
           "*     ",
           "******",
           "*    *",
           "*    *",
           "******"],

}

def clearlove():
	for row in range(7):
		for char in message:
			printedMessage[row] += (str(characters[char][row])+"  ")

	offset = WIDTH
	##操作系统判断
	import platform
	if "Windows" in str(platform.architecture()):
		command = "cls"
	else:
		command = "clear"
	while True:
		try:
			os.system(command)
			for row in range(7):
				print(" "*offset+printedMessage[row][max(0, offset*-1):WIDTH-offset])
			offset -= 1
			if offset <= ((len(message)+2)*6)-1:
				offset = WIDTH
			time.sleep(0.05)
		except KeyboardInterrupt:
			print("\nUser use Ctrl-C to break...")
			sys.exit(1)