from __future__ import annotations

from alpaca.utils import Visitor
from alpaca.concepts import Type, TypeFactory
from eisen.common import binary_ops, boolean_return_ops, implemented_primitive_types
from eisen.state.basestate import BaseState
from eisen.state.state_posttypecheck import State_PostTypeCheck
from eisen.state.typecheckerstate import TypeCheckerState
from eisen.common.restriction import PrimitiveRestriction, ImmutableRestriction
import eisen.adapters as adapters
from eisen.validation.validate import Validate
from eisen.validation.callunwrapper import CallUnwrapper
from eisen.validation.restructure_is_statement import RestructureIsStatement
from eisen.validation.typeparser import TypeParser

from eisen.validation.builtin_print import Builtins

State = TypeCheckerState

class TypeChecker(Visitor):
    """this evaluates the flow of types throughout the ast, and records which
    type flows up through each ast.
    """

    def __init__(self, debug: bool = False):
        super().__init__(debug=debug)
        self.typeparser = TypeParser()

    def run(self, state: BaseState):
        self.apply(TypeCheckerState.create_from_basestate(state))
        return State_PostTypeCheck.create_from_basestate(state)

    def apply(self, state: State) -> Type:
        # this guards the function such that if there is a critical exception thrown
        # downstream, the method will skip execution.
        if state.critical_exception:
            return state.get_void_type()

        result = self._route(state.get_ast(), state)
        if result is None: result = state.get_void_type()
        TypeChecker.set_returned_type(state, result)
        return result

    @classmethod
    def get_curried_type(cls, state: State, fn_type: Type, n_curried_args: int) -> Type:
        argument_type = fn_type.get_argument_type()
        if not argument_type.is_tuple():
            if n_curried_args == 1:
                return TypeFactory.produce_function_type(
                    arg=state.get_void_type(),
                    ret=fn_type.get_return_type(),
                    mod=fn_type.mod).with_restriction(ImmutableRestriction())
            raise Exception(f"tried to curry more arguments than function allows: {n_curried_args} {fn_type}")

        if len(argument_type.components) - n_curried_args == 1:
            # unpack tuple to just a single type
            curried_fn_args = argument_type.components[-1]
        elif len(argument_type.components) - n_curried_args == 0:
            curried_fn_args = state.get_void_type()
        else:
            curried_fn_args = TypeFactory.produce_tuple_type(argument_type.components[n_curried_args:])

        return TypeFactory.produce_function_type(
            arg=curried_fn_args,
            ret=fn_type.get_return_type(),
            mod=fn_type.mod).with_restriction(ImmutableRestriction())

    @classmethod
    def set_returned_type(cls, state: State, type: Type):
        state.get_node_data().returned_type = type

    @classmethod
    def add_reference_type(cls, state: State, name: str, type: Type):
        state.get_context().add_reference_type(name, type)

    def apply_to_first_child_of(self, state: State) -> Type:
        return self.apply(state.but_with_first_child())

    def apply_to_second_child_of(self, state: State) -> Type:
        return self.apply(state.but_with_second_child())

    def returns_void_type(f):
        """this signifies that the void type should be returned. abstracted so if
        the void_type is changed, we can easily configure it here.
        """
        def decorator(fn, state: State):
            f(fn, state)
            return state.get_void_type()
        return decorator

    @Visitor.for_tokens
    def token_(fn, state: State) -> Type:
        if state.get_ast().type in implemented_primitive_types:
            return (TypeFactory
                .produce_novel_type(name=state.get_ast().type)
                .with_restriction(PrimitiveRestriction()))
        elif state.get_ast().type == "nil":
            return TypeFactory.produce_nil_type()

        # debug only
        raise Exception(f"unexpected token type of {state.get_ast().type}, {state.get_ast().value}")

    @Visitor.for_ast_types("start", "return", "cond", "seq")
    def start_(fn, state: State):
        state.apply_fn_to_all_children(fn)

    @Visitor.for_ast_types("mod")
    def mod_(fn, state: State):
        adapters.Mod(state).enter_module_and_apply(fn)

    @Visitor.for_ast_types("!")
    def not_(fn, state: State) -> Type:
        return fn.apply_to_first_child_of(state)

    @Visitor.for_ast_types(".")
    def dot_(fn, state: State) -> Type:
        node = adapters.Scope(state)
        parent_type = fn.apply(state.but_with(ast=node.get_object_ast()))
        attr_name = node.get_attribute_name()
        if Validate.has_member_attribute(state, parent_type, attr_name).failed():
            return state.get_abort_signal()
        return parent_type.get_member_attribute_by_name(attr_name)

    @Visitor.for_ast_types("::")
    def scope_(fn, state: State) -> Type:
        node = adapters.ModuleScope(state)
        instance = node.get_end_instance()
        return instance.type

    @Visitor.for_ast_types("tuple", "params", "prod_type", "lvals", "curried")
    def tuple_(fn, state: State) -> Type:
        if len(state.get_ast()) == 0:
            return state.get_void_type()
        elif len(state.get_ast()) == 1:
            # if there is only one child, then we simply pass the type back, not as a tuple
            return fn.apply_to_first_child_of(state)
        return TypeFactory.produce_tuple_type(
            components=[fn.apply(state.but_with(ast=child)) for child in state.get_ast()])

    @Visitor.for_ast_types("if")
    def if_(fn, state: State) -> Type:
        adapters.If(state).enter_context_and_apply(fn)

    @Visitor.for_ast_types("while")
    def while_(fn, state: State) -> Type:
        adapters.While(state).enter_context_and_apply(fn)

    @classmethod
    def _shared_call_checks(cls, state: State, params_type: Type):
        node = adapters.RefLike(state.but_with_first_child())
        fn_type = node.resolve_reference_type(params_type)
        if Validate.instance_exists(state, node.get_name(), fn_type).failed():
            return state.get_abort_signal()

        if Validate.correct_argument_types(state,
            name=node.get_name(),
            arg_type=fn_type.get_argument_type(),
            given_type=params_type).failed():
                return state.get_abort_signal()
        return fn_type.get_return_type()

    @Visitor.for_ast_types("raw_call")
    def raw_call(fn, state: State) -> Type:
        guessed_params_type = fn.apply_to_second_child_of(state)

        # this will actually change the ast inplace, converting (raw_call ...)
        # into (call (ref ...) (params ...))
        if guessed_params_type == state.get_abort_signal():
            return state.get_abort_signal()
        params_type = CallUnwrapper.process(
            state=state,
            guessed_params_type=guessed_params_type,
            fn=fn)

        fn.apply(state.but_with(ast=state.first_child(), arg_type=params_type))
        if adapters.Call(state).is_print():
            return Builtins.get_type_of_print(state).get_return_type()

        return TypeChecker._shared_call_checks(state, params_type)

    @Visitor.for_ast_types("is")
    def is_(fn, state: State) -> Type:
        node = adapters.Is(state)
        # if the check is not against nil, treat this as a call to
        # some "is" function of a variant
        if node.get_type_name() != "nil":
            params_type = node.get_considered_type().parent_type
            RestructureIsStatement.run(state)
            fn.apply(state.but_with(ast=state.first_child(), arg_type=params_type))
            fn.apply(state.but_with_second_child())
            return TypeChecker._shared_call_checks(state, params_type)
        return state.get_bool_type()

    @Visitor.for_ast_types("curry_call")
    def curry_call_(fn, state: State) -> Type:
        fn_type = fn.apply_to_first_child_of(state)
        curried_args_type = fn.apply_to_second_child_of(state)
        n_curried_args = 1
        if curried_args_type.is_tuple():
            n_curried_args = len(curried_args_type.components)

        return TypeChecker.get_curried_type(state, fn_type, n_curried_args)

    @Visitor.for_ast_types("struct")
    def struct(fn, state: State) -> Type:
        node = adapters.Struct(state)
        if node.has_create_ast():
            fn.apply(state.but_with(ast=node.get_create_ast()))

    @Visitor.for_ast_types("variant")
    def variant_(fn, state: State) -> Type:
        fn.apply(state.but_with(ast=adapters.Variant(state).get_is_ast()))

    @Visitor.for_ast_types("interface", "impls")
    def interface_(fn, state: State) -> Type:
        # no action required
        return

    @Visitor.for_ast_types("cast")
    def cast(fn, state: State) -> Type:
        # (cast (ref name) (type into))
        left_type = fn.apply_to_first_child_of(state)
        right_type = fn.apply_to_second_child_of(state)

        if Validate.castable_types(
            state=state,
            type=left_type,
            cast_into_type=right_type).failed(): return state.get_abort_signal()
        return right_type

    @Visitor.for_ast_types("def", "create", ":=", "is_fn")
    def fn(fn, state: State) -> Type:
        adapters.CommonFunction(state).enter_context_and_apply(fn)

    @classmethod
    def _create_references(cls, state: State, names: list[str], type: Type):
        types = type.components if type.is_tuple() else [type] * len(names)
        if any(type is state.get_abort_signal() for type in types):
            state.critical_exception.set(True)
            return
        if Validate.all_names_are_unbound(state, names).failed():
            return state.get_abort_signal()
        for name, t in zip(names, types):
            TypeChecker.add_reference_type(state, name, t)
        return type

    @Visitor.for_ast_types(*adapters.InferenceAssign.ast_types)
    def idecls_(fn, state: State):
        node = adapters.InferenceAssign(state)
        names = node.get_names()
        type = fn.apply_to_second_child_of(state)
        type = type.with_restriction(node.get_restriction(hint=type))
        return TypeChecker._create_references(state, names, type)

    @Visitor.for_ast_types(*adapters.Typing.ast_types)
    def decls_(fn, state: State):
        node = adapters.Typing(state)
        names = node.get_names()
        type = fn.apply(state.but_with(ast=node.get_type_ast())).with_restriction(node.get_restriction())
        return TypeChecker._create_references(state, names, type)

    @Visitor.for_ast_types("fn_type", "para_type", *adapters.TypeLike.ast_types)
    def _type1(fn, state: State) -> Type:
        return fn.typeparser.apply(state)

    @Visitor.for_ast_types("=", "<-", *binary_ops)
    def binary_ops(fn, state: State) -> Type:
        left_type = fn.apply_to_first_child_of(state)
        right_type = fn.apply_to_second_child_of(state)

        if Validate.can_assign(state, left_type, right_type).failed():
            return state.get_abort_signal()
        return left_type

    @Visitor.for_ast_types(*boolean_return_ops)
    def boolean_return_ops_(fn, state: State) -> Type:
        left_type = fn.apply_to_first_child_of(state)
        right_type = fn.apply_to_second_child_of(state)

        if Validate.equivalent_types(state, left_type, right_type).failed():
            return state.get_abort_signal()
        return state.get_bool_type()

    @Visitor.for_ast_types("fn")
    def fn_(fn, state: State) -> Type:
        node = adapters.Fn(state)
        instance = node.resolve_function_instance(state.get_arg_type())
        if Validate.instance_exists(state, node.get_name(), instance).failed():
            return state.get_abort_signal()
        return instance.type

    @Visitor.for_ast_types("ref")
    def ref_(fn, state: State) -> Type:
        node = adapters.Ref(state)
        if node.is_print():
            return Builtins.get_type_of_print(state)

        type = node.resolve_reference_type()
        if Validate.instance_exists(state, node.get_name(), type).failed():
            return state.get_abort_signal()
        return type

    @Visitor.for_ast_types(*adapters.ArgsRets.ast_types)
    def args_(fn, state: State) -> Type:
        if not state.get_ast():
            return state.get_void_type()
        return fn.apply(state.but_with(ast=state.first_child()))

    @Visitor.for_ast_types("new_vec")
    def new_vec_(fn, state: State) -> Type:
        node = adapters.NewVec(state)
        return node.get_type()

    @Visitor.for_ast_types("index")
    def index_(fn, state: State) -> Type:
        return fn.apply_to_first_child_of(state).parametrics[0]

    @Visitor.for_ast_types("annotation")
    def annotation_(fn, state: State) -> Type:
        # Not implemented
        return


