import random

import numpy as np
import pytest

from common.crypto.paillier.context import PaillierContext
from common.crypto.paillier.paillier import Paillier

data = [
    (True, None, True, -1),
    (True, 7, True, -1),
    (True, 7, False, 1),
    (False, None, True, -1),
    (False, 7, True, -1),
    (False, 7, False, 1)
]

data2 = [
    (True,),
    (False,)
]

class TestPaillier():
    def setup_class(self):
        self.context = PaillierContext.generate(2048)
        self.epsilon = 1e-5

    def teardown_class(self):
        pass

    def test_context(self):
        a = self.context.serialize(save_private_key=False)
        b = PaillierContext.deserialize_from(a)
        with pytest.raises(AssertionError):
            assert self.context == b

        a = self.context.serialize(save_private_key=True)
        b = PaillierContext.deserialize_from(a)
        assert self.context == b

    @pytest.mark.parametrize("djn_on, precision, is_batch, num_cores", data)
    def test_unary(self, djn_on, precision, is_batch,  num_cores):
        s = (50,)
        if is_batch:
            p1 = np.random.random(s).astype(np.float32) * 100 - 50
        else:
            p1 = random.random() * 100 - 50

        # encrypt
        c1 = Paillier.encrypt(self.context, p1, precision=precision, max_exponent=None, obfuscation=True, num_cores=num_cores)

        # encrypt
        pub_context = self.context.to_public()
        c11 = Paillier.encrypt(pub_context, p1, precision=precision, max_exponent=None, obfuscation=True, num_cores=num_cores)

        # decrypt
        a = Paillier.decrypt(self.context, c1, num_cores=num_cores)
        assert (np.all(a - p1 < self.epsilon))

        b = Paillier.decrypt(self.context, c11, num_cores=num_cores)
        assert (np.all(b - p1 < self.epsilon))

        with pytest.raises(TypeError):
            Paillier.decrypt(pub_context, c1, num_cores=num_cores)

    @pytest.mark.parametrize("djn_on, precision, is_batch, num_cores", data)
    def test_binary(self, djn_on, precision, is_batch,  num_cores):
        s = (50,)
        if is_batch:
            p1 = np.random.random(s).astype(np.float32) * 100 - 50
            p2 = np.random.random(s).astype(np.float32) * 100 - 20
        else:
            p1 = random.random() * 100 - 50
            p2 = random.random() * 100 - 20

        # encrypt
        c1 = Paillier.encrypt(self.context, p1, precision=precision, max_exponent=None, obfuscation=True, num_cores=num_cores)
        c2 = Paillier.encrypt(self.context, p2, precision=precision, max_exponent=None, obfuscation=True, num_cores=num_cores)

        # sum
        if is_batch:
            c3 = sum(c1)
            a = Paillier.decrypt(self.context, c3, num_cores=num_cores)
            assert (a - sum(p1) < self.epsilon)

        # add
        c3 = c1 + c2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert (np.all(p3 - (p1 + p2) < self.epsilon))

        # sub
        c3 = c1 - c2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert(np.all(p3 - (p1 - p2) < self.epsilon))

        c21 = Paillier.ciphertext_from(self.context.to_public(), Paillier.serialize(c2))
        c3 = c1 - c21
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert(np.all(p3 - (p1 - p2) < self.epsilon))

        # add scalar
        c3 = c1 + p2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - (p1 + p2) < self.epsilon)

        c3 = p2 + c1
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - (p1 + p2) < self.epsilon)

        # sub scalar
        c3 = c1 - p2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - (p1 - p2) < self.epsilon)

        c3 = p2 - c1
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - (p2 - p1) < self.epsilon)

        c3 = c1 - p2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - (p1 - p2) < self.epsilon)

        c3 = p2 - c1
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - (p2 - p1) < self.epsilon)

        # multiply
        c3 = c1 * p2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - p1 * p2 < self.epsilon)

        c3 = p2 * c1
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - p1 * p2 < self.epsilon)

        c3 = c1 * p2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - p1 * p2 < self.epsilon)

        c3 = p2 * c1
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - p1 * p2 < self.epsilon)

        # divide
        c3 = c1 / p2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - p1 / p2 < self.epsilon)

        c3 = c1 / p2
        p3 = Paillier.decrypt(self.context, c3, num_cores=num_cores)
        assert np.all(p3 - p1 / p2 < self.epsilon)

    @pytest.mark.parametrize("p1_is_batch", data2)
    def test_ciphertext(self, p1_is_batch):
        s = (3, 40)
        context = Paillier.context(2048)
        if p1_is_batch:
            p1 = np.random.random(s).astype(np.float32) * 100 - 50
        else:
            p1 = random.random() * 100 - 50

        context2 = Paillier.context_from(context.to_public().serialize())

        c1 = Paillier.encrypt(context2, p1, precision=None, max_exponent=None, obfuscation=True)
        s1 = Paillier.serialize(c1)

        c2 = Paillier.ciphertext_from(context, s1)
        p2 = Paillier.decrypt(context, c2)
        assert np.all(p1 - p2 < 1e-10)

# def test_paillier():
#     djn_on = True
#     num_cores = 1
#     precision = None
#     cal_paillier(djn_on, precision, True, True, 1e-10, num_cores)
#     # cal_paillier(djn_on, precision, True, False, 1e-10, num_cores)
#     # cal_paillier(djn_on, precision, False, True, 1e-10, num_cores)
#     cal_paillier(djn_on, precision, False, False, 1e-10, num_cores)

# def test_ciphertext(p1_is_batch=True):
#     print("------------ciphertext------------")
#     s = (3, 40)
#     context = Paillier.context(2048)
#     if p1_is_batch:
#         p1 = np.random.random(s).astype(np.float32) * 100 - 50
#     else:
#         # p1 = random.random() * 100 - 50
#         p1 = np.random.random((1,)).astype(np.float32) * 100 - 50

#     c1 = Paillier.encrypt(context, p1, precision=None, max_exponent=None, obfuscation=True)
#     start = time.time()
#     s1 = Paillier.serialize(c1)
#     print('ciphertext serialize:', time.time() - start)

#     start = time.time()
#     c2 = Paillier.ciphertext_from(context, s1)
#     print('ciphertext deserialize:', time.time() - start)
#     p2 = Paillier.decrypt(context, c2)
#     assert np.all(p1 - p2 < 1e-10)

# if __name__ == "__main__":
#     test_context()
#     test_paillier()
#     test_ciphertext(True)


import curses
import locale
import logging
import time

def run(application_class):
    """Run a jinxes application subclass."""
    locale.setlocale(locale.LC_ALL, "")
    curses.wrapper(application_class)

class Exit(Exception):
    """Raise this exception to exit the main application loop."""
    pass

class Application(object):
    """Interactive Curses Application Class

    Abstracts and simplifies curses related calls for input and
    output processing.
    """
    DEFAULT_FG_COLOR = 4
    DEFAULT_BG_COLOR = 16
    BG_CHAR = ' '

    def __init__(self, scr):
        self.logger = logging.getLogger('jinxes')
        curses.curs_set(0)
        self.available_brush_ids = set(xrange(1, curses.COLOR_PAIRS))
        self.allocated_brush_ids = {}
        self.brushes = {}
        self.default_brush = self.get_brush(self.DEFAULT_FG_COLOR,
                                            self.DEFAULT_BG_COLOR)
        scr.nodelay(1)
        self.scr = scr
        scr.bkgdset(ord(self.BG_CHAR), self.default_brush)
        self.actors = {}
        self.paused = False
        self.brush_stacks = {}
        self._border = False
        self.run()

    def notify_created(self, actor):
        self.actors[actor.id] = actor

    def notify_destroyed(self, actor):
        self.clear_location_cache(actor)
        try:
            del self.actors[actor.id]
        except KeyError:
            pass

    def notify_visible(self, actor):
        if actor.visible:
            self.set_location_cache(actor)
        else:
            self.clear_location_cache(actor)

    def notify_moving(self, actor):
        self.clear_location_cache(actor)

    def notify_animating(self, actor):
        self.clear_location_cache(actor)

    def notify_moved(self, actor):
        pass

    def notify_animated(self, actor):
        pass

    def notify_updated(self, actor):
        self.set_location_cache(actor)

    def initialize(self, current):
        self.height, self.width = self.scr.getmaxyx()
        self.top = 0
        self.left = 0
        self.actors_by_location = {}
        for x in xrange(self.width):
            for y in xrange(self.height):
                self.actors_by_location[(x, y)] = []
        self.dirty_by_location = {}
        self.win = curses.newwin(0, 0, 0, 0)
        self.win.bkgd(ord(self.BG_CHAR), self.default_brush)

    def border(self):
        self._border = True
        self.top += 1
        self.left += 1
        self.width -= 2
        self.height -= 2

    def project_x(self, x, width):
        left = x - width * 0.5 / self.width
        return int(left * self.width + 0.5) + self.left

    def project_y(self, y, height):
        top = y - height * 0.5 / self.height
        return int(top * self.height + 0.5) + self.top

    @property
    def x1(self):
        return 1.0 / self.width

    @property
    def y1(self):
        return 1.0 / self.height

    def try_move(self, actor, current, floatx, floaty):
        if actor.bordered:
            halfh = actor.hsize * 0.5 / self.width
            halfv = actor.vsize * 0.5 / self.height
            left = 0.0
            top = 0.0
            right = 1.0
            bottom = 1.0
            if floatx < left + halfh:
                if actor.xvel:
                    floatx = (left + halfh) * 2 - floatx
                    actor.xvel = -actor.xvel
                else:
                    floatx = left + halfh
            elif floatx > right - halfh:
                if actor.xvel:
                    floatx = (right - halfh) * 2 - floatx
                    actor.xvel = -actor.xvel
                else:
                    floatx = right - halfh
            if floaty < top + halfv:
                if actor.yvel:
                    floaty = (top + halfv) * 2 - floaty
                    actor.yvel = -actor.yvel
                else:
                    floaty = top + halfv
            elif floaty > bottom - halfv:
                if actor.yvel:
                    floaty = (bottom - halfv) * 2 - floaty
                    actor.yvel = -actor.yvel
                else:
                    floaty = bottom - halfv
        screenx = self.project_x(floatx, actor.hsize)
        screeny = self.project_y(floaty, actor.vsize)

        if actor.collides:
            actor_collisions = actor.collisions(screenx, screeny)
            all_collisions = {}
            for x, y in actor_collisions:
                try:
                    others = self.actors_by_location[(x, y)]
                except KeyError:
                    continue
                for other in others:
                    if other == actor:
                        continue
                    if not other.collides:
                        continue
                    all_collisions.setdefault(other, []).append((x, y))
            for other, collisions in all_collisions.iteritems():
                if not self.collide(actor, other, current,
                                    collisions, floatx, floaty):
                    return actor.x, actor.y
        return floatx, floaty

    def set_location_cache(self, actor):
        for xoffset in xrange(actor.hsize):
            for yoffset in xrange(actor.vsize):
                if ord(actor.get_ch(xoffset, yoffset)[0]):
                    x = actor.screenx + xoffset
                    y = actor.screeny + yoffset
                    if (x >= self.left and x < self.left + self.width
                        and y >= self.top and y < self.top + self.height):
                        self.dirty_by_location[(x, y)] = True
                        if actor not in self.actors_by_location[(x, y)]:
                            actors = list(self.actors_by_location[(x, y)])
                            for i, other in enumerate(actors):
                                if actor < other:
                                    break
                            else:
                                self.actors_by_location[(x, y)].append(actor)
                                continue
                            self.actors_by_location[(x, y)].insert(i, actor)

    def clear_location_cache(self, actor):
        for xoffset in xrange(actor.hsize):
            for yoffset in xrange(actor.vsize):
                if ord(actor.get_ch(xoffset, yoffset)[0]):
                    x = actor.screenx + xoffset
                    y = actor.screeny + yoffset
                    if (x >= self.left and x < self.left + self.width
                        and y >= self.top and y < self.top + self.height):
                        self.dirty_by_location[(x, y)] = True
                        if actor in self.actors_by_location[(x, y)]:
                            self.actors_by_location[(x, y)].remove(actor)

    def get_location(self, x, y):
        ch, fg, bg = None, None, None
        for actor in reversed(self.actors_by_location[(x, y)]):
            if actor:
                x = x - actor.screenx
                y = y - actor.screeny
                c, f, b, inv = actor.get_ch(x, y)
                if inv:
                    f, b = b, f
                if ch is None and ord(c) and not actor.transparent:
                    ch = c.encode('utf-8')
                if fg is None:
                    fg = f
                if bg is None:
                    bg = b
                if ch is not None and fg is not None and bg is not None:
                    break

        ch = ch or self.BG_CHAR
        fg = fg or self.DEFAULT_FG_COLOR
        bg = bg or self.DEFAULT_BG_COLOR
        return ch, fg, bg

    def collide(self, actor, other, current, collisions, floatx, floaty):
        """Handle collision between actor and other.

        Return floatx, floaty to allow the movement."""
        return floatx, floaty

    def write(self, x, y, text, fg, bg):
        """Write a text string at location with brush."""
        brush = self.get_brush(fg, bg)
        try:
            self.win.addstr(y, x, text, brush)
        except curses.error:
            if x == self.width - 1 and y == self.height - 1:
                pass

    def get_brush(self, fg_color=None, bg_color=None):
        """Get a brush represented by fg and bg color.

        This brush can be used in further curses calls.  Note that the brush
        is and will be garbage collected if we run out of brushes and it is
        no longer needed.
        """
        if not fg_color:
            fg_color = self.DEFAULT_FG_COLOR
        if not bg_color:
            bg_color = self.DEFAULT_BG_COLOR
        str_id = '%s:%s' % (fg_color, bg_color)
        if not self.brushes.get(str_id):
            try:
                int_id = self.available_brush_ids.pop()
            except KeyError:
                self._collect_brushes()
                try:
                    int_id = self.available_brush_ids.pop()
                except KeyError:
                    raise Exception('out of brushes')
            curses.init_pair(int_id, fg_color, bg_color)
            brush_id = curses.color_pair(int_id)
            self.allocated_brush_ids[str_id] = int_id
            self.brushes[str_id] = brush_id
        return self.brushes[str_id]

    def _collect_brushes(self):
        """Reclaim ids for brushes that are no longer being used."""
        used_brushes = set(['%s:%s' % (self.DEFAULT_FG_COLOR,
                                       self.DEFAULT_BG_COLOR)])
        for x in xrange(self.width):
            for y in xrange(self.height):
                ch, fg, bg = self.get_location(x, y)
                used_brushes.add('%s:%s' % (fg, bg))
        for str_id in self.allocated_brush_ids.keys():
            if str_id not in used_brushes:
                int_id = self.allocated_brush_ids[str_id]
                self.available_brush_ids.append(int_id)
                del self.allocated_brush_ids[str_id]
                del self.brushes[str_id]

    def run(self):
        """Endless processing loop."""
        try:
            updated = current = time.time()
            self.initialize(current)
            while True:
                self.process_input(current)
                if not self.paused:
                    delta = current - updated
                    self.tick(current, delta)
                    updated = current
                self.redraw(current)
                current = time.time()
        except (Exit, KeyboardInterrupt):
            pass

    def process_input(self, current):
        """Input processing."""
        character = self.scr.getch()
        if character != curses.ERR:
            self.process_character(current, character)

    def process_character(self, current, character):
        """Delegate character to method."""
        if character == curses.KEY_RESIZE:
            method_name = 'handle_resize'
        else:
            try:
                method_name = 'handle_%c' % character
            except OverflowError:
                return
        method = getattr(self, method_name, None)
        if method:
            method(current)

    def tick(self, current, delta):
        """Do frame actions."""
        for key in list(self.actors.iterkeys()):
            actor = self.actors[key]
            actor.tick(current, delta)

    def redraw(self, current):
        for (x, y) in self.dirty_by_location.iterkeys():
            ch, fg, bg = self.get_location(x, y)
            self.write(x, y, ch, fg, bg)
        if len(self.dirty_by_location):
            self.dirty_by_location = {}
            if self._border:
                self.win.border()
            self.win.refresh()


