#
#           _.._        ,------------.
#        ,'      `.    ( We want you! )
#       /  __) __` \    `-,----------'
#      (  (`-`(-')  ) _.-'
#      /)  \  = /  (
#     /'    |--' .  \
#    (  ,---|  `-.)__`
#     )(  `-.,--'   _`-.
#    '/,'          (  Uu",
#      (_       ,    `/,-' )
#       `.__,  : `-'/  /`--'
#        |     `--'  |
#        `   `-._   /
#         \        (
#         /\ .      \.
#        / |` \     ,-\
#       /  \| .)   /   \
#      ( ,'|\    ,'     :
#      | \,`.`--"/      }
#      `,'    \  |,'    /
#     / "-._   `-/      |
#     "-.   "-.,'|     ;
#    /        _/["---'""]
#   :        /  |"-     '
#   '           |      /
#               `      |
#
# author: OYQ
# write_date: 2023.2.28
#

import sys
import time
import pygame
from constant import *

class Game(object):
    """游戏类"""

    click1 = None
    click2 = None
    red = True
    black = False
    index = 0
    chess_left_x = []
    chess_right_x = []
    chess_up_y = []
    chess_down_y = []
    chess_left_y = None
    chess_right_y = None
    chess_up_x = None
    chess_down_x = None
    name = None
    start_click_coord = None
    old_click_coord = None
    end_click_coord = None
    go = False
    m_chess_coord = {}
    no_go_coord = {}

    def __init__(self):
        """初始化"""

        pygame.init()
        pygame.mixer.init()
        # 初始化音效
        self.move = pygame.mixer.Sound("musics/move.WAV")
        self.eat = pygame.mixer.Sound("./musics/eat.WAV")
        self.move.set_volume(1)
        self.eat.set_volume(1)
        pygame.mixer.music.load("./musics/start.mp3")
        pygame.mixer.music.set_volume(0.5)
        pygame.mixer.music.play()
        # 初始化窗口
        pygame.display.set_caption(WINDOW_TITLE)
        self.window = pygame.display.set_mode(WINDOW_SIZE)
        # 初始化图片素材
        self.ico1 = pygame.image.load("./images/ico1.png")
        self.ico2 = pygame.image.load("./images/b_j.png")
        self.r_box = pygame.image.load("images/r_box.png")
        self.b_box = pygame.image.load("images/b_box.png")
        self.dot = pygame.image.load("./images/dot.png")
        self.bg1 = pygame.image.load("images/bg1.png")
        self.bg2 = pygame.image.load("images/bg2.png")
        self.b_z = pygame.image.load("images/b_z.png")
        self.b_p = pygame.image.load("images/b_p.png")
        self.b_c = pygame.image.load("images/b_c.png")
        self.b_m = pygame.image.load("images/b_m.png")
        self.b_x = pygame.image.load("images/b_x.png")
        self.b_s = pygame.image.load("images/b_s.png")
        self.b_j = pygame.image.load("images/b_j.png")
        self.r_z = pygame.image.load("images/r_z.png")
        self.r_p = pygame.image.load("images/r_p.png")
        self.r_c = pygame.image.load("images/r_c.png")
        self.r_m = pygame.image.load("images/r_m.png")
        self.r_x = pygame.image.load("images/r_x.png")
        self.r_s = pygame.image.load("images/r_s.png")
        self.r_j = pygame.image.load("images/r_j.png")
        self.bg = self.bg1, self.bg2
        self.b_chess = self.b_z, self.b_p, self.b_c, self.b_m, self.b_x, self.b_s, self.b_j
        self.r_chess = self.r_z, self.r_p, self.r_c, self.r_m, self.r_x, self.r_s, self.r_j
        self.chess_name = {
            "黑卒": self.b_chess[0], "黑炮": self.b_chess[1],
            "黑车": self.b_chess[2], "黑马": self.b_chess[3],
            "黑象": self.b_chess[4], "黑士": self.b_chess[5],
            "黑将": self.b_chess[6], "红卒": self.r_chess[0],
            "红炮": self.r_chess[1], "红车": self.r_chess[2],
            "红马": self.r_chess[3], "红象": self.r_chess[4],
            "红士": self.r_chess[5], "红将": self.r_chess[6]}

    def img_place(self):
        """放置棋盘和棋子"""

        count_init_coord()
        self.window.blit(self.bg[1], (0, 0))
        self.window.blit(self.bg[0], (128, 0))
        self.window.blit(self.b_chess[2], INIT_COORD[0])
        self.window.blit(self.b_chess[3], INIT_COORD[1])
        self.window.blit(self.b_chess[4], INIT_COORD[2])
        self.window.blit(self.b_chess[5], INIT_COORD[3])
        self.window.blit(self.b_chess[6], INIT_COORD[4])
        self.window.blit(self.b_chess[5], INIT_COORD[5])
        self.window.blit(self.b_chess[4], INIT_COORD[6])
        self.window.blit(self.b_chess[3], INIT_COORD[7])
        self.window.blit(self.b_chess[2], INIT_COORD[8])
        self.window.blit(self.b_chess[1], INIT_COORD[9])
        self.window.blit(self.b_chess[1], INIT_COORD[10])
        self.window.blit(self.b_chess[0], INIT_COORD[11])
        self.window.blit(self.b_chess[0], INIT_COORD[12])
        self.window.blit(self.b_chess[0], INIT_COORD[13])
        self.window.blit(self.b_chess[0], INIT_COORD[14])
        self.window.blit(self.b_chess[0], INIT_COORD[15])
        self.window.blit(self.r_chess[2], INIT_COORD[16])
        self.window.blit(self.r_chess[3], INIT_COORD[17])
        self.window.blit(self.r_chess[4], INIT_COORD[18])
        self.window.blit(self.r_chess[5], INIT_COORD[19])
        self.window.blit(self.r_chess[6], INIT_COORD[20])
        self.window.blit(self.r_chess[5], INIT_COORD[21])
        self.window.blit(self.r_chess[4], INIT_COORD[22])
        self.window.blit(self.r_chess[3], INIT_COORD[23])
        self.window.blit(self.r_chess[2], INIT_COORD[24])
        self.window.blit(self.r_chess[1], INIT_COORD[25])
        self.window.blit(self.r_chess[1], INIT_COORD[26])
        self.window.blit(self.r_chess[0], INIT_COORD[27])
        self.window.blit(self.r_chess[0], INIT_COORD[28])
        self.window.blit(self.r_chess[0], INIT_COORD[29])
        self.window.blit(self.r_chess[0], INIT_COORD[30])
        self.window.blit(self.r_chess[0], INIT_COORD[31])

    def click_1(self, click1, click2):
        """第一次点击"""

        for name1, old_coord, new_coord in zip(CHESS_NAME, INIT_COORD, INIT_RANGER):
            old_x = old_coord[0]
            old_y = old_coord[1]
            new_x = new_coord[0]
            new_y = new_coord[1]
            click1_x = click1[0]
            click1_y = click1[1]
            # 判断第一次点击的坐标是不是在棋子初始坐标范围内
            if old_x <= click1_x <= new_x and old_y <= click1_y <= new_y:
                # print("{}被点击了".format(name1))
                # print("第一次点击: 棋子范围:({}~{}, {}~{}), 点击坐标:{}".format(old_x, new_x, old_y, new_y, click1))
                self.click_2(click2, name1, old_coord, new_coord)
                return

    def click_2(self, click2, name1, old_coord, new_coord):
        """第二次点击"""

        def go_on(eat):
            """继续判断"""
            for name2, init_coord, init_ranger in zip(CHESS_NAME, INIT_COORD, INIT_RANGER):
                # 判断两次点击是否都是棋子
                # if init_coord[0] < min_x < init_ranger[0] and init_coord[1] < min_y < init_ranger[1]:
                if init_coord[0] <= click2_x <= init_ranger[0] and init_coord[1] <= click2_y <= init_ranger[1]:
                    # 判断两次点击的棋子是否不一样
                    if "红" in name1 and "黑" in name2 or "黑" in name1 and "红" in name2:
                        if self.logic(init_coord):
                            eat = True
                            NAME.append(name2)
                            coord.append(init_coord)
                            un1_coord.append(init_coord)
                            un2_coord.append(init_ranger)
                            if len(NAME):
                                self.operate(len(coord), coord, old_coord, new_coord, un1_coord, un2_coord, eat, name1,
                                             name2=NAME[-1])
                                eat = False
                else:
                    for un1, un2 in zip(UNPLACED_COORD, UNPLACED_RANGER):
                        un_x1 = un1[0]
                        un_y1 = un1[1]
                        un_x2 = un2[0]
                        un_y2 = un2[1]
                        if un_x1 < min_x < un_x2 and un_y1 < min_y < un_y2:
                            coord.append(un1)
                            un1_coord.append(un1)
                            un2_coord.append(un2)
                    if len(NAME):
                        self.operate(len(coord), coord, old_coord, new_coord, un1_coord, un2_coord, eat, name1,
                                     name2=NAME[-1])
                    else:
                        self.operate(len(coord), coord, old_coord, new_coord, un1_coord, un2_coord, eat, name1,
                                     name2=None)

        for min_coord, max_coord in zip(MIN_COORD, MAX_COORD):
            min_x = min_coord[0]
            min_y = min_coord[1]
            max_x = max_coord[0]
            max_y = max_coord[1]
            click2_x = click2[0]
            click2_y = click2[1]
            # 判断第二次点击的坐标是不是在棋子可落子的坐标范围内
            if min_x <= click2_x <= max_x and min_y <= click2_y <= max_y:
                # print("第二次点击: 中心范围:({}~{}, {}~{}), 点击坐标:{}".format(min_x, max_x, min_y, max_y, click2))
                coord = []
                un1_coord = []
                un2_coord = []
                e = False
                if "红" in name1 and self.red:
                    go_on(e)
                elif "黑" in name1 and self.black:
                    go_on(e)
                else:
                    return

    def no_go(self):
        if self.red:
            pygame.display.set_icon(self.ico2)
            self.black = True
            self.red = False
        elif self.black:
            pygame.display.set_icon(self.ico1)
            self.black = False
            self.red = True

    @staticmethod
    def logic(f_coord):
        """棋子走棋逻辑判断"""
        if f_coord in FEASIBLE_COORD:
            return True
        return False

    def operate(self, flag, coord, old_coord, new_coord, un1_coord, un2_coord, eat, name1, name2):
        """棋子操作"""

        def blit(n):
            """放置棋子"""

            if eat:
                CHESS_NAME.remove(name1)
                INIT_COORD.remove(old_coord)
                INIT_RANGER.remove(new_coord)
                CHESS_NAME.remove(name2)
                INIT_COORD.remove(un1_coord[-1])
                INIT_RANGER.remove(un2_coord[-1])
                CHESS_NAME.insert(0, name1)
                INIT_COORD.insert(0, un1_coord[-1])
                INIT_RANGER.insert(0, un2_coord[-1])
                UNPLACED_COORD.insert(0, old_coord)
                UNPLACED_RANGER.insert(0, new_coord)
                # print("事件: {}吃掉了{}".format(name1, name2))
                self.eat.play()

            else:
                CHESS_NAME.remove(name1)
                INIT_COORD.remove(old_coord)
                INIT_RANGER.remove(new_coord)
                UNPLACED_COORD.remove(un1_coord[-1])
                UNPLACED_RANGER.remove(un2_coord[-1])
                CHESS_NAME.insert(0, name1)
                INIT_COORD.insert(0, un1_coord[-1])
                INIT_RANGER.insert(0, un2_coord[-1])
                UNPLACED_COORD.insert(0, old_coord)
                UNPLACED_RANGER.insert(0, new_coord)
                # print("事件: {}从{}移动到{}".format(name1, old_coord, coord[0]))
                self.move.play()

            self.window.blit(self.bg[0], (128, 0))
            for a_name, init_coord in zip(CHESS_NAME, INIT_COORD):
                CHESS_STATE[a_name] = init_coord
            if name2 is not None and eat:
                for keys, value in zip(list(CHESS_STATE.keys()), list(CHESS_STATE.values())):
                    if name2 == keys:
                        del CHESS_STATE[name2]
            if name2 is not None and not eat:
                for keys, value in zip(list(CHESS_STATE.keys()), list(CHESS_STATE.values())):
                    if name2 == keys:
                        del CHESS_STATE[name2]
            for key, value in zip(CHESS_STATE.keys(), CHESS_STATE.values()):
                if eat:
                    if name2 != key:
                        for a in self.chess_name:
                            if a in key:
                                self.window.blit(self.chess_name[a], value)
                else:
                    if name1 != key:
                        for a in self.chess_name:
                            if a in key:
                                self.window.blit(self.chess_name[a], value)

            self.go = True
            self.old_click_coord = old_coord
            self.end_click_coord = coord[0]
            self.window.blit(n, coord[0])
            self.update()
            coord.clear()

        if flag and self.logic(un1_coord[-1]):

            for name in self.chess_name.keys():
                if name in name1:
                    self.no_go()
                    blit(self.chess_name[name])
        else:
            return False

    def show_dot(self, name1, d_coord, all_coord):
        """计算棋子可以走的点位"""

        def rule():
            if (d_coord[0] == all_coord[0] or d_coord[1] == all_coord[1]) and d_coord != all_coord:
                if all_coord[0] < d_coord[0]:
                    if all_coord in INIT_COORD:
                        self.chess_left_x.append(all_coord[0])
                        self.chess_left_x.sort(reverse=True)
                        self.chess_left_y = all_coord[1]
                    else:
                        if self.chess_left_x and self.chess_left_x[0] < all_coord[0]:
                            FEASIBLE_COORD.append(all_coord)
                        elif not self.chess_left_x and all_coord[0] < d_coord[0]:
                            FEASIBLE_COORD.append(all_coord)

                elif all_coord[0] > d_coord[0]:
                    if all_coord in INIT_COORD:
                        self.chess_right_x.append(all_coord[0])
                        self.chess_right_x.sort()
                        self.chess_right_y = all_coord[1]
                    else:
                        if self.chess_right_x and all_coord[0] < self.chess_right_x[0]:
                            FEASIBLE_COORD.append(all_coord)
                        elif not self.chess_right_x and d_coord[0] < all_coord[0]:
                            FEASIBLE_COORD.append(all_coord)

                elif all_coord[1] < d_coord[1]:
                    if all_coord in INIT_COORD:
                        self.chess_up_x = all_coord[0]
                        self.chess_up_y.append(all_coord[1])
                        self.chess_up_y.sort(reverse=True)
                    else:
                        if self.chess_up_y and self.chess_up_y[0] < all_coord[1]:
                            FEASIBLE_COORD.append(all_coord)
                        elif not self.chess_up_y and all_coord[1] < d_coord[1]:
                            FEASIBLE_COORD.append(all_coord)

                elif all_coord[1] > d_coord[1]:
                    if all_coord in INIT_COORD:
                        self.chess_down_x = all_coord[0]
                        self.chess_down_y.append(all_coord[1])
                        self.chess_down_y.sort()
                    else:
                        if self.chess_down_y and all_coord[1] < self.chess_down_y[0]:
                            FEASIBLE_COORD.append(all_coord)
                        elif not self.chess_down_y and d_coord[1] < all_coord[1]:
                            FEASIBLE_COORD.append(all_coord)

        def rule2():

            if "士" in name1:
                if d_coord[0] == all_coord[0] - CHESS_INTERVAL1 and d_coord[1] == all_coord[1] - CHESS_INTERVAL1:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] == all_coord[0] + CHESS_INTERVAL1 and d_coord[1] == all_coord[1] - CHESS_INTERVAL1:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] == all_coord[0] - CHESS_INTERVAL1 and d_coord[1] == all_coord[1] + CHESS_INTERVAL1:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] == all_coord[0] + CHESS_INTERVAL1 and d_coord[1] == all_coord[1] + CHESS_INTERVAL1:
                    FEASIBLE_COORD.append(all_coord)
            elif "将" in name1:
                if d_coord[0] == all_coord[0] - CHESS_INTERVAL1 and d_coord[1] == all_coord[1]:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] == all_coord[0] + CHESS_INTERVAL1 and d_coord[1] == all_coord[1]:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] == all_coord[0] and d_coord[1] == all_coord[1] - CHESS_INTERVAL1:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] == all_coord[0] and d_coord[1] == all_coord[1] + CHESS_INTERVAL1:
                    FEASIBLE_COORD.append(all_coord)

        if "红卒" in name1 and all_coord[1] <= d_coord[1]:
            if d_coord[1] <= 226:
                if d_coord[0] - CHESS_INTERVAL1 == all_coord[0] and d_coord[1] == all_coord[1]:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] + CHESS_INTERVAL1 == all_coord[0] and d_coord[1] == all_coord[1]:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] == all_coord[0] and d_coord[1] - CHESS_INTERVAL1 == all_coord[1]:
                    FEASIBLE_COORD.append(all_coord)
            elif all_coord[0] == d_coord[0] and d_coord[1] - CHESS_INTERVAL1 == all_coord[1]:
                FEASIBLE_COORD.append(all_coord)

        elif "黑卒" in name1 and all_coord[1] >= d_coord[1]:
            if d_coord[1] >= 282:
                if d_coord[0] - CHESS_INTERVAL1 == all_coord[0] and d_coord[1] == all_coord[1]:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] + CHESS_INTERVAL1 == all_coord[0] and d_coord[1] == all_coord[1]:
                    FEASIBLE_COORD.append(all_coord)
                elif d_coord[0] == all_coord[0] and d_coord[1] + CHESS_INTERVAL1 == all_coord[1]:
                    FEASIBLE_COORD.append(all_coord)
            elif all_coord[0] == d_coord[0] and d_coord[1] + CHESS_INTERVAL1 == all_coord[1]:
                FEASIBLE_COORD.append(all_coord)

        elif "炮" in name1 or "车" in name1:
            rule()
        elif "马" in name1:
            self.m_chess_coord["up_left"] = d_coord[0] - CHESS_INTERVAL1, d_coord[1] - CHESS_INTERVAL1 * 2
            self.m_chess_coord["up_right"] = d_coord[0] + CHESS_INTERVAL1, d_coord[1] - CHESS_INTERVAL1 * 2
            self.m_chess_coord["left_up"] = d_coord[0] - CHESS_INTERVAL1 * 2, d_coord[1] - CHESS_INTERVAL1
            self.m_chess_coord["left_down"] = d_coord[0] - CHESS_INTERVAL1 * 2, d_coord[1] + CHESS_INTERVAL1
            self.m_chess_coord["right_up"] = d_coord[0] + CHESS_INTERVAL1 * 2, d_coord[1] - CHESS_INTERVAL1
            self.m_chess_coord["right_down"] = d_coord[0] + CHESS_INTERVAL1 * 2, d_coord[1] + CHESS_INTERVAL1
            self.m_chess_coord["down_left"] = d_coord[0] - CHESS_INTERVAL1, d_coord[1] + CHESS_INTERVAL1 * 2
            self.m_chess_coord["down_right"] = d_coord[0] + CHESS_INTERVAL1, d_coord[1] + CHESS_INTERVAL1 * 2
            self.no_go_coord["go_left"] = d_coord[0] - CHESS_INTERVAL1, d_coord[1]
            self.no_go_coord["go_right"] = d_coord[0] + CHESS_INTERVAL1, d_coord[1]
            self.no_go_coord["go_up"] = d_coord[0], d_coord[1] - CHESS_INTERVAL1
            self.no_go_coord["go_down"] = d_coord[0], d_coord[1] + CHESS_INTERVAL1
        elif "象" in name1:
            self.m_chess_coord["up_left"] = d_coord[0] - CHESS_INTERVAL1 * 2, d_coord[1] + CHESS_INTERVAL1 * 2
            self.m_chess_coord["up_right"] = d_coord[0] + CHESS_INTERVAL1 * 2, d_coord[1] + CHESS_INTERVAL1 * 2
            self.m_chess_coord["down_left"] = d_coord[0] - CHESS_INTERVAL1 * 2, d_coord[1] - CHESS_INTERVAL1 * 2
            self.m_chess_coord["down_right"] = d_coord[0] + CHESS_INTERVAL1 * 2, d_coord[1] - CHESS_INTERVAL1 * 2
            self.no_go_coord["up_left"] = d_coord[0] - CHESS_INTERVAL1, d_coord[1] + CHESS_INTERVAL1
            self.no_go_coord["up_right"] = d_coord[0] + CHESS_INTERVAL1, d_coord[1] + CHESS_INTERVAL1
            self.no_go_coord["down_left"] = d_coord[0] - CHESS_INTERVAL1, d_coord[1] - CHESS_INTERVAL1
            self.no_go_coord["down_right"] = d_coord[0] + CHESS_INTERVAL1, d_coord[1] - CHESS_INTERVAL1

        elif "士" in name1 or "将" in name1:
            if "红" in name1:
                if CHESS_INTERVAL1 * 3 + CHESS_X <= all_coord[0] <= CHESS_INTERVAL1 * 5 + CHESS_X and CHESS_INTERVAL1 * 7 + CHESS_Y <= all_coord[1] <= CHESS_INTERVAL1 * 9 + CHESS_Y:
                    rule2()
            elif "黑" in name1:
                if CHESS_INTERVAL1 * 3 + CHESS_X <= all_coord[0] <= CHESS_INTERVAL1 * 5 + CHESS_X and CHESS_Y <= all_coord[1] <= CHESS_INTERVAL1 * 2 + CHESS_Y:
                    rule2()

    @staticmethod
    def play_music(music):
        """播放音频"""
        pygame.mixer.music.load("./musics/{}".format(music))
        pygame.mixer.music.set_volume(0.5)
        pygame.mixer.music.play()

    def event(self):
        """事件判断"""

        name = None
        all_music, num_list, index = random_num()
        print(all_music, num_list, index)
        while True:
            time.sleep(0.001)

            if not pygame.mixer.music.get_busy():
                music = all_music[num_list[self.index]]
                print(music, self.index)
                if self.index < index:
                    self.play_music(music)
                    self.index += 1
                    if self.index == index:
                        self.index = 0

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()

                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:
                        if self.click1 is None:
                            self.click1 = event.pos
                            if len(FEASIBLE_COORD):
                                FEASIBLE_COORD.clear()
                                self.chess_left_x.clear()
                                self.chess_right_x.clear()
                                self.chess_up_y.clear()
                                self.chess_down_y.clear()
                                self.m_chess_coord.clear()
                                self.no_go_coord.clear()
                            for n, old_coord, new_coord in zip(CHESS_NAME, INIT_COORD, INIT_RANGER):
                                old_x = old_coord[0]
                                old_y = old_coord[1]
                                new_x = new_coord[0]
                                new_y = new_coord[1]
                                click1_x = event.pos[0]
                                click1_y = event.pos[1]
                                CHESS_INIT[n] = old_coord
                                if old_x <= click1_x <= new_x and old_y <= click1_y <= new_y:
                                    name = n
                                    self.name = n
                                    self.start_click_coord = old_coord
                                    self.window.blit(self.r_box, old_coord)
                                    self.update()
                            all_coord = INIT_COORD + UNPLACED_COORD
                            if self.start_click_coord is not None:
                                for coord in all_coord:
                                    self.show_dot(name, self.start_click_coord, coord)
                                if "炮" in self.name:
                                    if len(self.chess_left_x) >= 2:
                                        FEASIBLE_COORD.append((self.chess_left_x[1], self.chess_left_y))
                                    if len(self.chess_right_x) >= 2:
                                        FEASIBLE_COORD.append((self.chess_right_x[1], self.chess_right_y))
                                    if len(self.chess_up_y) >= 2:
                                        FEASIBLE_COORD.append((self.chess_up_x, self.chess_up_y[1]))
                                    if len(self.chess_down_y) >= 2:
                                        FEASIBLE_COORD.append((self.chess_down_x, self.chess_down_y[1]))
                                elif "车" in self.name:
                                    print(self.chess_left_x)
                                    if len(self.chess_left_x) >= 1:
                                        FEASIBLE_COORD.append((self.chess_left_x[0], self.chess_left_y))
                                    if len(self.chess_right_x) >= 1:
                                        FEASIBLE_COORD.append((self.chess_right_x[0], self.chess_right_y))
                                    if len(self.chess_up_y) >= 1:
                                        FEASIBLE_COORD.append((self.chess_up_x, self.chess_up_y[0]))
                                    if len(self.chess_down_y) >= 1:
                                        FEASIBLE_COORD.append((self.chess_down_x, self.chess_down_y[0]))
                                elif "马" in self.name:
                                    for key1, value1 in self.no_go_coord.items():
                                        for key2, value2 in self.m_chess_coord.items():
                                            if value1 not in INIT_COORD and value1 in UNPLACED_COORD:
                                                if key1[3:] == key2[:2] or key1[3:] == key2[:4] or key1[3:] == key2[:5]:
                                                    if CHESS_X <= value2[0] <= CHESS_INTERVAL1 * 8 + CHESS_X and CHESS_Y <= value2[1] <= CHESS_INTERVAL1 * 9 + CHESS_Y:
                                                        FEASIBLE_COORD.append(value2)
                                elif "象" in self.name:
                                    for key3, value3 in self.no_go_coord.items():
                                        for key4, value4 in self.m_chess_coord.items():
                                            if value3 not in INIT_COORD and value3 in UNPLACED_COORD:
                                                if key3 == key4:
                                                    if CHESS_X <= value4[0] <= CHESS_INTERVAL1 * 8 + CHESS_X and CHESS_Y <= value4[1] <= CHESS_INTERVAL1 * 9 + CHESS_Y:
                                                        if "红" in self.name and value4[1] >= 282:
                                                            FEASIBLE_COORD.append(value4)
                                                        elif "黑" in self.name and value4[1] <= 226:
                                                            FEASIBLE_COORD.append(value4)
                                if not self.go:
                                    for key, value in CHESS_INIT.items():
                                        if value in FEASIBLE_COORD:
                                            if self.name[0] == key[0]:
                                                FEASIBLE_COORD.remove(value)
                                elif self.go:
                                    for key, value in CHESS_STATE.items():
                                        if value in FEASIBLE_COORD:
                                            if self.name[0] == key[0]:
                                                FEASIBLE_COORD.remove(value)

                                for a_coord in FEASIBLE_COORD:
                                    self.window.blit(self.dot, a_coord)
                                self.update()

                        else:
                            self.click2 = event.pos
                            self.click_1(self.click1, self.click2)
                            print("当前 red:{},black:{}".format(self.red, self.black))
                            self.click1 = None
                            self.click2 = None
                            if not self.go:
                                self.window.blit(self.bg[0], (128, 0))
                                for chess_name in self.chess_name.keys():
                                    for key, value in CHESS_INIT.items():
                                        if chess_name in key:
                                            self.window.blit(self.chess_name[chess_name], value)
                            else:
                                self.window.blit(self.bg[0], (128, 0))
                                for chess_name in self.chess_name.keys():
                                    for key, value in CHESS_STATE.items():
                                        if chess_name in key:
                                            self.window.blit(self.chess_name[chess_name], value)
                                self.window.blit(self.b_box, self.old_click_coord)
                                self.window.blit(self.b_box, self.end_click_coord)
                            self.update()

    @staticmethod
    def update():
        pygame.display.update()