# -*- coding: utf-8 -*-
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, redirect
from django.core.urlresolvers import reverse
from django.core.mail import send_mail, EmailMultiAlternatives
from django.conf import settings
from django.contrib import messages
from django.template import RequestContext
from django.template.loader import render_to_string
from django.db import transaction

from common.fields import emails_list
from cart import Cart
from cart.models import Order
from cart.forms import OrderForm

def show_cart(request):
    return render_to_response('cart.html', {},
        context_instance=RequestContext(request))

@transaction.commit_on_success
def order_cart(request):
    if request.method == 'POST':
        form = OrderForm(request.POST)
        if form.is_valid():
            subject = u'Заказ с сайта'
            recipients = []
            try:
                recipients.extend(emails_list(request.settings.email))
            except:
                recipients.append(settings.ADMINS[0][1])
            cart = Cart(request, init=True)
            # Order insertion
            if cart.objects:
                order = Order.objects.create(fio=form.cleaned_data['fio'],
                                             address='',
                                             phones=form.cleaned_data['phones'],
                                             email=form.cleaned_data['email'],
                                             comment=form.cleaned_data['comment'])
                for item in cart.objects:
                    order.items.create(label=item.label,
                                       amount=item.amount,
                                       price=item.price)
            subject = u'Поступил заказ с сайта %s' % settings.PROJECT_TITLE
            letter_context = form.cleaned_data
            letter_context.update({'site': settings.PROJECT_TITLE,
                                   'cart': cart, 'subject': subject})

            text_content = render_to_string('letters/order_text.txt', letter_context)
            html_content = render_to_string('letters/order_html.html', letter_context)

            msg = EmailMultiAlternatives(subject, text_content,
                recipients[0], recipients)
            msg.attach_alternative(html_content, "text/html")
            msg.send()
            cart.delete_all()
            success_message = request.infoblock.get('order_send_message', u"""
            Благодарим за то, что Вы воспользовались услугами нашего Интернет-магазина.
            Ваша заявка принята в обработку, и наш менеджер свяжется с Вами в ближайшее время для уточнения деталей.
            """)
            messages.add_message(request, messages.SUCCESS, success_message)
            return redirect(reverse('message_list'))
    else:
        form = OrderForm()
    return render_to_response('cart_order.html', {'form': form},
        context_instance=RequestContext(request))

def add_cart(request):
    cart = Cart(request)
    product = int(request.POST.get('product', 0))
    if product > 0:
        request = cart.add(product)
    return HttpResponse(cart.serialize())

def update_cart(request):
    cart = Cart(request)
    product = int(request.POST.get('product', '0'))
    amount = int(request.POST.get('amount', '0'))
    i = int(request.POST.get('i', '0'))
    data = None

    if product > 0 and amount >= 0:
        if amount == 0:
            cart.delete(product)
        else:
            cart.update({'product': product, 'amount': amount})
        return HttpResponse(cart.serialize())
    else:
        raise Http404

def delete_cart(request, id):
    cart = Cart(request)
    cart.delete(id)
    if request.META.get('HTTP_X_REQUESTED_WITH', '') == 'XMLHttpRequest':
        return HttpResponse(cart.serialize())
    else:
        return redirect(reverse('show_cart'))

def empty_cart(request):
    cart = Cart(request)
    cart.delete_all()
    return redirect('/')


import csv
import glob
import math
from pathlib import Path
import argparse

import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
from graph_tool.all import *
from extract_largest_component import write_largest_component

class ParameterExtraction:
    def __init__(self, graphs_path: str, export_file: str) -> None:
        super().__init__()
        self.graphs_path = Path(graphs_path)
        self.export_file = export_file

    def _iterate_edge_lists(self):
        if self.graphs_path.is_dir():
            for filename in glob.iglob(str(self.graphs_path) + '/**/*.edges', recursive=True):
                yield filename

    def _get_num_edges(self, graph: Graph):
        return graph.num_edges()

    def _get_num_vertices(self, graph: Graph):
        return graph.num_vertices()

    def _get_global_clustering_coefficient(self, graph: Graph):
        return global_clustering(graph)[0]

    def _get_pseudo_diameter(self, graph: Graph):
        return pseudo_diameter(graph)[0]

    def _get_assortativity(self, graph: Graph):
        return assortativity(graph, 'total')[0]

    def _get_scalar_assortativity(self, graph: Graph):
        return scalar_assortativity(graph, 'total')[0]

    def _get_density(self, graph: Graph):
        return (2 * graph.num_edges()) / (graph.num_vertices() * (graph.num_vertices() - 1))

    def _get_average_shortest_path(self, graph: nx.Graph):
        return nx.average_shortest_path_length(graph)

    # Degree distribution log normal?
    def get_degree_sequence(self, graph: nx.Graph):
        degree_sequence = sorted(nx.degree(G).values(), reverse=True)

    """
    DEGREE
    """

    def _get_avg_degree(self, graph: Graph):
        return 2 * (graph.num_edges() / graph.num_vertices())

    def _get_min_deg(self, graph: Graph):
        min_degree = math.inf
        for v in graph.vertices():
            degree = v.out_degree()
            if (degree < min_degree):
                min_degree = degree
        return min_degree

    def _get_max_deg(self, graph: Graph):
        max_degree = -1
        for v in graph.vertices():
            degree = v.out_degree()
            if (degree > max_degree):
                max_degree = degree
        return max_degree

    """
    VERTEX BETWEENNESS
    """

    def _get_max_vertex_betweenness(self, graph: Graph):
        vertex_betweenness, edge_betweenness = betweenness(graph)
        return max(vertex_betweenness.get_array())

    def _get_min_vertex_betweenness(self, graph: Graph):
        vertex_betweenness, edge_betweenness = betweenness(graph)
        return min(vertex_betweenness.get_array())

    def _get_mean_vertex_betweenness(self, graph: Graph):
        vertex_betweenness, edge_betweenness = betweenness(graph)
        return np.mean(vertex_betweenness.get_array())

    def _get_std_vertex_betweenness(self, graph: Graph):
        vertex_betweenness, edge_betweenness = betweenness(graph)
        return np.std(vertex_betweenness.get_array())

    """
    EDGE BETWEENNESS
    """

    def _get_max_edge_betweenness(self, graph: Graph):
        vertex_betweenness, edge_betweenness = betweenness(graph)
        return max(edge_betweenness.get_array())

    def _get_min_edge_betweenness(self, graph: Graph):
        vertex_betweenness, edge_betweenness = betweenness(graph)
        return min(edge_betweenness.get_array())

    def _get_mean_edge_betweenness(self, graph: Graph):
        vertex_betweenness, edge_betweenness = betweenness(graph)
        return np.mean(edge_betweenness.get_array())

    def _get_std_edge_betweenness(self, graph: Graph):
        vertex_betweenness, edge_betweenness = betweenness(graph)
        return np.std(edge_betweenness.get_array())

    """
    CLIQUE
    """

    def _get_clique_number(self, graph: nx.Graph):
        return nx.graph_clique_number(graph)

    def _get_number_of_cliques(self, graph: nx.Graph):
        return nx.graph_number_of_cliques(graph)

    """
    PLOT
    """

    def plot_data(self, csv_file: str):
        p = Path(csv_file)
        if p.exists():
            with open(str(p)) as csv_file:
                reader = csv.reader(csv_file, delimiter=',')
                next(reader)
                ccd = list()
                avd = list()
                for row in reader:
                    ccd.append(row[2])
                    avd.append(row[3])
            plt.scatter(ccd, avd)
            plt.show()

    def run(self, do_non_np=True):
        columns = [self._get_num_edges,
                   self._get_num_vertices,
                   self._get_global_clustering_coefficient,
                   self._get_avg_degree,
                   self._get_pseudo_diameter,
                   self._get_assortativity,
                   self._get_scalar_assortativity,
                   self._get_density,
                   self._get_min_deg,
                   self._get_max_deg,
                   self._get_max_vertex_betweenness,
                   self._get_min_vertex_betweenness,
                   self._get_mean_vertex_betweenness,
                   self._get_std_vertex_betweenness,
                   self._get_max_edge_betweenness,
                   self._get_min_edge_betweenness,
                   self._get_mean_edge_betweenness,
                   self._get_std_edge_betweenness]

        columns_nx = [
            self._get_average_shortest_path
        ]

        columns_nx_non_np = [
            self._get_clique_number,
            self._get_number_of_cliques,
        ]

        f = csv.writer(open(self.export_file, 'w'))
        f.writerow(map(lambda x: x.__name__, columns + columns_nx))
        for file in self._iterate_edge_lists():
            # Get data_real properties
            with open(file, 'r') as c:
                dialect = csv.Sniffer().sniff(c.read(1024))
                csv_options = {'delimiter': dialect.delimiter, 'quotechar': dialect.quotechar}

            # Create graph and write specified columns to new csv file
            g = load_graph_from_csv(file, directed=False, csv_options=csv_options)
            gx = nx.read_edgelist(file, delimiter=csv_options['delimiter'], create_using=nx.Graph(), nodetype=int)
            if nx.is_connected(gx):
                print('Did graph {}'.format(file))
                column_values = [c(g) for c in columns]
                column_values += [c(gx) for c in columns_nx]
                if do_non_np:
                    column_values += [c(gx) for c in columns_nx_non_np]
                f.writerow(column_values)
            else:
                print('Graph was not connected, skipping ... {}'.format(file))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Extraction of diversity of graph properties')
    parser.add_argument('data_input', metavar='I', type=str,
                        help='Input data_real directory')
    parser.add_argument('data_output', metavar='O', type=str,
                        help='Output CSV file')
    parser.add_argument('-np',
                        help='Do graph properties algorithm that are not in NP', action='store_true')
    parser.add_argument('-fix',
                        help='If not connected, extract largest component', action='store_true')
    args = parser.parse_args()

    if args.fix:
        print('Fixing graphs...')
        write_largest_component(args.data_input, args.data_output + '_fixed')
        p = ParameterExtraction(args.data_output + '_fixed', args.data_output)
    else:
        print('Do not fix graphs')
        p = ParameterExtraction(args.data_input, args.data_output)

    if args.np:
        print('NP true')
        p.run(do_non_np=True)
    else:
        print('NP false')
        p.run(do_non_np=False)