from django.contrib.auth.views import LogoutView
from django.urls import path

from DungeonFinder.users import views

urlpatterns = [
    path('login/', views.login, name='login'),
    path('logout/', LogoutView.as_view(template_name='base.jinja'), name='logout'),
    path('profile/', views.user_profile, name='profile'),
    path('profile/edit/', views.edit_profile, name='profile-edit'),
    path('player/<str:screen_name>/', views.player_profile, name='player-profile'),
    path('gm/<str:screen_name>/', views.gm_profile, name='gm-profile'),
    path('signup/', views.user_signup, name='signup'),
    path('signup/pending/', views.signup_pending, name='signup-pending'),
    path('signup/confirm/<str:key>/', views.signup_confirm, name='signup-confirm'),
    path('themes/', views.user_update_theme, name='user-themes'),
]


# Chris Samuel
# @chrisksamuel

#
#
#
#
#

from cs50 import get_string

# Space for students
students = []

# Prompt for students' names and dorms
for i in range(3):
    name = get_string("name: ")
    dorm = get_string("dorm: ")
    students.append({"name": name, "dorm": dorm})

# Print students' name and dorms
for students in students:
    print(f"{student['name']} is in {student['dorm']}.")


"""Solution code"""
import pathlib
import sys

class SectionRange:
    """Wrapper for the section ranges covered."""

    def __init__(self, start: int, end: int) -> None:
        self.start = start
        self.end = end

def parse(puzzle_input: str):
    """Parse input."""
    data: list[tuple[SectionRange, SectionRange]] = []
    for line in puzzle_input.splitlines():
        if line:
            ranges = line.split(",")
            first, second = ranges[0], ranges[1]
            first_split, second_split = first.split("-"), second.split("-")
            first_start, first_end = int(first_split[0]), int(first_split[1])
            second_start, second_end = int(second_split[0]), int(second_split[1])
            first_range, second_range = SectionRange(
                first_start, first_end
            ), SectionRange(second_start, second_end)
            data.append((first_range, second_range))
    return data

def part1(data: list[tuple[SectionRange, SectionRange]]):
    """Solve part 1."""
    overlap_count = 0
    for pair in data:
        (first, second) = pair
        # First contained within second
        if second.start <= first.start and first.end <= second.end:
            overlap_count += 1
        # Second contained within first
        elif first.start <= second.start and second.end <= first.end:
            overlap_count += 1
    return overlap_count

def part2(data: list[tuple[SectionRange, SectionRange]]):
    """Solve part 2."""
    overlap_count = 0
    for pair in data:
        (first, second) = pair
        # First overlaps partially with second
        if (
            second.start <= first.start <= second.end
            or second.start <= first.end <= second.end
        ):
            overlap_count += 1
        # Second overlaps partially with first
        elif (
            first.start <= second.start <= first.end
            or first.start <= second.end <= first.end
        ):
            overlap_count += 1
    return overlap_count

def solve(puzzle_input: str):
    """Solve the puzzle for the given input."""
    data = parse(puzzle_input)
    solution1 = part1(data)
    solution2 = part2(data)

    return solution1, solution2

if __name__ == "__main__":
    for path in sys.argv[1:]:
        print(f"{path}:")
        input_string = pathlib.Path(path).read_text("utf-8").strip()
        solutions = solve(input_string)
        print("\n".join(str(solution) for solution in solutions))


import json
import sys
from matplotlib import pyplot as plt

with open(sys.argv[1]) as jsonfile :
	donnee = json.load(jsonfile)

date = [0.0,0.125,0.25,0.375,0.5,0.625,0.75,0.875]
donnee_propre = [dict(),dict()]
for annee in donnee[0].keys() :
	donnee_propre[0][annee] = []
	donnee_propre[1][annee] = []
	for j in range(int(max(donnee[0][annee]))+1) :
		for position in date :
			donnee_propre[0][annee].append(j+position)
			if j+position in donnee[0][annee] :
				donnee_propre[1][annee].append(donnee[1][annee][donnee[0][annee].index(j+position)])
			else :
				pred = donnee_propre[1][annee][-1]
				ind = -2
				cherche = donnee_propre[0][annee][ind]
				while cherche not in donnee[0][annee] :
					ind -= 1
					cherche = donnee_propre[0][annee][ind]
				index = donnee[0][annee].index(donnee_propre[0][annee][ind])
				if index+1 < len(donnee[1][annee]) :
					succ = donnee[1][annee][index+1]
					val = (succ - pred)/(donnee[0][annee][index+1] - donnee[0][annee][index])*(j+position-donnee[0][annee][index]) + pred
				else :
					succ = donnee[1][str(int(annee) + 1)][0]
					val = (succ - pred)/(donnee[0][str(int(annee) + 1)][0] - donnee[0][annee][index])*(j+position-donnee[0][annee][index]) + pred
				donnee_propre[1][annee].append(val)

with open(sys.argv[2],'w') as jsonfile :
	json.dump(donnee_propre,jsonfile,indent = 4)

#for annee in donnee_propre[0] :
#	plt.plot(donnee_propre[0][annee], donnee_propre[1][annee], label=annee)
#	plt.legend()
#	plt.show()
#	plt.clf()


from scipy.fft import dct
from scipy.signal import convolve2d as ss_convolve2d
from copy import deepcopy as copy_deepcopy
from math import sqrt as math_sqrt
import numpy as np

def wpsnr(original_matrix, modified_matrix):
    original_matrix_copy = (copy_deepcopy(original_matrix) / 255.0)
    modified_matrix_copy = (copy_deepcopy(modified_matrix) / 255.0)
    difference = original_matrix_copy - modified_matrix_copy
    if not np.any(difference):
        return 255
    csf = np.genfromtxt('../wpsnr_weights/csf.csv', delimiter = ',')
    ew = ss_convolve2d(difference, np.rot90(csf, 2), mode = 'valid')
    quality = 20.0 * np.log10(1.0 / math_sqrt(np.mean(np.mean(ew ** 2))))
    return round(quality, 5)

def similarity(original_mark_array, new_mark_array):
    difference = original_mark_array - new_mark_array
    if not np.any(difference):
        return 24
    difference = np.zeros(len(new_mark_array)) - new_mark_array
    if not np.any(difference):
        return 0
    sim = np.sum(np.multiply(original_mark_array, new_mark_array)) / np.sqrt(np.sum(np.multiply(new_mark_array, new_mark_array)))
    return sim

