import pygame
from pygame.image import load_extended
import ticks
import gui
import yaml
import math
import languages

_font_code: pygame.font.Font
_font_victory: pygame.font.Font

def init():
    global _font_code, _font_victory
    _font_code = pygame.font.Font("src/res/font/JetBrainsMono-Bold.ttf", 25)
    _font_victory = pygame.font.Font("src/res/font/JetBrainsMono-Bold.ttf", 60)

def draw_text(screen: pygame.Surface, rect: pygame.Rect, data: str, colour, font: pygame.font.Font):
    font_surface = font.render(data, True, colour)
    screen.blit(font_surface, rect)

def fill_rect(screen: pygame.Surface, rect: pygame.Rect, colour):
    c = pygame.Color(colour)
    s = pygame.Surface(rect.size)  # the size of your rect
    s.set_alpha(c.a)  # alpha level
    s.fill(c)  # this fills the entire surface
    screen.blit(s, rect.topleft)

class SlicedSprite:
    def __init__(self, image: pygame.Surface, corner_size: int = 32):
        self.image = image
        self.corner = corner_size
        self.size = image.get_size()

    def draw(self, screen: pygame.Surface, rect: pygame.Rect, sizes: tuple, gap: int = 0):
        sizes = (max(sizes[0], 0), max(sizes[1], 1))
        # Top left
        screen.blit(
            self.image, rect,
            pygame.Rect(0, 0, self.corner, self.corner)
        )
        # Top
        top = pygame.transform.scale(
            self.image.subsurface(
                pygame.Rect(
                    self.corner, 0, self.size[0] - 2 * self.corner, self.corner
                )
            ).copy(),
            (sizes[0], self.corner)
        )
        screen.blit(top, (rect.x + self.corner, rect.y))
        # Top right
        screen.blit(
            self.image, (rect.x + sizes[0] + self.corner, rect.y),
            pygame.Rect(self.size[0] - self.corner, 0, self.corner, self.corner)
        )
        # Left
        left = pygame.transform.scale(
            self.image.subsurface(
                pygame.Rect(
                    0, self.corner, self.corner, self.size[1] - 2 * self.corner
                )
            ).copy(),
            (self.corner, sizes[1])
        )
        screen.blit(left, (rect.x, rect.y + self.corner))
        # Centre
        centre = pygame.transform.scale(
            self.image.subsurface(
                pygame.Rect(
                    self.corner, self.corner, self.size[0] - 2 * self.corner, self.size[1] - 2 * self.corner
                )
            ).copy(),
            (sizes[0], sizes[1] - gap)
        )
        screen.blit(centre, (rect.x + self.corner, rect.y + self.corner))
        # Right
        right = pygame.transform.scale(
            self.image.subsurface(
                pygame.Rect(
                    self.size[0] - self.corner, self.corner, self.corner, self.size[1] - 2 * self.corner
                )
            ).copy(),
            (self.corner, sizes[1] - gap)
        )
        screen.blit(right, (rect.x + sizes[0] + self.corner, rect.y + self.corner))
        # Bottom left
        screen.blit(
            self.image, (rect.x, rect.y + sizes[1] + self.corner),
            pygame.Rect(0, self.size[1] - self.corner, self.corner, self.corner)
        )
        # Bottom
        bottom = pygame.transform.scale(
            self.image.subsurface(
                pygame.Rect(
                    self.corner, self.size[1] - self.corner, self.size[0] - 2 * self.corner, self.corner
                )
            ).copy(),
            (sizes[0], self.corner)
        )
        screen.blit(bottom, (rect.x + self.corner, rect.y + sizes[1] + self.corner))
        # Bottom right
        screen.blit(
            self.image, (rect.x + sizes[0] + self.corner, rect.y + sizes[1] + self.corner),
            pygame.Rect(self.size[0] - self.corner, self.size[1] - self.corner, self.corner, self.corner)
        )

texture_atlas: pygame.Surface = load_extended("src/res/textures/atlas.png")
texture_res = 32
robot_atlas: pygame.Surface = load_extended("src/res/textures/robot.png")
coin_atlas: pygame.Surface = load_extended("src/res/textures/coin.png")
entity_res = 256
entity_ground = 192
click_threshold = 150
step_delay = 200
cursor_h = 16
win_rot_speed = 0.03
editor_scroll_speed = 40
render_zoom_speed = .2

# Each sprite uses a different dark colour against white bold text, and
# two adjacent sprites have very distinct colours. This was made with
# colour blindness in mind, to help create greater contrast between the
# code blocks.
code_block_textures: list = [
    SlicedSprite(load_extended("src/res/textures/blocks/block_red.png")),
    SlicedSprite(load_extended("src/res/textures/blocks/block_blue.png")),
    SlicedSprite(load_extended("src/res/textures/blocks/block_yellow.png")),
    SlicedSprite(load_extended("src/res/textures/blocks/block_green.png")),
    SlicedSprite(load_extended("src/res/textures/blocks/block_orange.png")),
    SlicedSprite(load_extended("src/res/textures/blocks/block_pink.png")),
]

class Level:
    def __init__(self, filename: str):
        text: str
        with open(filename, encoding='utf-8') as file:
            text = file.read()
        data = yaml.safe_load(text)
        # Available blocks
        self.blocks = data["blocks"]
        # Map data
        self.map = data["map"]
        # Map surface
        self.height = len(self.map)
        self.width = 0
        if self.height > 0:
            for row in self.map:
                if len(row) != len(self.map[0]):
                    raise ValueError("Invalid map, inconsistent row lengths.")
            self.width = len(self.map[0])
        self.level_map = pygame.Surface((self.width * texture_res, self.height * texture_res), pygame.SRCALPHA)

        player = data["player"]
        self.start_x = player["start-x"]
        self.start_y = player["start-y"]
        self.start_dir = player["start-dir"]

        stars = data["stars"]
        self.min_coins = stars["coins"]
        self.min_blocks = stars["blocks"]

        # Level number
        self.number = data["number"]

        for i in range(self.height):
            for j in range(self.width):
                tile = self.map[i][j]
                area = pygame.Rect(tile * texture_res, 0, texture_res, texture_res)
                dest = (j * texture_res, i * texture_res)
                self.level_map.blit(texture_atlas, dest, area)

    def get_block(self, x: int, y: int) -> int:
        if x < 0 or x >= self.width or y < 0 or y >= self.height:
            return 0
        return self.map[y][x]