if __name__ == "__main__":
    game = Game()
    game.img_place()
    game.update()
    game.event()


from flask import request

def get_zipkin_headers():
    try:
        request.headers
    except RuntimeError:
        return {}

    headers_of_interest = (
        'x-b3-flags',
        'x-b3-parentspanid',
        'x-b3-sampled',
        'x-b3-spanid',
        'x-b3-traceid',
        'x-ot-span-context',
        'x-request-id',
    )

    zipkin_headers = {}
    for header in headers_of_interest:
        value = request.headers.get(header, None)
        if value is not None:
            zipkin_headers[header] = value

    return zipkin_headers

__all__ = ['get_zipkin_headers']


from enum import IntEnum
import nutFs.Type
import aes128
import Print
import Hex
from binascii import hexlify as hx, unhexlify as uhx
import hashlib
import os.path

class BaseFile:
	def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		self.offset = 0x0
		self.size = None
		self.f = None
		self.crypto = None
		self.cryptoKey = None
		self.cryptoType = nutFs.Type.Crypto.NONE
		self.cryptoCounter = None
		self.cryptoOffset = 0
		self.ctr_val = 0
		self.isPartition = False
		self._children = []
		self._path = None
		self._buffer = None
		self._relativePos = 0x0
		self._bufferOffset = 0x0
		self._bufferSize = 0x1000
		self._bufferAlign = 0x1000
		self._bufferDirty = False

		if path and mode != None:
			self.open(path, mode, cryptoType, cryptoKey, cryptoCounter)

		self.setupCrypto(cryptoType, cryptoKey, cryptoCounter)

	def __enter__(self):
		return self

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

	def __del__(self):
		self.close()

	def enableBufferedIO(self, size, align = 0):
		self._bufferSize = size
		self._bufferAlign = align
		self._bufferOffset = None
		self._relativePos = 0x0

	def partition(self, offset = 0x0, size = None, n = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, autoOpen = True):
		if not n:
			n = File()
		#Print.info('partition: ' + str(self) + ', ' + str(n))

		n.offset = offset

		if not size:
			size = self.size - n.offset - self.offset

		n.size = size
		n.f = self
		n.isPartition = True

		self._children.append(n)

		#Print.info('created partition for %s %x, size = %d' % (n.__class__.__name__, offset, size))
		if autoOpen == True:
			n.open(None, None, cryptoType, cryptoKey, cryptoCounter)

		return n

	def removeChild(self, child):
		a = []

		for i in self._children:
			if i != child:
				a.append(i)

		self._children = a

	def read(self, size = None, direct = False):
		if not size:
			size = self.size

		return self.f.read(size)

	def readInt8(self, byteorder='little', signed = False):
		return self.read(1)[0]

	def readInt16(self, byteorder='little', signed = False):
		return int.from_bytes(self.read(2), byteorder=byteorder, signed=signed)

	def readInt32(self, byteorder='little', signed = False):
		return int.from_bytes(self.read(4), byteorder=byteorder, signed=signed)

	def readInt48(self, byteorder='little', signed = False):
		return int.from_bytes(self.read(6), byteorder=byteorder, signed=signed)

	def readInt64(self, byteorder='little', signed = False):
		return int.from_bytes(self.read(8), byteorder=byteorder, signed=signed)

	def readInt128(self, byteorder='little', signed = False):
		return int.from_bytes(self.read(16), byteorder=byteorder, signed=signed)

	def readInt(self, size, byteorder='little', signed = False):
		return int.from_bytes(self.read(size), byteorder=byteorder, signed=signed)

	def write(self, value, size = None):
		if size != None:
			value = value + '\0x00' * (size - len(value))
		#Print.info('writing to ' + hex(self.f.tell()) + ' ' + self.f.__class__.__name__)
		#Hex.dump(value)
		return self.f.write(value)

	def writeInt8(self, value, byteorder='little', signed = False):
		return self.write(value.to_bytes(1, byteorder))

	def writeInt16(self, value, byteorder='little', signed = False):
		return self.write(value.to_bytes(2, byteorder))

	def writeInt32(self, value, byteorder='little', signed = False):
		return self.write(value.to_bytes(4, byteorder))

	def writeInt64(self, value, byteorder='little', signed = False):
		return self.write(value.to_bytes(8, byteorder))

	def writeInt128(self, value, byteorder='little', signed = False):
		return self.write(value.to_bytes(16, byteorder))

	def writeInt(self, value, size, byteorder='little', signed = False):
		return self.write(value.to_bytes(size, byteorder))

	def seek(self, offset, from_what = 0):
		if not self.isOpen():
			raise IOError('Trying to seek on closed file')

		if from_what == 0:
			# seek from begining
			self.f.seek(self.offset + offset)
			#if self.cryptoType == nutFs.Type.Crypto.CTR:
			#	self.crypto.set_ctr(self.setCounter(self.offset + self.tell()))
			return
		elif from_what == 1:
			# seek from current position
			self.f.seek(self.offset + offset)

			#if self.cryptoType == nutFs.Type.Crypto.CTR:
			#	self.crypto.set_ctr(self.setCounter(self.offset + self.tell()))
			return
		elif from_what == 2:
			# see from end
			if offset > 0:
				raise Exception('Invalid seek offset')

			self.f.seek(self.offset + offset + self.size)

			#if self.cryptoType == nutFs.Type.Crypto.CTR:
			#	self.crypto.set_ctr(self.setCounter(self.offset + self.tell()))
			return

		raise Exception('Invalid seek type')

	def rewind(self, offset = None):
		if offset:
			self.seek(-offset, 1)
		else:
			self.seek(0)

	def setupCrypto(self, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		if cryptoType != -1:
			self.cryptoType = cryptoType

		if cryptoKey != -1:
			self.cryptoKey = cryptoKey

		if cryptoCounter != -1:
			self.cryptoCounter = cryptoCounter

		if self.cryptoType == nutFs.Type.Crypto.CTR or self.cryptoType == nutFs.Type.Crypto.BKTR:
			if self.cryptoKey:
				self.crypto = aes128.AESCTR(self.cryptoKey, nonce = self.cryptoCounter.copy())
				self.cryptoType = nutFs.Type.Crypto.CTR

				self.enableBufferedIO(0x10, 0x10)

		elif self.cryptoType == nutFs.Type.Crypto.XTS:
			if self.cryptoKey:
				self.crypto = aes128.AESXTS(self.cryptoKey)
				self.cryptoType = nutFs.Type.Crypto.XTS

				if self.size < 1 or self.size > 0xFFFFFF:
					raise IOError('AESXTS Block too large or small')

				self.rewind()
				self.enableBufferedIO(self.size, 0x10)

		elif self.cryptoType == nutFs.Type.Crypto.BKTR:
			self.cryptoType = nutFs.Type.Crypto.BKTR
		elif self.cryptoType == nutFs.Type.Crypto.NCA0:
			self.cryptoType = nutFs.Type.Crypto.NCA0
		elif self.cryptoType == nutFs.Type.Crypto.NONE:
			self.cryptoType = nutFs.Type.Crypto.NONE

	def open(self, path, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		if path != None:
			if self.isOpen():
				self.close()

			if isinstance(path, str):
				self.f = open(path, mode)
				self._path = path

				self.f.seek(0,2)
				self.size = self.f.tell()
				self.f.seek(0,0)
			elif isinstance(path, BaseFile):
				self.f = path
				self.size = path.size
			else:
				raise IOError('Invalid file parameter')

		self.setupCrypto(cryptoType, cryptoKey, cryptoCounter)

	def close(self):
		if self.f:
			self.flush()
			for i in self._children:
				i.close()
			self._children = []

			if not isinstance(self.f, BaseFile):
				self.f.close()
			else:
				self.f.removeChild(self)
			self.f = None

	def flush(self):
		if self.f:
			self.f.flush()

	def tell(self):
		return self.f.tell() - self.offset

	def eof(self):
		return self.tell() >= self.size

	def isOpen(self):
		return self.f != None

	def setCounter(self, ofs):
		ctr = self.cryptoCounter.copy()
		ofs >>= 4
		for j in range(8):
			ctr[0x10-j-1] = ofs & 0xFF
			ofs >>= 8
		return bytes(ctr)

	def setBktrCounter(self, ctr_val, ofs):
		ctr = self.cryptoCounter.copy()
		ofs >>= 4
		for j in range(8):
			ctr[0x10-j-1] = ofs & 0xFF
			ofs >>= 8

		for j in range(4):
			ctr[0x8-j-1] = ctr_val & 0xFF
			ctr_val >>= 8

		return bytes(ctr)

	def printInfo(self, maxDepth = 3, indent = 0):
		tabs = '\t' * indent
		if self._path:
			Print.info('%sFile Path: %s' % (tabs, self._path))
		Print.info('%sFile Size: %s' % (tabs, self.size))

	def sha256(self):
		hash = hashlib.sha256()

		self.rewind()

		if self.size >= 10000:
			while True:
				buf = self.read(1 * 1024 * 1024, True)
				if not buf:
					break
				hash.update(buf)
		else:
			hash.update(self.read(None, True))

		return hash.hexdigest()

class BufferedFile(BaseFile):
	def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		super(BufferedFile, self).__init__(path, mode, cryptoType, cryptoKey, cryptoCounter)

	def read(self, size = None, direct = False):
		if not size:
			size = self.size

		if self._relativePos + size > self.size:
			size = self.size - self._relativePos

		if size < 1:
			return b''

		if self._bufferOffset == None or self._buffer == None or self._relativePos < self._bufferOffset or (self._relativePos + size)  > self._bufferOffset + len(self._buffer):
			self.flushBuffer()
			#self._bufferOffset = self._relativePos & ~(self._bufferAlign-1)
			self._bufferOffset = (int(self._relativePos / self._bufferAlign) * self._bufferAlign)

			pageReadSize = self._bufferSize

			while self._relativePos + size > self._bufferOffset + pageReadSize:
				pageReadSize += self._bufferSize

			if pageReadSize > self.size - self._bufferOffset:
				pageReadSize = self.size - self._bufferOffset

			#Print.info('disk read %s\t\t: relativePos = %x, bufferOffset = %x, align = %x, size = %x, pageReadSize = %x, bufferSize = %x' % (self.__class__.__name__, self._relativePos, self._bufferOffset, self._bufferAlign, size, pageReadSize, self._bufferSize))
			super(BufferedFile, self).seek(self._bufferOffset)
			self._buffer = super(BufferedFile, self).read(pageReadSize)
			self.pageRefreshed()
			if len(self._buffer) == 0:
				raise IOError('read returned empty ' + hex(self.offset))

		offset = self._relativePos - self._bufferOffset
		r = self._buffer[offset:offset+size]
		self._relativePos += size
		return r

	def write(self, value, size = None):
		#if not size:
		#	size = len(value)
		size = len(value)

		if self._bufferOffset == None or self._buffer == None or self._relativePos < self._bufferOffset or (self._relativePos + size)  > self._bufferOffset + len(self._buffer):
			self.flushBuffer()

			# read page into memory
			pos = self.tell()
			self.read(size)
			self.seek(pos)

		offset = self._relativePos - self._bufferOffset
		self._buffer = self._buffer[:offset] + (value) + self._buffer[offset+size:]
		self._relativePos += size
		self._bufferDirty = True

		return

	def flushBuffer(self):
		if self.f != None and self._buffer != None and self._bufferDirty == True:
			#Print.info('writing dirty page')
			#Hex.dump(self._buffer)
			super(BufferedFile, self).seek(self._bufferOffset)
			super(BufferedFile, self).write(self.getPageFlushBuffer(self._buffer))
			self._bufferDirty = False

	def getPageFlushBuffer(self, buffer):
		if self.crypto:
			if self.cryptoType == nutFs.Type.Crypto.CTR:
				self.crypto.seek(self.offset + self._bufferOffset)
			elif self.cryptoType == nutFs.Type.Crypto.BKTR:
				self.crypto.seek(self.offset + self._bufferOffset)

			return self.crypto.encrypt(buffer)
		return buffer

	def flush(self):
		if self.f:
			self.flushBuffer()
			super(BufferedFile, self).flush()

	def pageRefreshed(self):
		pass

	def tell(self):
		return self._relativePos

	def close(self):
		self.flushBuffer()
		if BufferedFile:
			super(BufferedFile, self).close()

	def seek(self, offset, from_what = 0):
		if not self.isOpen():
			raise IOError('Trying to seek on closed file')

		f = self.f

		if from_what == 0:
			# seek from begining
			self._relativePos = offset
			return

		elif from_what == 1:
			# seek from current position
			if self._buffer:
				self._relativePos += offset
				return

			r = f.seek(self.offset + offset)
			return r

		elif from_what == 2:
			# see from end
			if offset > 0:
				raise Exception('Invalid seek offset')
			self._relativePos = self.size + offset
			return

		raise Exception('Invalid seek type')

class File(BufferedFile):
	def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		super(File, self).__init__(path, mode, cryptoType, cryptoKey, cryptoCounter)

	def pageRefreshed(self):
		if self.crypto:
			if self.cryptoType == nutFs.Type.Crypto.CTR or self.cryptoType == nutFs.Type.Crypto.BKTR:
				#Print.info('reading ctr from ' + hex(self._bufferOffset))
				self.crypto.seek(self.offset + self._bufferOffset)
			else:
				pass
				#Print.info('reading from ' + hex(self._bufferOffset))
			self._buffer = self.crypto.decrypt(self._buffer)
		return self._buffer

class MemoryFile(File):
	def __init__(self, buffer, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1, offset = None):
		super(MemoryFile, self).__init__()
		self._bufferOffset = offset or self._bufferOffset
		self.buffer = buffer
		self.size = len(buffer)
		self.setupCrypto(cryptoType = cryptoType, cryptoKey = cryptoKey, cryptoCounter = cryptoCounter)

		if self.crypto:
			if self.cryptoType == nutFs.Type.Crypto.CTR or self.cryptoType == nutFs.Type.Crypto.BKTR:
				self.crypto.seek(offset)

			self.buffer = self.crypto.decrypt(self.buffer)

	def read(self, size = None, direct = False):
		if size == None:
			size = self.size - self._relativePos

		return self.buffer[self._relativePos:self._relativePos+size]

	def write(self, value, size = None):
		return

	def seek(self, offset, from_what = 0):
		if from_what == 0:
			self._relativePos = offset
			return
		elif from_what == 1:
			self._relativePos = self.offset + offset
			return
		elif from_what == 2:
			if offset > 0:
				raise Exception('Invalid seek offset')

			self._relativePos = (self.offset + offset + self.size)
			return

	def open(self, path, mode = 'rb', cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		return

class CryptoFile(BufferedFile):
	def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		super(CryptoFile, self).__init__(path, mode, cryptoType, cryptoKey, cryptoCounter)

	def pageRefreshed(self):
		self._buffer = self.crypto.decrypt(self._buffer)
		return self._buffer

	def read2(self, size = None, direct = False):
		return self.crypto.decrypt(super(CryptoFile, self).read(size))

class AesXtsFile(CryptoFile):
	def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		super(AesXtsFile, self).__init__(path, mode, cryptoType, cryptoKey, cryptoCounter)

class AesCtrFile(CryptoFile):
	def __init__(self, path = None, mode = None, cryptoType = -1, cryptoKey = -1, cryptoCounter = -1):
		super(AesCtrFile, self).__init__(path, mode, cryptoType, cryptoKey, cryptoCounter)


import sqlite3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox

conn = sqlite3.connect('store.db')
c = conn.cursor()

c.execute('''
    CREATE TABLE IF NOT EXISTS items (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        quantity INTEGER,
        cost REAL
    )
''')

conn.commit()

def add_item():
    name = name_entry.get().strip()
    quantity = int(quantity_entry.get())
    cost = float(cost_entry.get())

    c.execute("INSERT INTO items (name, quantity, cost) VALUES (?, ?, ?)", (name, quantity, cost))
    conn.commit()

    name_entry.delete(0, tk.END)
    quantity_entry.delete(0, tk.END)
    cost_entry.delete(0, tk.END)

# Function to update inventory
def show_inventory():
    # Fetch all items from the database
    inventory_treeview.delete(*inventory_treeview.get_children())
    inventory_treeview.insert("", "end", values=("", "", ""), tags=("header",))

    c.execute("SELECT * FROM items")
    items = c.fetchall()

    # Update the inventory treeview
    for item in items:
        name = item[1].title()
        inventory_treeview.insert("", "end", values=(name, item[2], item[3]), tags=("item",))

def update_item():
    name = name_entry.get().strip()
    quantity = int(quantity_entry.get())
    cost = float(cost_entry.get())

    # Check if the item exists in the database
    c.execute("SELECT * FROM items WHERE name=?", (name,))
    item = c.fetchone()

    if item:
        # Update the quantity and cost of the item in the database
        c.execute("UPDATE items SET quantity=?, cost=? WHERE name=?", (quantity, cost, name))
        conn.commit()
        # Clear the entry fields
        name_entry.delete(0, tk.END)
        quantity_entry.delete(0, tk.END)
        cost_entry.delete(0, tk.END)
        # Clear the inventory listbox
        inventory_treeview.delete(*inventory_treeview.get_children())
        show_inventory()
    else:
        # Display an error message if the item doesn't exist in the database
        error_message = "Item not found in the database."
        tk.messagebox.showerror("Error", error_message)

root = tk.Tk()
root.title("Grocery Store Management")
root.geometry("650x800")
font_style = ("Courier", 24)
root.option_add("*Font", font_style)

# Label and entry fields for item details
name_label = tk.Label(root, text="Item Name:")
name_label.pack()
name_entry = tk.Entry(root)
name_entry.pack()

quantity_label = tk.Label(root, text="Quantity:")
quantity_label.pack()
quantity_entry = tk.Entry(root)
quantity_entry.pack()

cost_label = tk.Label(root, text="Cost:")
cost_label.pack()
cost_entry = tk.Entry(root)
cost_entry.pack()

# Button to add item
add_button = tk.Button(root, text="Add Item", command=add_item)
add_button.pack()

update_button = tk.Button(root, text="Update Item", command=update_item)
update_button.pack()

# Label for inventory
inventory_label = tk.Label(root, text="Inventory:")
inventory_label.pack()

# Button to update inventory
update_button = tk.Button(root, text="Show Inventory", command=show_inventory)
update_button.pack()

# Listbox to display inventory
# inventory_listbox = tk.Listbox(root)
# inventory_listbox.pack()
# inventory_listbox.config(width=40, height=15)

inventory_treeview = ttk.Treeview(root, columns=("name", "quantity", "cost"))
inventory_treeview.heading("#0", text="")
inventory_treeview.heading("name", text="Name")
inventory_treeview.heading("quantity", text="Quantity")
inventory_treeview.heading("cost", text="Cost")

# Set the column widths
inventory_treeview.column("#0", width=0, stretch=tk.NO)
inventory_treeview.column("name", width=150, anchor=tk.W)
inventory_treeview.column("quantity", width=150, anchor=tk.CENTER)
inventory_treeview.column("cost", width=150, anchor=tk.E)

# # Apply tag configuration for header and items
inventory_treeview.tag_configure("header", font=('Courier', 20, 'bold'))
inventory_treeview.tag_configure("item", font=('Courier', 20))

# Create a Scrollbar widget
scrollbar = ttk.Scrollbar(root, orient="vertical", command=inventory_treeview.yview)
scrollbar.pack(side="right", fill="y")

# Create a scrollbar for the treeview
inventory_treeview.configure(yscrollcommand=scrollbar.set)
inventory_treeview.configure(height=20)  # Change the height as desired

# Grid layout for the treeview and scrollbar
inventory_treeview.pack()

root.mainloop()
# Close the database connection when the application is closed
conn.close()


def get_alignments():
    sentences = "/home/nikolaj/PycharmProjects/LitteralJapaneseTranslation/src/fast_align-master/sentences_dev.parallel"
    alignments = "/home/nikolaj/PycharmProjects/LitteralJapaneseTranslation/src/fast_align-master/sentences_dev.align"
    sentences_file = open(sentences,"r",encoding="utf-8")
    alignments_file = open(alignments,"r",encoding="utf-8")

    sentence_line = sentences_file.readline()
    alignment_line = alignments_file.readline()
    i = 1
    sentence_translations = {}
    while sentence_line:
        sentence_translation = {}
        jp_en = sentence_line.split(" ||| ")
        jp_tokens = jp_en[0].split(" ")
        en_tokens = jp_en[1][:-1].split(" ")

        align_split = alignment_line.split("|||")
        align_pairs = align_split[2].strip().split(" ")
        align_scores = align_split[4].strip().split(" ")

        align_pairs.sort(key=lambda p: japanese_index(p))

        print(jp_tokens)
        print(en_tokens)
        for pair in align_pairs:
            (i1,i2) = pair.split("-")
            (i1,i2) = (int(i1),int(i2))
            score = align_scores[i2]
            jp = jp_tokens[i1]
            en = en_tokens[i2]
            if sentence_translation.get(jp) is None:
                sentence_translation[jp] = en
            else:
                sentence_translation[jp] = sentence_translation[jp] + " " + en
            print(jp, "=", en + " ("+score+")", end=" | ")
        print("\n")

        sentence_translations[i] = sentence_translation
        i += 1
        sentence_line = sentences_file.readline()
        alignment_line = alignments_file.readline()

    return sentence_translations

def japanese_index(pair: str):
    pair = pair.split("-")
    return int(pair[0])


## flask related
from flask import Flask, jsonify, request
app = Flask('PrivaDroid', static_url_path = '/static')

## change directory for dev purpose
import os
os.chdir('ActivityBuddyBundle/privadroid')

## util
include_test_users = False
from util import filter_out_test_user_data, fill_in_users_that_dont_have_events

## joined users
from user_join_event_provider import get_user_ad_id_to_join_events, \
                                    get_all_real_users_join_events, \
                                    compile_joined_users_by_category_analytics

real_user_ad_id_to_join_events = get_all_real_users_join_events(get_user_ad_id_to_join_events(), include_test_users)
joined_user_analytics = compile_joined_users_by_category_analytics(real_user_ad_id_to_join_events)
@app.route('/joinedusersjson')
def joinedusersjson():
    return jsonify({
        'unique_join_events': real_user_ad_id_to_join_events,
        'join_user_analytics': joined_user_analytics
    })

## demographic
from demographic_event_provider import get_user_ad_id_to_demographic_events, \
                                        compile_demographic_by_category_analytics

user_ad_id_to_demographic_event = filter_out_test_user_data(real_user_ad_id_to_join_events,  get_user_ad_id_to_demographic_events())
demographic_analytics = compile_demographic_by_category_analytics(user_ad_id_to_demographic_event)
@app.route('/demographicjson')
def demographicjson():
    return jsonify({
        'demographic_surveys': user_ad_id_to_demographic_event,
        'demographic_analytics': demographic_analytics
    })

## app install and survey events
from app_install_event_and_survey_provider import get_doc_id_to_app_install_events, \
                                                get_app_install_events_by_user_ad_id, \
                                                get_doc_id_to_app_install_survey_events, \
                                                get_app_install_and_survey_analytics

app_install_events_by_user = filter_out_test_user_data(real_user_ad_id_to_join_events, get_app_install_events_by_user_ad_id())
app_install_analytics = get_app_install_and_survey_analytics(app_install_events_by_user, user_ad_id_to_demographic_event, real_user_ad_id_to_join_events)
@app.route('/appinstallsjson')
def appinstallsjson():
    return jsonify({
        'app_install_events_by_user': app_install_events_by_user,
        'app_install_analytics': app_install_analytics
    })

## app uninstall and survey events
from app_uninstall_event_and_survey_provider import get_doc_id_to_app_install_events,  \
                                                    get_app_uninstall_events_by_user_ad_id, \
                                                    get_doc_id_to_app_uninstall_survey_events, \
                                                    get_app_uninstall_and_survey_analytics

app_uninstall_events_by_user = filter_out_test_user_data(real_user_ad_id_to_join_events, get_app_uninstall_events_by_user_ad_id())
app_uninstall_analytics = get_app_uninstall_and_survey_analytics(app_uninstall_events_by_user, user_ad_id_to_demographic_event, real_user_ad_id_to_join_events)
@app.route('/appuninstallsjson')
def appuninstallsjson():
    return jsonify({
        'app_uninstall_events_by_user': app_uninstall_events_by_user,
        'app_uninstall_analytics': app_uninstall_analytics
    })

## permission and grant/deny survey events and proactive permission events
from permission_event_and_survey_provider import get_doc_id_to_permission_event, \
                                                get_permission_grant_deny_events_by_user, \
                                                get_permission_event_and_survey_analytics

permission_events_by_users = filter_out_test_user_data(real_user_ad_id_to_join_events, get_permission_grant_deny_events_by_user())
permission_events_analytics = get_permission_event_and_survey_analytics(permission_events_by_users, real_user_ad_id_to_join_events, user_ad_id_to_demographic_event)
@app.route('/permissioneventsjson')
def permissioneventsjson():
    return jsonify({
        'permission_events_by_users': permission_events_by_users,
        'permission_events_analytics': permission_events_analytics
    })

## exit survey events
from exit_survey_event_provider import get_user_id_to_exit_survey_event

exit_survey_event_by_user = filter_out_test_user_data(real_user_ad_id_to_join_events, get_user_id_to_exit_survey_event())
@app.route('/exitsurveysjson')
def exitsurveysjson():
    return jsonify({
        'exit_surveys_by_user': exit_survey_event_by_user
    })

## heartbeat events
from heartbeat_event_provider import get_user_ad_id_to_heartbeat_events

heartbeat_events_by_user = filter_out_test_user_data(real_user_ad_id_to_join_events, get_user_ad_id_to_heartbeat_events())
@app.route('/heartbeateventsjson')
def heartbeateventsjson():
    return jsonify({
        'heartbeat_events_by_users': heartbeat_events_by_user
    })

## proactive permission events
from proactive_permission_event_provider import get_all_proactive_permission_events

all_proactive_events_by_users = get_all_proactive_permission_events(None if include_test_users else set(real_user_ad_id_to_join_events.keys()))
@app.route('/proactiveeventsjson')
def proactiveeventsjson():
    return jsonify({
        'proactive_permission_events': all_proactive_events_by_users
    })

## revoke permission notification click events and corresponding permission grant events
from revoke_permission_notification_click_event_provider import get_revoke_permission_by_users

revoke_permission_notification_events_by_user = filter_out_test_user_data(real_user_ad_id_to_join_events, get_revoke_permission_by_users())
@app.route('/revokepermissionnotificationclickeventsjson')
def revokepermissionnotificationclickeventsjson():
    return jsonify({
        'revoke_permission_click_events':  revoke_permission_notification_events_by_user
    })

## local storage sync log events and all the offline sync events
from local_storage_sync_log_event_provider import get_local_storage_sync_log_events_by_user

user_ad_id_to_list_of_offline_sync_log_events = filter_out_test_user_data(real_user_ad_id_to_join_events , get_local_storage_sync_log_events_by_user())
@app.route('/localstoragesynclogeventsjson')
def localstoragesynclogeventsjson():
    return jsonify({
        'local_storage_sync_events': user_ad_id_to_list_of_offline_sync_log_events
    })

## daily active user
from daily_active_user_helper import get_daily_active_user_analytics

daily_active_user_analytics = get_daily_active_user_analytics(app_install_events_by_user, app_uninstall_events_by_user, user_ad_id_to_list_of_offline_sync_log_events, heartbeat_events_by_user, all_proactive_events_by_users, permission_events_by_users, real_user_ad_id_to_join_events, user_ad_id_to_demographic_event, real_user_ad_id_to_join_events)
@app.route('/dailyactiveuserjson')
def dailyactiveuserjson():
    return jsonify({
        'daily_active_users': daily_active_user_analytics
    })

## individual user
@app.route('/userjson')
def userjson():
    user_ad_id = request.args.get('id')
    return jsonify({
        'join_event': real_user_ad_id_to_join_events[user_ad_id],
        'demographic_event': user_ad_id_to_demographic_event[user_ad_id] if user_ad_id in user_ad_id_to_demographic_event.keys() else None,
        'app_install_events': app_install_events_by_user[user_ad_id] if user_ad_id in app_install_events_by_user.keys() else None,
        'app_uninstall_events': app_uninstall_events_by_user[user_ad_id] if user_ad_id in app_uninstall_events_by_user.keys() else None,
        'offline_sync_events': user_ad_id_to_list_of_offline_sync_log_events[user_ad_id] if user_ad_id in user_ad_id_to_list_of_offline_sync_log_events.keys() else None,
        'heartbeat_events': heartbeat_events_by_user[user_ad_id] if user_ad_id in heartbeat_events_by_user.keys() else None,
        'proactive_events': all_proactive_events_by_users[user_ad_id] if user_ad_id in all_proactive_events_by_users.keys() else None,
        'permission_events': permission_events_by_users[user_ad_id] if user_ad_id in permission_events_by_users.keys() else None,
        'daily_active': daily_active_user_analytics['user_active_date'][user_ad_id]
    })

## exit survey mturk
from mturk_exit_survey_provider import calculate_cronbachs_alpha
@app.route('/mturkexitsurveyjson')
def mturkexitsurveyjson():
    from exit_survey_analysis.GoogleFormCronbachsAlpha import GoogleFormCronbachsAlpha
    v1_50_batch = GoogleFormCronbachsAlpha('./exit_survey_analysis/PrivaDroid_Exit_Survey_MTurk_GForm_Responses_V1_50.csv', 1)
    return jsonify({
        'initial_50_with_7_point_scale': calculate_cronbachs_alpha('./exit_survey_analysis/PrivaDroid_Exit_Survey_MTurk_GForm_Responses_V1_50.csv', 1),
        'total_100_with_7_point_scale': calculate_cronbachs_alpha('./exit_survey_analysis/PrivaDroid_Exit_Survey_MTurk_GForm_Responses_V1_100.csv', 1),
        '100_with_5_point_scale': calculate_cronbachs_alpha('./exit_survey_analysis/PrivaDroid_Exit_Survey_MTurk_GForm_Responses_V2.csv', 2)
    })

## start server
if __name__ == '__main__':
    # app.run(host='127.0.0.1', port='5001')

    app.run(host='0.0.0.0', port='5001')


from stanza.server import CoreNLPClient
import pandas as pd
import neuralcoref
from pipeline_ie.config import Config
import time

class Coref:

    def __init__(self, nlp, coref_mode, data, coref_output=False):
        self.nlp = nlp
        self.coref_mode = coref_mode
        self.data = data
        self.coref_output = coref_output
        self.configuration = Config()

    def input_data(self):
        """
        Create a list of text from the column of given DataFrame.

        NOTE: Any processing if required to be done on sentences can be written here.

        :return:
            - list_text: list
                list of sentences
        """
        col_name = self.configuration.config.get('file_directory', 'input_column_name')
        list_text = self.data[col_name].astype(str).tolist()
        return list_text

    @staticmethod
    def coref_output_file(texts):
        """
        Write output after coreference resolution on given text to a csv file.
        :param texts: list
                list of texts.
        """
        df_coref_resolved = pd.DataFrame(texts, columns=['Coref_Resolved_Text'])
        df_coref_resolved.to_csv('Text_Coref.csv')

    @staticmethod
    def create_phrase(mention, ann):
        """
        Create a list of tokens for given mention
        :param mention: mention object
        :param ann: annotation object
        Annotation object contains all mentions and coref chains for given text
        :return:
            - phrase: list
            phrase is a list containing all tokens for the given mention
        """
        phrase = []
        for i in range(mention.beginIndex, mention.endIndex):
            phrase.append(ann.sentence[mention.sentenceIndex].token[i].word)
        return phrase

    def corenlp_coref_resolution(self, memory, timeout, properties):
        """
        Perform coreference resolution on given text using Stanford CoreNLP
        :param
            - memory: str
            - timeout: int
            - properties: dict
        :return:
            - texts: list,
                List of sentences resolved and unresolved by coreference resolution operation.
        """

        # Start CoreNLP Server with required properties
        with CoreNLPClient(pipeline='StanfordCoreNLP', timeout=timeout, memory=memory,
                           properties=properties) as client:
            texts = self.input_data()
            index = 0
            time.sleep(10)
            for text in texts:
                doc = self.nlp(text)
                modified_text = [sentence.string.strip() for sentence in doc.sents]
                # submit the request to the server
                ann = client.annotate(text)
                # In each chain, replace the anaphora with the correct representative
                for coref in ann.corefChain:
                    mts = [mention for mention in coref.mention]
                    representative = coref.representative
                    phrase_rep = self.create_phrase(mts[coref.representative], ann)
                    antecedent = ' '.join(word for word in phrase_rep)
                    check_rep = 0
                    for mention in coref.mention:
                        if check_rep == representative:
                            check_rep += 1
                            continue
                        phrase = self.create_phrase(mts[check_rep], ann)
                        anaphor = ' '.join(word for word in phrase)
                        anaphor = anaphor + ' '
                        antecedent = antecedent + ' '
                        modified_text[mention.sentenceIndex] = modified_text[mention.sentenceIndex].replace(anaphor,
                                                                                antecedent)
                        check_rep += 1
                modified_text = ' '.join(modified_text)
                texts[index] = modified_text
                index += 1
        if self.coref_output is True:
            self.coref_output_file(texts)
        return texts

    def neural_coref_resolution(self):
        """
        Perform coreference resolution operation on given text using neuralcoref.
        Supports domain specific coreference resolution as per the spacy model used.

        :return:
            - texts: list,
                List of sentences resolved and unsresolved by coreference resolution operation.
        """
        coref = neuralcoref.NeuralCoref(self.nlp.vocab)
        self.nlp.add_pipe(coref, name='neuralcoref')
        texts = self.input_data()
        for index, text in enumerate(texts):
            doc = self.nlp(text)
            texts[index] = doc._.coref_resolved
        if self.coref_output is True:
            self.coref_output_file(texts)
        return texts

    def coref_resolution(self):
        """
        Execute coreference resolution methodology as per the coref mode mentioned either explicitly or implicitly.
        :return:
            - texts: list.
        """
        if self.coref_mode == "corenlp":
            properties = self.configuration.corenlp_coref_props()
            params = self.configuration.corenlp_params()
            memory, timeout = params[0], params[1]
            texts = self.corenlp_coref_resolution(memory, timeout, properties)
        elif self.coref_mode == "neuralcoref":
            texts = self.neural_coref_resolution()
        return texts


import time
import cv2
import imutils
import platform
import numpy as np
from threading import Thread
from queue import Queue
from Detection import Detection
from Record import Record

class Camera:

    def __init__(self, video_id):
        if cv2.ocl.haveOpenCL() :
            cv2.ocl.setUseOpenCL(True)
        self.capture = None
        self.width = 640
        self.height = 360
        self.thread = None
        self.stat = False
        self.current_time = 1
        self.preview_time = 1
        self.sec = 0
        self.Q = Queue(maxsize=128)
        self.started = False
        self.detection = Detection(video_id)
        self.soundRecord = Record()
        self.fps = 20.0
        self.isRecord = False
        fourcc = cv2.VideoWriter_fourcc(*'MJPG')
        self.videoWriter = cv2.VideoWriter('test.avi', fourcc, 8, (self.width, 480))

    def run(self, src = 0):

        if platform.system() == 'Windows' :
            self.capture = cv2.VideoCapture(src , cv2.CAP_DSHOW)

        else :
            self.capture = cv2.VideoCapture(src)

        self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
        self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)
        self.started = True
        self.detection.startTime = time.time()
        self.soundRecord.run()
        self.threadStart()

    def threadStart(self):
        if self.thread is None:
            self.thread = Thread(target=self.update, args=())
            self.thread.daemon = False
            self.thread.start()
        self.started = True

    def stop(self):
        self.started = False
        self.stopRecording()
        # if self.capture is not None:
        #     self.stopRecording()
        #     self.clear()

    def stopRecording(self):
        self.soundRecord.bRecord = False
        self.soundRecord.stopRecording()

    def update(self):
        while self.started:
            self.current_time = time.time() - self.preview_time
            (grabbed, frame) = self.capture.read()
            if grabbed and (self.current_time > 1./ self.fps):
                self.preview_time = time.time()
                self.Q.put(frame)
                self.videoWriter.write(frame)
                self.detection.detection(frame)

    def clear(self):
        with self.Q.mutex:
            self.Q.queue.clear()

    def read(self):
        return self.Q.get()

    def blank(self):
        return np.ones(shape=[self.height, self.width, 3], dtype=np.uint8)

    def bytescode(self):

        if not self.capture.isOpened():
            frame = self.blank()
        else :
            frame = imutils.resize(self.read(), width=int(self.width) )
            self.visualize(frame)
            if self.stat:
                cv2.rectangle(frame, (0,0), (120,30), (0,0,0), -1)
                fps = 'FPS : ' + str(self.fps())
        return cv2.imencode('.jpg', frame )[1].tobytes()

    def visualize(self, frame):
        cv2.putText(frame, "face: " + str(self.detection.face), (30, 45), cv2.FONT_HERSHEY_DUPLEX, 0.7, (147, 58, 31), 1)
        cv2.putText(frame, "head: " + str(self.detection.head), (30, 75), cv2.FONT_HERSHEY_DUPLEX, 0.7, (147, 58, 31), 1)
        cv2.putText(frame, "shoulder: " + str(self.detection.shoulder), (250, 45), cv2.FONT_HERSHEY_DUPLEX, 0.7, (147, 58, 31), 1)
        cv2.putText(frame, "gaze: " + str(self.detection.gaze), (250, 75), cv2.FONT_HERSHEY_DUPLEX, 0.7, (147, 58, 31), 1)
        cv2.line(frame, (self.detection.x_left - 5, self.detection.y_left), (self.detection.x_left + 5, self.detection.y_left), self.detection.gazeColor)
        cv2.line(frame, (self.detection.x_left, self.detection.y_left - 5), (self.detection.x_left, self.detection.y_left + 5), self.detection.gazeColor)
        cv2.line(frame, (self.detection.x_right - 5, self.detection.y_right), (self.detection.x_right + 5, self.detection.y_right), self.detection.gazeColor)
        cv2.line(frame, (self.detection.x_right, self.detection.y_right - 5), (self.detection.x_right, self.detection.y_right + 5), self.detection.gazeColor)
        cv2.rectangle(frame, (self.detection.fX, self.detection.fY), (self.detection.fX + self.detection.fW, self.detection.fY + self.detection.fH), self.detection.faceColor, 2)
        if self.detection.postureClass.results is not None:
            self.detection.mp_drawing.draw_landmarks(frame, self.detection.postureClass.results.pose_landmarks, {(12, 14), (11, 12), (11, 12)},
                                    None,
                                    self.detection.mp_drawing.DrawingSpec(color=self.detection.shoulderColor, thickness=2, circle_radius=4),
                                    )

            self.detection.mp_drawing.draw_landmarks(frame, self.detection.postureClass.results.face_landmarks, self.detection.mp_holistic.FACEMESH_CONTOURS,
                                        None,
                                        self.detection.mp_drawing.DrawingSpec(color=self.detection.headColor, thickness=1, circle_radius=1)
                                    )

    def fps(self):

        self.current_time = time.time()
        self.sec = self.current_time - self.preview_time
        self.preview_time = self.current_time

        if self.sec > 0 :
            fps = round(1/(self.sec),1)

        else :
            fps = 1
        return fps

    def __del__(self) :
        print( '* streamer class exit')
        if self.thread != None :
            self.capture.release()
            self.videoWriter.release()
            self.thread.join()
            self.stopRecording()


from Environment import *

maxHydrogen = MyInt(5, "Max Hydrogen Threads")
maxOxygen = MyInt(5, "Max Oxygen Threads")

hydrogenSemaphore = MySemaphore(0, "Hydrogen waiting")
oxygenSemaphore = MySemaphore(0, "Oxygen waiting")

hydrogenPipet = MySemaphore(2, "Hydrogen Pipet")
oxygenPipet = MySemaphore(1, "Oxygen Pipet")

def Hydrogen():
    while True:
        hydrogenPipet.wait()

        hydrogenSemaphore.wait()
        oxygenSemaphore.signal()

        hydrogenPipet.signal()

def Oxygen():
    while True:
        oxygenPipet.wait()

        hydrogenSemaphore.signal()
        hydrogenSemaphore.signal()

        oxygenSemaphore.wait()

        oxygenPipet.signal()

def setup():
    for i in range(maxHydrogen.v):
      subscribe_thread(Hydrogen)
    for i in range(maxOxygen.v):
      subscribe_thread(Oxygen)


#    Copyright (C) 2020 OrangeShell Developers
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    See https://www.gnu.org/licenses/ for a copy of the GNU GPL License
#
# 	 The ORANGEShell Repo can be found here: https://87ferrets.ml/FTP/OrangeShell/

# ---- import dependencies -----
import os
import sys

# try and get version args
try:
	Version = sys.argv[2]
except: # cannot get ver args, probs the user executed the file directly.
	print('This command cannot be run directly! Please use the "update" command in the shell to launch the update manager.')
	sys.exit()

# UPDATE
print('Welcome to the OrangeOS Update Wizard!')
VERIFY_START = input('Do you want to update OrangeOS to the latest version? Your user files will not be affected, but you may need to set a password again! Y/N: ') #ask for verif
if VERIFY_START == "y" or VERIFY_START == "Y":  # if user said "y" or "Y"...
	print('Starting the update...') # start update.
else: # else...
	print('Abort.') # ABORT
	sys.exit()
try:
	import requests # try and import requests
except:
	print('OrangeOS.Main.UpdateManager.Error.MissingComponentError: Component "requests" is missing and is needed to run OrangeOS Update Manager') # cannot import requests
print('=> Checking for updates ...')
try:
	orangeosver = requests.get('https://87ferrets.ml/SystemFetchArchive/OrangeOS/LV_STRING.INFO') # get Latest Version String
	VERSTRING = orangeosver.text.strip()
	if VERSTRING == Version: # if versionstring from file is the same as the version argument passed, the system is up to date and no need to update
		print('There is no need for an update! Aborting...')
		sys.exit(0)
	else:
            print('An update is available. You are using OrangeShell v' + str(Version) + ' but an update to OrangeShell v' + str(VERSTRING) + ' is available.') # else an update is available.
except:
	print('OrangeOS.Main.UpdateManager.Error.RequestFailedError: The request to the remote server failed. Cannot continue update.') # could not contact server
	sys.exit()

ynS = input('Do you want to update? y/n: ')
if ynS == "y" or ynS == "Y":
    print('Starting the update!')
else:
    print('Abort!')
    sys.exit(0)

print('SKIPPING USER FILES!')
print('==> Making backup of System...')
os.chdir('..')
def copyDir(INPUT, OUTPUT):
	print('Copying entire source directory "'+str(INPUT)+'" to destination "'+str(OUTPUT)+'"')
	os.system('cp -r '+ str(INPUT) +' '+ str(OUTPUT))
System_Dir = os.getcwd() + '/System'
copyDir(System_Dir, System_Dir + '.BACKUP/')	# make entire backup of system
print('Verifying backup...')
if os.path.isdir(System_Dir + '.BACKUP/'): # verify backup exists
	print('Backup Exists!')
else:
	print('OrangeOS.Main.UpdateManager.Error.ProcessError: Backup failed. Cannot continue as it is too dangerous.') # else backup doesnt exist, exit!
	sys.exit()
print('=> Deleting old system directory...')
os.system('rm -rf '+ System_Dir + '/') # delete System directory
print('=> Getting new system package from server...') # get pkg from server
def download_url(url, save_path, chunk_size=128):
    r = requests.get(url, stream=True)
    with open(save_path, 'wb') as fd:
        for chunk in r.iter_content(chunk_size=chunk_size):
            fd.write(chunk)
try:
	download_url("https://87ferrets.ml/SystemFetchArchive/OrangeOS/System.zip","System.zip") # get system.zip from server
except:
	print('OrangeOS.Main.UpdateManager.Error.RequestFailedError: The request to the remote server failed. Cannot continue update.')# cannot get.
	print('A fail was detected! Restoring from backup...') # restore backup
	os.system('mv System.BACKUP System')
	if os.path.isdir(System_Dir):
		print('Restored! Exiting...')
		sys.exit() # restored
	else:
		print('Oh dear!! Something went wrong and the backup could not be restored! Please re-install OrangeOS. Your user files should be untouched but you may have to re-create a new account.')
		sys.exit() # FAILED TO RESTORE!
try:
	import zipfile # try and import zipfile
except:
	print('OrangeOS.Main.UpdateManager.Error.MissingComponentError: Component "zipfile" is missing and is needed to run OrangeOS Update Manager') # cannot import
	print('A fail was detected! Restoring from backup...') # restore
	os.system('mv System.BACKUP System')
	if os.path.isdir(System_Dir):
		print('Restored! Exiting...')
		sys.exit() # restore
	else:
		print('Oh dear!! Something went wrong and the backup could not be restored! Please re-install OrangeOS. Your user files should be untouched but you may have to re-create a new account.')
		sys.exit() # FAILED TO RESTORE!!
try:
	with zipfile.ZipFile("System.zip", 'r') as zip_ref:
		zip_ref.extractall(os.getcwd()) # try and unzip system file
except:
	print('OrangeOS.Main.UpdateManager.Error.FileExtractionError: Could not extract System.zip file!') # cannot
	print('A fail was detected! Restoring from backup...') # restore backup
	os.system('mv System.BACKUP System')
	if os.path.isdir(System_Dir):
		print('Restored! Exiting...')
		sys.exit() # restored
	else:
		print('Oh dear!! Something went wrong and the backup could not be restored! Please re-install OrangeOS. Your user files should be untouched but you may have to re-create a new account.')
		sys.exit() # cannot restore
print('The upgrade was completed. ') # complete
print('Removing backup...')
os.system('rm -rf '+ System_Dir + '.BACKUP/') # rm backup
print('Removing temporary archive...')
os.system('rm System.zip') # rm system.zip file
print(' ====> On the first boot the user setup will launch which will help you set up OrangeOS even further by creating User Accounts that were present in an older installation. <====')
print('All done!') # done!


import json
import numpy as np
import os
import tensorflow as tf
import time
from typing import Any, Tuple, Callable
from queue import Queue, Empty
from threading import Thread, RLock

from absl import logging, flags
from datetime import datetime
from tensorflow.python.profiler.internal import _pywrap_traceme
from tensorflow.python.training import basic_session_run_hooks
from tensorflow.python.training import session_run_hook
from tensorflow.python.training import training_util

from monolith.native_training.alert import alert_manager
from monolith.native_training.alert import alert_pb2
from monolith.native_training.metric import cli
from monolith.native_training import utils
from monolith.native_training.metric.kafka_utils import KProducer
from monolith.native_training.metric.exit_hook import exit_hook

FLAGS = flags.FLAGS

class ThroughputMetricHook(tf.estimator.SessionRunHook):
  """ Log accumulated steps and time elapsed per step. """

  def __init__(self,
               model_name,
               start_time_secs,
               cluster_type="stable",
               run_every_n_secs=30):

    self._model_name = model_name
    self._start_time_secs = start_time_secs
    self._cluster_type = cluster_type
    self._run_every_n_secs = run_every_n_secs
    self._is_first_step = True
    self._mcli = cli.get_cli(utils.get_metric_prefix())
    am = alert_manager.get_default_alert_manager()
    if am:
      proto = alert_pb2.AlertProto()
      proto.training_alert.prefix = utils.get_metric_prefix()
      am.add_rules(proto)

  def begin(self):
    self._global_step_tensor = tf.compat.v1.train.get_global_step()

  def before_run(self, run_context):
    if self._is_first_step is True:
      self._emit_step = run_context.session.run(self._global_step_tensor)
      self._emit_time = int(time.time())
      if self._start_time_secs is not None:
        tags = {
            "model_name": self._model_name,
            "cluster_type": self._cluster_type
        }
        run_start_elapsed_time = self._emit_time - self._start_time_secs
        logging.info("Run start took {}s.".format(run_start_elapsed_time))
        self._mcli.emit_timer("run_start_elapsed_time.all",
                              run_start_elapsed_time, tags)
      self._is_first_step = False
    return session_run_hook.SessionRunArgs({
        "global_step": self._global_step_tensor,
    })

  def after_run(self, run_context, run_values):
    end_time = int(time.time())
    elapsed_time = end_time - self._emit_time
    if elapsed_time >= self._run_every_n_secs:
      global_step = run_values.results["global_step"]
      step_inerval = global_step - self._emit_step
      tags = {
          "model_name": self._model_name,
          "cluster_type": self._cluster_type
      }
      self._mcli.emit_counter("run_steps.all", step_inerval, tags)
      self._mcli.emit_timer("run_steps_elapsed_time.all",
                            elapsed_time / step_inerval, tags)
      self._emit_step = global_step
      self._emit_time = end_time

class StepLossMetricHook(tf.estimator.SessionRunHook):
  """ Log loss of each step. """

  def __init__(self, loss_tensor):
    self._loss_tensor = loss_tensor
    self._mcli = cli.get_cli(utils.get_metric_prefix())

  def before_run(self, run_context):
    return tf.estimator.SessionRunArgs(self._loss_tensor)

  def after_run(self, run_context, run_value):
    self._mcli.emit_store("step_loss", run_value.results)

class CustomMetricHook(tf.estimator.SessionRunHook):
  """ Log group of customed metircs for a batch. """

  def __init__(self, metric_tensors):
    for name in metric_tensors:
      tensor = metric_tensors[name]
      if len(tensor.shape.dims) > 0:
        raise ValueError("The metric tensor should be a scalar!")
      if tensor.dtype.base_dtype not in (tf.float32, tf.int32):
        raise ValueError(
            "The dtype of a metric tensor should be either tf.float or tf.int32!"
        )
    if len(metric_tensors) == 0:
      raise ValueError("At least one metric tensor should be offered!")
    self._metric_tensors = metric_tensors
    self._mcli = cli.get_cli(utils.get_metric_prefix())

  def before_run(self, run_context):
    return tf.estimator.SessionRunArgs(self._metric_tensors)

  def after_run(self, run_context, run_value):
    metric_values = run_value.results
    for name in metric_values:
      self._mcli.emit_store(name, float(metric_values[name]))

class Tf2ProfilerHook(tf.estimator.SessionRunHook):
  """ Using TF2 profiler in esitmator """

  def __init__(self,
               logdir: str,
               init_step_range: Tuple[int, int],
               save_steps: int = None,
               save_secs: int = None,
               options: tf.profiler.experimental.ProfilerOptions = None):
    """Only one of save_steps and save_secs should be provided."""
    self._logdir = logdir
    self._options = options
    self._start_step, self._end_step = init_step_range
    if self._start_step is not None and (self._end_step is None or self._end_step <= self._start_step):
      raise ValueError("End step invalid, start_step: {}, end_step: {}".format(self._start_step, self._end_step))
    self._default_delta = 10
    self._delta = self._end_step - self._start_step if self._end_step is not None else self._default_delta
    if save_steps is not None and save_steps <= self._delta:
      raise ValueError("Save steps must be greater than delta steps(default: {})".format(self._default_delta))
    self._timer = tf.estimator.SecondOrStepTimer(every_steps=save_steps,
                                                 every_secs=save_secs)
    self._current_step = 0
    self._trace_me = None

    self._profiling = False

  def begin(self):
    try:
      # if enable_sync_training, there is no tf.distribute.Server
      # we need start profiler server
      if FLAGS.enable_sync_training:
        tf.profiler.experimental.server.start(6666)
    except:
      logging.warning("cannot start profiler server at 6666")

  def before_run(self, run_context):
    # fix step-time graph, related issue: https://github.com/tensorflow/profiler/issues/282
    # TODO(huangruiteng): remove this after updating tensorflow
    if self._profiling:
      self._trace_me = _pywrap_traceme.TraceMe("TraceContext", graph_type="train", step_num=self._current_step)
    return tf.estimator.SessionRunArgs(fetches=None)

  def after_run(self, run_context, run_values: tf.estimator.SessionRunValues):
    self._current_step += 1
    if self._profiling:
      self._trace_me.Stop()
    if self._start_step is None:
      self._start_step = self._current_step + 500
      self._end_step = self._start_step + self._default_delta
    if self._current_step < self._start_step:
      return
    if self._current_step >= self._end_step:
      self._stop_profiling()
    if self._timer.should_trigger_for_step(self._current_step):
      self._start_profiling()
      self._timer.update_last_triggered_step(self._current_step)
      self._start_step = self._current_step
      self._end_step = self._start_step + self._delta

  def end(self, sess):
    if self._profiling:
      self._stop_profiling()

  def _start_profiling(self):
    try:
      tf.profiler.experimental.start(self._logdir, self._options)
      self._profiling = True
    except tf.errors.AlreadyExistsError:
      # Two cases:
      # 1. User profiles by themselves.
      # 2. When profiling by save_secs, it's still profiling after save_secs.
      # OK to ignore here.
      self._profiling = True

  def _stop_profiling(self):
    try:
      if self._profiling:
        self._profiling = False
        tf.profiler.experimental.stop()
    except tf.errors.UnavailableError:
      # Maybe user terminates profiling
      self._profiling = False

class ByteCCLTelemetryHook(tf.estimator.SessionRunHook):
  """Log telemetry information at regular intervals"""

  def __init__(self, interval: int):
    """Log telemetry information at regular intervals"""
    self._interval = interval
    self._last_step = 0
    logging.info(f"Created ByteCCL telemetry hook, interval={interval}")

  def begin(self):
    self._global_step_tensor = training_util._get_or_create_global_step_read()
    if self._global_step_tensor is None:
      raise RuntimeError(
          "Global step should be created to use ByteCCLTelemetryHook")

  def before_run(self, run_context):
    return tf.estimator.SessionRunArgs(self._global_step_tensor)

  def after_run(self, run_context, run_values: tf.estimator.SessionRunValues):
    current_step = run_values.results
    if current_step > self._last_step + self._interval:
      self._log_telemetry()
      self._last_step = current_step

  def end(self, sess):
    pass

  def _log_telemetry(self):
    import byteps.tensorflow as bps
    if bps.rank() == 0:
      telemetry = bps.get_telemetry()
      # sample a few operations and show them
      samples = []
      num_allreduce_ops = 0
      for name, mean, stdev, count in telemetry:
        name = str(name)
        is_alltoall = 'alltoall' in name.lower()
        if is_alltoall or ('PushPull' in name and num_allreduce_ops < 3):
          num_allreduce_ops += 1
          entry = f'name: {name} mean(ms): {mean:.2f} stdev(ms): {stdev:.2f} count: {count}'
          samples.append(entry)
      if samples:
        logging.info(f'Communication telemetry: {samples} ...')

class NVProfilerHook(Tf2ProfilerHook):

  def __init__(self,
               init_step_range: Tuple[int, int],
               save_steps: int = None,
               save_secs: int = None,
               options: tf.profiler.experimental.ProfilerOptions = None):
    super().__init__(None, init_step_range, save_steps, save_secs)
    import ctypes
    self._libcudart = ctypes.cdll.LoadLibrary("libcudart.so")  # linux

  def _start_profiling(self):
    # http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__PROFILER.html,
    self._libcudart.cudaProfilerStart()
    self._profiling = True

  def _stop_profiling(self):
    if self._profiling:
      self._profiling = False
      self._libcudart.cudaProfilerStop()

class KafkaMetricHook(tf.estimator.SessionRunHook):
  """ Log group of customed metircs for a batch. """
  __instance = None

  def __new__(cls, *args, **kwargs):
    if cls.__instance is None:
      cls.__instance = super().__new__(cls)
      cls.__instance._kproducer = None
      cls.__instance._init_kafka()

    return cls.__instance

  @classmethod
  def _init_kafka(cls):
    brokers = os.getenv('KAFKA_BROKER_LIST', None)
    topic = os.getenv('KAFKA_TOPIC_NAME', None)
    if brokers is None or topic is None:
      logging.info(
          'KafkaMetricHook init kafka failed, brokers: {}, topic: {}'.format(
              brokers, topic))
      return

    cls.__instance._kproducer = KProducer(brokers, topic)
    logging.info(
        'KafkaMetricHook init kafka success, brokers: {}, topic: {}'.format(
            brokers, topic))

  def __init__(self, deep_insight_op=None):
    if deep_insight_op is None:
      collection = tf.compat.v1.get_collection(key='deep_insight_op')
      if collection:
        if isinstance(collection, (list, tuple)):
          deep_insight_op = collection[0]
        else:
          deep_insight_op = collection
    self._metric_tensors = {'deep_insight_op': deep_insight_op}

  def before_run(self, run_context):
    return tf.estimator.SessionRunArgs(self._metric_tensors)

  def after_run(self, run_context, run_value):
    if self._kproducer:
      metric_values = run_value.results
      msgs = metric_values.get('deep_insight_op')
      if msgs is not None and len(msgs) > 0:
        self._kproducer.send(msgs)

  def end(self, session):
    if self._kproducer:
      self._kproducer.close()
      logging.info('KafkaMetricHook end, flush msg, success: {}, failed: {}'.\
        format(self._kproducer.success(), self._kproducer.failed()))
      self._kproducer = None

def default_parse_fn(obj: Any) -> Any:
  if obj is not None:
    if isinstance(obj, (str, bytes)):
      return json.loads(obj)
  return obj

def default_layout_fn(obj, indent=None) -> str:
  if isinstance(obj, str):
    return obj
  else:
    try:
      return json.dumps(obj, indent=indent)
    except:
      return repr(obj)

def vepfs_layout_fn(obj) -> str:
  req_time = obj.get('__REQ_TIME__') or obj.get('req_time')
  gid = obj.get('__FEED_ID__') or obj.get('feedid') or obj.get('gid') or 'gid'
  uid = obj.get('__UID__') or obj.get('userid') or obj.get('uid') or 'uid'
  predict_scores = json.dumps(obj['predict']) if 'predict' in obj else None
  labels = json.dumps(obj['label']) if 'label' in obj else None
  return f"{req_time};{gid};{uid};{predict_scores};{labels}"

def vepfs_key_fn(obj, worker_id: int, base_name: str) -> str:
  model_name = obj.get('model_name') or 'model_name'
  date = obj.get('__REQ_TIME__') or obj.get('req_time')
  return os.path.join(base_name, model_name, date, f'worker_{worker_id}')

class WriteOnlyFileAndStat(object):

  def __init__(self,
               key: str,
               layout_fn: Callable[[Any], str] = None,
               batch_size: int = 1024,
               partition_size: int = None,
               file_ext: str = 'txt'):
    self.current_partition: int = 0
    self.current_offset: int = 0
    self.last_update_time: float = time.time()
    self.buffer: List[Any] = []

    self.batch_size = batch_size
    self.partition_size = partition_size or int(1e6)
    self.layout_fn = layout_fn or default_layout_fn
    self.file_ext = file_ext

    assert key is not None
    self.key = key
    self.stream = None
    self._lock = RLock()

  def write(self, obj):
    if len(self.buffer) >= self.batch_size:
      self.flush()

    with self._lock:
      if obj is not None:
        self.buffer.append(self.layout_fn(obj))
        self.current_offset += 1
        self.last_update_time = time.time()

  def write_many(self, objs):
    if objs:
      for obj in objs:
        self.write(obj)

  def flush(self, check: bool = True):
    with self._lock:
      if self.stream is None:
        if not tf.io.gfile.exists(path=self.key):
          tf.io.gfile.makedirs(path=self.key)
        part_name = os.path.join(
            self.key, f'part_{self.current_partition:06d}.{self.file_ext}')
        self.stream = tf.io.gfile.GFile(part_name, 'w+')

      if self.stream is not None:
        if self.buffer:
          self.stream.write('\n'.join(self.buffer))
          self.stream.write('\n')
          self.buffer = []
        self.stream.flush()

      if check and self.current_offset >= self.partition_size:
        self.current_partition += 1
        self.current_offset = 0
        self.stream.close()
        part_name = os.path.join(
            self.key, f'part_{self.current_partition:06d}.{self.file_ext}')
        self.stream = tf.io.gfile.GFile(part_name, 'w+')

  def close(self):
    with self._lock:
      self.flush(check=False)
      if self.stream is not None:
        self.stream.close()
        self.stream = None

  def is_available(self):
    return (time.time() - self.last_update_time) < 24 * 60 * 60

class FileMetricHook(tf.estimator.SessionRunHook):
  """ Log group of customed metircs for a batch. """
  __instance = None

  def __new__(cls, *args, **kwargs):
    if cls.__instance is None:
      cls.__instance = super().__new__(cls)
    return cls.__instance

  def __init__(self,
               deep_insight_op=None,
               *,
               worker_id: int = None,
               parse_fn: Callable[[Any], Any] = None,
               key_fn: Callable[[Any, int, str], str] = None,
               layout_fn: Callable[[Any], str] = None,
               batch_size: int = 1024,
               partition_size: int = None,
               base_name: str = '/vepfs/jaguar_deepinsight_results',
               file_ext: str = 'txt'):
    if deep_insight_op is None:
      collection = tf.compat.v1.get_collection(key='deep_insight_op')
      if collection:
        if isinstance(collection, (list, tuple)):
          deep_insight_op = collection[0]
        else:
          deep_insight_op = collection
      else:
        deep_insight_op = None

    self._worker_id = worker_id
    self._key_fn = key_fn
    self._layout_fn = layout_fn or default_layout_fn
    self._parse_fn = parse_fn or default_parse_fn
    self._batch_size = batch_size
    self._partition_size = partition_size
    self._base_name = base_name
    self._file_ext = file_ext

    self._queue: Queue = Queue()
    self._files: Dict[str, WriteOnlyFileAndStat] = {}
    self._stopped = False
    self._metric_tensors = {'deep_insight_op': deep_insight_op}
    self._thread = None

  def before_run(self, run_context):
    return tf.estimator.SessionRunArgs(self._metric_tensors)

  def after_run(self, run_context, run_value):
    if self._thread is None:
      self._thread = Thread(target=self._send)
      self._thread.start()

    metric_values = run_value.results
    msgs = metric_values.get('deep_insight_op')
    if msgs is not None:
      if isinstance(msgs, (list, tuple, np.ndarray)):
        for msg in msgs:
          if msg:
            self._queue.put(msg)
      else:
        self._queue.put(msgs)

  def end(self, session):
    logging.info('end FileMetricHook: empty the queue ...')
    while not self._queue.empty():
      time.sleep(1)
    logging.info('end FileMetricHook: queue is empty, begin to stop thread ...')
    self._stopped = True
    if self._thread is not None:
      self._thread.join()
      self._thread = None
    logging.info(
        'end FileMetricHook: thread stopped, begin to close open file ...')
    for fs in self._files.values():
      fs.close()
    logging.info('end FileMetricHook: all done! ')

  def _send(self):
    last_check_time = time.time()
    while not self._stopped:
      try:
        item = self._queue.get(timeout=1)
        item = self._parse_fn(item)
      except Empty as e:
        continue

      key = self._key_fn(item, self._worker_id, self._base_name)
      if key not in self._files:
        file_and_stat = WriteOnlyFileAndStat(
            key,
            layout_fn=self._layout_fn,
            batch_size=self._batch_size,
            partition_size=self._partition_size,
            file_ext=self._file_ext)
        self._files[key] = file_and_stat
      else:
        file_and_stat = self._files[key]
      file_and_stat.write(item)

      if time.time() - last_check_time > 600:
        to_remove = set()
        for key, fs in self._files.items():
          if not fs.is_available():
            fs.close()
            to_remove.add(key)

        for key in to_remove:
          del self._files[key]
        last_check_time = time.time()


# Execute Javascript using selenium
import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get("https://yahoo.com")
driver.maximize_window()
time.sleep(1)
# Refresh the page
driver.execute_script("history.go(0)")
time.sleep(1)

# Get page title
title = driver.execute_script("return document.title")
print(title)

# click on element
element = driver.find_element(By.XPATH,"//span[text()='Mail']")
driver.execute_script("arguments[0].click()",element)
time.sleep(1)

# scroll down to bottom of page

driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")
time.sleep(1)

# Get inner text of web page
text = driver.execute_script("return document.documentElement.innerText")
print(text)

driver.get("https://amazon.in")
driver.maximize_window()

wait = WebDriverWait(driver,10)
wait.until(ec.visibility_of_element_located((By.XPATH,
                                    "//span[text()='Best Sellers in Books']")))

ele=driver.find_element(By.XPATH,"//span[text()='Best Sellers in Books']")

# scroll to a particular element
driver.execute_script("arguments[0].scrollIntoView(true)",ele)   # important

time.sleep(4)

# Generate alert message
driver.get("https://google.com")
driver.execute_script("alert('Alert generated - selenium - python')")

time.sleep(2)
alert = driver.switch_to.alert
alert.accept()
time.sleep(2)

info = driver.execute_script("return navigator.userAgent")
print(info)

driver.close()


import torch

def qort(q, v):
    """
    Rotate vector(s) v about the rotation described by quaternion(s) q.
    Expects a tensor of shape (*, 4) for q and a tensor of shape (*, 3) for v,
    where * denotes any number of dimensions.
    Returns a tensor of shape (*, 3).
    """
    assert q.shape[-1] == 4
    assert v.shape[-1] == 3
    assert q.shape[:-1] == v.shape[:-1]

    qvec = q[..., 1:]
    uv = torch.cross(qvec, v, dim=len(q.shape)-1)
    uuv = torch.cross(qvec, uv, dim=len(q.shape)-1)
    return v + 2 * (q[..., :1] * uv + uuv)

def qinverse(q, inplace=False):
    # We assume the quaternion to be normalized
    """
    The quaternions provided in the code are from the camera coordinate to the world coordinate.
    Therefore, the quaternions from the world coordinate to the camera coordinate is the transpose of quaternions from
    the camera coordinates to the world coordinate.The precondition is that the quaternion is a unit quaternion.
    So the inverse of the quaternions is equal to the transposition of the quaternions.
    """
    if inplace:
        q[..., 1:] *= -1
        return q
    else:
        w = q[..., :1]
        xyz = q[..., 1:]
        return torch.cat((w, -xyz), dim=len(q.shape)-1)


def read_input():
    cs = set()
    with open('input', 'r') as f:
        for line in f:
            l, r = line.strip().split('/')
            cs.add((int(l), int(r)))
    return cs

min_length = 1
strongest = -1

def find_strongest(components, required_pins=0,  strength=0, length=0):
    global min_length, strongest
    if length > min_length:
        strongest = strength
        min_length = length
    if strength > strongest and length == min_length:
        strongest = strength
    for c in components:
        if c[0] == required_pins or c[1] == required_pins:
            pins = c[0] if c[1] == required_pins else c[1]
            find_strongest(components - {c}, pins, strength + c[0] + c[1], length + 1)

components = read_input()
find_strongest(components)
print(strongest)