def detection(original_image, watermarked_image, attacked_image):
    # Settings
    chunk_size = (8, 8)
    spots_to_swap = [[(2, 6), (3, 5)], [(5, 3), (6, 2)], [(0, 7), (7, 0)]]
    mark_size = 1024
    attacked_mark_extracted = np.zeros(mark_size, dtype = np.float64)
    original_mark_extracted = np.zeros(mark_size, dtype = np.float64)
    optimal_average = 64
    inverting_limit = 44.5
    mark_partitioning = [325, 650]
    threshold = 12.6

    # Sort the chunk based on their average in the spatial domain (ascending order)
    chunks = []
    for i in range(0, original_image.shape[0], chunk_size[0]):
        for j in range(0, original_image.shape[1], chunk_size[1]):
            chunk = original_image[i : i + chunk_size[0], j : j + chunk_size[1]]
            temp = {'coordinates' : (i, i + chunk_size[0], j, j + chunk_size[1]), 'average' : np.average(chunk)}
            chunks.append(temp)
    chunks_sorted = sorted(chunks, key = lambda d : d['average'], reverse = False)

    # Find the index where the average is > optimal_average
    index_average = 0
    for i in range(len(chunks_sorted)):
        if chunks_sorted[i]['average'] > optimal_average:
            index_average = i
            break
    if len(chunks_sorted) - index_average < mark_size:
        index_average -= mark_size # A possible improvement could be index_average -= (mark_size - len(chunk_sorted) - index_average)
        if index_average < 0:
            index_average = 0

    # Walk the image chunk by chunk
    portion_index = 0
    for i in range(mark_size):
        # Change the spots to swap
        if i >= mark_partitioning[0] and i < mark_partitioning[1]:
            portion_index = 1
        elif i >= mark_partitioning[1]:
            portion_index = 2
        # Apply the DCT to the chunk
        original_chunk = original_image[chunks_sorted[i + index_average]['coordinates'][0] : chunks_sorted[i + index_average]['coordinates'][1], chunks_sorted[i + index_average]['coordinates'][2] : chunks_sorted[i + index_average]['coordinates'][3]]
        original_chunk_dct = dct(dct(original_chunk, axis = 0, norm = 'ortho'), axis = 1, norm = 'ortho')
        attacked_chunk = attacked_image[chunks_sorted[i + index_average]['coordinates'][0] : chunks_sorted[i + index_average]['coordinates'][1], chunks_sorted[i + index_average]['coordinates'][2] : chunks_sorted[i + index_average]['coordinates'][3]]
        attacked_chunk_dct = dct(dct(attacked_chunk, axis = 0, norm = 'ortho'), axis = 1, norm = 'ortho')
        watermarked_chunk = watermarked_image[chunks_sorted[i + index_average]['coordinates'][0] : chunks_sorted[i + index_average]['coordinates'][1], chunks_sorted[i + index_average]['coordinates'][2] : chunks_sorted[i + index_average]['coordinates'][3]]
        watermarked_chunk_dct = dct(dct(watermarked_chunk, axis = 0, norm = 'ortho'), axis = 1, norm = 'ortho')
        # Check the mark value of the attacked image
        if (((original_chunk_dct[spots_to_swap[portion_index][0]] > original_chunk_dct[spots_to_swap[portion_index][1]]) and (attacked_chunk_dct[spots_to_swap[portion_index][0]] > attacked_chunk_dct[spots_to_swap[portion_index][1]]))
            or  ((original_chunk_dct[spots_to_swap[portion_index][0]] < original_chunk_dct[spots_to_swap[portion_index][1]]) and (attacked_chunk_dct[spots_to_swap[portion_index][0]] < attacked_chunk_dct[spots_to_swap[portion_index][1]]))):
            attacked_mark_extracted[i] = 0
        else:
            attacked_mark_extracted[i] = 1
        # Check the mark value of the watermarked image
        if (((original_chunk_dct[spots_to_swap[portion_index][0]] > original_chunk_dct[spots_to_swap[portion_index][1]]) and (watermarked_chunk_dct[spots_to_swap[portion_index][0]] > watermarked_chunk_dct[spots_to_swap[portion_index][1]]))
            or ((original_chunk_dct[spots_to_swap[portion_index][0]] < original_chunk_dct[spots_to_swap[portion_index][1]]) and (watermarked_chunk_dct[spots_to_swap[portion_index][0]] < watermarked_chunk_dct[spots_to_swap[portion_index][1]]))):
            original_mark_extracted[i] = 0
        else:
            original_mark_extracted[i] = 1

    # Calculate the wpsnr between the watermarked image and the attacked image
    wpsnr_wa = wpsnr(watermarked_image, attacked_image)

    # Check if we have to invert a part of the mark
    temp = [0, mark_partitioning[0], mark_partitioning[1], mark_size]
    for r in range(len(temp) - 1):
        accuracy = 0
        for k in range(temp[0 + r], temp[1 + r]):
            if original_mark_extracted[k] == attacked_mark_extracted[k]:
                accuracy += 1
        if ((accuracy / (temp[1 + r] - temp[0 + r])) * 100) < inverting_limit:
            attacked_mark_extracted[temp[0 + r] : temp[1 + r]] = np.array([0 if attacked_mark_extracted[k] == 1 else 1 for k in range(temp[0 + r], temp[1 + r])])

    # Calculate the similarity and return
    sim = similarity(original_mark_extracted, attacked_mark_extracted)

    if sim >= threshold:
        return (True, wpsnr_wa) # Mark found
    else:
        return (False, wpsnr_wa) # Mark not found


import os

def ejercicio1():
    dic={'hi':'holi','how':'como','are':'estas','you':'tu','my':'mi','name':'nombre','is':'es','the':'el'}
    fra=input('introduce la frase en "ingles: ')
    fra=fra.lower()
    pal=fra.split()
    for i in range(len(pal)):
        if pal[i]in dic:
            pal[i]=dic[pal[i]]
    tra = ' '.join(pal)
    print("Frase traducida:", tra)
    print()

if __name__ == "__main__":
    os.system('cls')
    ejercicio1()


import os
from re import S
import sys
import glob
from PIL import Image, ImageDraw, ImageFont, ImageOps
import cv2
import pytesseract
from pytesseract import Output
import traceback
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
import json
from CosineSimilarity import CosineSimilarity

class TesseractRoadSignsRecognizer:

  def __init__(self, anno_file, lang = 'eng'):

    self.annotation_file = anno_file  # json file
    self.load_annotation_file()

    self.lang = lang
    print("We use lang '%s'" % (self.lang))

    #self.config = '--psm 6'

    self.config = '--oem 3 --psm 6'

  def is_roadsigns_name(self, t):
    # Checking text t is acceptable name as the roadsigns.
    rc = False
    if len(t) >0:
      if t.isdecimal() or t.isupper(): #not t.islower():
        rc= True
    return rc

  def get_string_list(self, img):
    dic  = pytesseract.image_to_data(img, lang=self.lang, output_type=Output.DICT, config=self.config)

    text = dic['text']
    #print(boxes)
    strings = []
    if len(text)>0:
      for t in text:
        if self.is_roadsigns_name(t):
          strings.append(t)
    return strings, dic

  def to_double_quote(self, vec):
    s = []
    for v in vec:
     print(v)
     x = '"' + v + '"'
     s.append(x)
    return S

  def load_annotation_file(self):
    self.annotation = None
    with open(self.annotation_file, 'r') as json_file:
       self.annotation = json.load(json_file)
    print(self.annotation)
    self.roadsigns = self.annotation["roadsigns"]
    for sign in self.roadsigns:
      class_name = sign["class_name"]
      strings    = sign["strings"]
      print(" ---- {} {}".format(class_name, strings))

  def list_to_string(self, list):
    string = ""
    for l in list:
      string = string + l + " "
    return string

  def compute_similarity(self, strings_list):
    cos_sim    = 0
    cname      = ""
    annotation = ""
    similarity = CosineSimilarity()
    if len(strings_list) != 0:
      strings    = self.list_to_string(strings_list)

      for sign in self.roadsigns:
        class_name   = sign["class_name"]
        anno_strings_list = sign["strings"]
        if len(anno_strings_list) >0:
          anno_strings = self.list_to_string(anno_strings_list)
          #print("====================------------{} {}".format(anno_strings, strings))
          sim = similarity.compute(anno_strings, strings)
          if sim > cos_sim:
            cname      = class_name
            cos_sim    = sim
            annotation = anno_strings

    return (annotation, cname, cos_sim)

  def write_bounding_boxes(self, img, cname, d, string_list, output_file):
    n_boxes = len(d['level'])
    xmin = 4000
    ymin = 4000
    xmax = 0
    ymax = 0
    # img: PIL image object
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype('arial.ttf', 16)

    if len(string_list) >0:

      for i in range(n_boxes):
        if(d['text'][i] != ""):
          (x, y, w, h) = (d['left'][i], d['top'][i], d['width'][i], d['height'][i])
          #cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0, 255), 2)
          if x < xmin:
            xmin = x
          if y < ymin:
            ymin = y
          if (x+w) > xmax:
            xmax = x+w
          if (y+h) > ymax:
            ymax = y+h
      color = (0, 140, 0, 255)

      draw.rectangle([(xmin, ymin), (xmax, ymax)],
                    outline=color, width=2)

      draw.text((2, 2),
              cname,
              fill=color,
              font=font)
    img.save(output_file)

  # recognize
  def run(self, images_dir, output_dir):

    files  = glob.glob( images_dir + "/*.jpg")
    files += glob.glob( images_dir + "/*.png")
    COLON = ': '
    CONMA = ','
    NL = "\n"

    for file in files:
      basename = os.path.basename(file)
      fname    = basename.split(".")[0]

      output_file = os.path.join(output_dir, fname + ".txt")
      with open(output_file, "w", encoding='UTF-8') as f:
        img = Image.open(file)
        gray = img.convert('L')
        #rev = 255 - gray
        rev = ImageOps.invert(gray)
        filename = os.path.basename(file)
        list1, dic1 = self.get_string_list(img)
        list2, dic2 = self.get_string_list(rev)
        string_list = list1
        rec_dic     = dic1
        if len(list2) > len(list1):
          string_list = list2
          rec_dic     = dic2
        (annotation, cname, cos_sim) = self.compute_similarity(string_list)

        output_image_file = os.path.join(output_dir, filename)
        self.write_bounding_boxes(img, cname, rec_dic, string_list, output_image_file)
        line = basename + CONMA + str(string_list) + CONMA + cname + CONMA + str(cos_sim)

        print(line)
        f.writelines(line + NL)

# python  TesseractRoadSignsRecognizer.py ./sample  ./annotation/roadsigns160.json ./detection

if __name__ == "__main__":
  images_dir   = ""
  anno_file    = ""
  output_dir   = ""
  try:
    if len(sys.argv) == 4:
      images_dir   = sys.argv[1]
      anno_file    = sys.argv[2]
      output_dir   = sys.argv[3]
    else:
      raise Exception("Invalid argument")

    if not os.path.exists(images_dir):
      raise Exception("Not found images_dir " + images_dir)

    if not os.path.exists(anno_file):
      raise Exception("Not found annotation file " + anno_file)

    if not os.path.exists(output_dir):
      os.makedirs(output_dir)

    recognizer = TesseractRoadSignsRecognizer(anno_file)

    recognizer.run(images_dir, output_dir)

  except:
    traceback.print_exc()


# list comprehension anatomy [<return result><iterate> if]
# the code below will replace the following code
#   res = []
#   for i in range(100):
#       res.append(i)

# numbers 0..99
l1 = [i for i in range(100)]

l2 = [i for i in range(100) if i % 2 == 0]

# replace all negative numbers in list with 0
# if have an else statement, the anatomy of the comprehension will be
# [<element_if_true> if <condition> else <element_if_false> for <element> in <iterable>]
input_numbers = [0, -11, 896, 0, -4, 45, 25, -1, -33, 23]
l3 = [0 if i < 0 else i for i in input_numbers]

fruits = ["mango", "kiwi", "strawberry", "guava", "pinapple", "mandarin", "orange"]
capitalized_fruits = [ fruit.capitalize() for fruit in fruits] # to bring the first letter of each fruit to uppercas
longer_than_5_letters = [ fruit for fruit in fruits if len(fruit) > 5]

numbers = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -5, -4, -3, -8, -10, 56, -45, 67, -2]
# select even numbers that are <0
mod_numbers = [num for num in numbers if num < 0 and num % 2 == 0]
print(mod_numbers)


from unittest import TestCase

class Solution:
    def __init__(self):
        self.d = {}

    def isScramble(self, s1: str, s2: str) -> bool:
        case = (s1, s2)
        if case in self.d:
            return self.d[case]
        lt = len(s1)
        if lt == 1:
            return s1 == s2
        letter_counter = [0] * 26
        for i in range(lt):
            letter_counter[ord(s1[i]) - 97] += 1
            letter_counter[ord(s2[i]) - 97] -= 1
        for i in range(26):
            if letter_counter[i] != 0:
                self.d[case] = False
                return False

        for i in range(1, lt):
            if (self.isScramble(s1[:i], s2[:i]) and self.isScramble(s1[i:], s2[i:])) \
                    or (self.isScramble(s1[:i], s2[-i:]) and self.isScramble(s1[i:], s2[:-i])):
                self.d[case] = True
                return True
        self.d[case] = False
        return False