class Game:
    def __init__(self):
        # Code
        self.code = None
        self.gen = None
        self.steps = 1
        self.code_start = 0
        # Blocks (source)
        self.blocks = []
        # UI interactions
        self.block_dragged = None
        self.block_offset = (0, 0)
        self.click_start = -1
        self.click_start_pos = None
        self.click_type = 0  # 1 = pan, 2 = drag block
        # 3D angles
        self.yaw = math.pi / 4
        self.pitch = math.pi / 6
        self.scroll = 1
        self.zoom = 1
        self.old_view = (0, 0)  # (yaw, pitch)
        # UI integrations
        self.elem = None  # Container for rendering game scene
        self.level = None  # Current level object
        self.enabled = False  # false = in title screen
        self.coins = []
        # Game
        self.robot_x = 0
        self.robot_y = 0
        self.robot_dir = 0
        # Levels
        self.state = 0
        self.coin_counter = 0
        # Level stats
        self.unlocked_level = 1
        self.levels = []

    def enable(self, document: gui.DocumentXML, level: Level, screen: pygame.Surface):
        self.elem = document.ids["game"]
        self.level = level
        self.enabled = True
        lvl_size = max(self.level.width, self.level.height) * texture_res

        self.zoom = min(self.elem.rect.w / 2, self.elem.rect.h / 2) / lvl_size
        self.scroll = 1
        self.yaw = math.pi / 4
        self.pitch = math.pi / 6

        self.code = Code(document)

        self.robot_x = level.start_x
        self.robot_y = level.start_y
        self.robot_dir = level.start_dir

        btnlist: gui.Element = document.ids["blocklist"]
        btnlist.children.clear()
        self.blocks = []

        self.coins = []
        for i, row in enumerate(self.level.map):
            for j, col in enumerate(row):
                if col == 4:
                    self.coins.append((j, i))

        for i, b in enumerate(level.blocks):
            block = defined_blocks[b]
            self.blocks.append(Blocklist(document, *block))
        document.calc_draw(screen.get_clip())
        for b in self.blocks:
            b.update()
        document.calc_draw(screen.get_clip())
        document.hover_element = document.trace_element(pygame.mouse.get_pos())

    def disable(self):
        self.elem = None
        self.level = None
        self.enabled = False
        self.state = 0
        self.gen = None
        self.blocks = []

    def handle_event(self, _: pygame.Surface, event: pygame.event.Event):
        if not self.enabled:
            return
        mpos = pygame.mouse.get_pos()

        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                self.click_start = ticks.get_time()
                self.click_start_pos = mpos
                if self.elem.rect.collidepoint(mpos):
                    self.click_type = 1  # drag/pan
                    self.old_view = (self.yaw, self.pitch)
                else:
                    for b in self.blocks:
                        b: Blocklist
                        if b.block.get_box().collidepoint(mpos):
                            self.click_type = 2
                            self.block_dragged = b.get_new_block(pygame.Rect(mpos[0], mpos[1], 0, 0))
                            self.block_offset = (mpos[0] - b.block.pos.x, mpos[1] - b.block.pos.y)
                            break
                    else:
                        ret = self.code.trace_block(mpos)
                        rect: pygame.Rect = self.code.elem.rect
                        if ret is not None:
                            self.click_type = 3
                            self.block_dragged = ret[1]
                            self.block_offset = (mpos[0] - ret[1].pos.x - rect.x, mpos[1] - ret[1].pos.y - rect.y)
                            self.code.remove_block(ret[0])
            elif event.button == 4:
                if self.elem.rect.collidepoint(mpos):
                    self.scroll = min(self.scroll + render_zoom_speed, 4)
                elif self.code.elem.rect.collidepoint(mpos):
                    self.code.scroll = min(self.code.scroll + editor_scroll_speed, 0)
            elif event.button == 5:
                if self.elem.rect.collidepoint(mpos):
                    self.scroll = max(self.scroll - render_zoom_speed, 0.5)
                elif self.code.elem.rect.collidepoint(mpos):
                    self.code.scroll -= editor_scroll_speed
        elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
            click_duration = ticks.get_time() - self.click_start
            if self.click_type == 2:
                if self.code.elem.rect.collidepoint(mpos):
                    self.code.place_block(self.block_dragged)
                elif click_duration < click_threshold:
                    self.code.place_block(self.block_dragged)
            elif self.click_type == 3:
                if self.code.elem.rect.collidepoint(mpos):
                    self.code.place_block(self.block_dragged)
            self.click_type = 0
            self.click_start = -1
        elif event.type == pygame.VIDEORESIZE:
            lvl_size = max(self.level.width, self.level.height) * texture_res
            self.zoom = min(self.elem.rect.w / 2, self.elem.rect.h / 2) / lvl_size

    def lose(self):
        self.gen = None
        self.state = 2

    def win(self):
        self.unlocked_level = max(self.unlocked_level, self.level.number + 1)
        self.gen = None
        self.state = 1

        level_stats = (
            True,
            self.code.get_block_count() <= self.level.min_blocks,
            self.coin_counter >= self.level.min_coins
        ).count(True)
        level_idx = self.level.number - 1
        if level_idx < len(self.levels):
            self.levels[level_idx] = max(level_stats, self.levels[level_idx])
        elif level_idx == len(self.levels):
            self.levels.append(level_stats)

    def update(self):
        if not self.enabled:
            return
        mpos = pygame.mouse.get_pos()
        now = ticks.get_time()
        for b in self.blocks:
            b.update()
        self.code.update()
        if self.gen is not None:
            if self.steps * step_delay < now - self.code_start:
                try:
                    move = next(self.gen)
                    self.move_bot(move)
                    self.steps += 1
                except StopIteration:
                    self.gen = None
        if self.state > 0:
            self.update_position(self.yaw + win_rot_speed)
        if self.click_start > -1:
            click_duration = ticks.get_time() - self.click_start
            if self.click_type == 1:
                n_yaw = (mpos[0] - self.click_start_pos[0]) / 100 + self.old_view[0]
                n_pitch = (mpos[1] - self.click_start_pos[1]) / 400 + self.old_view[1]
                self.update_position(n_yaw, n_pitch, None)
            elif self.click_type == 2:
                if click_duration >= click_threshold:
                    self.block_dragged: Codeblock
                    self.block_dragged.pos = pygame.Rect(
                        mpos[0] - self.block_offset[0],
                        mpos[1] - self.block_offset[1],
                        0, 0
                    )
                    self.block_dragged.update(None, self.block_dragged.pos.topleft)
                    if self.code.elem.rect.collidepoint(mpos):
                        self.code.cursor_closest(mpos)
            elif self.click_type == 3:
                self.block_dragged: Codeblock
                self.block_dragged.pos = pygame.Rect(
                    mpos[0] - self.block_offset[0],
                    mpos[1] - self.block_offset[1],
                    0, 0
                )
                self.block_dragged.update(None, self.block_dragged.pos.topleft)
                if self.code.elem.rect.collidepoint(mpos):
                    self.code.cursor_closest(mpos)

    def update_position(self, yaw=None, pitch=None, zoom=None):
        if yaw:
            self.yaw = yaw % (math.pi * 2)
        if pitch:
            self.pitch = min(max(pitch, math.pi / 12), math.pi / 4)
        if zoom:
            self.zoom = zoom

    def run_code(self):
        self.code_start = ticks.get_time()
        self.gen = self.code.exec()
        self.steps = 1

        self.robot_x = self.level.start_x
        self.robot_y = self.level.start_y
        self.robot_dir = self.level.start_dir

        self.state = 0
        self.coins = []
        self.coin_counter = 0
        for i, row in enumerate(self.level.map):
            for j, col in enumerate(row):
                if col == 4:
                    self.coins.append((j, i))

    def move_bot(self, move):
        old_pos = self.robot_x, self.robot_y
        if move == "forward":
            pos_offset = (
                (0, -1),
                (-1, 0),
                (0, 1),
                (1, 0),
            )[self.robot_dir]
            self.robot_x += pos_offset[0]
            self.robot_y += pos_offset[1]
        elif move == "left":
            self.robot_dir = (self.robot_dir + 1) % 4
        elif move == "right":
            self.robot_dir = (self.robot_dir - 1) % 4

        block = self.level.get_block(self.robot_x, self.robot_y)

        collected = None
        for c in self.coins:
            if (self.robot_x, self.robot_y) == c:
                collected = c
        if collected is not None:
            self.coins.remove(collected)
            self.coin_counter += 1

        if block == 0:
            self.robot_x, self.robot_y = old_pos
        elif block == 1:
            self.lose()
        elif block == 3:
            self.win()

    def draw(self, screen: pygame.Surface):
        if not self.enabled:
            return
        self.code.render(screen)
        self.render_scene(screen)
        dest = screen.subsurface(self.elem.rect)
        for b in self.blocks:
            b: Blocklist
            b.draw(screen)
        if self.click_start > -1:
            click_duration = ticks.get_time() - self.click_start
            if self.click_type == 2:
                if click_duration >= click_threshold:
                    self.block_dragged: Codeblock
                    self.block_dragged.draw(screen)
            elif self.click_type == 3:
                self.block_dragged: Codeblock
                self.block_dragged.draw(screen)
        if self.state == 1:
            text = languages.get_str("level.win")
            text_width = _font_victory.size(text)[0]
            pos = pygame.Rect((self.elem.rect.w - text_width) / 2, 10, 0, 0)
            draw_text(dest, pos, text, 0xFF00FFFF, _font_victory)
        elif self.state == 2:
            text = languages.get_str("level.lose")
            text_width = _font_victory.size(text)[0]
            pos = pygame.Rect((self.elem.rect.w - text_width) / 2, 10, 0, 0)
            draw_text(dest, pos, text, 0xFF00FFFF, _font_victory)

    def render_scene(self, screen: pygame.Surface):
        true_zoom = self.zoom * self.scroll
        dest = screen.subsurface(self.elem.rect)
        # Transform axis vectors
        x_axis = pygame.math.Vector2(texture_res * true_zoom, 0)
        y_axis = pygame.math.Vector2(0, texture_res * true_zoom)
        x_axis = x_axis.rotate(math.degrees(-self.yaw))
        y_axis = y_axis.rotate(math.degrees(-self.yaw))
        x_axis.y *= math.sin(self.pitch)
        y_axis.y *= math.sin(self.pitch)
        # Transform rendered map
        map_render = pygame.transform.rotozoom(self.level.level_map, math.degrees(self.yaw), true_zoom)
        map_render = pygame.transform.scale(
            map_render,
            (int(map_render.get_width()),
             int(map_render.get_height() * math.sin(self.pitch)))
        )
        # pos_x = self.elem.rect.x + (self.elem.rect.w / 2)
        # pos_y = self.elem.rect.y + (self.elem.rect.h / 2)
        pos_x = self.elem.rect.w / 2
        pos_y = self.elem.rect.h / 2
        # Scale robot sprite
        angle = ((self.yaw + self.robot_dir * math.pi / 2 + math.pi * 9 / 8) % (math.pi * 2)) * 8 / (math.pi * 2)
        bot_render = robot_atlas.subsurface(
            pygame.Rect(
                int(angle) * entity_res,
                0,
                entity_res,
                entity_res
            )
        ).copy()
        coin_state = int(ticks.get_time() / 250 - self.yaw * 4 / (math.pi * 2)) % 4
        # coin_state = int(ticks.get_time() / 250) % 4
        coin_render = coin_atlas.subsurface(
            pygame.Rect(
                coin_state * entity_res,
                0,
                entity_res,
                entity_res
            )
        ).copy()
        # Entities
        entities = []
        for c in self.coins:
            entities.append(
                (pygame.transform.rotozoom(coin_render, 0, true_zoom / (entity_res / 32)), *c)
            )
        entities.append((
            pygame.transform.rotozoom(bot_render, 0, true_zoom / (entity_res / 32)),
            self.robot_x,
            self.robot_y,
        ))
        to_render = []
        for e in entities:
            ent_pos_real = (e[1] - self.level.width / 2 + .5, e[2] - self.level.height / 2 + .5)
            ent_pos = x_axis * ent_pos_real[0] + y_axis * ent_pos_real[1] + pygame.math.Vector2(pos_x, pos_y)
            to_render.append((e[0], ent_pos.x, ent_pos.y))
        to_render.sort(key=lambda x: x[2])
        # Rendering
        dest.blit(map_render, (pos_x - map_render.get_width() / 2, pos_y - map_render.get_height() / 2))

        for e in to_render:
            # print(e)
            dest.blit(
                e[0],
                (
                    e[1] - (entity_res * true_zoom) / (entity_res / 16),
                    e[2] - (entity_ground * true_zoom) / (entity_res / 32)
                )
            )

# Source of blocks, from which they spawn and get dragged out of
class Blocklist:
    def __init__(self, document: gui.DocumentXML, block_name: str, colour: int = 0, container: bool = False, times=4):
        btnlist: gui.Element = document.ids["blocklist"]
        self.elem = gui.Space(document, "space", { "margin": "60px" })
        btnlist.add_child(self.elem)
        self.name = block_name
        self.colour = colour
        self.container = container
        self.times = times
        if container:
            self.sprite = code_block_textures[colour]
            self.block = CodeContainer(code_block_textures[colour], block_name, pygame.Rect(0, 0, 0, 0), times)
        else:
            self.sprite = code_block_textures[colour]
            self.block = Codeblock(code_block_textures[colour], block_name, pygame.Rect(0, 0, 0, 0))

    def get_new_block(self, rect: pygame.Rect):
        if self.container:
            return CodeContainer(self.sprite, self.name, rect, self.times)
        else:
            return Codeblock(self.sprite, self.name, rect)

    def update(self):
        self.block.pos = self.elem.rect
        self.block.pos = pygame.Rect(self.elem.rect.move(-48, -48))
        self.elem.length = f"{self.block.get_box().w}px"

    def draw(self, screen: pygame.Surface):
        self.block.draw(screen)

defined_blocks = {
    "left": ("left", 0, False),
    "forward": ("forward", 1, False),
    "right": ("right", 2, False),
    "repeat4": ("repeat4", 3, True, 4),
    "repeat8": ("repeat8", 4, True, 8),
}

class Codeblock:
    def __init__(self, sprite: SlicedSprite, name: str, pos: pygame.Rect):
        self.sprite = sprite
        self.name = name
        self.pos = pos

    def draw(self, screen: pygame.Surface):
        text = languages.get_str("level.blocks." + self.name)
        size = _font_code.size(text)
        size = (size[0] - 32, size[1] - 32)
        self.sprite.draw(screen, self.pos, size)
        draw_text(
            screen,
            pygame.Rect(self.pos.x + 16, self.pos.y + 16, 0, 0),
            text,
            0xFFFFFFFF,
            _font_code
        )

    def get_box(self, off: tuple = (0, 0)) -> pygame.Rect:
        size = _font_code.size(languages.get_str("level.blocks." + self.name))
        return pygame.Rect(
            self.pos.x + off[0],
            self.pos.y + off[1],
            size[0] + 32,
            size[1] + 32
        )

    def update(self, cursors, off: tuple):
        pass