import chess
import chess.engine
import numpy as np
from board_basics import *
import chessboard_detection
import pyautogui
import cv2
import mss
import math
from random import randint
from time import sleep
import copy
import os
import time
import sys

from chess.engine import EngineTerminatedError

class NoValidPosition(Exception):

   pass
class PositionChanged(Exception):

   pass

class Board_position:
    def __init__(self,minX,minY,maxX,maxY,factor):
        self.minX = minX
        self.minY = minY
        self.maxX = maxX
        self.maxY = maxY
        self.factor =factor
        self.current = None

    def print_custom(self):
        return ("from " + str(self.minX) + "," + str(self.minY) + " to " + str(self.maxX) + ","+ str(self.maxY))

class Game_state:

    def __init__(self):
        self.we_play_white = True #This store the player color, it will be changed later
        self.moves_to_detect_before_use_engine = -1 #The program uses the engine to play move every time that this variable is 0
        self.expected_move_to_detect = "" #This variable stores the move we should see next, if we don't see the right one in the next iteration, we wait and try again. This solves the slow transition problem: for instance, starting with e2e4, the screenshot can happen when the pawn is on e3, that is a possible position. We always have to double check that the move is done.
        self.previous_chessboard_image = [] #Storing the chessboard image from previous iteration
        self.executed_moves = [] #Store the move detected on san format
        self.engine = chess.engine.SimpleEngine.popen_uci("engine/stockfish-11-64")
        # self.engine = chess.engine.SimpleEngine.popen_uci("engine/komodo-11.01-64-osx")
        self.board = chess.Board() #This object comes from the "chess" package, the moves are stored inside it (and it has other cool features such as showing all the "legal moves")
        self.board_position_on_screen = []
        self.sct = mss.mss()

    def check_for_castling(self,potential_starts, potential_arrivals):
        valid_move_string = ""
        # Detect castling king side with white
        if ("e1" in potential_starts) and ("h1" in potential_starts) and ("f1" in potential_arrivals) and (
                "g1" in potential_arrivals):
            valid_move_string = "e1g1"
            potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == "e1"))
            potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == "f1"))

        # Detect castling queen side with white
        if ("e1" in potential_starts) and ("a1" in potential_starts) and ("c1" in potential_arrivals) and (
                "d1" in potential_arrivals):
            valid_move_string = "e1c1"
            potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == "e1"))
            potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == "c1"))

        # Detect castling king side with black
        if ("e8" in potential_starts) and ("h8" in potential_starts) and ("f8" in potential_arrivals) and (
                "g8" in potential_arrivals):
            valid_move_string = "e8g8"
            potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == "e8"))
            potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == "f8"))

        # Detect castling queen side with black
        if ("e8" in potential_starts) and ("a8" in potential_starts) and ("c8" in potential_arrivals) and (
                "d8" in potential_arrivals):
            valid_move_string = "e8c8"
            potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == "e8" ))
            potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == "c8"))

        return valid_move_string,potential_starts

    def get_valid_move(self, potential_starts, potential_arrivals, current_chessboard_image):

        print("Starts and arrivals:",potential_starts, potential_arrivals)
        if len( potential_arrivals)==0 and len(potential_starts)==0:
            return "",[]

        valid_move_string,potential_starts = self.check_for_castling(potential_starts, potential_arrivals)

        if valid_move_string:
            return valid_move_string,[potential_starts,potential_arrivals]

        rest = []
        if len(potential_starts)==2 and len(potential_arrivals)==0:
            print('recapture with same piece')

            capture_moves_own=list(self.board.generate_legal_captures())
            # print(capture_moves_own)
            for move in capture_moves_own:
                if chess.Move.uci(move)[:2] == potential_starts[0] or chess.Move.uci(move)[:2] == potential_starts[1]:
                    try:
                        self.board.push(move)
                    except:
                        continue

                    capture_moves_opponent = list(self.board.generate_legal_captures())
                    for move_opp in capture_moves_opponent:
                        if chess.Move.uci(move_opp)[:2] == potential_starts[0] or chess.Move.uci(move_opp)[:2] == potential_starts[1]:
                            self.board.pop()
                            potential_arrivals.append(chess.Move.uci(move)[-2:])
                            break

        for start in potential_starts:
            for arrival in potential_arrivals:

                # print("moves"+start+arrival)
                uci_move = start+arrival
                if start == arrival:
                    continue
                move = chess.Move.from_uci(uci_move)
                if move in self.board.legal_moves:
                    valid_move_string = uci_move
                    print(valid_move_string)
                    rest = []
                    if len(potential_starts) >= 2 or len(potential_arrivals) >= 2:
                        potential_starts = np.delete(potential_starts,np.argwhere(potential_starts == start))
                        rest = [potential_starts,potential_arrivals]
                else:
                    uci_move_promoted = uci_move + 'q'
                    promoted_move = chess.Move.from_uci(uci_move_promoted)
                    if promoted_move in self.board.legal_moves:
                        rest = []
                        valid_move_string = uci_move_promoted
                        print("There has been a promotion to queen")
                        if len(potential_starts) >= 2 or len(potential_arrivals) >= 2:
                            potential_starts = np.delete(potential_starts, np.argwhere(potential_starts == start))
                            rest = [potential_starts, potential_arrivals]

        return valid_move_string, rest

    def register_move_if_needed(self):

        new_board = chessboard_detection.get_chessboard(self)
        old_board = self.previous_chessboard_image
        diff = cv2.absdiff(new_board, old_board)
        if diff.mean() == 0:
            return False, ([], []), (old_board, new_board)
        cv2.waitKey(50)
        new_board2 = chessboard_detection.get_chessboard(self)
        # cv2.waitKey(10)
        # new_board3 = chessboard_detection.get_chessboard(self)
        while cv2.absdiff(new_board,new_board2).mean()>0:# or cv2.absdiff(new_board,new_board3).mean()>0:
            new_board = chessboard_detection.get_chessboard(self)
            cv2.waitKey(50)
            new_board2 = chessboard_detection.get_chessboard(self)
            # cv2.waitKey(10)
            # new_board3 = chessboard_detection.get_chessboard(self)

        potential_starts, potential_arrivals = get_potential_moves(self.previous_chessboard_image,new_board,self.we_play_white)
        if len(potential_starts)>6 or len(potential_arrivals)>6:
            self.previous_chessboard_image=new_board
            raise PositionChanged
            # pass
        valid_move_string1, rest = self.get_valid_move(potential_starts,potential_arrivals,new_board)
        if rest:
            # print('premove to process')
            print("Valid move string 1:" + valid_move_string1)
            if len(valid_move_string1) > 0:
                valid_move_UCI = chess.Move.from_uci(valid_move_string1)
                valid_move_registered = self.register_move(valid_move_UCI,new_board)
                new_board = chessboard_detection.get_chessboard(self)
                potential_starts = rest[0]
                potential_arrivals = rest[1]
                valid_move_string1, rest = self.get_valid_move(potential_starts, potential_arrivals, new_board)
                if len(valid_move_string1) > 0:
                    valid_move_UCI = chess.Move.from_uci(valid_move_string1)
                    valid_move_registered = self.register_move(valid_move_UCI, new_board)

                    return True, valid_move_string1,(old_board,new_board)
        else:
            print("Valid move string 1:" + valid_move_string1)
            if len(valid_move_string1) > 0:
                valid_move_UCI = chess.Move.from_uci(valid_move_string1)
                valid_move_registered = self.register_move(valid_move_UCI,new_board)
                return True, valid_move_string1,(old_board,new_board)
        # if len(potential_arrivals)>0 or len(potential_starts)>0:

        return False, (potential_starts,potential_arrivals),(old_board,new_board)

    def register_move(self,move,board_image):
        if move in self.board.legal_moves:
            print("Move has been registered")
            self.executed_moves = np.append(self.executed_moves,self.board.san(move))
            self.board.push(move)
            self.moves_to_detect_before_use_engine  -= 1
            self.previous_chessboard_image = board_image
            return True
        else:
            return False

    def get_square_center(self,square_name):
        row,column = convert_square_name_to_row_column(square_name,self.we_play_white)
        position = self.board_position_on_screen
        centerX = int(position.minX + (column + 0.5) *(position.maxX-position.minX)/8)
        centerY = int(position.minY + (row + 0.5) *(position.maxY-position.minY)/8)
        return centerX,centerY

    def play_next_move(self,factor,strength,variance):
        pyautogui.PAUSE = 0
        starttime = time.time()
        print("\nUs to play: Calculating next move")

        try:
            info = self.engine.analyse(self.board, chess.engine.Limit(time=0.01))  # chess.engine.Limit(depth=20))

            score = info["score"]
            if strength<=2000:
                move_time = (strength + (randint(1, variance))) / 1000
                engine_process = self.engine.play(self.board,  chess.engine.Limit(time=move_time))

                # self.board.push(engine_process.move)
                # score_move = self.engine.analyse(self.board, chess.engine.Limit(time=0.01))["score"]

                # if (score_move.relative.score() == None and score.relative.score() != None):
                #     self.board.pop()

                # elif (score_move.relative.score() != None and score.relative.score() == None):
                #     self.board.pop()
                #     fen_str,detected_board = self.build_fen(self.we_are_white,rochade = '-' )
                #     self.board.set_fen(fen_str)
                #     return self.play_next_move(factor,strength,variance)

                # elif (score_move.relative.score() == None and score.relative.score() == None):
                #     if (abs(score_move.relative.score(mate_score=100000)) > abs(score.relative.score(mate_score=100000))):
                #         self.board.pop()
                #     else:
                #         self.board.pop()
                #         fen_str,detected_board = self.build_fen(self.we_play_white,rochade="-")
                #         self.board.set_fen(fen_str)
                #         return self.play_next_move(factor,strength,variance)

                # elif (abs(score_move.relative.score(mate_score=100000)) > abs(score.relative.score(mate_score=100000))):
                #     #bad move

                #     self.board.pop()
                #     fen_str,detected_board = self.build_fen(self.we_play_white,rochade="-")
                #     self.board.set_fen(fen_str)
                #     return self.play_next_move(factor,strength,variance)

                #     #rescan board and find new move
                # else:
                #     self.board.pop()

            else:
                print('depth_mode')
                move_time = time.time()
                engine_process = self.engine.play(self.board, chess.engine.Limit(depth=20))
                move_time = time.time() - move_time

                self.board.push(engine_process.move)
                score_move = self.engine.analyse(self.board, chess.engine.Limit(time=0.01))["score"]

                if (score_move.relative.score() == None and score.relative.score() != None):
                    self.board.pop()

                elif (score_move.relative.score() != None and score.relative.score() == None):
                    self.board.pop()
                    fen_str,detected_board = self.build_fen(self.we_play_white,rochade="-")
                    self.board.set_fen(fen_str)
                    return self.play_next_move(factor,strength,variance)

                elif (score_move.relative.score() == None and score.relative.score() == None):
                    if (abs(score_move.relative.score(mate_score=100000)) > abs(score.relative.score(mate_score=100000))):
                        self.board.pop()
                    else:
                        self.board.pop()
                        fen_str,detected_board = self.build_fen(self.we_play_white,rochade="-")
                        self.board.set_fen(fen_str)
                        return self.play_next_move(factor,strength,variance)

                elif (abs(score_move.relative.score(mate_score=100000)) > abs(score.relative.score(mate_score=100000))):
                    #bad move

                    self.board.pop()
                    fen_str,detected_board = self.build_fen(self.we_play_white,rochade="-")
                    self.board.set_fen(fen_str)
                    return self.play_next_move(factor,strength,variance)

                    #rescan board and find new move
                else:
                    self.board.pop()

        except EngineTerminatedError:
            print('restart')
            self.engine = chess.engine.SimpleEngine.popen_uci("engine/stockfish-11-64")
            # self.engine = chess.engine.SimpleEngine.popen_uci("engine/komodo-11.01-64-osx")

            return 0,0

        postthink = time.time()

        best_move = engine_process.move
        best_move_string = best_move.uci()
        #print("Play next move")

        #print(bestMove)
        origin_square = best_move_string[0:2]
        destination_square = best_move_string[2:4]

        centerXOrigin, centerYOrigin = self.get_square_center(origin_square)
        centerXDest, centerYDest = self.get_square_center(destination_square)
        factor /= 2
        centerXOrigin *= factor
        centerYOrigin *= factor
        centerXDest *= factor
        centerYDest *= factor
        # print(f"preparetime: {time.time()-postthink}")

        # mousetime=time.time()
        # Having the positions we can drag the piece:
        pyautogui.moveTo(int(centerXOrigin), int(centerYOrigin), 0.0001)
        # pyautogui.click(clicks=2,button='left')
        pyautogui.dragTo(int(centerXOrigin), int(centerYOrigin) + 1, button='left', duration=0.2)  # This small click is used to get the focus back on the browser window

        pyautogui.dragTo(int(centerXDest), int(centerYDest), button='left', duration=0.11)
        # print(f"mousetime: {time.time()-mousetime}")

        if best_move.promotion != None:
            print("Promoting to a queen")
            # Deal with queen promotion:
            cv2.waitKey(100)
            pyautogui.dragTo(int(centerXDest), int(centerYDest) + 1, button='left',
                             duration=0.1)  # Always promoting to a queen

        print("Done playing move", origin_square, destination_square)
        # curr_chessboard = chessboard_detection.get_chessboard(self)
        # diff = cv2.absdiff(self.previous_chessboard_image,curr_chessboard)

        # if diff.mean() == 0:
        #     print('move_error')
        #     castling = self.get_castling_rights()
        #     fen,vis = self.build_fen(self.we_play_white, castling)
        #     self.board.set_fen(fen)
        #     self.moves_to_detect_before_use_engine = 0
        # else:
        #     self.moves_to_detect_before_use_engine = 2
        self.moves_to_detect_before_use_engine = 2
        # print(f"movetime: {time.time()-starttime-move_time}")
        return score, move_time

    def get_castling_rights(self):
        rights=''
        if self.board.has_kingside_castling_rights(True):
            rights+='K'
        if self.board.has_queenside_castling_rights(True):
            rights += 'Q'
        if self.board.has_kingside_castling_rights(False):
            rights+='k'
        if self.board.has_queenside_castling_rights(False):
            rights += 'q'
        if len(rights)==0:
            rights+='-'
        return rights

    def build_fen(self,we_are_white,rochade = 'KQkq' ):
        position_detection = chessboard_detection.get_chessboard(self, (1024, 1024))
        self.previous_chessboard_image = chessboard_detection.get_chessboard(self)
        # cv2.imshow('dsd',position_detection)
        # cv2.waitKey(0)
        #   board_basics.is_white_on_bottom(position_detection)
        self.we_play_white = we_are_white

        to_move = 'w' if we_are_white else 'b'

        self.moves_to_detect_before_use_engine = 0  # if v.get() else 1

        pieces = sorted(os.listdir('pieces'))

        vis_glob = np.array([])
        piece_notation = ['b', 'k', 'n', 'p', 'q', 'r', '*', 'B', 'K', 'N', 'P', 'Q', 'R']
        fen_str = ''

        # rochade = 'KQkq'

        order = range(8) if we_are_white else reversed(range(8))
        for i in order:
            vis = np.array([])

            image_list = [get_square_image(i, j, position_detection) for j in (range(8) if we_are_white else reversed(range(8)))]
            answers = piece_on_square_list(image_list)
            for answer in answers:
                im = cv2.imread(os.path.join('pieces', pieces[answer]))
                if vis.size == 0:
                    vis = im
                    fen_str += piece_notation[answer]
                else:
                    if we_are_white:
                        vis = np.concatenate((vis,im), axis=1)
                    else:
                        vis = np.concatenate((im, vis), axis=1)
                    fen_str += piece_notation[answer]

            fen_str += '/'
            if vis_glob.size == 0:
                vis_glob = vis
            else:
                if we_are_white:
                    vis_glob = np.concatenate(( vis_glob,vis), axis=0)
                else:
                    vis_glob = np.concatenate((vis, vis_glob), axis=0)

        fen_str = self.transform_fen(fen_str,to_move,rochade)
        # fen_str= fen_str.replace("  "," ")
        return fen_str,vis_glob

    def visulize_fen(self,fen):
        pass

    def transform_fen(self, fen_str, to_move, rochade, en_passant='-',halfmoves='0',move='1'):
        fen_str = fen_str[:-1] + ' ' + to_move + ' ' + rochade + ' ' + en_passant + ' ' + halfmoves + ' ' + move

        for i in range(len(fen_str)):
            if fen_str[i] == ' ':
                break
            count = 0
            if fen_str[i] == '*':
                while fen_str[i] == '*':
                    count += 1

                    fen_str = fen_str[0: i:] + fen_str[i + 1::]
                fen_str = fen_str[:i] + str(count) + fen_str[i:]
        return fen_str

    def our_side(self):
        # TODO use pawns to get side
        position_detection = chessboard_detection.get_chessboard(self, (800, 800))
        piece_notation = ['b', 'k', 'n', 'p', 'q', 'r', '*', 'B', 'K', 'N', 'P', 'Q', 'R']

        black_king_position=()
        white_king_position = ()
        order = range(8)
        for i in order:
            vis = np.array([])
            # order2 = range(8)
            image_list = [get_square_image(i, j, position_detection) for j in range(8)]
            answers = piece_on_square_list(image_list)
            if piece_notation.index('k') in answers:
                black_king_position = (i, 0)
            if piece_notation.index('K') in answers:
                white_king_position= (i,0)

        if not white_king_position or not black_king_position:
            raise NoValidPosition
        if black_king_position[0]<white_king_position[0]:
            return 'white'
        elif black_king_position[0]>white_king_position[0]:
            return 'black'
        else:
            return 'unsure'

    def build_fen_guess_side(self):

        position_detection = chessboard_detection.get_chessboard(self, (1024, 1024))
        position_detection2 = chessboard_detection.get_chessboard(self, (612, 612))

        self.previous_chessboard_image = chessboard_detection.get_chessboard(self)

        self.moves_to_detect_before_use_engine = 0  # if v.get() else 1

        fen_str = ''
        # position_detection = chessboard_detection.get_chessboard(self, (1024, 1024))
        piece_notation = ['b', 'k', 'n', 'p', 'q', 'r', '*', 'B', 'K', 'N', 'P', 'Q', 'R']

        pieces = sorted(os.listdir('pieces'))

        vis_glob = np.array([])

        rochade = '-'

        im_list = []
        black_king_position = -1
        white_king_position = -1

        prediction_time = 0

        for i in range(8):
            for j in range(8):

                # step_time = time.time()
                answer = piece_on_square(get_square_image(i, j, position_detection))
                answer2 = piece_on_square(get_square_image(i, j, position_detection2))
                if answer != answer2:
                    position_detection3 = chessboard_detection.get_chessboard(self, (2048, 2048))
                    answer = piece_on_square(get_square_image(i, j, position_detection3))

                # prediction_time += (time.time() - step_time)
                if piece_notation.index('k') == answer:
                    black_king_position = i*8+j
                if piece_notation.index('K') == answer:
                    white_king_position = i*8+j

                im = cv2.imread(os.path.join('pieces', pieces[answer]))
                im_list.append(im)
                fen_str += piece_notation[answer]

            fen_str += '/'

        print(f"-->Prediction: {prediction_time}")

        if  white_king_position ==-1 or  black_king_position==-1:
            raise NoValidPosition
        if black_king_position < white_king_position:

            for im_row in list(chunks(im_list, 8)):
                vis = np.array([])
                for img in im_row:
                    if vis.size == 0:
                        vis = img
                    else:
                        vis = np.concatenate((vis, img), axis=1)
                if vis_glob.size == 0:
                    vis_glob = vis
                else:
                    vis_glob = np.concatenate((vis_glob, vis), axis=0)
            self.we_play_white = True
            return True, self.transform_fen(fen_str, 'w', rochade), vis_glob

        else:

            for im_row in list(chunks((im_list), 8)):
                vis = np.array([])
                for img in im_row:
                    if vis.size == 0:
                        vis = img
                    else:
                        vis = np.concatenate((vis, img), axis=1)
                if vis_glob.size == 0:
                    vis_glob = vis
                else:
                    vis_glob = np.concatenate((vis_glob, vis), axis=0)
            self.we_play_white = False
            return False, self.transform_fen(((fen_str[:-1])[::-1] + '/'), 'b', rochade), vis_glob