class ScrambleStringTest(TestCase):
    def test_is_scramble(self):
        sol = Solution()
        tests = [
            ('great', 'rgeat', True),
            ('abcde', 'caebd', False),
            ('a', 'a', True),
            ('abcdefghijklmnopq', 'efghijklmnopqcadb', False),
            ('eebaacbcbcadaaedceaaacadccd', 'eadcaacabaddaceacbceaabeccd', False)
        ]
        for test in tests:
            self.assertEqual(test[2], sol.isScramble(test[0], test[1]))


mapper = {"shards": "Shadowmourne", "fragments": "Valanyr", "motes": "Dragonwrath"}

key_materials = {'shards': 0, 'fragments': 0, 'motes': 0}
junk = {}

while True:
    data = input().split()
    is_found = False
    for index in range(0, len(data), 2):
        quantity = int(data[index])
        item = data[index + 1].lower()

        if item in key_materials:
            key_materials[item] += quantity
        else:
            if item not in junk:
                junk[item] = quantity
            else:
                junk[item] += quantity

        for key, value in key_materials.items():
            if value >= 250:
                print(f"{mapper[key]} obtained!")
                key_materials[key] -= 250
                is_found = True
                break
        if is_found:
            break
    if is_found:
        break

ordered_key = sorted(key_materials.items(), key=lambda x: (-x[1], x[0]))

for k_item, k_quantity in ordered_key:
    print(f"{k_item}: {k_quantity}")

ordered_junk = sorted(junk.items(), key=lambda x: x[0])

for j_item, j_quantity in ordered_junk:
    print(f"{j_item}: {j_quantity}")


from random import randrange

class Dot:
    def __init__(self, x, y, color):
        self.x = x
        self.y = y
        self.color = str(color)[0]

    def __str__(self):
        return self.color

    def __repr__(self):
        return f"x = {self.x}, y = {self.y}, color = {self.color}"

emptyColor = "."

class Grid:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.grid = []
        for h in range(height):
            thisRow = []
            for w in range(width):
                thisRow.append(Dot(w, h, emptyColor))
            self.grid.append(thisRow)

    def get(self, x, y):
        return self.grid[y][x]

    def set(self, x, y, color):
        self.get(x, y).color = str(color)[0]

    def __str__(self):
        strRep = ""
        for h in range(self.height):
            for w in range(self.width):
                strRep += str(self.get(w, h)) + "  "
            strRep += "\n"
        return strRep

    def drawLine(self, x1, y1, x2, y2, color):
        if x1 not in range(0, self.width) or x2 not in range(0, self.width) \
                or y1 not in range(0, self.height) or y2 not in range(0, self.height):
            print("Out of bounds!")
            return
        if x1 == x2:
            for i in range(min(y1, y2), max(y1, y2)):
                self.set(x1, i, color)
            return
        if y1 == y2:
            for i in range(min(x1, x2), max(x1, x2)):
                self.set(i, y1, color)
            return
        slope = (y2 - y1) / (x2 - x1)
        yInt = y2 - (slope * x2)
        if abs(slope) < 1:
            for xValue in range(min(x1, x2), max(x1, x2) + 1):
                # print(f"{xValue}, {(slope * (xValue - lX)) + lY}")
                yExact = (slope * xValue) + yInt
                yValue = round(yExact)
                self.set(xValue, yValue, color)
        else:
            for yValue in range(min(y1, y2), max(y1, y2) + 1):
                xExact = (yValue - yInt) / slope
                xValue = round(xExact)
                self.set(xValue, yValue, color)

    def clear(self):
        for h in range(self.height):
            for w in range(self.width):
                self.set(w, h, emptyColor)

def main():
    width = int(input("Insert width: "))
    height = int(input("Insert height: "))
    lines = int(input("Insert amount of lines: "))
    thisGrid = Grid(width, height)
    for i in range(lines):
        x1 = randrange(width)
        x2 = randrange(width)
        y1 = randrange(height)
        y2 = randrange(height)
        thisGrid.drawLine(x1, y1, x2, y2, chr(ord("A") + i))
        thisGrid.set(x1, y1, "s")
        thisGrid.set(x2, y2, "e")
    print(thisGrid)
        # thisGrid.clear()

main()


"""
Subclass of scikit-learn's GroupKFold cross validator to perform re-sampling
within each fold.

Due to how scikit-learn implements the split() function via indices, only
random oversampling and random undersampling can be performed.
"""

from collections import Counter
from imblearn.over_sampling import RandomOverSampler
import numpy as np
import pandas as pd
import pickle

import sklearn
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier
from sklearn.preprocessing import normalize
from sklearn.metrics import f1_score, accuracy_score
import sklearn.model_selection as sk_model_select
from sklearn.utils.validation import indexable

from model_util import build_cv_groups

class GroupKFold(sk_model_select.GroupKFold):
    def __init__(self, n_splits, random_state):
        super().__init__(n_splits)
        self.random_state = random_state

    def split(self, X, y=None, groups=None):
        """
        Calls GroupKFold split function, then resamples the training index.
        """
        #train_idx, test_idx = super().split(X, y=y, groups=groups)
        for train_idx, test_idx in super().split(X, y=y, groups=groups):
            #X, y, groups = indexable(X, y, groups)
            fold_train_X = X[train_idx]
            if hasattr(y, "values"):
                fold_train_y = y.values[train_idx]
            else:
                fold_train_y = y[train_idx]
            # print(X.shape)
            # print(y.shape)
            # print(fold_train_X.shape)
            # print(fold_train_y.shape)

            # Need to remap fold indices back to the overall indices
            idx_dict = {fold_idx : train_idx[fold_idx] for fold_idx in range(len(fold_train_y))}

            # print(Counter(y.values[train_idx]))
            sm = RandomOverSampler(random_state=self.random_state)
            # X_res, y_res actually thrown away
            X_res, y_res = sm.fit_resample(fold_train_X, fold_train_y)
            idx_res = sm.sample_indices_
            train_idx_res = [idx_dict[idx] for idx in idx_res]
            # print(Counter(y_res))
            # print(Counter(y.values[train_idx_res]))

            yield train_idx_res, test_idx

if __name__ == '__main__':
    predict_targets = [
    'contact_type',
    'q1_want',
    'q2_talk',
    'q3_loan',
    'q4_closeness'
    ]

    replace_dict_4clf = {
        'contact_type': {
            "work": 0,
            "friend": 1,
            "task": 2,
            "family_live_separate": 1,
            "family_live_together": 3,
            "sig_other": 3
        }
    }

    replace_dict_6clf = {
        'contact_type': {
            "work": 0,
            "friend": 1,
            "task": 2,
            "family_live_separate": 3,
            "family_live_together": 4,
            "sig_other": 5
        }
    }

    contact_types_6clf = list(replace_dict_6clf['contact_type'].keys())
    contact_types_4clf = ["work", "social", "task", "family_together"]

    age_qlabels = ["age_q" + str(x) for x in range(1,5)]

    top5_all_sb_train_data = pickle.load(open('../data/final_sandbox/top5_all_train_features.df', 'rb'))
    top5_all_sb_test_data = pickle.load(open('../data/final_sandbox/top5_all_test_features.df', 'rb'))

    top5_all_data = pd.concat([top5_all_sb_train_data, top5_all_sb_test_data], axis=0)
    top5_all_data = top5_all_data.replace(replace_dict_4clf)
    top5_all_data['ego_age_q'], bins = pd.qcut(top5_all_data['ego_age'], q=4, labels=age_qlabels, retbins=True)

    """Try a random forest estimator"""
    top5_all_q1 = top5_all_data.loc[top5_all_data['ego_age_q'] == 'age_q1']
    top5_all_q1_train_y = top5_all_q1['contact_type']
    top5_all_q1_train_X = top5_all_q1.drop(['pid', 'combined_hash', 'ego_age_q'] + predict_targets, axis=1, errors='ignore')
    top5_all_q1_train_X = normalize(top5_all_q1_train_X)

    groups = build_cv_groups(top5_all_q1['pid'])

    group_kfold_res = GroupKFold(n_splits=5, random_state=2)

    cv_scores = []

    for fold_train_idx, fold_test_idx in group_kfold_res.split(top5_all_q1_train_X, top5_all_q1_train_y, groups):

        top5_all_q1_clf = RandomForestClassifier(random_state=2, n_jobs=4, n_estimators=100, warm_start=False)
        fold_train_X = top5_all_q1_train_X[fold_train_idx]
        fold_train_y = top5_all_q1_train_y.values[fold_train_idx]
        fold_test_X = top5_all_q1_train_X[fold_test_idx]
        fold_test_y = top5_all_q1_train_y.values[fold_test_idx]

        print(Counter(fold_train_y))
        top5_all_q1_clf.fit(fold_train_X, fold_train_y)
        predict = top5_all_q1_clf.predict(fold_test_X)
        cv_scores.append(accuracy_score(fold_test_y, predict))

    print(cv_scores)
    print(np.mean(cv_scores))


from typing import Dict
import pandas as pd
from state import State
import numpy as np
from collections.abc import Sequence

def get_key(state: State):
    return state.dealer + state.player * 100

class Q:
    def __init__(self, state: State):
        self.state = state
        self.N = 1
        self.nHits = 0
        self.nSticks = 0
        self.hitValue = 0
        self.stickValue = 0
        self.bestValue = 0

    def updateN(self, action):
        self.N += 1
        if action == "hit":
            self.nHits += 1
        else:
            self.nSticks += 1

    def updateQ(self, TotalReward, action):
        if action == "hit":
            self.hitValue += 1 / self.N * (TotalReward - self.hitValue)
        else:
            self.stickValue += 1 / self.N * (TotalReward - self.stickValue)

        self.bestValue = max([self.hitValue, self.stickValue])

    def __repr__(self):
        return str([self.state, self.N, self.bestValue])

class Experience:
    def __init__(self, N_0):
        self.N_0 = N_0
        self.QDict = {}  # Dict[int, Q]
        self.episode = []

    def update(self, state: State, action, reward=0):
        if state.terminal:
            for q in self.episode:
                q[0].updateQ(reward, q[1])
            self.episode = []

        else:
            key = get_key(state)
            if key in self.QDict:
                self.QDict[key].updateN(action)
            else:
                self.QDict[key] = Q(state)

            self.episode.append((self.QDict[key], action))

    def get_action(self, state):
        key = get_key(state)
        if key in self.QDict:
            eps = np.random.uniform()
            if eps < self.N_0 / (self.N_0 + self.QDict[key].N):
                if self.QDict[key].hitValue > self.QDict[key].stickValue:
                    return "hit"
                else:
                    if self.QDict[key].hitValue < self.QDict[key].stickValue:
                        return "stick"

        return np.random.choice(["hit", "stick"])

    def __repr__(self):
        return str(self.QDict)

    def get_V(self):
        V = np.zeros((10, 21))
        for qa in self.QDict:
            V[self.QDict[qa].state.dealer - 1, self.QDict[qa].state.player - 1] = self.QDict[qa].bestValue
        return V

    def get_V_df(self):
        keys = []
        values = []
        for qa in self.QDict:
            keys.append(qa)
            values.append(self.QDict[qa].bestValue)
        return pd.DataFrame({"state": keys, "V": values})

    def get_loss(self, V_opt):
        values = []
        opt_values = []
        for qa in self.QDict:
            values.append(self.QDict[qa].bestValue)
            opt_values.append(V_opt[V_opt["state"] == qa]["V"].values[0])
        if len(values) == V_opt.shape[0]:
            return np.linalg.norm(np.array(opt_values) - np.array(values)) ** 2
        else:
            return 10000


# -*- coding: utf-8 -*-

__name__ = 'reload#'
__type__ = 'plugin'
__desc__ = 'reloads all plugins that have the doreload() method'

import wx
import os
import sys

def run(txtctrl, log = None, **kwargs):
  editra_dir = os.path.sep.join(os.path.dirname(__file__).split(os.path.sep)[0:-3])
  if (editra_dir) not in sys.path:
    sys.path.append(editra_dir)

  plgmgr = wx.GetApp().GetPluginManager()
  for plugin in plgmgr.GetPlugins():
      plugin = plgmgr.__getitem__(plugin)

      if plugin:
          if hasattr(plugin, 'doreload'):
              log('Reloading plugin: %s' % str(plugin))
              #plugin.doreload()
              wx.CallAfter(plugin.doreload)
              #wx.CallLater(1000, plugin.doreload)