class CodeContainer(Codeblock):
    def __init__(self, sprite: SlicedSprite, name: str, pos: pygame.Rect, times):
        super().__init__(sprite, name, pos)
        self.children = []
        self.height = 0
        self.times = times

    def draw(self, screen: pygame.Surface):
        for i, b in enumerate(self.children):
            b: Codeblock
            b.draw(screen)

        text = languages.get_str("level.blocks." + self.name)
        size = _font_code.size(text)
        size = (size[0] - 32, size[1] + self.height)
        self.sprite.draw(screen, self.pos, size, self.height)
        draw_text(
            screen,
            pygame.Rect(self.pos.x + 16, self.pos.y + 16, 0, 0),
            text,
            0xFFFFFFFF,
            _font_code
        )

    def get_block_count(self):
        count = 0
        for b in self.children:
            if type(b) is CodeContainer:
                b: CodeContainer
                count += b.get_block_count()
            count += 1
        return count

    def update(self, cursors, off: tuple):
        current_y = 0
        size = _font_code.size(languages.get_str("level.blocks." + self.name))
        off = (off[0] + 32, off[1] + 32 + size[1])
        for i, b in enumerate(self.children):
            b: Codeblock
            if cursors is not None and len(cursors) > 0 and cursors[0] == i:
                if len(cursors) == 1:
                    current_y += cursor_h
                n_off = (off[0], off[1] + current_y)
                b.update(cursors[1:], n_off)
            else:
                n_off = (off[0], off[1] + current_y)
                b.update(None, n_off)
            b.pos = pygame.Rect(n_off[0], n_off[1], 0, 0)
            current_y += b.get_box().h
        if cursors is not None and len(cursors) > 0 and cursors[0] == len(self.children):
            current_y += cursor_h
        self.height = current_y

    def draw_cursor(self, screen: pygame.Surface, cursors, off: tuple):
        current_y = 0
        size = _font_code.size(languages.get_str("level.blocks." + self.name))
        off = (off[0] + 32, off[1] + 32 + size[1])
        for i, b in enumerate(self.children):
            b: Codeblock
            if cursors is not None and len(cursors) > 0 and cursors[0] == i:
                if len(cursors) == 1:
                    fill_rect(screen, pygame.Rect(off[0], off[1] + current_y, 1000, cursor_h), 0xFFFFFF1F)
                    current_y += cursor_h
                n_off = (off[0], off[1] + current_y)
                if type(b) is CodeContainer:
                    b: CodeContainer
                    b.draw_cursor(screen, cursors[1:], n_off)
            current_y += b.get_box().h
        if cursors is not None and len(cursors) > 0 and cursors[0] == len(self.children):
            fill_rect(screen, pygame.Rect(off[0], off[1] + current_y, 1000, cursor_h), 0xFFFFFF1F)
            current_y += cursor_h

    def trace_block(self, pos: tuple, off: tuple):
        for i, b in enumerate(self.children):
            b: Codeblock
            if b.get_box(off).collidepoint(pos):
                if type(b) is CodeContainer:
                    b: CodeContainer
                    ret = b.trace_block(pos, off)
                    if ret is None:
                        return [i], b
                    else:
                        return [i, *ret[0]], ret[1]
                else:
                    return [i], b
        return None

    def cursor_closest(self, pos: tuple, off: pygame.Rect, stack: list):
        vpos = pygame.Vector2(pos)
        size = _font_code.size(languages.get_str("level.blocks." + self.name))
        closest = [*stack, 0]
        closest_dis = pygame.Vector2(
            self.pos.x + off.x,
            self.pos.y + 32 + size[1] + off.y
        ).distance_squared_to(vpos)
        for i, b in enumerate(self.children):
            b: Codeblock
            block_pos = (b.pos.x + off.x, b.pos.y + off.y)
            this_dis = pygame.Vector2(block_pos).distance_squared_to(vpos)
            if closest_dis is None or this_dis < closest_dis:
                closest = [*stack, i]
                closest_dis = this_dis
            if type(b) is CodeContainer:
                b: CodeContainer
                this_cur, this_dis = b.cursor_closest(pos, off, [*stack, i])
                if this_dis < closest_dis:
                    closest = this_cur
                    closest_dis = this_dis
        if len(self.children) > 0:
            last_b = self.children[-1]
            block_pos = (last_b.pos.x + off.x, last_b.pos.y + off.y + last_b.get_box().h)
            last_dis = pygame.Vector2(block_pos).distance_squared_to(vpos)
            if last_dis < closest_dis:
                closest = [*stack, len(self.children)]
                closest_dis = last_dis

        # self.set_cursor(closest)
        return closest, closest_dis

    def get_box(self, off: tuple = (0, 0)) -> pygame.Rect:
        size = _font_code.size(languages.get_str("level.blocks." + self.name))
        return pygame.Rect(
            self.pos.x + off[0],
            self.pos.y + off[1],
            size[0] + 32,
            size[1] + 64 + self.height
        )

    def exec(self):
        for b in self.children:
            b: Codeblock
            if type(b) is CodeContainer:
                b: CodeContainer
                for i in range(b.times):
                    yield from b.exec()
            else:
                yield b.name

class Code:
    def __init__(self, document: gui.DocumentXML):
        self.elem: gui.Element = document.ids["code"]
        self.scroll = 0
        self.blocks = []
        self.cursors = [0]  # For nested blocks

    def get_block_count(self):
        count = 0
        for b in self.blocks:
            if type(b) is CodeContainer:
                b: CodeContainer
                count += b.get_block_count()
            count += 1
        return count

    def place_block(self, block: Codeblock):
        context = self.blocks
        for c in self.cursors[:-1]:
            context = context[c].children
        context.insert(self.cursors[-1], block)
        self.cursors[-1] += 1

    def remove_block(self, index: list):
        context = self.blocks
        for c in index[:-1]:
            context = context[c].children
        if index[-1] < self.cursors[-1]:
            self.cursors[-1] -= 1
        context.pop(index[-1])

    def trace_block(self, pos: tuple):
        for i, b in enumerate(self.blocks):
            b: Codeblock
            rect: pygame.Rect = self.elem.rect
            if b.get_box(rect.topleft).collidepoint(pos):
                if type(b) is CodeContainer:
                    b: CodeContainer
                    ret = b.trace_block(pos, rect.topleft)
                    if ret is None:
                        return [i], b
                    else:
                        return [i, *ret[0]], ret[1]
                else:
                    return [i], b
        return None

    def cursor_closest(self, pos: tuple):
        vpos = pygame.Vector2(pos)
        closest = [0]
        closest_dis = None
        for i, b in enumerate(self.blocks):
            b: Codeblock
            block_pos = (b.pos.x + self.elem.rect.x, b.pos.y + self.elem.rect.y)
            this_dis = pygame.Vector2(block_pos).distance_squared_to(vpos)
            if closest_dis is None or this_dis < closest_dis:
                closest = [i]
                closest_dis = this_dis
            if type(b) is CodeContainer:
                b: CodeContainer
                this_cur, this_dis = b.cursor_closest(pos, self.elem.rect, [i])
                if this_dis < closest_dis:
                    closest = this_cur
                    closest_dis = this_dis
        if len(self.blocks) > 0:
            last_b = self.blocks[-1]
            block_pos = (last_b.pos.x + self.elem.rect.x, last_b.pos.y + self.elem.rect.y + last_b.get_box().h)
            last_dis = pygame.Vector2(block_pos).distance_squared_to(vpos)
            if last_dis < closest_dis:
                closest = [len(self.blocks)]
                closest_dis = last_dis

        self.set_cursor(closest)
        return closest, closest_dis

    def update(self):
        current_y = self.scroll
        for i, b in enumerate(self.blocks):
            b: Codeblock
            if i == self.cursors[0]:
                if len(self.cursors) == 1:
                    current_y += cursor_h
                b.update(self.cursors[1:], (0, current_y))
            else:
                b.update(None, (0, current_y))
            b.pos = pygame.Rect(0, current_y, 0, 0)
            current_y += b.get_box().h

    def draw_cursor(self, screen: pygame.Surface):
        current_y = self.scroll
        for i, b in enumerate(self.blocks):
            b: Codeblock
            if i == self.cursors[0]:
                if len(self.cursors) == 1:
                    fill_rect(screen, pygame.Rect(0, current_y, 1000, cursor_h), 0xFFFFFF1F)
                    current_y += cursor_h
                if type(b) is CodeContainer:
                    b: CodeContainer
                    b.draw_cursor(screen, self.cursors[1:], (0, current_y))
            current_y += b.get_box().h
        if self.cursors is not None and len(self.cursors) > 0 and self.cursors[0] == len(self.blocks):
            fill_rect(screen, pygame.Rect(0, current_y, 1000, cursor_h), 0xFFFFFF1F)
            current_y += cursor_h

    def set_cursor(self, path: list):
        self.cursors = path
        self.update()

    def render(self, screen: pygame.Surface):
        dest = screen.subsurface(self.elem.rect)
        for i, b in enumerate(self.blocks):
            b: Codeblock
            b.draw(dest)
        self.draw_cursor(dest)

    def exec(self):
        for b in self.blocks:
            b: Codeblock
            if type(b) is CodeContainer:
                b: CodeContainer
                for i in range(b.times):
                    yield from b.exec()
            else:
                yield b.name

    # def reset(self):
    #     pass
    #
    # def step(self):
    #     pass


import torch
import torch.nn as nn
import torch.optim
from tensorboardX import SummaryWriter
import os
import numpy as np
import glob
import shutil
import dataset
import unet
import copy
import torchvision

WATERSHED_ENDPOINTS = [0, 1, 2, 3, 4, 5, 6, 7, 10, 15, 25, 35, 55, 100, 200, 362]
# neural net will classify pixels as label i if its distance (rounded to the nearest integer) to a lens center is in the half-open interval [WATERSHED_ENDPOINTS[i], WATERSHED_ENDPOINTS[i+1])

NUM_WATERSHED_CLASSES = len(WATERSHED_ENDPOINTS) #= 16

# weighting based on relative sizes of level sets and some ad-hoc normalization/clipping/upweighting of center pixel (level = 0); definitely not optimized!
LOSS_WEIGHTS = np.array([40, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 12.96, 2.6244, 1.,1.]).astype(np.float32)

class Trainer():

	def __init__(self, args):
		self.args = copy.deepcopy(args)
		if args.watershed:
			model = unet.unet_model.UNet(1,NUM_WATERSHED_CLASSES)
			self.num_classes = NUM_WATERSHED_CLASSES
		else:
			model = torchvision.models.resnet34(num_classes=3)
			self.num_classes = 3
		self.model=model
		self.build_datasets()
		self.build_optimizer()

	def build_optimizer(self):
		model = self.model
		args = self.args
		parameters = model.parameters()
		if args.SGD:
			self.optimizer = torch.optim.SGD(parameters, args.learning_rate, momentum=args.momentum, weight_decay=args.weight_decay)
		else:
			self.optimizer = torch.optim.Adam(parameters, args.learning_rate, weight_decay=args.weight_decay)

	def build_datasets(self):
		args = self.args
		if args.watershed:
			self.train_loader, self.val_loader = dataset.get_dataloaders(args.batch_size, augment=True, skip_no_lenses_frames=False, watershed_endpoints=WATERSHED_ENDPOINTS)
		else:
			self.train_loader, self.val_loader = dataset.get_classifier_dataloaders(args.batch_size, augment=True)

	def train(self):
		args = self.args
		args.print_out()
		setup_save(self.model, args)
		self.model = self.model.cuda()
		self.model.train()
		self.writer = SummaryWriter(args.save_dir + '/tensorboard')
		self.writer.add_text('args', str(sorted(args.__dict__.items())))
		for i in range(1,args.epochs+1):
			self.train_epoch(i)
			self.validate_epoch(i)
			self.save_checkpoint(i)
			if args.debug: break

	def loss(self, image, output, label):
		args = self.args
		if args.watershed:
			loss_function = nn.CrossEntropyLoss(weight=torch.tensor(LOSS_WEIGHTS)).cuda()
			# output from (B,n,H,W) to (B,H,W,n)
			for i, j in [[1, 2], [2, 3]]:
				output = torch.transpose(output, i, j)
			loss = loss_function(output.contiguous().view(-1, self.num_classes), label.view(-1))
		else:
			loss_function = nn.CrossEntropyLoss().cuda()
			loss = loss_function(output.view(-1,self.num_classes), label.view(-1))
		return loss

	def train_epoch(self, epoch):
		args = self.args
		model, train_loader, optimizer,writer = self.model, self.train_loader, self.optimizer, self.writer
		model.train()
		train_len = len(train_loader)
		global_step = train_len * (epoch-1)
		adjust_learning_rate(self.optimizer, args, epoch)
		self.writer.add_scalar('learning_rate', self.optimizer.param_groups[0]['lr'], epoch)
		for i, (image, label) in enumerate(train_loader):
			global_step += 1
			image = image.cuda()
			label = label.cuda()
			output = model(image).cuda()
			loss = self.loss(image,output,label)
			optimizer.zero_grad()
			loss.backward()
			for p in model.parameters():
				if p.grad is not None:
					p.grad.data.clamp_(-args.grad_clip_by_value,args.grad_clip_by_value)
			optimizer.step()
			self.iteration_hook(global_step, loss, image, output, label)
			if args.debug: break

			if i == 0:
				for j in range(image.shape[0]):
					writer.add_image('input/train/%d'%i, viz_format(image[j:j+1]), global_step)
			if args.watershed:
				prediction_mask = torch.argmax(output, dim=1, keepdim=True).view(-1, 1, 256, 256)
				for j in range(image.shape[0]):
					writer.add_image('label/train/%d' % i, viz_format(label[j:j + 1]), global_step)
					writer.add_image('prediction/train/%d'%i, viz_format(prediction_mask[j:j+1]), global_step)

	def save_checkpoint(self, epoch):
		args = self.args
		model = self.model
		if args.save:
			if args.save_freq and epoch % args.save_freq == 0: # if args.save_freq > 0, save with that frequency
				torch.save(model.state_dict(), args.save_dir + '/epoch%s.pth' % str(epoch).zfill(3))
				print('Saving model at epoch %d' % epoch)
			elif epoch == args.epochs: # save at end of training
				torch.save(model.state_dict(), args.save_dir + '/epoch%s.pth' % str(epoch).zfill(3))
				print('Saving model at epoch %d' % epoch)

	def iteration_hook(self, global_step, loss, image, output, label):
		args = self.args
		if summary_checkpoint(global_step) or args.debug or True:
			self.writer.add_scalar('loss/training_loss', loss.data.item(), global_step)
			print('training_loss %.2f' % loss.data.item())

	def validate_epoch(self, epoch):
		args = self.args
		val_loader, model, writer = self.val_loader, self.model, self.writer
		losses = AverageMeter()

		# switch to evaluate mode
		model.eval()
		for i, (image, label) in enumerate(val_loader):
			label = label.cuda()
			image = image.cuda()
			output = model(image).cuda()

			loss = self.loss(image, output, label)
			losses.update(loss.data.item(), image.size(0))

			# images
			if epoch == 0 and i == 0:
				for j in range(image.shape[0]):
					writer.add_image('input/val/%d' % j, viz_format(image[j:j + 1]), epoch)

			if args.watershed and i == 0:
				prediction_mask = torch.argmax(output, dim=1, keepdim=True)
				for j in range(image.shape[0]):
					writer.add_image('label/val/%d' % j, viz_format(label[j:j + 1]), epoch)
					writer.add_image('prediction/val/%d' % j, viz_format(prediction_mask[j:j + 1]), epoch)
			if args.debug: break

		# scalars
		writer.add_scalar('loss/val_loss_avg', losses.avg, epoch)
		print('===== Epoch %d, val_loss_avg: %.2f' % (epoch, losses.avg))

		return losses.avg