# Create a function called "chunks" with two arguments, l and n:
def chunks(l, n):
    # For item i in a range that is a length of l,
    for i in range(0, len(l), n):
        # Create an index range for l of n items:
        yield l[i:i+n]


import PySimpleGUI as sg
import os
import copy
import random
from pattern.es import tag

PATH = '.'

BLANK = 0
A = 1
B = 2
C = 3
D = 4
E = 5
F = 6
G = 7
H = 8
I = 9
J = 10
K = 11
L = 12
LL = 13
M = 14
N = 15
Ñ = 16
O = 17
P = 18
Q = 19
R = 20
RR = 21
S = 22
T = 23
U = 24
V = 25
W = 26
X = 27
Y = 28
Z = 29

# Orientacion de las palabras
ORIENTATION_RIGHT = 1
ORIENTATION_DOWN = 2
ORIENTATION_ERROR = -1
ORIENTATION_NONE = 0

# Tablero en blanco de 10x10
initial_tablero = [[BLANK, ] * 10, [BLANK, ] * 10, [BLANK, ] * 10, [BLANK, ] * 10, [BLANK, ] * 10,
                 [BLANK, ] * 10, [BLANK, ] * 10, [BLANK, ] * 10, [BLANK, ] * 10, [BLANK, ] * 10]