# region import
import datetime
import sqlite3
import threading
import time
import types
from functools import wraps
from typing import Callable, List

from numpy.random import default_rng
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import CallbackContext

from basicfunc import *
from cfg import *

try:
    from typing import TYPE_CHECKING
except Exception:
    TYPE_CHECKING = False

if TYPE_CHECKING:
    from main import AntaresBot
# endregion

# region const
SECONDS_IN_A_DAY = 24 * 60 * 60

randgenerator = default_rng()

_RT = TypeVar("_RT")
# endregion

# region function

def chatisfromme(update: Update) -> bool:
    """检查是否来自`MYID`"""
    return getchatid(update) == MYID

def isfromme(update: Update):
    return getfromid(update) == MYID

def getfromid(update: Update) -> int:
    """返回`from_user.id`"""
    return update.message.from_user.id

def getchatid(update: Update) -> int:
    """返回`chat_id`"""
    return update.effective_chat.id

def getmsgid(update: Update) -> int:
    """返回message_id"""
    if update.message is not None:
        return update.message.message_id
    if update.channel_post is not None:
        return update.channel_post.message_id
    if update.edited_channel_post is not None:
        return update.edited_channel_post.message_id
    raise ValueError("无法从update获取msgid")

def isprivate(update: Update) -> bool:
    return update.effective_chat.type == "private"

def isgroup(update: Update) -> bool:
    return update.effective_chat.type.find("group") != -1

def ischannel(update: Update) -> bool:
    return update.effective_chat.type == "channel"

def flattenButton(
    buttons: List[InlineKeyboardButton], numberInOneLine: int
) -> InlineKeyboardMarkup:
    btl: List[List[InlineKeyboardButton]] = []
    while len(buttons) > numberInOneLine:
        btl.append(buttons[:numberInOneLine])
        buttons = buttons[numberInOneLine:]
    if len(buttons) > 0:
        btl.append(buttons)
    return InlineKeyboardMarkup(btl)

def getTimeStamp() -> int:
    """精确到毫秒的时间戳."""
    return int(1000*(time.time() - (1 << 30)))

# endregion

# region classes

class botmessages(object):
    __slots__ = ["chat", "msgid"]

    def __init__(self, chat: int, msgid: int) -> None:
        self.chat = chat
        self.msgid = msgid

    def __hash__(self) -> int:
        return hash(self.chat*10000000000+self.msgid)

    def __eq__(self, o: 'botmessages') -> bool:
        try:
            return self.chat == o.chat and self.msgid == o.msgid
        except Exception:
            return False

    def __expr__(self) -> str:
        return str(self.chat)+' '+str(self.msgid)

    def __str__(self) -> str:
        return self.__expr__()

class dateStringStruct(object):
    __slots__ = ["_year", "_month", "_day", "__dict__"]

    def __init__(self, s: str) -> None:
        if "." not in s and " " not in s:
            raise ValueError("dateStringStruct不接受此类型的参数")
        if "." in s:
            args = s.split(".")
        else:
            args = s.split()
        if len(args) < 2 or len(args) > 3:
            raise ValueError("dateStringStruct不接受此类型的参数")
        try:
            if len(args) == 3:
                self.year = int(args[0])
                args = args[1:]
            self.month, self.day = map(int, args)
        except Exception:
            raise ValueError("dateStringStruct接收到的参数无效")

    @property
    def year(self) -> Optional[int]:
        if "_year" not in self.__dict__:
            return None
        return self._year

    @year.setter
    def year(self, _y: int):
        self._year = _y

    @property
    def month(self) -> int:
        return self._month

    @month.setter
    def month(self, _m: int):
        if _m <= 0 or _m > 12:
            raise ValueError(f"month should be in 1-12, got {_m}")
        self._month = _m

    @property
    def day(self) -> int:
        return self._day

    @day.setter
    def day(self, _d: int):
        if _d <= 0 or _d > 31:
            raise ValueError(f"day should be in 1-31, got {_d}")
        self._day = _d

    @property
    def original(self) -> str:
        ans = ""
        if self.year:
            ans = f"{self.year}."
        ans += f"{self.month}.{self.day}"
        return ans

    def __repr__(self) -> str:
        ans = ""
        if self.year:
            ans = f"{self.year}年"
        ans += f"{self.month}月{self.day}日"
        return ans

    @classmethod
    def fromReprString(cls, s: str) -> str:
        ans = ""
        if "年" in s:
            ans, s = s.split("年")
            ans += "."
        s = s.split("月")
        ans += s[0] + "."
        s = s[1].lstrip()

        ans += s[: s.find("日")]
        return cls(ans)

    def __gt__(self, o: "dateStringStruct") -> bool:
        if self.year and o.year:
            if self.year > o.year:
                return True
            if self.year < o.year:
                return False
        if self.month > o.month:
            return True
        if self.month < o.month:
            return False
        return self.day > o.day

class timeStringStruct(object):
    __slots__ = ["_sec", "_hour", "_min", "__dict__"]

    def __init__(self, s: str) -> None:
        if ":" not in s:
            raise ValueError("timeStringStruct 不接受此类型的参数")
        args = s.split(":")
        if len(args) < 2 or len(args) > 3:
            raise ValueError("timeStringStruct 不接受此类型的参数")
        try:
            if len(args) == 3:
                self.sec = int(args[2])
                args = args[:2]
            self.hour, self.minute = map(int, args)
        except Exception:
            raise ValueError("timeStringStruct 接收到的参数无效")

    @property
    def sec(self) -> int:
        if "_sec" not in self.__dict__:
            return None
        return self._sec

    @sec.setter
    def sec(self, _s: int):
        if _s < 0 or _s >= 60:
            raise ValueError(f"sec should be in 0-59, got {_s}")
        self._sec = _s

    @property
    def hour(self) -> int:
        return self._hour

    @hour.setter
    def hour(self, _h: int):
        if _h < 0 or _h >= 24:
            raise ValueError(f"hour should be in 0-23, got {_h}")
        self._hour = _h

    @property
    def minute(self) -> int:
        return self._min

    @minute.setter
    def minute(self, _m: int):
        if _m < 0 or _m >= 60:
            raise ValueError(f"minute should be in 0-59, got {_m}")
        self._min = _m

    def original(self) -> str:
        if len(str(self.hour)) == 1:
            ans = f"0{self.hour}"
        else:
            ans = str(self.hour)
        if len(str(self.minute)) == 1:
            ans += f":0{self.minute}"
        else:
            ans += f":{self.minute}"
        if self.sec:
            if len(str(self.sec)) == 1:
                ans += f":0{self.sec}"
            else:
                ans += f":{self.sec}"
        return ans

    def __repr__(self) -> str:
        return self.original()

    def evalLeftSec(self) -> int:
        loctime = datetime.datetime.now()
        nowh = loctime.hour
        nowm = loctime.minute
        nows = loctime.second
        ans = (self.hour - nowh) * 60
        ans += self.minute - nowm
        ans = ans * 60 - nows + 1
        if ans <= 0:
            ans += SECONDS_IN_A_DAY
        return ans  # 延迟1秒

    def allSecs(self) -> int:
        ans = self.minute * 60 + self.hour * 3600
        if self.sec:
            ans += self.sec
        return ans

class delayLock(object):
    """Delay a few seconds at `__exit__`."""

    def __init__(self, delaySeconds: int = 10) -> None:
        self.__lock = threading.Lock()
        self.__delay = delaySeconds

    def __enter__(self) -> bool:
        return self.__lock.__enter__()

    def __exit__(self, *args, **kwargs) -> Optional[bool]:
        def _f():
            time.sleep(self.__delay)
            return self.__lock.__exit__(*args, **kwargs)

        threading.Thread(target=_f).start()

    def locked(self) -> bool:
        return self.__lock.locked()

    def acquire(self):
        self.__lock.acquire()

    def release(self):
        def _f():
            time.sleep(self.__delay)
            self.__lock.release()

        threading.Thread(target=_f).start()

class multiSubLock(object):
    """Only used in multiLock. See `multiLock`."""

    def __init__(self, _multiLock: 'multiLock', msg: botmessages) -> None:
        self._ml = _multiLock
        self.msg = msg

    def __enter__(self) -> bool:
        while True:
            while self.locked():
                time.sleep(1)
            with self._ml._lock:
                if self.locked():
                    continue
                self._ml.memory[self.msg] = self
                return True

    def __exit__(self, *args, **kwargs) -> Optional[bool]:
        def _f():
            time.sleep(self._ml.delay)
            with self._ml._lock:
                self._ml.memory.pop(self.msg)
                return True

        threading.Thread(target=_f).start()

    def locked(self) -> bool:
        return (self.msg in self._ml.memory)

    def acquire(self):
        self.__enter__()

    def release(self):
        self.__exit__()

class multiLock(object):
    """
    A lock with some data.
    If a lock acquire with the same data as another, its blocked until the first is done.
    """

    def __init__(self, delaytime: int = 0) -> None:
        self.delay = delaytime
        self._lock = threading.Lock()
        self.memory: Dict[botmessages, multiSubLock] = dict()

    def __getitem__(self, msg: botmessages) -> multiSubLock:
        return multiSubLock(self, msg)

class fakeBotObject(object):
    """
    bot instance的伪装类。
    在并发情形下，bot object会在一个command callback函数执行完成之前获取
    新的lastuser，lastchat等信息。在一个update的范围内，如果需要保证这些
    参数是不会发生改变的，使用这个类来伪装成一个botinstance传给callback
    method。注意：除了上述三个数据不会发生改变以外，其他数据是会发生改变的。
    """

    __slots__ = ["_real_bot_obj", "lastchat", "lastuser", "lastmsgid"]

    def __init__(self, bot) -> None:
        self._real_bot_obj = bot
        self.lastchat = 0
        self.lastuser = 0
        self.lastmsgid = -1

    def _to_real(self) -> 'AntaresBot':
        """
        Return the true bot object of main bot.
        """
        return self._real_bot_obj

    def __getattr__(self, attr):
        x = getattr(self._real_bot_obj, attr)
        if callable(x) and (not isinstance(x, types.FunctionType) and not callable(x.__self__)):
            # judge if x is static method or class method.
            # If x is, then return the original x,
            # since it doesn't use any fakeBotObject data.

            def wraped_func(*args, **kwargs):
                return getattr(type(self._real_bot_obj), attr)(self, *args, **kwargs)

            return wraped_func
        return x

    def __setattr__(self, __name: str, __value: Any) -> None:
        if __name in ["lastchat", "lastuser", "lastmsgid", "_real_bot_obj"]:
            object.__setattr__(self, __name, __value)
            return
        self._real_bot_obj.__dict__[__name] = __value

class workingMethodFilter(object):
    ...