def adjust_learning_rate(optimizer, args, epoch):
	"""Sets the learning rate to the initial LR decayed by 10 after args.lr_decay_step steps"""
	lr = args.learning_rate * (0.1 ** (epoch // args.lr_decay_step))
	for param_group in optimizer.param_groups:
		param_group['lr'] = lr

def summary_checkpoint(step):
	if step == 1 or step % 10 == 0: return True

class AverageMeter(object):
	"""Computes and stores the average and current value"""
	def __init__(self):
		self.reset()

	def reset(self):
		self.val = 0
		self.avg = 0
		self.sum = 0
		self.count = 0

	def update(self, val, n=1):
		self.val = val
		self.sum += val * n
		self.count += n
		self.avg = self.sum / self.count

def viz_format(img):
	assert len(img.shape) == 4, img.shape
	if img.shape[1] == 1:
		img = torch.tensor(img[0,0]*255/torch.max(img[0,0]),dtype=torch.uint8)
	elif img.shape[1] == 3:
		img = torch.tensor(img[0] * 255 / torch.max(img[0]), dtype=torch.uint8)
	return img

def get_save_dir(args):
	return os.getcwd() + '/%s/%s' % (args.exp_folder, args.exp_name)

def setup_save(model, args):
	save_dir = args.save_dir
	os.makedirs(save_dir)
	with open(save_dir + '/args.txt', 'w+') as f:
		f.write(str(vars(args)))
		f.write(str(model))
	os.makedirs(save_dir + '/code')
	scripts = glob.glob(os.getcwd() + '/*.py')
	for script in scripts:
		shutil.copy(script, save_dir + '/code/' + os.path.basename(script))  # save state of code, for reproducibility
	if args.save:
		torch.save(model.state_dict(), save_dir + '/epoch000.pth')


from django.shortcuts import render, redirect #Son los accesos directos y la redirección
from django.views import generic #importa listas genericas

from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse_lazy #Crea la URL cuando es necesario
from django.contrib.auth.decorators import login_required, permission_required #Recurre a la seguridadpara loguearse y los permisos que recibe elusuario
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin #Marca los errores de logueo
from django.http import HttpResponse #Para visualizar la pagina que es requerida en el momento
from datetime import datetime  #para la importación y manipulación de fecha y hora
from django.contrib import messages

from django.contrib.auth import authenticate #Importa para realizar la autenticación del usuario

from bases.views import SinPrivilegios #Los privilegios que recibe el usuario

from .models import Solicitud #de modelos se importa solicitud
from .forms import SolicitudForm #de formas se importa las formas de la solicitud

from reportlab.pdfgen import canvas #de reporte importa los metodos figuras, imagen, texto.
from reportlab.platypus import SimpleDocTemplate, Paragraph, TableStyle, Image #de reporte importa para la creación del documento, tabla de estilos y imagen
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle #de reporte se importa los estilos
from reportlab.lib import colors #de reportes se importan los colores
from reportlab.lib.pagesizes import letter, A4, inch, elevenSeventeen #de reporte se importa el tamaño de letra, su tipo
from reportlab.platypus import Table
from io import BytesIO #Los datos del archivo en bytes
from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY #de reporte se importa la posición del cuerpo dentro del documento
from becas import settings

class SolicitudView(generic.ListView): #visualizaicón de la solicitud
    model = Solicitud #El modelo
    template_name = "solicitudes/becas_list.html"  #Lo que se va a mostrar a la persona de las listas de solicitudes
    context_object_name = "bec"
    permission_required = "solicitud.view_solicitud" #Los permisos de la solicitud

def entregados(request): #La función nos muestra las entregadas
    en = Solicitud.objects.filter(entrega='ENTREGADO') #Nos mostrara si nuestra fue entregada
    return render(request, 'solicitudes/entregasi_list.html', {'en': en})
    #Retornara a las listas y la entrega aparecera en la lista

def no_entregados(request): #La función nos muestra las no entregadas
    en = Solicitud.objects.filter(entrega='NO ENTREGADO')
    return render(request, 'solicitudes/entregano_list.html', {'en': en})
    #Retornara a las listas y en esta caso no aparecera en listas

class SolicitudNew(SinPrivilegios, SuccessMessageMixin, generic.CreateView): #Dentro de esta clase es para realizar nuevas solicitudes
    model = Solicitud #Nuestro modelo solicitud
    template_name = "solicitudes/becas_form.html" #lo que visualizara el usuario en la web solicitud y las formas de becas
    form_class = SolicitudForm #Nuestra clase formas, solicitud de formas
    success_url = reverse_lazy("solicitudes:beca_list")
    permission_required = "solicitud.add_solicitud" #Los permisos para agregar esa solicitud
    context_object_name = 'obj'
    success_message = "Registro Agregado Satisfactoriamente" #La impresión de pantalla

    def form_valid(self, form): #La función valida la forma/solicitud
        form.instance.uc = self.request.user #Dependiendo la instancia te pedira ingresar un dato faltante.
        return super().form_valid(form) #retorna a la validación de la forma

class SolicitudEdit(generic.UpdateView): #Nuestra clase llamada solicitudeditar
    model = Solicitud
    template_name = "solicitudes/becas_form.html" #Visualizar solicitudes y becas
    context_object_name = 'obj'
    form_class = SolicitudForm #Manda llamar a las formas requeridas en la solicitud
    success_url = reverse_lazy("solicitudes:beca_list")
    success_message = "Solicitud Editada" #Muestra que fueron editados los datos
    permission_required = "solicitud.change_solicitud" #Ve si existen los permisos para esas modificaciónes

def delete(request, solicitud_id): #función eliminar
    # Recuperamos la instancia de la persona y la borramos
    instancia = Solicitud.objects.get(id=solicitud_id)
    instancia.delete()

    # Después redireccionamos de nuevo a la lista
    return redirect('/solicitudes/solicitud')

def reporte(request, pk):#Función para generar reportes

    response = HttpResponse(content_type='application/pdf') #Para que la pagina permita visualizar un pdf
    report = generarPDF(pk) #Reporte que se generara en pdf
    buff = BytesIO() #El tipo de dato de información donde se almacena
    doc = SimpleDocTemplate(buff,
                            pagesize=A4,
                            rightMargin=40,
                            leftMargin=40,
                            topMargin=30,
                            bottomMargin=18,
                            )  #Es el tamaño de su estructura en que se generara el pdf
    doc.build(report) #Construye el reporte
    response.write(buff.getvalue())
    buff.close() #Para cerra el pdf
    return response #nos regresa a la opción response.

def texto(texto, tamanio): #Función de texto para reporte
    styles = getSampleStyleSheet() #Estilo de letra y formato
    style = 'Heading{}'.format(tamanio) #tamaño del archivo y texto
    return Paragraph(texto, styles[style]) #retorna a el texto y estilos de texto

def generarPDF(pk): #Función generar pdf
    title1 = ParagraphStyle('parrafos',
                            alignment=TA_CENTER,
                            fontSize=20,
                            fontName="Times-Bold",
                            spaceAfter=30,
                            spaceBefore=0
                            ) #Mostrara el titulo dentro del pdf, su tamaño, tipo de letra, donde se situa

    body = ParagraphStyle('parrafos',
                          alignment=TA_JUSTIFY,
                          fontSize=12,
                          fontName="Courier",
                          leftIndent=36,
                          spaceAfter=20,
                          spaceBefore=20
                          ) #El cuerpo dentro del pdf, tamaño, tipo de letra y donde se situa
    # header_bold = ParagraphStyle('parrafos',
    # alignment=TA_CENTER,
    # fontSize=15,
    # fontName="Times-Bold",
    # spaceAfter=5,
    # spaceBefore=15
    # )

    info = [] #La iformación del usuario
    I = Image(settings.PATH_MEDIA+'ljr.jpg')
    I.drawHeight = 1.0*inch
    I.drawWidth = 1.0*inch
    I.hAlign = 'LEFT'

    info.append(I)

    e = Solicitud.objects.get(pk=pk)

    title_ = Paragraph("SOLICITUD DE BECA 2020 ", title1) #Todo esto va dentro del cuerpo del pdf o visualización del admin
    info.append(title_)
    info.append(Paragraph("NOMBRE: {}".format(e.nombre), body))
    info.append(Paragraph("APELLIDO PATERNO: {}".format(e.ap), body))
    info.append(Paragraph("APELLIDO MATERNO: {}".format(e.am), body))
    info.append(Paragraph("DOMICILIO: {}".format(e.domicilio), body))
    info.append(Paragraph("COLONIA: {}".format(e.colonia), body))
    info.append(Paragraph("TELEFONO: {}".format(e.telefono), body))
    info.append(Paragraph("FECHA DE NACIMIENTO: {}".format(e.fn), body))
    info.append(Paragraph("GRADO ACADEMICO: {}".format(e.ga), body))
    info.append(Paragraph("MATRICULA: {}".format(e.matricula), body))
    info.append(Paragraph("FORMACIÓN ARTISTICA: {}".format(
        e.formacion_artistica), body))
    info.append(Paragraph("MODALIDAD: {}".format(e.modalidad), body))
    info.append(Paragraph("GENERO: {}".format(e.genero), body))
    info.append(Paragraph("CORREO: {}".format(e.correo), body))
    return info #Retorna a info


# -*- coding: utf-8 -*-
class Romenia:
	'''Construtor da classe Romenia
	vizinhos: dicionario que contém os vizinhos da cidade
	custos: dicionario que contém as distâncias da cidade as suas vizinhas
	'''
	def __init__(self, vizinhos = {}, custos ={}):
		self.cidades = vizinhos
		self.custo = custos

	'''
	Insere os vizinhos e as distâncias da cidade atual
	key : cidade atual
	vizinhos: dicionario que contém os vizinhos da cidade(key do dict)
	custos: dicionario que contém as distâncias da cidade(key do dict) as suas vizinhas
	'''
	def insereCidades(self, key, vizinhos = [], custos = []):
		if self.cidades!=None:
			if key in self.cidades:
				if (all(vizinhos)):
					for i in range(0,len(vizinhos)):
						self.cidades[key].append(vizinhos[i])
						self.custo[key].append(custos[i])
				else:
					self.cidades[key].append(vizinhos)
					self.custo[key].append(custos)
			else:
				self.cidades[key] = vizinhos
				self.custo[key] = custos

	'''
	Retorna a posição do vizinho no dicionario se existir, caso não retorna False
	'''
	def indexPos(self, origem, vizinho):
		try:
			return self.cidades[origem].index(vizinho)
		except ValueError:
			return False

	'''
	Retorna a distancia de uma cidade a outra
	'''
	def pegaCusto(self, origem, vizinho):
		if origem in self.cidades:
			try:
				if self.cidades[origem].index(vizinho):
					a = self.indexPos(origem, vizinho)
					return self.custo[origem][a]
			except ValueError:
				return False
		return False

	def numVizinhos(self, origem):
		return len(self.cidades[origem])
	'''
	Retorna os vizinhos e as distâcias da cidade atual
	'''
	def pegaVizinhos(self, cidade):
		lista = []
		for i in range(0, len(self.cidades[cidade])):
			lista.append((self.cidades[cidade][i],self.custo[cidade][i]))
		return lista

	#Verifica se existe essa cidade na Romenia
	def verificaCidade(self, cidade):
		for keys in self.cidades:
			if keys == cidade:
				return True
		return False


# :의 왼쪽에는 해달 월의 며칠인지, 그리고 오른쪽에는 그 날의 매출이 적혀 있습니다.
#
# data 폴더의 chicken.txt 파일을 읽어 들이고, strip과 split을 써서 12월 코빠닭의 하루 평균 매출을 출력하세요. 평균을 구하기 위해서는 총 매출을 총 일수로 나누면 됩니다.
#
# 참고로 현재 제공된 파일에는 31일이 있지만, 어떤 달은 31일이 아닐 수도 있습니다. 이 점을 고려해서 확장성 있는 코드를 작성해 주시길 바랍니다.
#
# 출력 결과는 아래와 같습니다.

sell_sum = 0
days = 0

with open('data/chicken.txt','r',encoding='UTF8') as ch:
    for i in ch:
        days += 1
        data = i.split()
        sell_sum += int(data[1])

print(sell_sum/days)


from datetime import datetime

from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from .models import Profile

class CustomUserCreationForm(UserCreationForm):
    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")

    def clean(self):
        email = self.cleaned_data.get('email')
        if User.objects.filter(email=email).exists():
            raise ValidationError("User with that email already exists.")
        return self.cleaned_data

class ProfileForm(forms.ModelForm):
     class Meta:
        model = Profile
        fields = ['dob', 'image']
        forms.DateInput.input_type='date'
        widgets={
            'dob' : forms.DateInput(attrs={'class' : 'form-control', 'name' : 'dob', 'id' : 'dob', 'value' : '{{ user_id.dob }}'}),
            'image': forms.FileInput(attrs={'class' : 'form-control', 'name' : 'image', 'id' : 'image', 'label': 'Update your profile photo'}),
        }
        labels = {
        'dob': "Date of Birth",
        'image' : "Import Profile Image"
    }


from tkinter import *
import tkinter as tk

global p
p ='O'
global P
P = ["_","_","_","_","_","_","_","_","_"]

def przelicz(i,b,l):
    global p
    global P
    if P[i] == "_":
        l.config(text = 'teraz gracz: '+p)
        if p != 'O':
            p = 'O'
        else:
            p = 'X'
        P[i] = p
        print(str(i)+" "+p+" ")
        b.config(text = p)
    wygrana(l)

def wygrana(l):
    global P
    bo = False
    if P[0]==P[4] and P[0]==P[8]:
        bo = True
    elif P[2]==P[4] and P[2]==P[6]:
        bo = True
    elif P[0]==P[3] and P[0]==P[6]:
        bo = True
    elif P[1]==P[4] and P[1]==P[7]:
        bo = True
    elif P[2]==P[5] and P[2]==P[8]:
        bo = True
    elif P[0]==P[1] and P[0]==P[2]:
        bo = True
    elif P[3]==P[4] and P[3]==P[5]:
        bo = True
    elif P[6]==P[7] and P[6]==P[8]:
        bo = True
    if  bo == True :
        l.config(text = "wygrał gracz "+p)

if __name__ == '__main__':
    root = tk.Tk()
    root.title('kółko i krzyżyk')

    label= Label(root, text = "zaczyna gracz: O")
    label.pack(side = TOP, fill = 'both')

    frame1 = Frame(root)
    frame1.pack(fill = 'both', expand = 'true', )

    b1 = tk.Button(frame1, text = "_", command =  lambda: przelicz(0,b1,label), height = 6, width = 6)
    b1.grid(column = 1, row = 1)

    b2 = tk.Button(frame1, text = "_", command =  lambda: przelicz(1,b2,label), height = 6, width = 6)
    b2.grid(column = 2, row = 1)

    b3 = tk.Button(frame1, text = "_", command =  lambda: przelicz(2,b3,label), height = 6, width = 6)
    b3.grid(column = 3, row = 1)

    b4 = tk.Button(frame1, text = "_", command =  lambda: przelicz(3,b4,label), height = 6, width = 6)
    b4.grid(column = 1, row = 2)

    b5 = tk.Button(frame1, text = "_", command =  lambda: przelicz(4,b5,label), height = 6, width = 6)
    b5.grid(column = 2, row = 2)

    b6 = tk.Button(frame1, text = "_", command =  lambda: przelicz(5,b6,label), height = 6, width = 6)
    b6.grid(column = 3, row = 2)

    b7 = tk.Button(frame1, text = "_", command =  lambda: przelicz(6,b7,label), height = 6, width = 6)
    b7.grid(column = 1, row = 3)

    b8 = tk.Button(frame1, text = "_", command =  lambda: przelicz(7,b8,label), height = 6, width = 6)
    b8.grid(column = 2, row = 3)

    b9 = tk.Button(frame1, text = "_", command =  lambda: przelicz(8,b9,label), height = 6, width = 6)
    b9.grid(column = 3, row = 3)

    root.mainloop()


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

'''
date: 2016/07/12
role: 配置文件解析类 1.ini解析 2.nginx配置文件解析
usage: 1.all_optu = parseIni(conf_file,'Mysql')    all_opdi = all_optu.getOption() or all_opdi = all_optu.getOption("a","b","c") or all_opdi = all_optu.getOption("a")
2.ngx_conf = parseNgx(conf_file) all_block = ngx_conf.loadFile()
notice: 1.2016/07/12   添加获取指定所有的键值,如果只取一个键，则直接返回值
2. 2016/07/18 添加nginx配置文件解析类
'''
from __future__ import absolute_import
import sys,os

#sys.path.append('%s/operate'% os.path.dirname(os.getcwd()))
from yunwei.operate.prefix import log
logIns = log('131')

import ConfigParser

###nginx类文件操作类
class parseNgx:
    def __init__(self,log_path,path):
        ###log_path为日志写入文件
        logIns = log('131',log_path)
        ###配置文件路径
        self.path = path

    def loadFile(self):
        ###判断配置文件path是否存在
        if not os.path.isfile(self.path):
            logIns.writeLog('error','%s not exist'% self.path)
            raise IOError('131,conf file not exist %s'% self.path)

        ###读取配置文件
        conf = ''
        with open(self.path, 'r') as f:
            conf = f.read()

        ###定义初始变量
        self.config = conf
        self.length = len(self.config) - 1
        self.count  = 0

        ###返回列表的字典
        return self.parseBlock()

    def parseBlock(self):
        ###相关变量定义
        re_data  = []
        data_buf = ''
        param_name  = None
        param_value = None

        ###逐个字符遍历
        while self.count < self.length:
            if '\n' == self.config[self.count]:
                if data_buf and param_name:
                    if param_value is None:
                        param_value = []
                    param_value.append(data_buf.strip())
                    data_buf = ''
            elif ' ' == self.config[self.count] or '\t' == self.config[self.count]:
                if not param_name and len(data_buf.strip()) > 0:
                    param_name = data_buf.strip()
                    data_buf   = ''
                else:
                    data_buf += self.config[self.count]
            elif ';' == self.config[self.count]:
                if isinstance(param_value, list):
                    param_value.append(data_buf.strip())
                    re_data.append({'name': param_name, 'value': param_value, 'type': 'item'})
                else:
                    param_value = data_buf.strip()
                    re_data.append({'name': param_name, 'value': param_value.split(' '), 'type': 'item'})

                param_name  = None
                param_value = None
                data_buf = ''
            elif '{' == self.config[self.count]:
                self.count += 1
                ###递归
                data_block  = self.parseBlock()
                re_data.append({'name': param_name, 'param': data_buf.strip(), 'value': data_block, 'type': 'block'})
                param_name  = None
                param_value = None
                data_buf    = ''
            elif '}' == self.config[self.count]:
                self.count += 1
                return re_data
            elif '#' == self.config[self.count]:
                while self.count < self.length and '\n' != self.config[self.count]:
                    self.count += 1
            else:
                data_buf += self.config[self.count]
            self.count += 1

        ###返回结果
        return re_data

###重写ConfigParser类,取消全部转小写
class myrawconf(ConfigParser.RawConfigParser):
    def __init__(self,defaults=None):
        ConfigParser.RawConfigParser.__init__(self,defaults=None,allow_no_value=True)
    def optionxform(self, optionstr):
        return optionstr

###重写ConfigParser类,取消全部转小写
class myconf(ConfigParser.ConfigParser):
    def __init__(self,defaults=None):
        ConfigParser.ConfigParser.__init__(self,defaults=None)
    def optionxform(self, optionstr):
        return optionstr

###ini文件操作类
class parseIni:
    def __init__(self,log_path,path,section):
        ###log_path为日志写入文件
        logIns = log('131',log_path)

        self.path = path
        self.sect = section

    def getOption(self,*keys):
        ###判断配置文件path是否存在
        if not os.path.isfile(self.path):
            logIns.writeLog('error','%s not exist'% self.path)
            raise IOError('131,file not exist %s'% self.path)

        ###解析文件
        try:
            fh_conf = myrawconf()
            fh_conf.read(self.path)
        except:
            try:
                fh_conf = myconf()
                fh_conf.readfp(open(self.path))
            except:
                fh_conf = ConfigParser.ConfigParser()
                fh_conf.read(self.path)

        ###确认配置文件有无配置层
        list_section = fh_conf.sections()

        res_back = {}
        if self.sect in list_section:
            ###取出section下的所有配置项
            res_list = fh_conf.items(self.sect)

            ###转换成字典
            res_dict = dict(res_list)

            if keys:
                ###取出指定的键
                for k,v in res_dict.items():
                    if k in keys:
                        res_back[k] = v
            else:
                res_back = res_dict
        else:
            logIns.writeLog('error','%s not have %s'% (self.path,self.sect))
            raise ValueError('131,%s not have %s'% (self.path,self.sect))

        ###如果只取一个键，则返回值，其他返回字典
        if keys and len(keys) == 1:
            return res_back.get(keys[0],'')

        return res_back


import numpy as np

x1=np.array([[1,2,3],[0,6,4],[5,2,8]])
mu=x1.mean()
std=x1.std()
xs=(x1-mu)/std
o=np.hstack(x1)
v=list(o)
for i in range(len(v)):
  print(v[i])
  if(v[i]>1):
    v.remove(i)
  #i=0


from __future__ import (absolute_import, division,
                        print_function)

import numpy as np
from collections import OrderedDict
import copy
import os
import re

from atom.api import (Atom, Str, observe, Dict, List, Int, Bool)

from skbeam.fluorescence import XrfElement as Element
from skbeam.core.fitting.xrf_model import K_LINE, L_LINE, M_LINE
from skbeam.core.fitting.background import snip_method

from .fileio import save_fitdata_to_hdf

import multiprocessing

import logging
logger = logging.getLogger()

class ROIModel(Atom):
    """
    This class defines basic data structure for roi calculation.

    Attributes
    ----------
    prefix : str
        prefix name
    line_val : float
        emission energy of primary line
    left_val : float
        left boundary
    right_val : float
        right boundary
    default_left : float
    default_right : float
    step : float
        min step value to change
    show_plot : bool
        option to plot
    """
    prefix = Str()
    line_val = Int()
    left_val = Int()
    right_val = Int()
    default_left = Int()
    default_right = Int()
    step = Int(1)
    show_plot = Bool(False)

    @observe('left_val')
    def _value_update(self, change):
        if change['type'] == 'create':
            return
        logger.debug('left value is changed {}'.format(change))

    @observe('show_plot')
    def _plot_opt(self, change):
        if change['type'] == 'create':
            return
        logger.debug('show plot is changed {}'.format(change))

class SettingModel(Atom):
    """
    Control roi calculation according to given inputs.

    Parameters
    ----------
    parameters : Dict
        parameter values used for fitting
    data_dict : Dict
        dict of 3D data
    img_dict : Dict
        Reference to the respective field of the ``FileIOModel`` object
    element_for_roi : str
        inputs given by users
    element_list_roi : list
        list of elements after parsing
    roi_dict : dict
        dict of ROIModel object
    enable_roi_computation : Bool
        enables/disables GUI element that start ROI computation
        At least one element must be selected and all entry in the element
          list must be valid before ROI may be computed

    result_folder : Str
        directory which contains HDF5 file, in which results of processing are saved
    hdf_path : Str
        full path to the HDF5 file, in which results are saved
    hdf_name : Str
        name of the HDF file, in which results are saved

    data_title : str
        The title of the selected dataset (from ``fileio`` module)
    data_title_base : str
        The title changed for internal use (suffix is removed)
    data_title_adjusted : str
        The title changed for internal use (suffix 'sum' is removed if it exists)
    suffix_name_roi : str
        The suffix may have values 'sum', 'det1', 'det2' etc.
    """
    parameters = Dict()
    data_sets = Dict()
    img_dict = Dict()

    element_for_roi = Str()
    element_list_roi = List()
    roi_dict = OrderedDict()
    enable_roi_computation = Bool(False)

    subtract_background = Bool(False)

    result_folder = Str()

    hdf_path = Str()
    hdf_name = Str()

    data_title = Str()
    data_title_base = Str()
    data_title_adjusted = Str()
    suffix_name_roi = Str()

    def filename_update(self, change):
        """
        Observer function to be connected to the fileio model
        in the top-level gui.py startup

        Parameters
        ----------
        changed : dict
            This is the dictionary that gets passed to a function
            with the @observe decorator
        """
        self.hdf_name = change['value']
        # output to .h5 file
        self.hdf_path = os.path.join(self.result_folder, self.hdf_name)

    def result_folder_changed(self, change):
        """
        Observer function to be connected to the fileio model
        in the top-level gui.py startup

        Parameters
        ----------
        changed : dict
            This is the dictionary that gets passed to a function
            with the @observe decorator
        """
        self.result_folder = change['value']

    def data_title_update(self, change):
        """
        Observer function to be connected to the fileio model
        in the top-level gui.py startup

        Parameters
        ----------
        changed : dict
            This is the dictionary that gets passed to a function
            with the @observe decorator
        """
        self.data_title = change['value']

        # It is assumed, that ``self.data_title`` was created in the ``fileio`` module
        #   and has dataset label attached to the end of it.
        #   The labels are ``sum``, ``det1``, ``det2`` etc. depending on the number
        #   of detector channels.
        self.suffix_name_roi = self.data_title.split('_')[-1]

        self.data_title_base = '_'.join(self.data_title.split("_")[:-1])

        if self.suffix_name_roi == "sum":
            # If suffix is 'sum', then remove the suffix
            self.data_title_adjusted = self.data_title_base
        else:
            # Else keep the original title
            self.data_title_adjusted = self.data_title

    def __init__(self, *args, **kwargs):
        self.parameters = kwargs['default_parameters']
        # Initialize with an empty string (no elements selected)
        self.element_for_roi = ""
        self.enable_roi_computation = False

    @observe('element_for_roi')
    def _update_element(self, change):
        """
        Get element information as a string and parse it as a list.
        This element information means the ones for roi setup.
        """
        self.element_for_roi = self.element_for_roi.strip(' ')
        # Remove leading and trailing ','
        self.element_for_roi = self.element_for_roi.strip(',')
        # Remove leading and trailing '.'
        self.element_for_roi = self.element_for_roi.strip('.')
        try:
            if len(self.element_for_roi) == 0:
                logger.debug('No elements entered.')
                self.remove_all_roi()
                self.element_list_roi = []
                self.enable_roi_computation = False
                return
            elif ',' in self.element_for_roi:
                element_list = [v.strip(' ') for v in self.element_for_roi.split(',')]
            else:
                element_list = [v for v in self.element_for_roi.split(' ')]

            # with self.suppress_notifications():
            #     self.element_list_roi = element_list
            logger.debug('Current elements for ROI sum are: {}'.format(element_list))
            self.update_roi(element_list)
            self.element_list_roi = element_list
            self.enable_roi_computation = True
        except Exception as ex:
            logger.warning(f"Incorrect specification of element lines for ROI computation: {ex}")
            self.enable_roi_computation = False

    def data_sets_update(self, change):
        """
        Observer function to be connected to the fileio model
        in the top-level gui.py startup

        Parameters
        ----------
        changed : dict
            This is the dictionary that gets passed to a function
            with the @observe decorator
        """
        self.data_sets = change['value']

    def img_dict_update(self, change):
        """
        Observer function to be connected to the fileio model
        in the top-level gui.py startup

        Parameters
        ----------
        change : dict
            This is the dictionary that gets passed to a function
            with the @observe decorator
        """
        self.img_dict = change['value']

    def update_parameter(self, param):
        self.parameters = copy.deepcopy(param)

    def select_elements_from_list(self, element_list):
        self.element_for_roi = ', '.join(element_list)

    def use_all_elements(self):
        self.element_for_roi = ', '.join(K_LINE+L_LINE)  # +M_LINE)

    def clear_selected_elements(self):
        self.element_for_roi = ""

    def remove_all_roi(self):
        self.roi_dict.clear()

    def update_roi(self, element_list, std_ratio=4):
        """
        Update elements without touching old ones.

        Parameters
        ----------
        element_list : list
            list of elements for roi
        std_ratio : float, optional
            Define the range of roi for given element.

        Notes
        -----
        The unit of energy is in ev in this function. The reason is
        SpinBox in Enaml can only read integer as input. To be updated.
        """

        eline_list = K_LINE + L_LINE + M_LINE

        for v in element_list:
            if v in self.roi_dict:
                continue

            if v not in eline_list:
                raise ValueError(f"Emission line {v} is unknown")

            if '_K' in v:
                temp = v.split('_')[0]
                e = Element(temp)
                val = int(e.emission_line['ka1']*1000)
            elif '_L' in v:
                temp = v.split('_')[0]
                e = Element(temp)
                val = int(e.emission_line['la1']*1000)
            elif '_M' in v:
                temp = v.split('_')[0]
                e = Element(temp)
                val = int(e.emission_line['ma1']*1000)

            delta_v = int(self.get_sigma(val/1000)*1000)

            roi = ROIModel(prefix=self.suffix_name_roi,
                           line_val=val,
                           left_val=val-delta_v*std_ratio,
                           right_val=val+delta_v*std_ratio,
                           default_left=val-delta_v*std_ratio,
                           default_right=val+delta_v*std_ratio,
                           step=1,
                           show_plot=False)

            self.roi_dict.update({v: roi})

        # remove old items not included in element_list
        for k in self.roi_dict.copy().keys():
            if k not in element_list:
                del self.roi_dict[k]

    def get_sigma(self, energy, epsilon=2.96):
        """
        Calculate the std at given energy.
        """
        temp_val = 2 * np.sqrt(2 * np.log(2))
        return np.sqrt((self.parameters['fwhm_offset']['value']/temp_val)**2 +
                       energy*epsilon*self.parameters['fwhm_fanoprime']['value'])

    def get_roi_sum(self):
        """
        Save roi sum into a dict.

        Returns
        -------
        dict
            nested dict as output
        """
        roi_result = {}

        datav = self.data_sets[self.data_title]

        logger.info(f"Computing ROIs for dataset {self.data_title} ...")

        temp = {}
        data_raw = np.asarray(datav.raw_data)

        if self.subtract_background:
            # TODO: Implementation of background subtraction is not memory efficient
            #   and may cause problems when processing large scans. Eventually it
            #   needs to be rewritten, so that the data is processed in batches and
            #   no complete copy of raw data is created in memory. This does not affect
            #   computation of ROI without background subtraction (which is typical).

            logger.info(f"Subtracting background ...")

            num_processors_to_use = multiprocessing.cpu_count()
            logger.info(f"Cpu count: {num_processors_to_use}")
            pool = multiprocessing.Pool(num_processors_to_use)

            result_pool = [pool.apply_async(
                _subtract_background_one_line,
                (data_raw[n, :, :],
                 self.parameters['e_offset']['value'],
                 self.parameters['e_linear']['value'],
                 self.parameters['e_quadratic']['value'],
                 self.parameters['non_fitting_values']['background_width']))
                 for n in range(data_raw.shape[0])]

            data_roi = []
            for r in result_pool:
                data_roi.append(r.get())

            pool.terminate()
            pool.join()

            data_roi = np.array(data_roi)

            logger.info(f"Background subtraction completed.")

        else:
            data_roi = data_raw

        for k, v in self.roi_dict.items():
            leftv = v.left_val/1000
            rightv = v.right_val/1000
            sum2D = calculate_roi(data_roi,
                                  e_offset=self.parameters['e_offset']['value'],
                                  e_linear=self.parameters['e_linear']['value'],
                                  range_v=[leftv, rightv])
            sum2D = sum2D.astype(np.float64, copy=False)  # Convert to 64-bit representation
            temp.update({k: sum2D})
            logger.debug(f"Calculation is completed for {v.prefix}, {self.data_title}, {k}")

        # Save ROI data to HDF5 file
        self.saveROImap_to_hdf(temp)

        # Add scalers to the ROI dataset, so that they can be selected from Image Wizard.
        # We don't want to save scalers to the file, since they are already in the file.
        # So we add scalers after data is saved.
        scaler_key = f"{self.data_title_base}_scaler"
        if scaler_key in self.img_dict:
            temp.update(self.img_dict[scaler_key])

        roi_result[f"{self.data_title_adjusted}_roi"] = temp

        logger.info("ROI is computed.")
        return roi_result

    def saveROImap_to_hdf(self, data_dict_roi):

        # Generate the path to computed ROIs in the HDF5 file
        det_name = "detsum"  # Assume that ROIs are computed using the sum of channels

        # Search for channel name in the data title. Channels are named
        #   det1, det2, ... , i.e. 'det' followed by integer number.
        # The channel name is always located at the end of the ``data_title``.
        # If the channel name is found, then build the path using this name.
        srch = re.search("det\d+$", self.data_title)  # noqa: W605
        if srch:
            det_name = srch.group(0)
        inner_path = f"xrfmap/{det_name}"

        try:
            save_fitdata_to_hdf(self.hdf_path, data_dict_roi, datapath=inner_path,
                                data_saveas='xrf_roi', dataname_saveas='xrf_roi_name')
        except Exception as ex:
            logger.error(f"Failed to save ROI data to file '{self.hdf_path}'\n"
                         f"    Exception: {ex}")
        else:
            logger.info(f"ROI data was successfully saved to file '{self.hdf_name}'")

def calculate_roi(data3D, e_offset, e_linear, range_v):
    """
    Calculate 2D map for given ROI.

    Parameters
    ----------
    data3D : 3D array
    e_offset : float
        offset - coefficient for polynomial approximation of energy axis
    e_linear : float
        linear coefficient of polynomial approximation of energy axis
    e_quadratic : float
        quadratic coefficient of polynomial approximation of energy axis
    background_width : float
        parameter of snip algorithm for background estimation
    range_v : list
        range for ROI calculation for the element
    use_snip : bool
        True - subtract background before computing ROIs
        False - do not subtract background before computing ROIs

    Returns
    -------
    array
        2D map
    """
    data3D = np.asarray(data3D)
    range_v = np.asarray(range_v)
    range_v = (range_v - e_offset)/e_linear
    range_v = [int(round(v)) for v in range_v]
    # return np.sum(data3D[range_v[0]:range_v[1], :, :], axis=0)*e_linear
    return np.sum(data3D[:, :, range_v[0]:range_v[1]], axis=2)  # * e_linear

def _subtract_background_one_line(data_line, e_off, e_lin, e_quad, width):
    """
    Subtract background from spectra in a single line of the image

    Parameters
    ----------

    data_line : ndarray
        spectra for one line of an image, size NxM, N-the number of
        pixels in the line, M - the number of points in one spectrum (typically 4096)
    e_off : float
        offset - coefficient for polynomial approximation of energy axis
    e_lin : float
        linear coefficient of polynomial approximation of energy axis
    e_quad : float
        quadratic coefficient of polynomial approximation of energy axis
    background_width : float
        parameter of snip algorithm for background estimation

    Returns
    -------

    ndarray of the same shape as data_line. Contains spectra with subtracted background.
    """

    data_line = np.copy(data_line)
    xx, _ = data_line.shape
    for n in range(xx):
        bg = snip_method(data_line[n, :],
                         e_off=e_off,
                         e_lin=e_lin,
                         e_quad=e_quad,
                         width=width)
        data_line[n, :] -= bg
    return data_line


#!/usr/local/bin python3
# http://www.geeksforgeeks.org/dynamic-programming-set-8-matrix-chain-multiplication/

def matrix_chain_order(p, n):
    # m[i, j] = # of minimum multiplcations needed to compute
    # A[i]A[i+1]..A[j] where dimension of A[i] = p[i-1]p[i]

    m = [[float('inf') for _ in range(n)] for _ in range(n)]

    # when multiplying one matrix, cost = 0
    for i in range(1, n):
        m[i][i] = 0

    # 길이는 2부터 n-1까지
    for L in range(2, n):
        # 길이가 L일때 시작할수 있는 i 범위
        for i in range(1, n-L+1):
            j = i+L-1  # 시작 i, 길이 L일때 끝값 j
            # i, j 사이 k지점에 괄호가 있을 때
            for k in range(i, j): # q = cost/scalar multiplications
                q = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j]
                m[i][j] = min(q, m[i][j])

    return m[1][n-1]

arr = [1, 2, 3, 4]
size = len(arr)
print("# of minimum of multiplications is ", matrix_chain_order(arr, size))


import re
import fileinput

stack = 0
total = 0

ignore = re.compile(r'!.')
garbage = re.compile(r'<.*?>')

line = next(iter(fileinput.input())).strip()

print(line)
line = re.sub(ignore, "", line)
print(line)
garbages = re.findall(garbage, line)

print(sum(len(g) - 2 for g in garbages))


from scipy.io import loadmat
from scipy.signal import butter, lfilter

import numpy as np

import math

from pyriemann.estimation import Covariances, Coherences
from pyriemann.tangentspace import TangentSpace, FGDA

sample_rate = 512 #in Hz
num_channels = 12
path = './db/'

# load train data
def load_train_data(path_to_file):
    annots = loadmat(path_to_file)
    raw_eeg_data = annots['RawEEGData']
    labels = annots['Labels']

    return raw_eeg_data, labels

# load evaluate data
def load_eval_data(path_to_file):
    annots = loadmat(path_to_file)
    raw_eeg_data = annots['RawEEGData']

    return raw_eeg_data

def get_coh(X):
    coh = Coherences().transform(X)
    return coh[:,:,:,0]

def get_covar(X):
    covar = Covariances(estimator='lwf').transform(X)
    return covar

def get_riemann_ts(X):
    covar = Covariances(estimator='lwf').transform(X)
    tang = TangentSpace().fit_transform(covar)
    return tang

# Butterworth Bandpass Filter
# Source: https://scipy-cookbook.readthedocs.io/items/ButterworthBandpass.html
def butter_bandpass(lowcut, highcut, fs, order=5):
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a = butter(order, [low, high], btype='band')
    return b, a

def butter_bandpass_filter(signal, lowcut, highcut, fs, order=5):
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    n_trials, n_chans, n_time = signal.shape
    filtered = np.zeros(signal.shape)
    for i in range(n_trials):
        for j in range(n_chans):
            filtered[i][j] = lfilter(b, a, signal[i][j])
    return filtered

def get_data_within(patient_number, trim=(-1536,0), low=8, high=24, order=5):
    if patient_number<1 or patient_number>10:
        print('Invalid Patient Number')
        return None

    print('Mode = within')
    if patient_number<10:
        patient_str = '0'+str(patient_number)
    else:
        patient_str = str(patient_number)

    tlow, thigh = trim
    raw_data, labels = load_train_data(path+'parsed_P'+patient_str+'T.mat')
    if thigh==0:
        raw_data = raw_data[:,:,tlow:]
    else:
        raw_data = raw_data[:,:,tlow:thigh]
    labels = np.squeeze(labels)
    labels -= 1
    y = labels

    raw_eval = load_eval_data(path+'parsed_P'+patient_str+'E.mat')
    if thigh==0:
        raw_eval = raw_eval[:,:,tlow:]
    else:
        raw_eval = raw_eval[:,:,tlow:thigh]

    print('Loaded data for patient %d'%(patient_number))

    #filter data
    X = butter_bandpass_filter(raw_data, low, high, sample_rate, order=order)

    #filter evaluation data
    X_eval = butter_bandpass_filter(raw_eval, low, high, sample_rate, order=order)

    return X, y, X_eval

def get_data_inter(patient_number, trim=(-1536,0), low=8, high=24, order=5, mode="test"):
    if patient_number<1 or patient_number>10:
        print('Invalid Patient Number')
        return None

    tlow, thigh = trim
    print('Mode = inter')
    raw_train = np.array([])
    y_train = np.array([])
    for i in range(1,11):
        if i!=patient_number and i!=9 and i!=10:
            if i<10:
                patient_str = '0'+str(i)
            else:
                patient_str = str(i)
            raw_data_train, labels = load_train_data(path+'parsed_P'+patient_str+'T.mat')
            if thigh==0:
                raw_data_train = raw_data_train[:,:,tlow:]
            else:
                raw_data_train = raw_data_train[:,:,tlow:thigh]
            labels = np.squeeze(labels)
            labels -= 1
            print('Loaded data for patient %d'%(i))

            if raw_train.size==0:
                raw_train = raw_data_train
                y_train = labels
            else:
                raw_train = np.concatenate((raw_train, raw_data_train))
                y_train = np.concatenate((y_train, labels))

    if patient_number<10:
        patient_str = '0'+str(patient_number)
    else:
        patient_str = str(patient_number)

    if mode=="test":
        raw_test, labels = load_train_data(path+'parsed_P'+patient_str+'T.mat')
        if thigh==0:
            raw_test = raw_test[:,:,tlow:]
        else:
            raw_test = raw_test[:,:,tlow:thigh]
        labels = np.squeeze(labels)
        labels -= 1
        y_test = labels

    raw_eval = load_eval_data(path+'parsed_P'+patient_str+'E.mat')
    if thigh==0:
        raw_eval = raw_eval[:,:,tlow:]
    else:
        raw_eval = raw_eval[:,:,tlow:thigh]

    print('Loaded data for patient %d'%(patient_number))

    #filter training data
    X_train = butter_bandpass_filter(raw_train, low, high, sample_rate, order=order)

    if mode=="test":
        #filter testing data
        X_test = butter_bandpass_filter(raw_test, low, high, sample_rate, order=order)

    #filter evaluation data
    X_eval = butter_bandpass_filter(raw_eval, low, high, sample_rate, order=order)

    if mode=="test":
        return X_train, y_train, X_test, y_test, X_eval

    return X_train, y_train, X_eval

def mat_to_vect(mat):
    mat_size = mat.shape[0]
    vect_size = mat_size*mat_size
    vect = np.zeros(vect_size)
    idx=0
    for i in range(mat_size):
        for j in range(mat_size):
            vect[idx] = mat[i][j]
            idx+=1
    return vect

def symm_to_vect(mat):
    mat_size = mat.shape[0]
    vect_size = int((mat_size*(mat_size+1))/2)
    vect = np.zeros(vect_size)
    idx=0
    for i in range(mat_size):
        for j in range(i, mat_size):
            vect[idx] = mat[i][j]
            idx+=1
    return vect

def extract_covar_windows(series, win_size, hop_size):
    channels, num_samples = series.shape
    num_wins = int(math.ceil((num_samples-win_size)/hop_size))+1
    time_wins = np.zeros((num_wins, channels, win_size))
    covar_size = int((channels*(channels+1))/2)
    covar_wins = np.zeros((covar_size, num_wins))
    for i in range(num_wins):
        if i<num_wins-1:
            time_wins[i,:,:] = series[:,i*hop_size:i*hop_size+win_size]
        else:
            time_wins[i,:,:num_samples-i*hop_size] = series[:,i*hop_size:num_samples]
    covar = get_covar(time_wins)
    for i in range(num_wins):
        covar_wins[:,i] = symm_to_vect(covar[i])
    return covar_wins

def extract_riemann_windows(series, win_size, hop_size):
    channels, num_samples = series.shape
    num_wins = int(math.ceil((num_samples-win_size)/hop_size))+1
    time_wins = np.zeros((num_wins, channels, win_size))
    covar_size = int((channels*(channels+1))/2)
    for i in range(num_wins):
        if i<num_wins-1:
            time_wins[i,:,:] = series[:,i*hop_size:i*hop_size+win_size]
        else:
            time_wins[i,:,:num_samples-i*hop_size] = series[:,i*hop_size:num_samples]
    covar = np.transpose(get_riemann_ts(time_wins))
    return covar


# ______1__
#n = int(input())
#array = list(map(int, input().split(' ')))
# print(min(array), max(array))

#_______2__
# n = int(input())
# array = list(map(int, input().split(' ')))
# mx = array[0]
# mn = array[0]

# for i in range(len(array)):
#     if mx < array[i]:
#         mx = array[i]
#     if mn > array[i]:
#         mn = array[i]
# print(mn, mx)

#_______3__
n = int(input())
array = list(map(int, input().split(' ')))
maximum = array[0]
minimum = array[0]

for i in array:
    if maximum < i:
        maximum = i
    if minimum > i:
        minimum = i

print(minimum, maximum)


class Solution(object):
    wlist = [' ', '*', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
    def dfs(self, digits, cur, res, num):
        if num == len(digits):
            res.append(cur)
            return
        for i in range(len(self.wlist[ord(digits[num])-48])):
            self.dfs(digits, cur+self.wlist[ord(digits[num])-48][i], res, num+1)

    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        res = []
        if len(digits) > 0:
            self.dfs(digits, '', res, 0)
        return res


"""View module for handling requests about categories"""
from django.http import HttpResponseServerError
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from rest_framework import serializers, status
from solehubapi.models import Order, User

class OrderView(ViewSet):
    """Level up Order view"""

    def create(self, request):
        """Handle GET requests for single order

        Returns:
            Response -- JSON serialized order
        """

        custId = User.objects.get(pk=request.data["customer_id"])

        order = Order.objects.create(
            status=request.data["status"],
            customer_id=custId,
            payment_type=request.data["payment_type"]

        )
        serializer = OrderSerializer(order)
        return Response(serializer.data)

    def retrieve(self, request, pk):
      try:
        order = Order.objects.get(pk=pk)
        serializer = OrderSerializer(order)
        return Response(serializer.data)
      except order.DoesNotExist as ex:
            return Response({'message': ex.args[0]}, status=status.HTTP_404_NOT_FOUND)

    def update(self, request, pk):
        """Handle PUT requests for a order

        Returns:
            Response -- Empty body with 204 status code
        """

        order = Order.objects.get(pk=pk)
        order.status = request.data["status"]
        order.customer_id = User.objects.get(pk=request.data["customer_id"])
        order.payment_type = request.data["payment_type"]
        order.save()

        return Response(None, status=status.HTTP_204_NO_CONTENT)

    def list(self, request):
        """Handle GET requests to get all category

        Returns:
            Response -- JSON serialized list of category
        """
        order = Order.objects.all()

        customer_id = request.query_params.get('customer_id', None)
        status = request.query_params.get('status')

        if customer_id is not None:
            try:
                # customer_id query param is converted to an integer
                customer_id = int(customer_id)
            except ValueError:
                return Response({'message': 'Invalid customer_id'}, status=status.HTTP_400_BAD_REQUEST)

            #filter orders by customer_id
            order = order.filter(customer_id=customer_id)

        if status is not None:
            if status.lower() in ['true', 'false']:
                status = status.lower() == 'true'
                order = order.filter(status=status)
            else:
                return Response({'message': 'Invalid status value'}, status=status.HTTP_400_BAD_REQUEST)

        serializer = OrderSerializer(order, many=True)
        return Response(serializer.data)

    def destroy(self, request, pk):
        order = Order.objects.get(pk=pk)
        order.delete()
        return Response(None, status=status.HTTP_204_NO_CONTENT)

class OrderSerializer(serializers.ModelSerializer):
    """JSON serializer for categories
    """
    class Meta:
        model = Order
        fields = ('id', 'customer_id', 'status', 'payment_type')
        depth = 1


from .augment import NBSelectRays, PerturbZvals, RandomBGColor, SelectRays
from .compose import Compose, ToTensor
from .create import (BatchSample, DeleteUseless, ExampleSample, GetPts,
                     GetRays, GetViewdirs, GetZvals, HashBatchSample,
                     HashGetRays, HashSetImgids, KilonerfGetRays,
                     LoadImageAndCamera, NBGetRays, Sample)
from .transforms import FlattenRays, ToNDC

__all__ = [
    'Compose',
    'GetViewdirs',
    'GetZvals',
    'GetPts',
    'GetBounds',
    'GetRays',
    'Sample',
    'BatchSample',
    'DeleteUseless',
    'ToNDC',
    'ToTensor',
    'FlattenRays',
    'PerturbZvals',
    'SelectRays',
    'KilonerfGetRays',
    'HashGetRays',
    'HashSetImgids',
    'ExampleSample',
    'NBGetRays',
    'NBSelectRays',
    'RandomBGColor',
    'LoadImageAndCamera',
    'HashBatchSample',
]


def check(new, queen):
    #놓을 수 없는 위치에 있다면?
    #같은 행은 애초에 밑에서 걸러짐
    for i in range(new[0]): #지금까지 진행한 행 확인
        if new[1]==queen[i] or abs(new[0]-i)==abs(new[1]-queen[i]):
            return False
    return True

def solution(n, depth, queen):
    global result
    if depth==n:
        result+=1
        return
    for col in range(n):
        if not check((depth,col), queen):
            continue
        queen[depth]=col
        solution(n,depth+1, queen)

if __name__ =="__main__":
    n=int(input())
    queen = [-1 for _ in range(n)]
    result = 0
    solution(n,0, queen)
    print(result)
"""
문제
- N*N 체스판 위 N개의 퀸이 서로 공격할 수 없게 놓는 문제
문제 유형
- 백트레킹
자료구조
- 리스트 : 퀸의 위치 저장
사용한 아이디어
- 0행 0열 부터 N행 N열까지 차례대로 퀸을 놓는다
- 여기서 1차원 리스트의 인덱스는 행, 값은 열을 의미
- 만약 같은 행에 이미 퀸이 있다면 다음 행으로
- 만약 같은 행에 이미 퀸이 있다면 다음 열로
- 만약 대각선 상에 퀸이 있다면 열을 한개씩 더해준다
- 이렇게 진행하다 재귀의 깊이가 체스판과 동일 해지면 result+1
"""


# project : baekjoon python algorithm practice
# user : marble
# date : 20. 3. 7.
# time : 오후 8:29
# problem : https://www.acmicpc.net/problem/10798
# problem type : simple

max_len = -1
s = []
for i in range(5):
    s.append(input().strip())
    max_len = max(max_len, len(s[i]))

result = ''
for i in range(max_len):
    for j in range(5):
        if len(s[j]) <= i:
            continue
        result += s[j][i]

print(result)


from graphics import *
import math

def main():

        #with 600x300 mapping 25px = 1 Coords
        win = GraphWin('Circle intersection',600,300)
        win.setCoords(0,0,24,12)
        win.setBackground('White')

############## Depict Map  ##############

        #Chart background with X,Y center line
        chartBG = Rectangle(Point(1,11),Point(11,1))
        chartBG.setFill('grey')
        chartBG.draw(win)

        Line(Point(6,1),Point(6,11)).draw(win)
        Line(Point(1,6),Point(11,6)).draw(win)

        # indicator bar 12.5px (0.5 Coord each)
        for i in range(2,23):
            i = i/2
            Line(Point(0.75,i),Point(1.25,i)).draw(win)
            Line(Point(i,10.75),Point(i,11.25)).draw(win)

        # number bar
        z = q = 6

        for i in range(0,11):
            num = Text(Point(0.5,z),i)
            num.setSize(6)
            num.draw(win)

            num2 = Text(Point(z,11.5),i)
            num2.setSize(6)
            num2.draw(win)

            num3 = Text(Point(q,11.5),i*-1)
            num3.setSize(6)
            num3.draw(win)

            num3 = Text(Point(0.5,q),i*-1)
            num3.setSize(6)
            num3.draw(win)

            z = z+0.5
            q = q-0.5

############## Depict Interface ##############

        #introduction
        intro1 = Text(Point(17.40,10.75),'Program to calculate X value where')
        intro1.setStyle('bold')
        intro1.draw(win)

        intro2 = Text(Point(15.8,10),'Y intersection with circle.')
        intro2.setStyle('bold')
        intro2.draw(win)

        #Radius entry
        Text(Point(15.75,8.5),'Circle radius (value 1-10): ').draw(win)
        inputR = Entry(Point(14,7.5),10)
        inputR.setText('0')
        inputR.draw(win)

        #Y Line entry
        Text(Point(18,6),'Horizon line intersection (value 10 to -10): ').draw(win)
        inputY = Entry(Point(14,5),10)
        inputY.setText('0')
        inputY.draw(win)

        #X Result entry
        Text(Point(14.5,3.5),'X intersection at: ').draw(win)
        Text(Point(12.2,2.70),'+').draw(win)
        Text(Point(12.2,2.25),'-').draw(win)

        answerX = Entry(Point(14.5,2.5),10)
        answerX.setText('?')
        answerX.draw(win)

        #Fake button Entry
        Fbutton = Rectangle(Point(19,2),Point(23.5,0.5))
        Fbutton.setFill('green')
        Fbutton.draw(win)

        FbuttonT =  Text(Point(21.25,1.25),'Find Answer!')
        FbuttonT.draw(win)

############## Calculation ##############

        # pause for input
        win.getMouse()

        # get variable
        R = eval(inputR.getText())
        Y = eval(inputY.getText())

        # calculate and
        X = math.sqrt(R**2-Y**2)

        # force only 2 decimal
        X = round(X,2)

############## Output  ##############

        # print answer in entry box

        answerX.setText(X)

        # depict circle
        R = R/2     # because 1Coords = 1/2 unit in map
        resultC = Circle(Point(6,6),R)
        resultC.setFill('yellow')
        resultC.draw(win)

        # re-draw the X,Y because circle overlap it
        Line(Point(6,1),Point(6,11)).draw(win)
        Line(Point(1,6),Point(11,6)).draw(win)

        # depict Y intersection line
        Y = Y/2+6       # because 1Coords = 1/2 unit in map
        lineY = Line(Point(1,Y),Point(11,Y))
        lineY.setFill('green')
        lineY.draw(win)

        # depict both X point in Map
        X = X/2         # because 1Coords = 1/2 unit in map
        Xa = X+6        # make it both start at center of Map (position Coord=6)
        Xb = 6-X

        resultPa = Circle(Point(Xa,Y),0.1)
        resultPa.setFill('red')
        resultPa.draw(win)

        resultPb = Circle(Point(Xb,Y),0.1)
        resultPb.setFill('red')
        resultPb.draw(win)

        FbuttonT.setText('Quit')

        #pause for exit
        win.getMouse()
        win.close()

main()


# 상하좌우
N = int(input())
plans = input().split()
x, y = 1, 1
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
move = ['L', 'R', 'U', 'D']

for i in plans:
    for j in range(len(move)):
        if i == move[j]:
            nx = x + dx[j]
            ny = y + dy[j]
    if nx < 1 or nx > N or ny < 1 or ny > N:
        continue
    x, y = nx, ny

print(x, y)

# 시각
h = int(input())
count = 0
for i in range(h + 1):
    for j in range(60):
        for k in range(60):
            if '3' in str(i) + str(j) + str(k):
                count += 1
print(count)

# 왕실의 나이트
temp = input()
row = int(temp[1])
column = int(ord(temp[0])) - int(ord('a')) + 1

steps = [(-2, -1), (-1, -2), (1, -2), (2, -1), (2, 1), (1, 2), (-1, 2), (-2, 1)]
result = 0
for i in steps:
    next_row = row + i[0]
    next_col = column + i[1]
    if next_row >= 1 & next_row <= 8 & next_col >= 1 & next_col <= 8:
        result = result + 1
print(result)

# 게임 개발
N, M = map(int, input().split())
A, B, d = map(int, input().split())
map = [[0] * M for _ in range(N)]
map[A][B] = 1
array = []
for i in range(N):
    array.append(list(map(int, input().split())))
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]

def turn_left():
    global d
    d -= 1
    if d == -1:
        d = 3

count = 1
turn_time = 0
while True:
    turn_left()
    nx = A + dx[d]
    ny = B + dy[d]
    if map[nx][ny] == 0 and array[nx][ny] == 0:
        map[nx][ny] = 1
        x = nx
        y = ny
        count += 1
        turn_time = 0
        continue
    else:
        turn_time += 1
    if turn_time == 4:
        nx = x - dx[d]
        ny = y - dy[d]
        if array[nx][ny] == 0:
            x = nx
            y = ny
        else:
            break
        turn_time = 0
print(count)


import json
from typing import Dict, List, Set

import requests

WIKIPEDIA_REQUEST_URL = "http://en.wikipedia.org/w/api.php?action=query"

def _get_wikipedia_title(request_token: List[str]) -> Dict[str, str]:
    '''
    Returns Dict with <pageid>: title
    '''
    out_format = "json"
    srprop = "sectiontitle"
    srlimit = 1  # just the most relevant only
    srsearch = " ".join(request_token)

    request_url = f"{WIKIPEDIA_REQUEST_URL}&list=search&format={out_format}&srprop={srprop}&srlimit={srlimit}&srsearch={srsearch}"

    results: Dict[int, str] = {}
    try:
        for r in requests.get(request_url).json()["query"]["search"]:
            results[str(r["pageid"])] = r["title"]
    except Exception:
        pass

    return results

def _get_wikipedia_categories(pageids: Set[int]) -> List[str]:
    out_format = "json"
    prop = "categories"
    pageids = "|".join(list(pageids))

    request_url = f"{WIKIPEDIA_REQUEST_URL}&format={out_format}&prop={prop}&pageids={pageids}"

    categories: List[str] = []
    try:
        for page_id, r in requests.get(request_url).json()["query"]["pages"].items():
            for category in r["categories"]:
                categories.append(category["title"].replace("Category:", ""))
    except Exception:
        pass

    return categories

def request_wikipedia(top_words: List[str]) -> List[str]:
    top_words = [x.replace("_", " ") for x in top_words]  # get rid of _ in phrase

    page_ids_titles = _get_wikipedia_title(top_words)
    categories = _get_wikipedia_categories(page_ids_titles.keys())

    return categories

if __name__ == "__main__":
    token = [
        "artes",
        "august",
        "appointment",
        "beaufort",
        "be"
    ]
    page_ids_titles = _get_wikipedia_title(token)  # (["henry", "viii"])
    categories = _get_wikipedia_categories(page_ids_titles.keys())

    print(page_ids_titles)
    print()
    print(categories)