# Metadata de las letras
blank = {'letra': '', 'imagen': os.path.join(PATH, 'blank.png')}
a = {'letra': 'A', 'imagen': os.path.join(PATH, 'a.png')}
b = {'letra': 'B', 'imagen': os.path.join(PATH, 'b.png')}
c = {'letra': 'C', 'imagen': os.path.join(PATH, 'c.png')}
d = {'letra': 'D', 'imagen': os.path.join(PATH, 'd.png')}
e = {'letra': 'E', 'imagen': os.path.join(PATH, 'e.png')}
f = {'letra': 'F', 'imagen': os.path.join(PATH, 'f.png')}
g = {'letra': 'G', 'imagen': os.path.join(PATH, 'g.png')}
h = {'letra': 'H', 'imagen': os.path.join(PATH, 'h.png')}
i = {'letra': 'I', 'imagen': os.path.join(PATH, 'i.png')}
j = {'letra': 'J', 'imagen': os.path.join(PATH, 'j.png')}
k = {'letra': 'K', 'imagen': os.path.join(PATH, 'k.png')}
l = {'letra': 'L', 'imagen': os.path.join(PATH, 'l.png')}
ll = {'letra': 'LL', 'imagen': os.path.join(PATH, 'll.png')}
m = {'letra': 'M', 'imagen': os.path.join(PATH, 'm.png')}
n = {'letra': 'N', 'imagen': os.path.join(PATH, 'n.png')}
ñ = {'letra': 'Ñ', 'imagen': os.path.join(PATH, 'ñ.png')}
o = {'letra': 'O', 'imagen': os.path.join(PATH, 'o.png')}
p = {'letra': 'P', 'imagen': os.path.join(PATH, 'p.png')}
q = {'letra': 'Q', 'imagen': os.path.join(PATH, 'q.png')}
r = {'letra': 'R', 'imagen': os.path.join(PATH, 'r.png')}
rr = {'letra': 'RR', 'imagen': os.path.join(PATH, 'rr.png')}
s = {'letra': 'S', 'imagen': os.path.join(PATH, 's.png')}
t = {'letra': 'T', 'imagen': os.path.join(PATH, 't.png')}
u = {'letra': 'U', 'imagen': os.path.join(PATH, 'u.png')}
v = {'letra': 'V', 'imagen': os.path.join(PATH, 'v.png')}
w = {'letra': 'W', 'imagen': os.path.join(PATH, 'w.png')}
x = {'letra': 'X', 'imagen': os.path.join(PATH, 'x.png')}
y = {'letra': 'Y', 'imagen': os.path.join(PATH, 'y.png')}
z = {'letra': 'Z', 'imagen': os.path.join(PATH, 'z.png')}

images = {BLANK: blank, A: a, B: b, C: c, D: d, E: e, F: f,
          G: g, H: h, I: i, J: j, K: k, L: l, LL: ll, M: m,
          N: n, Ñ: ñ, O: o, P: p, Q: q, R: r, RR: rr, S: s,
          T: t, U: u, V: v, W: w, X: x, Y: y, Z: z}

initial_atril = []

images_keys = list(images.keys())
images_keys.remove(0)
for i in range(0,7):
    initial_atril.append(random.choice(images_keys))

def render_square(image, key):
    return sg.RButton('', image_filename=image, size=(1, 1), pad=(0, 0), key=key)

'''
Refresca el atril en base a un movimiento. Esto se realiza haciendo un update en
los botones dependiento los nuevos valores del "board"
En este caso, si encuentra valores en 0,
actualizaría la imagen del boton con un "blank"
'''
def redraw_atril(window, board):
    for i in range(7):
        piece_image = images[board[i]]['imagen']
        elem = window.FindElement(key=i)
        elem.Update(image_filename=piece_image)

'''
Refresca el tablero en base a un movimiento. Esto se realiza haciendo un update en
los botones dependiento los nuevos valores del "board"
'''
def redraw_tablero(window, board):
    for i in range(10):
        for j in range(10):
            piece_image = images[board[i][j]]['imagen']
            elem = window.FindElement(key=(i, j))
            elem.Update(image_filename=piece_image)

# Define qué tipo de movimiento se debera seguir en la agregacion de letras al tablero
def get_orientation(movimiento_actual, movimiento_anterior):
    orientation = ORIENTATION_ERROR
    # eje X sumo 1 y la Y quedo igual, se va pa la derecha
    if movimiento_anterior[0] == movimiento_actual[0] and movimiento_anterior[1]+1 == movimiento_actual[1]:
        orientation = ORIENTATION_RIGHT
    if movimiento_anterior[0]+1 == movimiento_actual[0] and movimiento_anterior[1] == movimiento_actual[1]:
        orientation = ORIENTATION_DOWN
    return orientation

'''
Define si el movimiento es el correcto dependiendo de qué sentido se haya
fijado al principio de agregada la segunda letra
'''
def correct_movement(movimiento_actual, movimiento_anterior, orientation):
    if get_orientation(movimiento_actual, movimiento_anterior) == orientation:
        return True
    else:
        return False

def Play():
    board_tablero = copy.deepcopy(initial_tablero)
    board_atril = copy.deepcopy(initial_atril)

    # Genero una matriz de 10x10 de tipo RButton con las imagenes en blanco
    tablero = []
    for i in range(10):
        row = []
        for j in range(10):
            piece_image = images[BLANK]
            row.append(render_square(piece_image['imagen'], key=(i, j)))
        tablero.append(row)

    # Genero un array de 7 elementos de tipo RButton con las imágenes de las letras aleatorias
    atril = []
    for i in range(7):
        row = []
        piece_image = images[board_atril[i]]
        row.append(render_square(piece_image['imagen'], key=i))
        atril.append(row)

    board_tab = [[sg.Button('CHECK')], [sg.Column(atril), sg.Column(tablero)]]
    window = sg.Window('ScrabbleAr', default_button_element_size=(12, 1), auto_size_buttons=False).Layout(board_tab)

    word = ''
    move_from = move_to = -1
    first_movement = True
    orientation = ORIENTATION_NONE
    # Temporal para no permitir el click en el atril de los "blancos"
    keys_chosen = []

    while True:
        while True:
            button, value = window.Read()
            if button == 'CHECK':
                if len(word) >= 2 and len(word) <=7:
                    wordType = tag(word)[0][1]
                    if wordType == 'VB':
                        sg.Popup('La palabra existe y es un verbo: ', word)
                    else:
                        sg.Popup('La palabra no es un verbo: ', word)
                    # Si esta bien, calcular puntos y luego cambia el turno
                else:
                    sg.Popup('Atención: ', 'La palabra formada no cumple con los mínimos ni máximos')
            if button in (None, 'Exit'):
                exit()
            # Click origen
            if type(button) is int:
                if button in keys_chosen:
                    sg.Popup('Atención: ', 'Click incorrecto, este elemento esta vacio')
                    break
                if move_from != -1:
                    sg.Popup('Atención: ', 'Click incorrecto, debe insistir en el tablero')
                    break
                move_from = button
                # Busco que numero de letra esta en la posicion clickeada
                piece = board_atril[move_from]
                letter_choosen = images[board_atril[move_from]]['letra']
                keys_chosen.append(button)
            # click destino
            if type(button) is tuple:
                if move_from == -1:
                    sg.Popup('Atención: ', 'Click incorrecto, debe insistir en el atril')
                    break
                move_to = button
                row, col = move_to

                if first_movement == False:
                    if orientation == ORIENTATION_NONE:
                        orientation = get_orientation(move_to, move_to_anterior)
                    if orientation == ORIENTATION_ERROR:
                        sg.Popup('Atención: ', 'No se pudo calcular el sentido')
                        orientation = ORIENTATION_NONE
                        break
                    if not correct_movement(move_to, move_to_anterior, orientation):
                        sg.Popup('Atención: ', 'Movimiento incorrecto')
                        break

                # La posicion de la letra que se fue queda en 0
                board_atril[move_from] = BLANK
                # El tablero queda con el numero "nuevo"
                board_tablero[row][col] = piece
                # Luego tengo que "redibujar" ambos tableros
                redraw_atril(window, board_atril)
                redraw_tablero(window, board_tablero)
                word = word + letter_choosen

                move_to_anterior = move_to
                move_from = move_to = -1
                first_movement = False
                break