class databaseManager(object):
    conn: sqlite3.Connection

    def __init__(self, botinstance: "AntaresBot", dbpath: str) -> None:
        self.database = dbpath
        self.conn = None
        self.botinstance = botinstance
        self.tables: List[str] = []
        self.lock = threading.Lock()

    def connect(self):
        if self.conn is not None:
            try:
                self.conn.close()
            except Exception:
                ...
        self.conn = sqlite3.connect(self.database)

    def close(self):
        if self.conn is not None:
            try:
                self.conn.close()
            except Exception:
                ...
            self.conn = None

    def _getPrimaryKey(self, table: str) -> str:
        c = self.conn.cursor()
        c.execute(f"PRAGMA table_info({table});")
        for r in c.fetchall():
            if r[-1] > 0:
                return r[1]
        return ""

    def _select(
        self, table: str, where: Optional[Dict[str, Any]] = None, need: Optional[List[str]] = None
    ) -> list:
        parseArgs: List[str] = []
        command = "SELECT "
        if need is None:
            command += "* FROM "
        else:
            command += ", ".join(need) + " FROM "

        command += table

        if where is not None:
            command += " WHERE "
            l = []
            for k, v in where.items():
                thispart = f"{k}="
                if type(v) is str:
                    thispart += "?"
                    parseArgs.append(v)
                else:
                    thispart += str(v)
                l.append(thispart)
            command += " AND ".join(l)

        command += ";"

        self.botinstance.debuginfo(command)
        if len(parseArgs) > 0:
            self.botinstance.debuginfo("parsing args: "+' '.join(parseArgs))

        c = self.conn.cursor()

        c.execute(command, parseArgs)

        return c.fetchall()

    def _insert(self, table: str, datadict: dict):
        c = self.conn.cursor()
        command = f"INSERT INTO {table}("
        command2 = f"VALUES("
        parseArgs: List[str] = []
        sep = ""
        for k, v in datadict.items():
            command += sep + str(k)
            if type(v) is str:
                command2 += f"{sep} ?"
                parseArgs.append(v)
            else:
                command2 += sep + " " + str(v)
            sep = ","
        command += ")"
        command2 += ");"

        command += command2

        self.botinstance.debuginfo(command)
        if len(parseArgs) > 0:
            self.botinstance.debuginfo("parsing args: "+' '.join(parseArgs))
        c.execute(command, parseArgs)
        self.conn.commit()

    def _update(self, table: str, datadict: dict, pkey: str):
        c = self.conn.cursor()

        command = f"UPDATE {table} SET "
        parseArgs: List[str] = []
        sep = ""
        setlength = 0

        for k, v in datadict.items():
            if str(k) == pkey:
                continue
            setlength += 1
            command += sep + str(k) + "="
            if type(v) is str:
                command += "?"
                parseArgs.append(v)
            else:
                command += str(v)
            sep = ","

        if setlength == 0:
            self.botinstance.debuginfo(
                "nothing to set, no need to update database")
            return

        command += f" WHERE {pkey}="
        if type(datadict[pkey]) is str:
            command += f"?;"
            parseArgs.append(datadict[pkey])
        else:
            command += str(datadict[pkey]) + ";"

        self.botinstance.debuginfo(command)
        if len(parseArgs) > 0:
            self.botinstance.debuginfo("parsing args: "+' '.join(parseArgs))

        c.execute(command, parseArgs)
        self.conn.commit()

    def _delete(self, table: str, where: Optional[Dict[str, Any]] = None):
        c = self.conn.cursor()
        cmd = f"DELETE FROM {table}"
        parseArgs: List[str] = []

        if where is not None:
            cmd += f" WHERE "
            l = []
            for k, v in where.items():
                thispart = f"{k}="
                if type(v) is str:
                    thispart += "?"
                    parseArgs.append(v)
                else:
                    thispart += str(v)
                l.append(thispart)
            cmd += " AND ".join(l)

        cmd += ";"

        self.botinstance.debuginfo(cmd)
        if len(parseArgs) > 0:
            self.botinstance.debuginfo("parsing args: "+' '.join(parseArgs))

        c.execute(cmd, parseArgs)
        self.conn.commit()

    def _seenThisPkey(self, table: str, pk: str, pkeyval):
        return bool(self._select(table, {pk: pkeyval}))

    def insertInto(self, table: str, datadict: dict):
        with self:
            pk = self._getPrimaryKey(table)
            upd = False
            if pk != "":
                if pk not in datadict:
                    raise ValueError("插入表的数据必须要有主键")
                if self._seenThisPkey(table, pk, datadict[pk]):
                    self.botinstance.debuginfo("已经存储过该key，更新目标")
                    upd = True

            if upd:
                self._update(table, datadict, pk)
            else:
                self._insert(table, datadict)

    def insertMany(self, table: str, manydata: List[dict], no_pkey_check: bool = False):
        with self:
            pk = self._getPrimaryKey(table)
            for data in manydata:
                upd = False
                if not no_pkey_check and pk != "":
                    if pk not in data:
                        raise ValueError("插入表的数据必须要有主键")
                    if self._seenThisPkey(table, pk, data[pk]):
                        upd = True
                if upd:
                    self._update(table, data, pk)
                else:
                    self._insert(table, data)

    def select(
        self,
        table: str,
        where: Optional[Dict[str, Any]] = None,
        need: Optional[List[str]] = None,
    ) -> list:
        with self:
            ans = self._select(table, where, need)
            return ans

    def execute(self, cmd: List[str]):
        """execute a list of commands."""
        with self:
            for c in cmd:
                self.conn.cursor().execute(c)
            self.conn.commit()

    def delete(self, table, where: Optional[Dict[str, Any]] = None):
        with self:
            self._delete(table, where)

    def clean(self, table: str):
        with self:
            self._delete(table)

    def __enter__(self):
        self.lock.acquire()
        self.connect()
        return True

    def __exit__(self, *args, **kwargs):
        self.close()
        self.lock.release()
        return True

class CallbackDataServer(object):
    """store callback data in a dict."""

    def __init__(self) -> None:
        self.callbackDataMemory: Dict[str, str] = dict()

    def getData(self, key: str) -> str:
        ans = dictpop(self.callbackDataMemory, key)
        if ans is None:
            raise ValueError("无效的callbackData索引")
        return ans

    def setData(self, key: str, value: str) -> None:
        if key in self.callbackDataMemory:
            raise ValueError("callbackData索引已存在")
        self.callbackDataMemory[key] = value

class handleStatus(object):
    __slots__ = ["block", "normal"]

    def __init__(self, normal: bool, block: bool) -> None:
        self.block: bool = block
        self.normal: bool = normal

    def __bool__(self):
        ...

    def blocked(self):
        return self.block

handlePassed = handleStatus(True, False)

class handleBlocked(handleStatus):
    __slots__ = []

    def __init__(self, normal: bool = True) -> None:
        super().__init__(normal=normal, block=True)

    def __bool__(self):
        return self.normal

# endregion

# region decorator

class commandCallback(object):
    def __init__(self, func: Callable) -> None:
        wraps(func)(self)

    def __call__(self, *args, **kwargs):
        numOfArgs = len(args) + len(kwargs.keys())
        if numOfArgs != 2:
            raise TypeError(f"指令的callback function参数个数应为2，但接受到{numOfArgs}个")
        return self.__wrapped__(*args, **kwargs)

    def __get__(self, instance, cls):
        if instance is not None:
            raise TypeError("该装饰器不适用于方法")
        return self

class commandCallbackMethod(object):
    """
    表示一个指令的callback函数，仅限于类的成员方法。
    调用时，会执行一次指令的前置函数。
    """

    def __init__(self, func: Callable[[Update, CallbackContext], _RT]) -> None:
        wraps(func)(self)
        # self.run_async = True
        self.instance: "AntaresBot" = None

    def __call__(self, *args, **kwargs):
        numOfArgs = len(args) + len(kwargs.keys())
        if numOfArgs != 2:
            raise RuntimeError(f"指令的callback function参数个数应为2，但接受到{numOfArgs}个")

        if len(args) == 2:
            fakeinstance = self.preExecute(*args)
        elif len(args) == 1:
            fakeinstance = self.preExecute(args[0], **kwargs)
        else:
            fakeinstance = self.preExecute(**kwargs)

        inst = self.instance
        with inst.locks.botlock:
            if any(
                x in inst.blacklist
                for x in (fakeinstance.lastchat, fakeinstance.lastuser)
            ):
                fakeinstance.errorInfo("你在黑名单中，无法使用任何功能")
                return

        return self.__wrapped__(fakeinstance, *args, **kwargs)

    def preExecute(self, update: Update, context: "CallbackContext") -> "AntaresBot":
        """在每个command Handler前调用，是指令的前置函数"""
        if self.instance is None:
            raise RuntimeError("command callback method还未获取实例")
        return self.instance.renewStatus(update)

    def __get__(self, instance, cls):
        if instance is None:
            raise TypeError("该装饰器仅适用于方法")
        if self.instance is None:
            self.instance = instance
        return self

# endregion


import numpy as np

from LSTM import LSTM
from utils.data_converter import *
from utils.preprocess import *
from crf import *

params = {
    "pretrain": True, # change to False to try random embeddings
    "learning_rate": 0.0001,
    "hidden_size": 200, # hidden size of the nn
    "cell": "GRU", # or LSTM, changes the type of nn cell
    "num_layers": 1,
    "model": "BiLSTM", # BiLSTM, LSTM or CRF
    "keep_ratio": 0.5,
    "tags": "BIOES", # can be IOB, BIOS or BIOES
    "crf": True, # change it to False to use typical loss
    "char": True, # use character embeddings
    "char_method": "BiLSTM", # or CNN
    "features": True,
    "char_hidden": 100
}

def main():
    # reads the dataset
    conll_sents = read_conll('data/eng.train')
    conll_tags = get_column(conll_sents, -1)
    conll_words = get_column(conll_sents, 0)

    test_sents = read_conll('data/eng.testb')
    test_tags = get_column(test_sents, -1)

    if params["tags"] == "BIO":
        conll_tags = tags_from_conll(conll_tags, scheme='bio')
        test_tags = tags_from_conll(test_tags, scheme="bio")
    elif params["tags"] == "BIOES":
        conll_tags = tags_from_conll(conll_tags, scheme='bioes')
        test_tags = tags_from_conll(test_tags, scheme='bioes')

    conll_add1 = get_column(conll_sents, 1)
    conll_add2 = get_column(conll_sents, 2)

    if params["model"] == "CRF":
        X = np.array(conll_sents)
        y = np.array(conll_tags)
        #X_train, X_test, y_train, y_test = train_test_split(X, y,  test_size=0.2, random_state=33)

        crf(X, y, test_sents, test_tags)
    else:

        print("Train data includes", len(conll_sents), "sentences")
        unique_tags = set(tag for item in conll_tags for tag in item)
        print(len(unique_tags), "distinct tags found:", unique_tags)
        unique_POS = set(tag for item in conll_add1 for tag in item)
        POS_dict = {pos: idx for idx, pos in enumerate(unique_POS)}

        unique_POS2 = set(tag for item in conll_add2 for tag in item)
        POS_dict2 = {pos: idx for idx, pos in enumerate(unique_POS2)}

        print("Finding distinct words in the data")
        vocab, chars, params["max_char"], params["max_len"] = get_vocabs_chars(conll_words)
        params["max_char"] = 20
        print("There are", len(vocab), "different words in the dataset")

        if params["pretrain"]:
            print("Loading GloVe pretrained vectors")
            embeddings = read_embedding(vocab, 'embeddings/glove.300.txt')
        else:
            embeddings = None

        char_embeddings = read_embedding(chars, 'embeddings/glove.char.txt')

        print("Converting tags to numbers")
        conll_tags = tags_to_id(conll_tags, unique_tags)

        X = np.array(conll_sents)
        y = np.array(conll_tags)
        print("Splitting data to train and test")
        X_train, X_test, y_train, y_test, indices_train, indices_test = train_test_split(X, y, range(len(conll_sents)),
                                                                                test_size=0.2, random_state=33)
        X_train = list(X_train)
        X_test = list(X_test)

        if params["features"]:
            print("Extracting features")
            train_feat = list()
            test_feat = list()
            testb_feat_x = list()
            # generates features for each word
            for sent_idx, sent in enumerate(conll_sents):
                sent_feat = [get_features(sent, idx, POS_dict, POS_dict2) for idx in range(len(sent))]
                while len(sent_feat) < params["max_len"]:
                    # default feature vector for padding tokens
                    pad = np.array([3, 3, 3, 3, 3, 3, 3, 3, 3, 1])
                    sent_feat.append(pad/ sum(pad))
                if sent_idx in indices_train:
                    train_feat.append(np.array(sent_feat))
                else:
                    test_feat.append(np.array(sent_feat))
            max_test = max(len(sent) for sent in test_sents)
            for sent_idx, sent in enumerate(test_sents):
                sent_feat = [get_features(sent, idx, POS_dict, POS_dict2) for idx in range(len(sent))]
                while len(sent_feat) < max_test:
                    # default feature vector for padding tokens
                    pad = np.array([3, 3, 3, 3, 3, 3, 3, 3, 3, 1])
                    sent_feat.append(pad/ sum(pad))
                testb_feat_x.append(np.array(sent_feat))
            params["feat_len"] = 10
            train_feat = just_batch(np.array(train_feat))
            test_feat = just_batch(np.array(test_feat))
            testb_feat = just_batch(np.array(testb_feat_x))

        else:
            train_feat = list()
            test_feat = list()
            testb_feat = list()

        if params["char"]:
            print("Generating character embeddings")
            X_train_char, train_char_lengths = ids_to_char(chars, vocab, X_train, params["max_char"], params["max_len"])
            X_test_char, test_char_lengths = ids_to_char(chars, vocab, X_test, params["max_char"], params["max_len"])
            testb_char, testb_char_lengths = ids_to_char(chars, vocab, test_sents, params["max_char"], max_test)

            train_char = just_batch(X_train_char)
            len_batch = just_batch(train_char_lengths)
            train_char_batch = list(zip(train_char, len_batch))

            test_char = just_batch(X_test_char)
            test_len_batch = just_batch(test_char_lengths)
            test_char_batch = list(zip(test_char, test_len_batch))

            testb_char_b = just_batch(testb_char)
            testb_len_batch = just_batch(testb_char_lengths)
            testb_char_batch = list(zip(testb_char_b, testb_len_batch))
        else:
            train_char_batch = list()
            test_char_batch = list()
            testb_char_batch = list()

        X_train = words_to_id(vocab, X_train)
        X_test = words_to_id(vocab, X_test)
        testb = words_to_id(vocab, test_sents)

        train_batch = get_batches(X_train, y_train, max_length=params["max_len"], pad_idx=vocab.index("<pad>"))
        test_batch = get_batches(X_test, y_test, max_length=params["max_len"], pad_idx=vocab.index("<pad>"))
        testb_batch = get_batches(testb, max_length=max_test, pad_idx=vocab.index("<pad>"))

        lstm = LSTM(params, vocab, embeddings, len(unique_tags), chars, char_embeddings)
        lstm.build()
        conll_sents = read_conll('data/eng.train')
        lstm.run_model(train_batch, test_batch, train_char_batch, test_char_batch,
                       [conll_sents[i] for i in indices_test], {idx: tag for idx, tag in enumerate(unique_tags)}, train_feat, test_feat,
                       testb_feat, testb_char_batch, testb_batch, read_conll('data/eng.testb'), max_test)

if __name__ == '__main__':
  main()


# -*- coding: utf-8 -*-
# 进口第一类医疗器械（含第一类体外诊断试剂）备案信息

import re
from selenium import webdriver
from gjypjd.utils import *
import json
import time

def main():
    option = None
    mysql_db = DataBase()
    # 配置文件中开启是否无头，生产阶段关闭
    if if_headless():
        option = webdriver.ChromeOptions()
        option.add_argument(argument='headless')
        option.add_argument('--no-sandbox')

    for i in range(1, 588):  # 遍历587个一级目录网页
        try:
            browser = webdriver.Chrome(chrome_options=option)
            url_1 = 'http://app1.sfda.gov.cn/datasearchcnda/face3/search.jsp?tableId=104&State=1&bcId=152904498781962056127955207188&State=1&curstart=' + str(
                i) + '&State=1&tableName=TABLE104&State=1&viewtitleName=COLUMN1384&State=1&viewsubTitleName=COLUMN1376,COLUMN1371&State=1&tableView=%25E8%25BF%259B%25E5%258F%25A3%25E7%25AC%25AC%25E4%25B8%2580%25E7%25B1%25BB%25E5%258C%25BB%25E7%2596%2597%25E5%2599%25A8%25E6%25A2%25B0%25EF%25BC%2588%25E5%2590%25AB%25E7%25AC%25AC%25E4%25B8%2580%25E7%25B1%25BB%25E4%25BD%2593%25E5%25A4%2596%25E8%25AF%258A%25E6%2596%25AD%25E8%25AF%2595%25E5%2589%2582%25EF%25BC%2589%25E5%25A4%2587%25E6%25A1%2588%25E4%25BF%25A1%25E6%2581%25AF&State=1&cid=0&State=1&ytableId=0&State=1&searchType=search&State=1'
            browser.get(url_1)
            s = browser.page_source.replace('amp;', '')
            m = re.findall(r'content.jsp\?tableId=104&tableName=TABLE104&tableView=进口第一类医疗器械（含第一类体外诊断试剂）备案信息&Id=\d+', s,
                           re.M)
            browser.close()

            for j in range(len(m)):
                url_2 = 'http://app1.sfda.gov.cn/datasearchcnda/face3/' + m[j]
                browser = webdriver.Chrome(chrome_options=option)
                browser.get(url_2)
                sql = "insert into t_jkdylylqx_hdyltwzdsj_baxx(c_bh, dt_insertTime, c_url, b_content,c_json, c_page) VALUES (REPLACE(UUID(),\"-\",\"\"), sysdate(), %s,%s,%s,%s)"
                mysql_db.exetcute_sql(sql, [url_2, browser.page_source, parse2json(browser.page_source),
                                            str(i) + '_' + str(j + 1)])
                # pickle.loads(s) 可用该方法将乱码汉字转换
                browser.close()
        except Exception as e:
            print(e)
            time.sleep(5)

def parse2json(html):
    '''
    备案号 bah
    产品类别 cplb
    备案人名称 barmc
    备案人组织机构代码 barzzjgdm
    备案人注册地址 barzcdz
    生产地址 scdz
    代理人 dlr
    代理人注册地址 dlrzcdz
    产品名称或产品分类名称 cpmchcpflmc
    型号/规格或包装规格xhgghbzgg
    产品有效期 cpyxq
    产品描述或主要组成成份 cpmshzyzccf
    预期用途 yqyt
    备注 bz
    备案单位badw
    备案日期barq
    变更情况bgqk
    备案状态bazt

    '''
    reg_dict = dict()
    result_json = dict()

    reg_dict['bah'] = r'备案号	\s*(.*)
'
    reg_dict['cplb'] = r'产品类别	\s*(.*)
'
    reg_dict['barmc'] = r'备案人名称	\s*(.*)
'
    reg_dict['barzzjgdm'] = r'备案人组织机构代码	\s*(.*)
'
    reg_dict['barzcdz'] = r'备案人注册地址	\s*(.*)
'
    reg_dict['scdz'] = r'生产地址	\s*(.*)
'
    reg_dict['dlr'] = r'代理人	\s*(.*)
'
    reg_dict['dlrzcdz'] = r'代理人注册地址	\s*(.*)
'
    reg_dict['cpmchcpflmc'] = r'产品名称或产品分类名称	\s*(.*)
'
    reg_dict['xhgghbzgg'] = r'规格或包装规格	\s*(.*)
'
    reg_dict['cpyxq'] = r'产品有效期	\s*(.*)
'
    reg_dict['cpmshzyzccf'] = r'产品描述或主要组成成份	\s*(.*)
'
    reg_dict['yqyt'] = r'预期用途	\s*(.*)
'
    reg_dict['bz'] = r'备注	\s*(.*)
'
    reg_dict['badw'] = r'备案单位	\s*(.*)
'
    reg_dict['barq'] = r'备案日期	\s*(.*)
'
    reg_dict['bgqk'] = r'变更情况	\s*(.*)
'
    reg_dict['bazt'] = r'备案状态	\s*(.*)
'
    for i, v in reg_dict.items():
        reg_search = re.search(v, html)
        if reg_search is not None:
            result_json[i] = reg_search.group(1)
        else:
            result_json[i] = ''
    return json.dumps(result_json, ensure_ascii=False)

if __name__ == '__main__':
    main()


import sys

# Find Spark
import findspark
findspark.init()

from pyspark import SparkContext
from pyspark.sql import SparkSession
from pyspark.sql.types import *

from pyspark.ml.recommendation import ALS
from pyspark.ml.evaluation import RegressionEvaluator

# Import mlflow
import mlflow
import mlflow.spark

# Define schema for movies dataset
moviesStruct = [StructField("movieId", IntegerType(), True),
    StructField("title", StringType(), True),
    StructField("genres", StringType(), True)]

moviesSchema = StructType(moviesStruct)

# Define schema for ratings dataset
ratingsStruct = [StructField("userId", IntegerType(), True),
StructField("movieId", IntegerType(), True),
StructField("rating", DoubleType(), True),
StructField("timestamp", IntegerType(), True)]

ratingsSchema = StructType(ratingsStruct)

if __name__ == "__main__":

    spark = SparkSession \
        .builder \
        .appName("Movie lens model") \
        .getOrCreate()

    # Get hyper parameters from command line
    maxIter = float(sys.argv[1]) if len(sys.argv) > 1 else 5
    regParam = float(sys.argv[2]) if len(sys.argv) > 2 else 0.01

    print("MaxIter {}, RegParam {}.".format(maxIter, regParam))

    # Read movies from HDFS
    moviesDf = spark.read.format("csv") \
        .option("header", "false") \
        .option("delimiter", "::") \
        .schema(moviesSchema) \
        .load("file:///home/mcheghal/Documents/sylace/bcg/mllib/ml-1m/movies.dat")

    # moviesDf.show(10, False)

    # Read ratings from HDFS
    ratingsDf = spark.read.format("csv") \
        .option("header", "false") \
        .option("delimiter", "::") \
        .schema(ratingsSchema) \
        .load("file:///home/mcheghal/Documents/sylace/bcg/mllib/ml-1m/ratings.dat")

    # ratingsDf.show(10)

    # Splitting training data
    training, test = ratingsDf.randomSplit([0.8, 0.2], seed=12345)

    # Got 1000209 ratings from 6040 users on 3883 movies.
    print("Training {}, test {}.".format(training.count(), test.count()))

    als = ALS(maxIter=maxIter,
              regParam=regParam, \
              implicitPrefs=False, \
              userCol="userId", \
              itemCol="movieId", \
              ratingCol="rating", \
              coldStartStrategy="drop")

    model = als.fit(training)

    predictions = model.transform(test)
    evaluator = RegressionEvaluator(metricName="rmse", labelCol="rating", predictionCol="prediction")

    rmse = evaluator.evaluate(predictions)
    print("Root-mean-square error = " + str(rmse))

    # Log hyper parameters
    mlflow.log_param("maxIter", maxIter)
    mlflow.log_param("regParam", regParam)

    # Log some metrics
    mlflow.log_metric("rmse", rmse)

    # Lo the model
    mlflow.spark.log_model(model, "model")
    print("Model saved in run %s" % mlflow.active_run().info.run_uuid)

    spark.stop()


#!/usr/bin/python3.5
import cv2
import sys
import numpy as np
import json

if len(sys.argv) < 2:
    print("Please call `./calibrate_camera_by_video.py <video>` to calibrate your camera.")
    sys.exit(-1)

# Start the video capture with the given video file
video_path = sys.argv[1]
video_capture = cv2.VideoCapture(video_path)
patternSize = (7, 5)

# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((5*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:5].T.reshape(-1,2)

# create the arguments of the calibrate camera function.
objpoints = []
imgpoints = []
imgSize = None
frameCount = 0

# while the camera is open,
while video_capture.isOpened():
    ret, frame = video_capture.read()
    # stop if we can't read a frame from the video e.g. its finished
    if ret is False:
        break
    frameCount += 1
    if frameCount % 50 != 1:
        continue

    # convert the image to gray
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # find the chessboard pattern with the given size
    ret, corners = cv2.findChessboardCorners(gray, patternSize)
    # store the current image's size to be used in calibrate camera.
    imgSize = gray.shape[::-1]

    # if we have found corners for the frame
    if ret is True and corners is not None:
        # refine corner locations
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)

        # append the object points
        objpoints.append(objp)
        # append the image points at the same order with objpoints
        imgpoints.append(corners2)

# given a list of matching object points and image points, calculate the camera calibration arguments
rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, imgSize, None, None)