Play()


from __future__ import division

import blockdiag.drawer
from blockdiag.utils import XY, Box

from nwdiag.metrics import DiagramMetrics

class DiagramDraw(blockdiag.drawer.DiagramDraw):
    def create_metrics(self, *args, **kwargs):
        return DiagramMetrics(*args, **kwargs)

    def __init__(self, _format, diagram, filename=None, **kwargs):
        super(DiagramDraw, self).__init__(_format, diagram, filename, **kwargs)
        self.drawer.set_options(jump_forward='vertical',
                                jump_radius=self.metrics.jump_radius,
                                jump_shift=self.metrics.jump_shift)

    @property
    def groups(self):
        return self.diagram.groups

    def pagesize(self, scaled=False):
        return super(DiagramDraw, self).pagesize(scaled).to_integer_point()

    def _draw_background(self):
        super(DiagramDraw, self)._draw_background()
        self.trunklines_shadow()

    def trunklines_shadow(self):
        for network in self.diagram.networks:
            if network.hidden is False and network.color != 'none':
                self.trunkline(network, shadow=True)

    def trunklines(self):
        metrics = self.metrics
        for network in self.diagram.networks:
            if network.hidden is False:
                self.trunkline(network)

                if (self.diagram.external_connector and
                   (network == self.diagram.networks[0])):
                    r = metrics.trunk_diameter // 2

                    pt = metrics.network(network).top
                    pt0 = XY(pt.x, pt.y - metrics.span_height * 2 // 3)
                    pt1 = XY(pt.x, pt.y - r)

                    self.drawer.line([pt0, pt1], fill=network.linecolor)

    def trunkline(self, network, shadow=False):
        metrics = self.metrics
        m = metrics.network(network)
        r = metrics.trunk_diameter // 2

        pt1, pt2 = m.trunkline
        box = Box(pt1.x, pt1.y - r, pt2.x, pt2.y + r)

        if shadow:
            xdiff = self.metrics.shadow_offset.x
            ydiff = self.metrics.shadow_offset.y // 2

            box = Box(pt1.x + xdiff, pt1.y - r + ydiff,
                      pt2.x + xdiff, pt2.y + r + ydiff)

        if self.format == 'SVG':
            from blockdiag.imagedraw.simplesvg import pathdata

            path = pathdata(box[0], box[1])
            path.line(box[2], box[1])
            path.ellarc(r // 2, r, 0, 0, 1, box[2], box[3])
            path.line(box[0], box[3])
            path.ellarc(r // 2, r, 0, 0, 1, box[0], box[1])

            if shadow:
                self.drawer.path(path, fill=self.shadow, filter='blur')
            else:
                self.drawer.path(path, fill=network.color,
                                 outline=network.linecolor)

                path = pathdata(box[2], box[3])
                path.ellarc(r // 2, r, 0, 0, 1, box[2], box[1])
                self.drawer.path(path, fill='none', outline=network.linecolor)

                # for edge jumping
                line = (XY(box[0], box[1]), XY(box[2], box[1]))
                self.drawer.line(line, fill='none', jump=True)
        else:
            lsection = Box(box[0] - r // 2, box[1], box[0] + r // 2, box[3])
            rsection = Box(box[2] - r // 2, box[1], box[2] + r // 2, box[3])

            if shadow:
                color = self.shadow
                _filter = 'blur'
            else:
                color = network.color
                _filter = None

            # fill background
            self.drawer.rectangle(box, outline=color,
                                  fill=color, filter=_filter)
            self.drawer.ellipse(lsection, outline=color,
                                fill=color, filter=_filter)
            self.drawer.ellipse(rsection, outline=color,
                                fill=color, filter=_filter)

            if not shadow:
                upper = (XY(box[0], box[1]), XY(box[2], box[1]))
                self.drawer.line(upper, fill=network.linecolor, jump=True)

                bottom = (XY(box[0], box[3]), XY(box[2], box[3]))
                self.drawer.line(bottom, fill=network.linecolor, jump=True)

                self.drawer.arc(lsection, 90, 270, fill=network.linecolor)
                self.drawer.ellipse(rsection, outline=network.linecolor,
                                    fill=network.color)

    def _draw_elements(self):
        self.trunklines()

        for network in self.diagram.networks:
            self.trunkline_label(network)

        super(DiagramDraw, self)._draw_elements()

    def trunkline_label(self, network):
        if network.display_label:
            m = self.metrics.network(network)
            self.drawer.textarea(m.textbox, network.display_label,
                                 self.metrics.font_for(network),
                                 fill=network.textcolor, halign="right")

    def node(self, node, **kwargs):
        m = self.metrics

        for connector in m.node(node).connectors:
            self.draw_connector(connector)
            if hasattr(connector, 'subject'):
                network = connector.subject.network
            else:
                network = connector.network

            if network in node.address:
                label = node.address[network]
                self.drawer.textarea(connector.textbox, label,
                                     self.metrics.font_for(node),
                                     fill=node.textcolor, halign="left")

        super(DiagramDraw, self).node(node, **kwargs)

    def draw_connector(self, connector):
        if hasattr(connector, 'subject'):
            linecolor = connector.subject.network.linecolor
        else:
            linecolor = connector.network.linecolor
        self.drawer.line(connector.line, fill=linecolor, jump=True)

    def group_label(self, group):
        if group.label:
            m = self.metrics.cell(group)
            self.drawer.textarea(m.grouplabelbox, group.label,
                                 self.metrics.font_for(group),
                                 valign='top', fill=group.textcolor)


# -*- coding: utf-8 -*-
"""
Python 18_11_05

"""

# 맞교환

a = 20
b = 30

a = b
a

k = 'Korea'
j = 'Japan'

k, j = j, k
k
j

# 원소 넣기 / packing, unpacking

d = (1, 2, 3, 4)
t = d
t
t1, t2, t3, t4 = t
print(t1, t2, t3, t4)

# 데코레이터, @staticmethod, @classmethod
class Date(object):
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
        print(" Date__init__ ")

    def __str__(self):
        return "{}년 {}월 {}일 생산".format(self.year, self.month, self.day)

class Ktx:
    def __init__(self, station, fee):
        self.station = station
        self.fee = fee
        print("인수 2개 __init__")

    def __del__(self):
        print(" __del__ ")

    def __str__(self):
        return " {} *** {}원 ".format(self.station, self.fee)

k1 = Ktx("부산역", 49000)
k2 = Ktx("대전역", 24000)

print(k1)
print(k2)

k3 = Ktx() ## error. station, fee argument를 안 받았기 때문.

class Ktx:
    def __init__(self, station, fee):
        self.station = station
        self.fee = fee
        print("인수 2개 __init__")
    # 다음 부분 추가
    def __init__(self):
        self.station = "이름 없음"
        self.fee = 0
        print("인수 없음 __init__")

    def __del__(self):
        print(" __del__ ")

    def __str__(self):
        return " {} *** {}원 ".format(self.station, self.fee)

k3 = Ktx()

print(k3)

# 합쳐서 다음과 같이 표현 가능
class Ktx:
    def __init__(self, station = "이름 없음", fee = 0): ## Default 설정
        self.station = station
        self.fee = fee
        print("인수 2개 __init__")

    def __del__(self):
        print(" __del__ ")

    def __str__(self):
        return " {} *** {}원 ".format(self.station, self.fee)

k4 = Ktx() # 인자를 하나도 안 준 경우 default
print(k4)

k5 = Ktx("울산역") # 하나만 준 경우 할당된 인자 외에 default
print(k5)

k5.station
a = k5.station
a

# get, set 추가
class Ktx:
    def __init__(self, station = "이름 없음", fee = 0): ## Default 설정
        self.station = station
        self.fee = fee
        print("인수 2개 __init__")

    def __del__(self):
        print(" __del__ ")

    def __str__(self):
        return " {} *** {}원 ".format(self.station, self.fee)

    def get_station(self):
        return self.station

    def get_fee(self):
        return self.fee

    def set_station(self, station):
        self.station = station

    def set_fee(self, fee):
        self.fee = fee

k1 = Ktx("부산역", 49000)
k2 = Ktx("대전역", 24000)
k2.set_station("목포역")
k2.set_fee(47000)
print(k1, k2)

# cnt 추가(class 변수)
## classmethod(객체 하나하나에 종속되는 것이 아닌 class 전체에서 사용하는 method)
class Ktx:
    cnt = 0  ## class 변수

    @staticmethod
    def get_cnt_st():
        print("현재 객체수는 : ", Ktx.cnt)

    @classmethod
    def get_cnt(cls):
        print("현재 객체 수는 : ", Ktx.cnt)

    def __init__(self, station = "이름 없음", fee = 0): ## Default 설정
        self.station = station
        self.fee = fee
        Ktx.cnt += 1
        print("인수 2개 __init__")

    def __del__(self):
        Ktx.cnt -= 1
        print(" __del__ ")

    def __str__(self):
        return " {} *** {}원 ".format(self.station, self.fee)

    def get_station(self):
        return self.station

    def get_fee(self):
        return self.fee

    def set_station(self, station):
        self.station = station

    def set_fee(self, fee):
        self.fee = fee

k1 = Ktx("부산역", 49000)
k2 = Ktx("대전역", 24000)
k3 = Ktx()
k4 = Ktx("울산역")

Ktx.cnt
k1.cnt ## 객체를 통해서도 class 변수에 접근 가능( 왜?? )
Ktx.get_cnt()

del Ktx, k1, k2, k3, k4

# comprehension method

import sys

a = 100
b = 200
aa = [2, 4, 6]
bb = ["kbs", "mbc", "sbs"]

sys.getsizeof(a)
sys.getsizeof(b)
sys.getsizeof(aa)
sys.getsizeof(bb)

aa = []
len(aa)
for i in range(20):
    aa.append(i + 5)

aa
sys.getsizeof(aa)

jj = [j + 5 for j in range(10)]
jj
sys.getsizeof(jj)

kk = (i for i in range(20))
kk

kk.__next__()
sys.getsizeof(kk)
next(kk)

jj = [j for j in range(100)]
jj
j3 = iter(jj)
sys.getsizeof(jj)
sys.getsizeof(j3)

sys.path
sys.maxsize

# time
import time

## 1970년 1월 1일 0시 0분 0초 기준
t1 = time.time()
print(" {} 초".format(t1))
print(" {} 초".format(int(t1)))

## 구조체 : method가 없고 field만 있는 class
t2 = time.gmtime() ## global time
print(t2)
print("{}/{}/{}".format(t2.tm_year, t2.tm_mon, t2.tm_mday))
print("{}:{}:{}".format(t2.tm_hour, t2.tm_min, t2.tm_sec))

t3 = time.localtime() ## 내 컴퓨터 시간
print(t3)
print("{}/{}/{}".format(t3.tm_year, t3.tm_mon, t3.tm_mday))
print("{}:{}:{}".format(t3.tm_hour, t3.tm_min, t3.tm_sec))

start = time.time()
for i in range(1000):
    print("싫어", end = '')
end = time.time()

print("\n")
print( " 소요 시간 : ", end - start)

# datetime
import datetime as dt

now = dt.datetime.now()
print("{}/{}/{}".format(now.year, now.month, now.day))
print("{}:{}:{}".format(now.hour, now.minute, now.second))

import calendar as cld

c = cld.calendar(2018)
print(c)

print(cld.month(2019,5))

def whatwdy():
    week = ["월", "화", "수", "목", "금", "토", "일"]
    print(" 생년월일을 입력하세요.")
    year = int(input(" 연도 > "))
    month = int(input(" 월 > "))
    day = int(input(" 일 > "))

    q = cld.weekday(year, month, day)
    print(" 나는 {}요일에 태어났어요.".format(week[q]))

whatwdy()

# file 다루기

f = open("c:\\dd\\mon.txt", "r")
a = f.read()
print(a)
f.close()

f = open("c:\\dd\\33.txt", "w")
f.write("배가 고파요\n")
f.write("배꼽시계가 울려요\n")
f.close()
## 그냥 w로 불러와 쓰면 덮어쓴다. a 사용
f = open("c:\\dd\\33.txt", "a")
f.write("빨리 끝내주세요\n")
f.close()
f = open("c:\\dd\\44.txt", "a")
for i in range(50):
    f.write("배고파")
f.close()

f.write("\n")
for i in range(5):
    name = input(" 이름 > ")
    f.write(name)
    f.write("\n")

f.close()

f = open("c:\\dd\\ace.txt", "r")
print(f.read())

# sql 연결

import sqlite3 as sql

conn = sql.connect('c:\\dd\\adb') # db 연결
c = conn.cursor() # 커서 연결

c.execute('drop table if exists Lunch')
c.execute("create table Lunch(menu char(20), price int)")
c.execute("insert into Lunch values('비빔밥', 7000)")
c.execute("insert into Lunch values('볶음밥', 8000)")
c.execute("insert into Lunch values('짜장면', 6000)")

conn.commit()

c.execute("select * from Lunch")
k = c.fetchall()

for i in k:
    print(" {} {}원".format(i[0], i[1]))

c.execute('drop table if exists ltx')

c.close() # 커서 닫고
conn.close() # db 닫고

menu = input(" 좋아하는 메뉴 : ")
price = int(input(" 가격 : "))
c.execute("insert into Lunch(menu, price) values(?, ?)", (menu, price))

#################################
a = []

with open("c:\\dd\\ss.txt", 'r') as f:
	for i in range(10):
		a.append(f.readline().split())

for i in range(len(a)):
	for j in range(1,4):
		a[i][j] = int(a[i][j])
	a[i].append(sum(a[i][1:4]))
	a[i].append(round((a[i][4] / 3), 2))

korT = 0
engT = 0
matT = 0

for i in range(len(a)):
	korT += a[i][1]
	engT += a[i][2]
	matT += a[i][3]

korA = korT / len(a)
engA = engT / len(a)
matA = matT / len(a)

everyT = korT + engT + matT
everyA = everyT / (3 * len(a))
#########################

## 성적 처리

conn = sql.connect('c:\\dd\\adb')
c = conn.cursor()

c.execute("drop table if exists students")
c.execute("create table students(\
        name char(20), kor int, eng int, mat int, tot int, avg int)")

sql1 = "insert into students(name, kor, eng, mat, tot, avg) values(?, ?, ?, ?, ?, ?)"

for i in range(10):
    c.execute(sql1, (a[i][0], a[i][1], a[i][2], a[i][3], a[i][4], round(a[i][5])))

c.execute("select * from students")
conn.commit()
kk = c.fetchall()

f = open('c:\\dd\\source.txt', 'w')

f.write(" *************** 성 적 표 ************** \n")
f.write(" *************************************** \n")
f.write("  이 름  국어  영어  수학  총점    평균  \n")
f.write(" *************************************** \n")

for i in range(len(a)):
	f.write(" {} {:5d} {:5d} {:5d} {:5d} {:7.2f} \n"
              .format(kk[i][0], kk[i][1], kk[i][2], kk[i][3], kk[i][4], kk[i][5]))

f.write(" ************************************** \n")
f.write(" 총평균 {:5.1f} {:5.1f} {:5.1f} {:5d} {:7.2f} \n"
      .format(korA, engA, matA, everyT, everyA))

f.close()

#############################성적 처리 source.txt로 저장
########################################################

# 엑셀 파일 부르기

import openpyxl

exf = openpyxl.load_workbook('c:\\dd\\ss.xlsx')
aws = exf.active

print(" *************** 성 적 표 ************** ")
print(" *************************************** ")
print("  이 름  국어  영어  수학  총점    평균  ")
print(" *************************************** ")

for i in aws.rows:
    index = i[0].row
    name = i[0].value
    kor = i[1].value
    eng = i[2].value
    mat = i[3].value
    total = kor + eng + mat
    avg = total / 3

    aws.cell(row = index, column = 5).value = total
    aws.cell(row = index, column = 6).value = avg

    print(" {} {:5d} {:5d} {:5d} {:5d} {:7.2f} "
              .format(name, kor, eng, mat, total, avg))

print(" *************************************** ")
exf.save("c:\\dd\\report.xlsx")
exf.close()

# 예외 처리
g = [j*5 for j in range(10)]
gg = iter(g)
while True:
    try:
        num = next(gg)

    except:
        print(" 범위 끝났어 ")
        break
    print(num)

a = [1, 2, 3]

try:
    #a[0] / 0
    #a[5] = 6
    a[2] + "good"

except ZeroDivisionError:
    print(" 0으로 못나눠용 ")

except IndexError:
    print(" 인덱스를 벗어났어 ")

except TypeError:
    print(" type이 맞지 않아 ")

finally:
    print(" 무조건 실행 ")

# 난수 생성

import random

print(" * 0 ~ 1 사이의 값 * ")
print(" ****************** ")
for i in range(10):
    print(random.random())

print(" * 1 ~ 1000 사이의 값 * ")
print(" ********************* ")
for i in range(10):
    print(random.randint(1,1000))

## 로또 번호 추출
for i in range(5):
    num = random.sample(range(1,46), 6)
    num.sort()
    print(num)

# os modules

import os
os.system("notepad")
os.system("mspaint")
os.sys
os.path
os.mkdir("dir")
os.mkdir("c:\\dd\\OK")
os.mkdir("c:\\dd\\파이썬")

## os 모듈 이용
def osmodules():
    import os
    import random as rd

    while True:
        print(" ***** 메 뉴 ***** ")
        print(" ***************** ")
        print("  1. 계산기        ")
        print("  2. 메모장        ")
        print("  3. 명령 프롬프트 ")
        print("  4. 숫자 맞추기   ")
        print("  0. 프로그램 종료 ")
        print(" ***************** ")
        menu = int(input(" 메뉴를 고르세요 > "))

        if menu == 0:
            print(" 종료헙니다. ")
            break

        if menu == 1:
            print(" 계산기 실행 ")
            os.system('calc')

        if menu == 2:
            print(" 메모장 실행 ")
            os.system('calc')

        if menu == 3:
            print(" 명령 프롬프트 실행 ")
            os.system('cmd')

        if menu == 4:
            print(" 숫자 맞추기 실행 ")
            num = int(input(" 1부터 원하는 숫자 범위를 고르세요 > "))
            random_number = rd.randint(1,num)

            cnt = 0
            print("1 ~", num, " 중에 고르세요!")

            while True:
                pick = int(input("Pick > "))
                cnt += 1
                if pick == random_number:
                    print("{}번 만에 맞추셨습니다!".format(cnt))
                    break

                elif pick > random_number:
                    print("{} 보다는 작습니다!".format(pick))

                else:
                    print("{} 보다는 큰 것 같습니다!".format(pick))
                    continue

        else:
            print(" 존재하지 않는 메뉴입니다. ")
            print(" 다시 고르세요. ")
            continue


# -*- coding: utf-8 -*-
"""
Created on Wed May  6 13:47:27 2015

@author: tim
"""

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

import sqlite3

from tornado.options import define,options
define("port",default=8000,help="run on the given port",type=int)

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [(r"/(\w+)",WorkHandler)]
        tornado.web.Application.__init__(self,handlers,debug=True)

class WorkHandler(tornado.web.RequestHandler):
    def get(self,word):
        conn = sqlite3.connect('book.db')
        curs = conn.cursor()
        curs.execute('select * from book where _rowid_ =?',word)
        word_doc=curs.fetchone()
        if word_doc:
            self.write(word_doc[0]+'\n')
        else:
            self.set_status(404)
            self.write({"error":"Word not found"})
    def post(self,word):
        definition = self.get_argument('name')
        conn = sqlite3.connect('book.db')
        curs = conn.cursor()
        curs.execute('select * from book where _rowid_ =?',word)
        word_doc=curs.fetchone()
        if word_doc:
            curs.execute('update book set name = ?',word_doc[0])
        else:
            curs.insert('insert into book values(?,?)',[(definition,10000)])
        curs.commit()
        self.write(word_doc)

if __name__ == "__main__":
    tornado.options.parse_command_line()
    http_server = tornado.httpserver.HTTPServer(Application())
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()


#!/usr/bin/env python

# This displays in a JSON variable, the list of RDF URLs exposed by the SLP protocol.
# Because these queries are slow, there is a caching mechanism which can be controlled
# with a CGI parameter.

import os
import re
import cgi
import time
import glob
import math
import lib_common

# Writes to the file descriptor, the JSON variable.
def MakeCacheSlp(filDes):
	service_filter = "http.rdf"

	filDes.write( "Content-type: text/javascript\n\n" )

	# This variable name is used in the Javascript function FillSlpUrlsTable.
	# And also by some Javascript code in merge_rdf_inputs_graphviz_only.htm
	filDes.write( "var slps = [" )

	# Only the services we want. They are published by the slpd process of machines on the LAN.
	stream = os.popen("slptool findsrvs service:" + service_filter)
	# service:ftp.smallbox://192.168.100.1:21,65535
	lbl = 0
	for line in stream:
		# print "Li=" + line
		matchObj = re.match( r'service:([^:]*):/?/?([^,]*),?(.*)', line, re.M|re.I)
		if matchObj:
			filDes.write(	'[' \
				+ '"' + matchObj.group(1) + '",' \
				+ '"http://' + matchObj.group(2) + '",' \
				+ '"' + matchObj.group(3) + '",' \
				+ '"label_' + str(lbl)  + '"' \
				+ '],' )
			lbl = lbl + 1

	# print( '["a","b","c","d"]' )
	filDes.write( "];" )

# This generates a form containing the SLP urls in a variable.
# It manages a cache, because SLP queries are slow.

arguments = cgi.FieldStorage()

# Validity in seconds.
# HARDCODE_LIMIT
try:
	cache_validity = arguments["validity"].value
except KeyError:
	# Default, valid during one hour.
	cache_validity = 3600

nowSeconds = int( time.time() )

cache_directory = lib_common.TmpDir() + "/"

cache_prefix = "cache_slp."

glob_prefix = cache_directory + cache_prefix
possible_caches = glob.glob( glob_prefix + "*" )

best_cache = ''
best_stamp = 0

for fil in possible_caches:
	# print("fil=" + fil )
	# Reads the time-stamp at the end of the cache filename.
	timstamp_str = fil[ len(glob_prefix) : ]
	timstamp_int = int( timstamp_str )
	if timstamp_int > best_stamp:
		# Maybe removes the old cache.
		if best_stamp != 0 :
			os.remove(best_cache)
		best_stamp = timstamp_int
		best_cache = fil

if best_stamp < nowSeconds - cache_validity:
	# If a cache file was found, but is invalid, removes it.
	if best_stamp != 0 :
		os.remove(best_cache)
	best_cache = glob_prefix + str(nowSeconds)
	filDes = open(best_cache,'w')
	MakeCacheSlp(filDes)
	filDes.close()

# TODO: If the file is empty, maybe the validity could be shorter?

filDes = open(best_cache, 'r')
print( filDes.read() )

# The file descriptor might be stdout
# in case we cannot write to a temporary file.

# TODO
# We assume that some or all of these URLs are in fact bookmarks pages which contain
# the URLs that we want. The advantage is that when we create a dynamic CGI
# with a specific set of CGI parameters, it is not necessary to register it with
# SLP or any other exposing mechanism.
#
# What must be done is:
#	- Expose bookmarks.
#	- Have a way to distinguish  normal URL from bookmarks.
#	- To make things cleaner: Maybe return categories of links.
#	This is necessary to show that an URL can be destroyed.
#
#
# Also: Create a cache so there is no need to make a SLP query at each call.
#
# Convention: the service "http.bookmark" indicates a bookmark of RDF cgis.


from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
dc = DesiredCapabilities.CHROME
dc['goog:loggingPrefs'] = {'browser': 'ALL'}
driver = webdriver.Chrome(executable_path="/Users/jiniab/Downloads/chromedriver-3", desired_capabilities=dc)
driver.get("https://www.google.com")
for e in driver.get_log('browser'):
    print(str(e))
driver.quit()


from pwn import *
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from server_genCookie import encode_profile, profile_for

# Configuration data
HOST = '127.0.0.1'
PORT_GEN = 12345
PORT_TEST = 12445

if __name__ == '__main__':

    # Opening connection to the server that generates a cookie
    conn_gen = remote(HOST, PORT_GEN)
    email = b'aaaaaaa@b.com'

    # Sending data
    conn_gen.send(email)
    cookie = conn_gen.recv()
    print("Encrypted cookie is: " + cookie.hex())

    # Computing cookie info
    # length of email is 13 bytes in order to align the start of the "admin" exactly at third block
    cookie_info = encode_profile(profile_for(email.decode()))
    print(cookie_info[0:AES.block_size])
    print(cookie_info[AES.block_size:2*AES.block_size])

    # Computing cookie info
    # this time we try to align the "admin" word to the second block
    padded_message = b'A'*10 + pad(b'admin', AES.block_size)
    cookie_info = encode_profile(profile_for(padded_message.decode()))
    print(cookie_info[0:AES.block_size])
    print(cookie_info[AES.block_size:2*AES.block_size])

    conn_gen.close()

    # Opening again connection to the server that generates a cookie
    conn_gen = remote(HOST, PORT_GEN)

    # Sending data
    conn_gen.send(padded_message)
    cookie_2 = conn_gen.recv()
    print()
    print()
    print(cookie_2)
    conn_gen.close()

    # Crafting authentication cookie and check on server
    auth_cookie = cookie[0:32] + cookie_2[16:32]
    conn_test = remote(HOST, PORT_TEST)
    conn_test.send(auth_cookie)
    response = conn_test.recv()

    print(response.decode())

Cryptography/Python/02 - Attacks on ECB/Copy and Paste Attack (CPA)/attacker.py


import heapq
from typing import List

class Solution1_DP:
    def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:
        mask = 0
        self.profits = profits
        self.capital = capital
        self.max_tasks = 2**len(self.profits)
        return self.solve(0, k, w) + w

    def set_bit(self, mask, bit):
        mask |= 1 << bit
        return mask

    def solve(self, mask, k, w):
        if k == 0 or mask == self.max_tasks - 1:
            return 0

        max_profit = 0

        for i in range(len(self.profits)):
            taken = (mask & (1 << i))>>i == 1
            if self.capital[i] <= w and not taken:
                f = True
                bbit = self.set_bit(mask, i)
                # print(mask, bbit)
                tmp = self.solve(bbit, k - 1, w + self.profits[i]) + self.profits[i]

                if tmp > max_profit:
                    max_profit = tmp

        return max_profit

class Solution_without_heap:
    def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:
        visited = 0
        self.profits = profits
        self.capital = capital

        # greedy solution
        # 1. find the maximum profit for available projects (a. not taken b. capital <= current_capital
        # 2. Do that project: a. add the profit to w  b. mark it as visited

        for i in range(k):
            max_prof = -1
            max_i = -1

            for project_i in range(len(self.capital)):
                # check if project is available
                if self.get_bit(visited, project_i) == 0 and self.capital[project_i] <= w:
                    if max_prof < self.profits[project_i]:
                        max_prof = self.profits[project_i]
                        max_i = project_i

            if max_prof == -1:
                return w

            w += self.profits[max_i]
            visited = self.set_bit(visited, max_i)

        return w

    def set_bit(self, mask, bit):
        mask |= 1 << bit
        return mask

    def get_bit(self, mask, bit):
        return (mask & (1 << bit)) >> bit

class Solution:
    def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:
        visited = 0
        self.profits = profits
        self.capital = capital
        cap_profit_heap = list(zip(self.capital, self.profits))
        heapq.heapify(cap_profit_heap)

        # greedy solution + Heap for maximum available profit
        # 1. find the "maximum profit" for available projects (a. not taken b. capital <= current_capital
        # 2. Do that project: a. add the profit to w  b. mark it as visited

        available_projects_profits = []

        for i in range(k):
            for project_i in range(len(cap_profit_heap)):
                cap, profit = cap_profit_heap[0]

                if cap <= w:
                    heapq.heappush(available_projects_profits, profit * -1)
                    heapq.heappop(cap_profit_heap)
                else:
                    break

            if len(available_projects_profits) == 0:
                return w

            w += heapq.heappop(available_projects_profits) * -1

        return w

if __name__ == '__main__':
    m = Solution().findMaximizedCapital(1, 2, [1,2,3], [1,1,2])
    print(m)
    # m = Solution().findMaximizedCapital(2, 0, [1,2,3], [0,1,1])
    # print(m)


import logging

from django.contrib.auth.models import User
from dry_rest_permissions.generics import DRYPermissions
from rest_framework import mixins, status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

from api.models import UserDetail
from api.serializers import UserDetailSerializer, UserTeamSerializer

log = logging.getLogger("__name__")

class UserViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    This viewset automatically provides `list` actions.
    """

    serializer_class = UserTeamSerializer
    queryset = User.objects.all()

    def list(self, request, **kwargs):
        if not request.user.is_superuser:
            # no super user so return only the current user
            queryset = self.filter_queryset(self.get_queryset()).filter(
                id=request.user.id
            )
        else:
            # super user can query all users
            queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

class UserDetailViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` actions.

    The list action will always return the current user's userdetail as a list
    or an empty list if the current user has no userdetail
    """

    permission_classes = (DRYPermissions,)
    serializer_class = UserDetailSerializer
    queryset = UserDetail.objects.all()

    custom_serializer_map = {
        "list": UserDetailSerializer,
    }

    def list(self, *args, **kwargs):
        try:
            userdetail = [self.request.user.userdetail]
        except UserDetail.DoesNotExist:
            userdetail = []
        serializer = self.get_serializer(userdetail, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=["get"], url_path="me", url_name="me")
    def me(self, request):
        try:
            userdetail = self.request.user.userdetail
        except UserDetail.DoesNotExist or AttributeError:
            userdetail = None
        serializer = self.get_serializer(userdetail, many=False)
        return Response(serializer.data)

    def create(self, request, *args, **kwargs):
        try:
            userdetail = self.request.user.userdetail
            # return forbidden if the user has already a userdetail
            return Response(status=status.HTTP_403_FORBIDDEN)
        except:
            pass
        return super().create(request, *args, **kwargs)

    def perform_create(self, serializer):
        serializer.save(
            user=self.request.user,
        )