print(json.dumps({
    'rms': rms,
    'camera_matrix': [[f for f in arr] for arr in camera_matrix],
    'dist_coefs': [f for f in dist_coefs[0]]
}))


def three_sum(nums):
  res = []
  nums.sort()

  for i in range(len(nums)-2):
    if i > 0 and nums[i] == nums[i-1]:
      continue

    l, r = i + 1, len(nums) - 1
    while l < r:
      sm = nums[i] + nums[l] + nums[r]
      if sm < 0:
        l += 1
      elif sm > 0:
        r -= 1
      else:
        res.append([nums[i], nums[l], nums[r]])

        # while 안에 while 쓸 때에 조건문 다시 써줘서 오류를 피한다.
        while l < r and nums[l] == nums[l+1]:
          l += 1
        while l < r and nums[r] == nums[r-1]:
          r -= 1
        l += 1
        r -= 1

  return res

nums = [-1, 0, 1, 2, -1, -4]
"""
a+b+c = 0
[ [-1, 0, 1], [-1, -1, 2] ]
"""

print(three_sum(nums))


def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        swapped = False
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]  # swap
                swapped = True
        if not swapped:  # 최적화: 한 번도 교환되지 않았다면 리스트는 이미 정렬된 상태
            break
    return arr

# 예시
arr = [64, 34, 25, 12, 22, 11, 90]
print("Original array:", arr)
sorted_arr = bubble_sort(arr)
print("Sorted array:", sorted_arr)


import numpy as np
from PIL import Image, ImageTk
import matplotlib.pyplot as plt
from pickle import load
from keras.models import load_model
from keras.preprocessing.sequence import pad_sequences
from keras.applications.xception import Xception
import tkinter as tk
from tkinter import filedialog
from tkinter.filedialog import askopenfile
import os
from gtts import gTTS

def extract_features(filename, model):
    try:
        image = Image.open(filename)
    except Exception as e:
        print("An error occured when opening the image from the specified path \n ERROR: ",e)
    image = image.resize((299,299))
    image = np.array(image)
    #converting 4 channel images to 3
    if image.shape[2] == 4:
        image = image[...,:3]
    image = np.expand_dims(image, axis=0)
    image = image/127.5
    image = image - 1.0
    feature = model.predict(image)
    return feature
def word_for_id(integer, tokenizer):
    for word, index in tokenizer.word_index.items():
        if index == integer:
            return word
    return None

def generate_desc(model, tokenizer, photo, max_length):
    in_text = 'start'
    for i in range(max_length):
        sequence = tokenizer.texts_to_sequences([in_text])[0]
        sequence = pad_sequences([sequence], maxlen = max_length)
        pred = model.predict([photo,sequence], verbose = 0)
        pred = np.argmax(pred)
        word = word_for_id(pred, tokenizer)
        if word is None:
            break
        in_text += ' ' + word
        if word == 'end':
            break
    return in_text

def predict_model(filename):
    max_length = 34
    tokenizer = load(open("tokenizer.p",'rb'))
    model = load_model('models/model_9.h5')
    xception_model = Xception(include_top = False, pooling = 'avg')
    photo = extract_features(filename, xception_model)
    description = generate_desc(model, tokenizer, photo, max_length)
    print("\nGenerating description...\n")
    print('Predicted description : {} \n'.format(description))
    print('Google GTTS audio...')
    audio_description = ' '.join(description.split(' ')[1:-1])
    text_to_speech(audio_description)

def text_to_speech(text):
    speech = gTTS(text)
    speech_file = 'speech.mp3'
    speech.save(speech_file)
    os.system('afplay ' + speech_file)

window = tk.Tk()
window.geometry("500x500")  # Size of the window
window.title('Image Describer')
my_font1=('times', 18, 'bold')
l1 = tk.Label(window,text='Image Describer',width=30,font=my_font1,bg='#fff', fg='#f00')
l1.grid(row=1,column=1)
b1 = tk.Button(window, text='Upload Image',
   width=20,command = lambda:upload_file())
b1.grid(row=2,column=1)

def upload_file():
    global img
    f_types = [('Jpg Files', '*.jpg')]
    filename = filedialog.askopenfilename(filetypes=f_types)
    print(filename)
    img = ImageTk.PhotoImage(file=filename)
    b2 =tk.Button(window,image=img) # using Button
    b2.grid(row=3,column=1)
    predict_model(filename)

window.mainloop()


import sys
from collections import deque
input = sys.stdin.readline

def bfs(index, k):
    queue = deque([])
    queue.append((index, sys.maxsize))
    visited = [0 for _ in range(n)]
    visited[index] = 1
    answer = 0

    while queue:
        node, dis = queue.popleft()
        if dis >= k:
            answer += 1
        for v in usado[node]:
            if visited[v[0]] == 0:
                queue.append((v[0], min(dis, v[1])))
                visited[v[0]] = 1

    return answer

n, q = map(int, input().split())
usado = [[] for _ in range(n)]

for i in range(n - 1):
    a, b, c = map(int, input().split())
    usado[a - 1].append([b - 1, c])
    usado[b - 1].append([a - 1, c])

for i in range(q):
    k, v = map(int, input().split())
    print(bfs(v - 1, k) - 1)


import time
import pytest

from pages.widgets_page import AccordionPage, AutocompletePage, DatePickerPage, SliderPage, ProgressBarPage, TabsPage, \
    ToolTipsPage, MenuPage

class TestAccordion:

    @pytest.mark.parametrize('section, tit', [('first', 'What is Lorem Ipsum?'),
                                              ('second', 'Where does it come from?'),
                                              ('third', 'Why do we use it?')])
    def test_accordion_page(self, driver, section, tit):
        accordion_page = AccordionPage(driver, "https://demoqa.com/accordian")
        accordion_page.open()
        title, content = accordion_page.check_accordion(section)
        assert content > 0
        assert title == tit

class TestAutocomplete:

    def test_add_multy_color(self, driver):
        autocomplete_page = AutocompletePage(driver, "https://demoqa.com/auto-complete")
        autocomplete_page.open()
        input_color = autocomplete_page.fill_input_multy_color()
        output_color = autocomplete_page.check_values_multy_color()
        assert input_color == output_color

    def test_autocomplete_remove_one_color(self, driver):
        autocomplete_page = AutocompletePage(driver, "https://demoqa.com/auto-complete")
        autocomplete_page.open()
        autocomplete_page.fill_input_multy_color()
        count_before, count_after = autocomplete_page.remove_one_color()
        assert count_before > count_after

    @pytest.mark.xfail(exception=TypeError)
    def test_autocomplete_remove_all_color(self, driver):
        autocomplete_page = AutocompletePage(driver, "https://demoqa.com/auto-complete")
        autocomplete_page.open()
        autocomplete_page.fill_input_multy_color()
        count_before, count_after = autocomplete_page.remove_all_color()
        assert count_before > count_after

    def test_single_color(self, driver):
        autocomplete_page = AutocompletePage(driver, "https://demoqa.com/auto-complete")
        autocomplete_page.open()
        input_color, output_color = autocomplete_page.fill_one_color()
        assert input_color == output_color

class TestDatePicker:

    def test_change_data(self, driver):
        date_piker_page = DatePickerPage(driver, "https://demoqa.com/date-picker")
        date_piker_page.open()
        date_before, date_after = date_piker_page.select_date()
        assert date_before != date_after

    def test_change_data_and_time(self, driver):
        date_piker_page = DatePickerPage(driver, "https://demoqa.com/date-picker")
        date_piker_page.open()
        date_before, date_after = date_piker_page.select_date_and_time()
        assert date_before != date_after

class TestSliderPage:
    def test_slider(self, driver):
        slider_page = SliderPage(driver, "https://demoqa.com/slider")
        slider_page.open()
        value_after, value_before = slider_page.change_slider_value()
        assert value_after != value_before

class TestProgressBarPage:
    def test_progress_bar(self, driver):
        progress_bar_page = ProgressBarPage(driver, "https://demoqa.com/progress-bar")
        progress_bar_page.open()
        before, after = progress_bar_page.change_progress_bar_value()
        print(before, after)
        assert before != after

class TestTabsPage:
    @pytest.mark.parametrize("tab, len", [('What', 574), ('Origin', 1059), ('Use', 613)])
    def test_change_tabs(self, driver, tab, len):
        tabs_page = TabsPage(driver, "https://demoqa.com/tabs")
        tabs_page.open()
        title, len_content = tabs_page.check_tabs(tab)
        assert title == tab
        assert len_content == len

class TestToolTips:

    def test_tool_tips(self, driver):
        tool_tips_page = ToolTipsPage(driver, 'https://demoqa.com/tool-tips')
        tool_tips_page.open()
        tool_tips_button, tool_tips_input, tool_tips_contrary, tool_tips_number = tool_tips_page.check_tool_tips()
        assert tool_tips_button == "You hovered over the Button"
        assert tool_tips_input == 'You hovered over the text field'
        assert tool_tips_contrary == 'You hovered over the Contrary'
        assert tool_tips_number == "You hovered over the 1.10.32"

class TestMenu:
    def test_menu(self, driver):
        menu_page = MenuPage(driver, "https://demoqa.com/menu")
        menu_page.open()
        menu = menu_page.check_nemu()
        assert menu == ['Main Item 1', 'Main Item 2\nSub Item\nSub Item\nSUB SUB LIST »', 'Sub Item', 'Sub Item',
                        'SUB SUB LIST »\nSub Sub Item 1\nSub Sub Item 2',
                        'Sub Sub Item 1', 'Sub Sub Item 2', 'Main Item 3']


def canTwoPartition(nums):
    """
    是否能分割成两个和相等的子集
    思路分析：这问题实际上属于0-1背包问题，典型的动态规划问题。
    1. 确定转移状态。dp[i][j]定义为从[0,i]子区间内挑选一些正整数，每个数只能用一次，使得这些数的和能够是j
    2. 状态转移方程。 如果nums[i]=j,那么dp[i][j]=True; 如果nums[i]<j,那么dp[i][j] = dp[i][j] or dp[i][j-nums[i]]
    3. 初始化。对于dp[0][0] = false,而dp[0][1]取决于j是否等于num[0]
    4. 输出。dp[len(nums)-1][target]
    :param nums:
    :return:
    算法分析：时间复杂度O(NC),空间复杂度O(NC),N代表[0,i]的区间长度，C代表[0,C]的区间长度
    """
    if not nums or len(nums) == 0:
        return False

    n = len(nums)

    # 求所有的和
    all_nums = sum(nums)

    # 如果是奇数，则不满足，需要分割的是两个相等和的子集，说明和一定是偶数
    if (all_nums & 1) == 1:
        return False

    target = all_nums // 2

    dp = [[True for _ in range(target + 1)] for _ in range(n)]

    for i in range(1, n):
        for j in range(target + 1):
            # 直接从上一行先把结果抄下来，然后再修正
            dp[i][j] = dp[i - 1][j]

            if nums[i] == j:
                dp[i][j] = True
                continue

            if nums[i] < j:
                dp[i][j] = dp[i][j] or dp[i][j - nums[i]]

    return dp[n - 1][target]

def canTwoPartitionPlus(nums):
    """
    是否能切割成两个和相等的子集
    动态规划优化——状态压缩，减少空间，二维变成一维,将原来的[0,i]区间的容量为j的数组转变成直接将前i个物品组合放进容量为c的背包里，得到的最大的价值
    :return:
    """
    n = len(nums)

    if not nums or n <= 0:
        return False

    all_sum = sum(nums)

    # 奇数不符合
    if (all_sum & 1) == 1:
        return False

    target = all_sum // 2

    dp = [nums[0] if j >= nums[0] else 0 for j in range(target + 1)]

    for i in range(1, n):
        j = target
        while j > 0:
            if nums[i] <= j:
                dp[j] = max(dp[j], (nums[i] + dp[j - nums[i]]))
            else:
                break
            j -= 1
        if dp[j] == target:
            return True
    return True if dp[target] == target else False

if __name__ == '__main__':
    print(canTwoPartitionPlus(nums=[1, 5, 11, 5]))