from ftree import treedata
import pgbase
import pygame
import numpy as np
import moderngl
import sys
import shapely.geometry
import networkx as nx
import itertools
import scipy.optimize
import scipy.spatial
import math
import time
import random
import os

##from ftree import shapelayout
##def entity_format(entity):
##    if type(entity) == treedata.Person:
##        sex = entity.get_sex()
##        if sex == "male":
##            colour = (0, 0.5, 1, 1)
##        elif sex == "female":
##            colour = (1, 0.5, 0.5, 1)
##        else:
##            colour = (1, 0.5, 0, 1)
##        name = " ".join(entity.get_first_names())
##        return shapelayout.height_frame(shapelayout.string((name if len(name) != 0 else "?"), (0, 0, 0, 1)), 0.9, colour)
##    elif type(entity) == treedata.Partnership:
##        return shapelayout.height_frame(shapelayout.letter("M", (0, 0, 0, 1)), 0.9, (0.7, 0.7, 0, 1))
##    else:
##        return shapelayout.height_frame(shapelayout.letter("?", (0, 0, 0, 1)), 0.9)

class TreeView(pgbase.canvas2d.Window2D):
    def __init__(self, tree, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.tree = tree

        self.bg_prog = self.ctx.program(
            vertex_shader = """
                #version 430
                in vec2 unit_pos;
                out vec4 gl_Position;
                out vec2 v_pos;

                void main() {
                    gl_Position = vec4(unit_pos, 0.0, 1.0);
                    v_pos = vec2(unit_pos);
                }
            """,
            fragment_shader = """
                #version 430
                in vec2 v_pos;
                out vec4 f_colour;

                uniform vec2 cam_center;
                uniform mat2 cam_mat;

                void main() {
                    vec2 pos = cam_mat * v_pos + cam_center;
                    bool bx = mod(pos.x, 2) < 1;
                    bool by = mod(pos.y, 2) < 1;

                    if ((bx && by) || (!bx && !by)) {
                        f_colour = 0.98 * vec4(1, 1, 1, 0);
                    } else {
                        f_colour = 1 * vec4(1, 1, 1, 0);
                    }
                }

            """,
        )
        vertices = self.ctx.buffer(np.array([[-1, -1], [1, -1], [-1, 1], [1, 1]]).astype('f4'))
        indices = self.ctx.buffer(np.array([[0, 1, 3], [0, 2, 3]]))
        self.bg_vao = self.ctx.vertex_array(self.bg_prog,
                                         [(vertices, "2f4", "unit_pos")],
                                         indices)

        self.entity_prog = self.ctx.program(
            vertex_shader = """
                #version 430
                in vec2 pos;
                out vec2 g_pos;

                in float border;
                out float g_border;

                in uint v_tex_idx;
                flat out uint g_tex_idx;

                void main() {
                    g_pos = pos;
                    g_tex_idx = v_tex_idx;
                    g_border = border;
                }
            """,
            geometry_shader = """
                #version 430
                layout (points) in;
                layout (triangle_strip, max_vertices = 100) out;
                in vec2 g_pos[];

                flat in uint g_tex_idx[];
                flat out uint f_tex_idx;

                in float g_border[];
                out float f_border;

                uniform vec2 cam_center;
                uniform mat2 cam_mat_inv;

                uniform float w;
                uniform float h;

                out vec2 f_tex_pos;

                void main() {
                    f_tex_idx = g_tex_idx[0];
                    f_border = g_border[0];

                    vec2 pos;

                    float bw = w + 2 * g_border[0];
                    float bh = h + 2 * g_border[0];

                    f_tex_pos = vec2(-g_border[0] / w, -g_border[0] / h);
                    pos = g_pos[0] + vec2(-bw, -bh);
                    gl_Position = vec4(cam_mat_inv * (pos - cam_center), 0, 1);
                    EmitVertex();
                    f_tex_pos = vec2(1 + g_border[0] / w, -g_border[0] / h);
                    pos = g_pos[0] + vec2(bw, -bh);
                    gl_Position = vec4(cam_mat_inv * (pos - cam_center), 0, 1);
                    EmitVertex();
                    f_tex_pos = vec2(1 + g_border[0] / w, 1 + g_border[0] / h);
                    pos = g_pos[0] + vec2(bw, bh);
                    gl_Position = vec4(cam_mat_inv * (pos - cam_center), 0, 1);
                    EmitVertex();
                    EndPrimitive();

                    f_tex_pos = vec2(-g_border[0] / w, -g_border[0] / h);
                    pos = g_pos[0] + vec2(-bw, -bh);
                    gl_Position = vec4(cam_mat_inv * (pos - cam_center), 0, 1);
                    EmitVertex();
                    f_tex_pos = vec2(-g_border[0] / w, 1 + g_border[0] / h);
                    pos = g_pos[0] + vec2(-bw, bh);
                    gl_Position = vec4(cam_mat_inv * (pos - cam_center), 0, 1);
                    EmitVertex();
                    f_tex_pos = vec2(1 + g_border[0] / w, 1 + g_border[0] / h);
                    pos = g_pos[0] + vec2(bw, bh);
                    gl_Position = vec4(cam_mat_inv * (pos - cam_center), 0, 1);
                    EmitVertex();
                    EndPrimitive();
                }
            """,
            fragment_shader = """
                #version 430
                in vec2 f_tex_pos;
                in float f_border;
                out vec4 f_colour;
                flat in uint f_tex_idx;

                uniform sampler2DArray tex;

                void main() {
                    if (f_tex_pos.x < 0 || f_tex_pos.x > 1 || f_tex_pos.y < 0 || f_tex_pos.y > 1) {
                        f_colour = vec4(0, 0, 0, 1);
                    } else {
                        f_colour = texture(tex, vec3(f_tex_pos, f_tex_idx));
                    }
                }

            """,
        )
        self.entity_prog["tex"] = 0
        self.entity_prog["w"] = 0.4
        self.entity_prog["h"] = 0.6
        self.entity_vao = None

        self.edge_prog = self.ctx.program(
            vertex_shader = """
                #version 430
                in vec2 top_pos;
                in vec2 bot_pos;
                in vec4 colour;
                out vec2 g_top_pos;
                out vec2 g_bot_pos;
                out vec4 g_colour;

                void main() {
                    g_top_pos = top_pos;
                    g_bot_pos = bot_pos;
                    g_colour = colour;
                }
            """,
            geometry_shader = """
                #version 430
                layout (points) in;
                layout (triangle_strip, max_vertices = 128) out;
                in vec2 g_top_pos[];
                in vec2 g_bot_pos[];
                in vec4 g_colour[];
                out vec4 g_colour_out;

                uniform vec2 cam_center;
                uniform mat2 cam_mat_inv;

                uniform float width;

                vec4 pos_to_gl(vec2 pos) {
                    return vec4(cam_mat_inv * (pos - cam_center), 0, 1);
                }

                void emit_line(vec2 p1, vec2 p2) {
                    vec2 vec = p2 - p1;
                    vec2 norm = width * normalize(vec2(-vec.y, vec.x));

                    gl_Position = pos_to_gl(p1 + norm);
                    EmitVertex();
                    gl_Position = pos_to_gl(p1 - norm);
                    EmitVertex();
                    gl_Position = pos_to_gl(p2 - norm);
                    EmitVertex();
                    EndPrimitive();

                    gl_Position = pos_to_gl(p1 + norm);
                    EmitVertex();
                    gl_Position = pos_to_gl(p2 + norm);
                    EmitVertex();
                    gl_Position = pos_to_gl(p2 - norm);
                    EmitVertex();
                    EndPrimitive();
                }

                void emit_joint(vec2 p1, vec2 p2, vec2 p3) {
                    vec2 vec12 = p2 - p1;
                    vec2 norm12 = width * normalize(vec2(-vec12.y, vec12.x));
                    vec2 vec23 = p3 - p2;
                    vec2 norm23 = width * normalize(vec2(-vec23.y, vec23.x));

                    gl_Position = pos_to_gl(p2);
                    EmitVertex();
                    gl_Position = pos_to_gl(p2 + norm12);
                    EmitVertex();
                    gl_Position = pos_to_gl(p2 + norm23);
                    EmitVertex();
                    EndPrimitive();

                    gl_Position = pos_to_gl(p2);
                    EmitVertex();
                    gl_Position = pos_to_gl(p2 - norm12);
                    EmitVertex();
                    gl_Position = pos_to_gl(p2 - norm23);
                    EmitVertex();
                    EndPrimitive();
                }

                float bez2(float f, float a, float b) {
                    return a + f * (b - a);
                }

                float bez3(float f, float a, float b, float c) {
                    return bez2(f, a + f * (b - a), b + f * (c - b));
                }

                float bez4(float f, float a, float b, float c, float d) {
                    return bez3(f, a + f * (b - a), b + f * (c - b), c + f * (d - c));
                }

                void main() {
                    g_colour_out = g_colour[0];

                    const int n = 10;
                    const float pi = 3.1415926535897932384626433;

                    vec2[n+2] pts;

                    vec2 p0 = g_top_pos[0];
                    vec2 p1 = g_top_pos[0] - vec2(0, 0.5);
                    vec2 p2 = g_top_pos[0] - vec2(0, 1);
                    vec2 p3 = g_bot_pos[0] + vec2(0, 1);
                    vec2 p4 = g_bot_pos[0] + vec2(0, 0.5);
                    vec2 p5 = g_bot_pos[0];

                    pts[0] = p0;
                    pts[n+1] = p5;

                    for (int i = 0; i < n; i++) {
                        float f = float(i) / float(n - 1);
                        f = 0.5 * (sin(pi * (f - 0.5)) + 1);
                        pts[i+1] = vec2(bez4(f, p1.x, p2.x, p3.x, p4.x), bez4(f, p1.y, p2.y, p3.y, p4.y));
                    }

                    for (int i = 0; i < n+1; i++) {
                        emit_line(pts[i], pts[i+1]);
                    }

                    for (int i = 0; i < n; i++) {
                        emit_joint(pts[i], pts[i+1], pts[i+2]);
                    }

                }
            """,
            fragment_shader = """
                #version 430
                in vec4 g_colour_out;
                out vec4 f_colour;

                void main() {
                    f_colour = g_colour_out;
                }

            """,
        )
        self.edge_prog["width"] = 0.07
        self.edge_vao = None

        self.tex = self.ctx.texture_array([400, 600, 2048], 4, dtype = "f1")
        self.node_surf_data = {}
        self.nodes_waiting_for_surf_update = set()
        self.visible_nodes = {} #node -> texture index

##        self.shapes = pgbase.canvas2d.ShapelyModel(self.ctx)

        self.node_heights = {}
        self.node_widths = {}

        self.root = None
        self.node_widths = {}
        self.node_heights = {}
        self.more_to_see_nodes = set([])
        self.cycle_edges = set([])

        #variables for changing root node animation
        self.node_draw_positions = {}

        self.moving_nodes = []
        self.moving_nodes_old_positions = np.zeros([0, 2])
        self.moving_nodes_new_positions = np.zeros([0, 2])
        self.last_rootchange_time = time.time()

        self.G = self.tree.digraph() #the full graph
        self.T = nx.DiGraph() #a tree subgraph of G which we will draw as much of as possible

        root = max(self.G.nodes(), key = lambda x : len(nx.ancestors(self.G, x)))
        for _ in range(0):
            root = next(iter(G.predecessors(root)))

        self.click_pos = None

        self.set_root(root)

    def set_root(self, root):
        self.root = root
        self.update_node_positions()

    def update_node_positions(self):
        old_node_draw_positions = {n : p for n, p in self.node_draw_positions.items()}

        #set self.node_heights and self.T
        self.T = nx.DiGraph()
        self.T.add_node(self.root)
        self.node_heights = {self.root : 0}
        if self.root in old_node_draw_positions:
            self.node_heights[self.root] = old_node_draw_positions[self.root][1]

        g_edges = set(self.G.edges())
        for t_edge in nx.bfs_edges(self.G.to_undirected(), self.root):
            if t_edge in g_edges:
                g_edge = t_edge
                self.T.add_edge(g_edge[0], g_edge[1])
                self.node_heights[t_edge[1]] = self.node_heights[t_edge[0]] - 1
            else:
                g_edge = (t_edge[1], t_edge[0])
                assert g_edge in g_edges
                self.T.add_edge(g_edge[0], g_edge[1])
                self.node_heights[t_edge[1]] = self.node_heights[t_edge[0]] + 1

        #set self.node_widths and self.more_to_see_nodes

        #successors
        #predecessors
        #ancestors
        #descendants

        ordering_node_widths = {node : self.node_widths.get(node, random.uniform(0, 1)) for node in self.T.nodes}

        def match(node, rw1, rw2):
            assert node in rw1
            assert node in rw2
            for a in rw1:
                for b in rw2:
                    if a != node and b != node:
                        assert a != b
            off = rw1[node] - rw2[node]
            rw2m = {b : w + off for b, w in rw2.items()}
            return rw1 | rw2m

        def center(rw, c):
            if len(rw) == 0:
                return rw
            else:
                min_w = min(list(rw.values()))
                max_w = max(list(rw.values()))
                off = 0.5 * (max_w + min_w)
                return {a : w - off for a, w in rw.items()}

        def stack_pair(rw1, rw2, side):
            #side = 0: place rw1 to the left of rw2
            #side = 1: place rw2 to the right of rw1
            assert 0 <= side <= 1

            rw1_max = {}
            for a in rw1:
                h = self.node_heights[a]
                if not h in rw1_max:
                    rw1_max[h] = rw1[a]
                else:
                    rw1_max[h] = max(rw1_max[h], rw1[a])
            rw2_min = {}
            for b in rw2:
                h = self.node_heights[b]
                if not h in rw2_min:
                    rw2_min[h] = rw2[b]
                else:
                    rw2_min[h] = min(rw2_min[h], rw2[b])

            for h in rw1_max.keys() | rw2_min.keys():
                assert not math.isnan(rw2_min.get(h, math.inf) - rw1_max.get(h, -math.inf))

            m = min(rw2_min.get(h, math.inf) - rw1_max.get(h, -math.inf) - 1 for h in rw1_max.keys() | rw2_min.keys())

            if m == math.inf:
                return center(rw1, 0) | center(rw2, 0)
            else:
                rw = {}
                for a, w in rw1.items():
                    rw[a] = w + m * (1 - side)
                for b, w in rw2.items():
                    rw[b] = w - m * side
                return rw

        def stack(rws):
            if len(rws) == 0:
                return {}
            elif len(rws) == 1:
                return rws[0]
            elif len(rws) == 2:
                return stack_pair(rws[0], rws[1], 0.5)
            else:
                k = len(rws) // 2
                return stack_pair(stack(rws[:k]), stack(rws[k:]), 0.5)

        def compute_widths_related(G, node):
            assert nx.is_tree(G.to_undirected())

            #decide on an order for things
            pred_lookup = {x : sorted(G.predecessors(x), key = lambda y : ordering_node_widths[y]) for x in G.nodes()}
            succ_lookup = {x : sorted(G.successors(x), key = lambda y : ordering_node_widths[y]) for x in G.nodes()}

            #heres how the algorithm works:
            #compute_upwards
            #    take a node and compute the positions of everything directly above it.
            #    directly above means all ancestors and all of their decendents lying inside the cone
            #compute_whole
            #    compute positions of all ancestors and _all_ of their decendents
            #    do this by using compute_upwards to find positions for all ancestors decendents inside the cone
            #    then go up the sides of the cone and place the remaining decendents fitted to each side of the cone

            def compute_widths_down_part(G, node, minh = -math.inf, excluded_succ = None):
                if excluded_succ is None:
                    excluded_succ = set([])
                assert self.node_heights[node] >= minh
                #add partnerships
                tops = [node]
                found_tops = set([node])
                for n in succ_lookup[node]:
                    if not n in excluded_succ:
                        if self.node_heights[n] >= minh:
                            for p in pred_lookup[n]:
                                if not p in found_tops:
                                    found_tops.add(p)
                                    if len(tops) % 2 == 0:
                                        tops = tops + [p]
                                    else:
                                        tops = [p] + tops
                tops = [{p : 0} for p in sorted(tops, key = lambda p : ordering_node_widths[p])]
                #add everything below
                bots = []
                for n in succ_lookup[node]:
                    if not n in excluded_succ:
                        if self.node_heights[n] >= minh:
                            bots.append(compute_widths_down_part(G, n, minh = minh))
                return center(stack(tops), 0) | center(stack(bots), 0)

            def compute_upwards(G, node, block_left, block_right, minh_left, minh_right):
                assert block_left or block_right
                preds = pred_lookup[node]
                minh_mid = self.node_heights[node] + 1
                tops = []
                for i, n in enumerate(preds):
                    if i == 0 == len(preds) - 1:
                        tops.append(compute_upwards(G, n, block_left, block_right, minh_left, minh_right))
                    elif i == 0 and block_left:
                        tops.append(compute_upwards(G, n, True, False, minh_left, minh_mid))
                    elif i == len(preds) - 1 and block_right:
                        tops.append(compute_upwards(G, n, False, True, minh_mid, minh_right))
                    else:
                        if i == 0:
                            tops.append(compute_whole(G, n, compute_widths_down_part(G, n, minh = minh_left, excluded_succ = {node}), minh_left = minh_left, minh_right = minh_mid))
                        elif i == len(preds) - 1:
                            tops.append(compute_whole(G, n, compute_widths_down_part(G, n, minh = minh_right, excluded_succ = {node}), minh_left = minh_mid, minh_right = minh_right))
                        else:
                            tops.append(compute_whole(G, n, compute_widths_down_part(G, n, minh = minh_mid, excluded_succ = {node}), minh_left = minh_mid, minh_right = minh_mid))

                top = center(stack(tops) , 0)
                if block_left and block_right:
                    return top | {node : 0}
                elif block_left:
                    ans = stack_pair({node : 0.0}, top, 0)
                    ans[node] = min(ans[node], 0.0)
                    return ans
                elif block_right:
                    ans = stack_pair(top, {node : 0.0}, 1)
                    ans[node] = max(ans[node], 0.0)
                    return ans
                else:
                    assert False #at least one of block_left/block_right should be True

            def compute_whole(G, node, base, minh_left, minh_right):
                assert node in base
                core = match(node, compute_upwards(G, node, True, True, minh_left, minh_right), base)

##                def yield_middle(x):
##                    ps = pred_lookup[x]
##                    if len(ps) == 1:
##                        yield x, ps[0]
##                        yield from yield_left_side(ps[0])

                def yield_left_side(x):
                    ps = pred_lookup[x]
                    if len(ps) >= 1:
                        yield x, ps[0]
                        yield from yield_left_side(ps[0])

                def yield_right_side(x):
                    ps = pred_lookup[x]
                    if len(ps) >= 1:
                        yield x, ps[-1]
                        yield from yield_right_side(ps[-1])

##                if (minh_both := minh_left) == minh_right:
##                    bottoms = []
##                    for a, b in yield_middle(node):
##                        for x in succ_lookup[b]:
##                            bottoms.append((x, compute_widths_down_part(G, x, minh = minh_both)))
##                    bottoms = sorted(bottoms, key = lambda pair : ordering_node_widths[pair[0]])
##                    bottoms = [piece for x, piece in bottoms]
##                    node = b #named becasue its at the top of the 1 wide stalk of the tree

                preds = pred_lookup[node]
                done = set([]) #so that we dont repeat descendants of things lying on the initial 1 wide stalk
                def gen_hang_left():
                    for a, b in yield_left_side(node):
                        if not b in done:
                            for x in reversed(succ_lookup[b]):
                                if not x is a:
                                    yield compute_widths_down_part(G, x, minh = minh_left)
                            done.add(b)

                def gen_hang_right():
                    for a, b in yield_right_side(node):
                        if not b in done:
                            for x in succ_lookup[b]:
                                if not x is a:
                                    yield compute_widths_down_part(G, x, minh = minh_right)
                            done.add(b)

                if minh_left <= minh_right:
                    hang_left = list(gen_hang_left())
                    hang_right = list(gen_hang_right())
                else:
                    hang_right = list(gen_hang_right())
                    hang_left = list(gen_hang_left())

                for hang in hang_left:
                    core = stack([hang, core])
                for hang in hang_right:
                    core = stack([core, hang])
                return core

            return center(compute_whole(G, node, compute_widths_down_part(G, node), -math.inf, -math.inf), 0)

        self.node_widths = compute_widths_related(self.T, self.root)

        self.more_to_see_nodes = set([])
        for node in self.node_widths:
            for x in itertools.chain(self.G.successors(node), self.G.predecessors(node)):
                if not x in self.node_widths:
                    self.more_to_see_nodes.add(node)

##        self.update_shapes_vao()

        self.moving_nodes = list(old_node_draw_positions.keys() & self.node_widths.keys())
        self.moving_nodes_old_positions = np.array([old_node_draw_positions[n] for n in self.moving_nodes])
        self.moving_nodes_new_positions = np.array([[self.node_widths[n], self.node_heights[n]] for n in self.moving_nodes])
        self.last_rootchange_time = time.time()

        self.visible_nodes = {ident : idx for idx, ident in enumerate(self.node_widths.keys() | self.moving_nodes)}
        self.nodes_waiting_for_surf_update = set(self.visible_nodes.keys())

    def get_surf_data(self, entity):
        if not entity in self.node_surf_data:
            if type(entity) == treedata.Person:
                surf = pygame.Surface([self.tex.width, self.tex.height], flags = pygame.SRCALPHA)

                sex = entity.get_sex()
                if sex is None:
                    bg_colour = [128, 128, 128, 255]
                elif sex == "male":
                    bg_colour = [64, 160, 255, 255]
                elif sex == "female":
                    bg_colour = [255, 64, 255, 255]
                else:
                    bg_colour = [112, 64, 255, 255]
                surf.fill(bg_colour)
                pgbase.surftools.write(surf, entity.name(), [0, 0, 1, 0.2], [0, 0, 0, 255])

                event_strs = entity.get_event_strings(["birth", "death"])

                y = 0.2
                for event_str in event_strs:
                    pgbase.surftools.write(surf, event_str, [0, y, 1, 0.1], [0, 0, 0, 255])
                    y += 0.1

            else:
                surf = pygame.Surface([self.tex.width, self.tex.height], flags = pygame.SRCALPHA)
                surf.fill([0, 0, 0, 0])
                pygame.draw.circle(surf, [0, 0, 0, 255], [surf.get_width() / 2, surf.get_height() / 2], surf.get_width() / 3)

            data = pygame.image.tostring(surf, "RGBA", 1)
            self.node_surf_data[entity] = data

        return self.node_surf_data[entity]

    def node_pos(self, node):
        #currently requires the x position to be preserved so that the interactive stuff works
        #can add a inverse node pos function if this needs to be changed in the future
        pos = self.node_draw_positions[node]
        return [pos[0], 2 * pos[1]]

    def update_vaos(self):
        import random

        H = self.G.subgraph(self.node_draw_positions.keys())

        nodes = list(H.nodes)
        buffer_vertices = self.ctx.buffer(np.array([self.node_pos(node) for node in nodes]).astype('f4'))
        tex_idx = self.ctx.buffer(np.array([self.visible_nodes[node] for node in nodes]))
        buffer_indices = self.ctx.buffer(np.array(range(len(nodes))))
        def get_border(node):
            if isinstance(self.tree.entity_lookup[node], treedata.Person):
                if node in self.more_to_see_nodes:
                    return 0.03
                else:
                    return 0.02
            else:
                return 0.0
        borders = self.ctx.buffer(np.array([get_border(node) for node in nodes]).astype('f4'))

        self.entity_vao = self.ctx.vertex_array(self.entity_prog,
                                                [(buffer_vertices, "2f4", "pos"),
                                                 (tex_idx, "u4", "v_tex_idx"),
                                                 (borders, "f4", "border")],
                                                buffer_indices)

        colour_tree_edge = [0, 0, 0, 1]
        colour_loop_edge = [1, 0, 1, 1]
        tree_edges = set(self.T.edges())

        edges = list(H.edges())
        buffer_top_vertices = self.ctx.buffer(np.array([self.node_pos(edge[0]) for edge in edges]).astype('f4'))
        buffer_bot_vertices = self.ctx.buffer(np.array([self.node_pos(edge[1]) for edge in edges]).astype('f4'))
        buffer_colours = self.ctx.buffer(np.array([(colour_tree_edge if edge in tree_edges else colour_loop_edge) for edge in edges]).astype('f4'))
        indices = self.ctx.buffer(np.array(range(len(edges))))
        self.edge_vao = self.ctx.vertex_array(self.edge_prog,
                                              [(buffer_top_vertices, "2f4", "top_pos"),
                                               (buffer_bot_vertices, "2f4", "bot_pos"),
                                               (buffer_colours, "4f4", "colour")],
                                              indices)

    def set_rect(self, rect):
        super().set_rect(rect)

    def tick(self, dt):
        d = 0.75
        if time.time() < self.last_rootchange_time + d and len(self.moving_nodes) != 0:
            f = (time.time() - self.last_rootchange_time) / d
            f = 0.5 * (math.cos(math.pi * (f - 1)) + 1)
            poses = f * self.moving_nodes_new_positions + (1 - f) * self.moving_nodes_old_positions
            self.node_draw_positions = {n : poses[i] for i, n in enumerate(self.moving_nodes)}
        else:
            self.node_draw_positions = {n : [self.node_widths[n], self.node_heights[n]] for n in self.node_widths}
        self.update_vaos()

        start_time = time.time()
        while time.time() - start_time < dt and len(self.nodes_waiting_for_surf_update) != 0:
            #generate some surfaces starting with the ones closest the center of the screen
            def distsq(a, b):
                return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2

            ident = min(self.nodes_waiting_for_surf_update, key = lambda ident : distsq(self.node_pos(ident), self.center)if ident in self.node_draw_positions else math.inf)
            self.nodes_waiting_for_surf_update.remove(ident)

            layer = self.visible_nodes[ident]
            self.tex.write(self.get_surf_data(self.tree.entity_lookup[ident]), viewport = (0, 0, layer, self.tex.width, self.tex.height, 1))

    def event(self, event):
        def dist(p1, p2):
            return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)

        CLICK_DIST = 30

        super().event(event)
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                self.click_pos = event.pos

        if event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                if not self.click_pos is None:
                    if dist(self.click_pos, event.pos) < CLICK_DIST:
                        pos = self.pygame_to_world(self.click_pos)
                        node = min(self.node_draw_positions.keys(), key = lambda node : dist(pos, self.node_pos(node)))
                        node_pos = self.node_pos(node)
                        scr_node_pos = self.world_to_pygame(node_pos)
                        if dist(self.click_pos, scr_node_pos) < CLICK_DIST:
                            self.set_root(node)
                            self.center = self.center - np.array(node_pos) + np.array(self.node_pos(node))
                            if not pgbase.tools.in_rect(self.world_to_pygame([0, 0]), self.rect):
                                self.center[0] = 0

                    else:
                        pos = self.pygame_to_world(self.click_pos)
                        node = min(self.node_draw_positions.keys(), key = lambda node : dist(pos, self.node_pos(node)))
                        node_pos = self.node_pos(node)
                        scr_node_pos = self.world_to_pygame(node_pos)
                        if dist(self.click_pos, scr_node_pos) < CLICK_DIST:
                            #move node and re-calculate positions using the new position to determine the ordering
                            self.node_widths[node] = self.pygame_to_world(event.pos)[0]
                            self.set_root(self.root)

                    self.click_pos = None

    def draw(self):
        super().set_uniforms([self.bg_prog, self.entity_prog, self.edge_prog])

        self.ctx.screen.use()
        self.ctx.clear(1, 1, 1, 1)

        self.ctx.enable_only(moderngl.BLEND)

        self.bg_vao.render(moderngl.TRIANGLES, instances = 1)
        if not self.edge_vao is None:
            self.edge_vao.render(moderngl.POINTS, instances = 1)
        if not self.entity_vao is None:
            self.tex.use(0)
            self.entity_vao.render(moderngl.POINTS, instances = 1)

def run(tree):
    assert type(tree) == treedata.Tree
    pgbase.core.Window.setup(size = [1600, 1000])
    pgbase.core.run_root(TreeView(tree))


'''
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000
For example, 2 is written as II in Roman numeral, just two one's added together. 12 is written as XII, which is simply X + II. The number 27 is written as XXVII, which is XX + V + II.

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

I can be placed before V (5) and X (10) to make 4 and 9.
X can be placed before L (50) and C (100) to make 40 and 90.
C can be placed before D (500) and M (1000) to make 400 and 900.
Given an integer, convert it to a roman numeral.
'''

class Solution(object):
    def intToRoman(self, numero):
        """
        :type num: int
        :rtype: str
        """
        equivalencia = {1:"I",5:"V",10:"X",50:"L",100:"C",500:"D",1000:"M"} #Tabla con las equivalencias
        romano = "" #Palabra que se va formando
        lista_numero = sorted(equivalencia.keys(), reverse=True) #Obtenemos los numeros ordenados de mayor a menor
        cont = 0 #Posicion de la lista que se va a mirar

        #Mientras el numero que estamos transformando sea mayor que 0 y no se acaben las equivalencias
        while numero > 0 and cont <= len(lista_numero) :
            if numero - lista_numero[cont] >= 0:
                #Si el numero contiene un 900
                if numero < 1000 and numero > 899:
                    romano += "CM"
                    numero = numero - 900
                #Si el numero contiene un 400
                elif numero < 500 and numero > 399:
                    romano += "CD"
                    numero = numero - 400
                #Si el numero contiene un 90
                elif numero < 100  and numero > 89:
                    romano += "XC"
                    numero = numero - 90
                #Si el numero contiene un 40
                elif numero < 50 and numero > 39:
                    romano += "XL"
                    numero = numero - 40
                elif numero == 9:
                    romano += "IX"
                    numero = numero - 9
                elif numero == 4:
                    romano += "IV"
                    numero = numero - 4
                else:
                    romano += equivalencia[lista_numero[cont]]
                    numero = numero - lista_numero[cont]

            elif numero - lista_numero[cont] > 0:
                return romano
            else:
                cont +=1

        return romano


from pathlib import Path
import copy

PROJECT_DIR = Path(__file__).resolve().parents[1]
INPUT_FILE         = PROJECT_DIR / "Day_11" / "input.txt"
EXAMPLE_INPUT_FILE = PROJECT_DIR / "Day_11" / "example_input.txt"

def get_input(filepath: Path) -> list[list[int]]:
    grid = []
    with open(filepath, "r") as f:
        for grid_line in f.readlines():
            grid.append([int(i) for i in grid_line.strip()])

    return grid

def update_grid(grid: list[list[int]]) -> int:
    # update grid inplace
    n_rows    = len(grid)
    n_cols    = len(grid[0])
    flashed   = []  # An octopus can only flash at most once per step!

    # 1. increase every element in the grid
    for row_i in range(n_rows):
        for col_i in range(n_cols):
            if(row_i, col_i) not in flashed:
                grid[row_i][col_i] += 1
            else:
                grid[row_i][col_i] = 0

    while True:
        # 2. check elements that flashed
        flash_buffer = []
        for row_i in range(n_rows):
            for col_i in range(n_cols):
                if grid[row_i][col_i] > 9 and (row_i, col_i) not in flashed:
                    # flash
                    flash_buffer.append((row_i, col_i))
                    flashed.append((row_i, col_i))

        # 3. check if anything flashed
        if flash_buffer == []:
            return len(flashed)

        # 4. increase neighbors of flashed elements
        for row_i, col_i in flash_buffer:
            for row_j in range(row_i-1, row_i+2):
                for col_j in range(col_i-1, col_i+2):
                    if row_j >= 0 and row_j < n_rows and col_j >= 0 and col_j < n_cols:
                        if(row_j, col_j) not in flashed:
                            grid[row_j][col_j] += 1
                        else:
                            grid[row_j][col_j] = 0

def print_grid(grid: list[list[int]]):
    for row in grid:
        print(row)

def part_1(grid: list[list[int]]) -> int:
    temp_grid = copy.deepcopy(grid)

    total_flashes = 0
    for _ in range(100):
        flashes = update_grid(temp_grid)
        total_flashes += flashes

    return total_flashes

def part_2(grid: list[list[int]]) -> int:
    temp_grid = copy.deepcopy(grid)

    update_grid_step = 0
    while True:
        update_grid_step += 1
        flashes = update_grid(temp_grid)
        if flashes >= 100:
            return update_grid_step

if __name__ == '__main__':
    # horizontal position of each crab
    # -> make all of their horizontal positions match while requiring them to spend as little fuel as possible
    print(INPUT_FILE)

    # parse input
    example_grid = get_input(EXAMPLE_INPUT_FILE)
    print_grid(example_grid)

    grid = get_input(INPUT_FILE)
    print_grid(grid)

    # Part 1
    print(part_1(example_grid))  # 1656
    print(part_1(grid))

    # Part 2
    print(part_2(example_grid))
    print(part_2(grid))


import pandas as pd
import pygal

df = pd.read_csv("dataNew.csv")

host_freq = pd.DataFrame(columns=['Host', 'Frequency'])
host_freq['Frequency'] = df.groupby('Host').size()
host_freq['Host'] = df.groupby('Host').agg({'Host': lambda x: list(x).__getitem__(1)})

df_attack = pd.read_csv("SQl-XSS.csv")
df_pages = df_attack[(df_attack.sqli_injection == True) | (df_attack.xss == True)]

#malcious ip xss
df_most_malicious = pd.DataFrame(columns=['Host', 'Frequency_xss', 'Frequency_sql', 'Frequency_lfi', 'FrequencyWebshell'])
df_most_malicious['Frequency_xss'] = df_attack[df_attack.xss == True].groupby('Host').size()
df_most_malicious['Frequency_sql'] = df_attack[df_attack.sqli_injection == True].groupby('Host').size()
df_most_malicious['Frequency_lfi'] = df_attack[df_attack.lfi == True].groupby('Host').size()
df_most_malicious['FrequencyWebshell'] = df_attack[df_attack.Webshell == True].groupby('Host').size()
df_most_malicious['Host'] = df_attack.groupby('Host').agg({'Host': lambda x: list(x).__getitem__(1)})
malcious_ip_xss = df_most_malicious.sort_values(['Frequency_xss', 'Frequency_sql'], ascending=[False, False])
sorted_malicious_ip= df_most_malicious.sort_values(['Frequency_xss', 'Frequency_sql', 'Frequency_lfi', 'FrequencyWebshell'], ascending=[False, False, False, False]).head(5)

line_chart = pygal.HorizontalBar()
line_chart.title = 'Top 5 dangerous IP'
for index, row in sorted_malicious_ip.head(5).iterrows():
    line_chart.add(row['Host'], row['Frequency_xss'] + row['Frequency_sql']+row['Frequency_lfi']+row['FrequencyWebshell'])
line_chart.render_to_file("Top5ip.svg")

# #TOP 5 IP ATTACKED
df_top_attack = pd.DataFrame(columns=['Endpoint', 'Frequency_xss', 'Frequency_sql', 'Frequency_lfi', 'FrequencyWebshell', 'Frequency'])
#EDW
df_attack = df_attack.applymap(lambda x: 1 if x == True else x)
df_attack = df_attack.applymap(lambda x: 0 if x == False else x)
df_top_attack['Endpoint'] = df_attack['Endpoint']

count = []
for index, row in df_attack.iterrows():
    count.append(row['xss'] + row['Webshell'] + row['sqli_injection'] + row['lfi'])
df_top_attack['Frequency'] = count

line_chart = pygal.HorizontalBar()
line_chart.title = 'Top 5 attacked endpoint'
df_new = pd.DataFrame({'count': df_top_attack.groupby('Endpoint').size()}).reset_index()
for index, row in df_new.sort_values('count', ascending=False).head(5).iterrows():
   line_chart.add(row['Endpoint'], row['count'])

line_chart.render_to_file("Top5endpoints.svg")


# Import socket module
from socket import *
# Create a TCP welcome server socket for handshake
#(AF_INET is used for IPv4 protocols)
#(SOCK_STREAM is used for TCP)
serverSocket = socket(AF_INET, SOCK_STREAM)
# Assign a port number
serverPort = 12000
# Bind the welcome socket to server address and server port
serverSocket.bind(("",serverPort))
# Listen to at most 1 connection at a time
serverSocket.listen(1)
# Server should be up and running and listening to the incoming connections
# send() and recv() are used for TCP socket
print("The server is ready to receive: ")
while True:
# Set up a new connection socket from the client
    connectionSocket, clientAddr = serverSocket.accept()
# Receives the request message from the client
    sentence = connectionSocket.recv(2048).decode()
    capitalizedSentence = sentence.upper()
# Send the capitalized message to the connection socket
    connectionSocket.send(capitalizedSentence.encode())
# Close the client connection socket
connectionSocket.close()


# -*- Mode: Python -*-

import coro
from coro.ssl import openssl

ssl_op_map = {
    "sslv2": openssl.SSL_OP.NO_SSLv3 | openssl.SSL_OP.NO_TLSv1,
    "sslv3": openssl.SSL_OP.NO_SSLv2 | openssl.SSL_OP.NO_TLSv1,
    "tlsv1": openssl.SSL_OP.NO_SSLv2 | openssl.SSL_OP.NO_SSLv3,
    "tlsv2": openssl.SSL_OP.NO_TLSv1 | openssl.SSL_OP.NO_TLSv1_1 | openssl.SSL_OP.NO_SSLv2,
    "sslv2sslv3": openssl.SSL_OP.NO_TLSv1,
    "sslv3tlsv1": openssl.SSL_OP.NO_SSLv2,
    "sslv2sslv3tlsv1": 0
}

from openssl import x509, pkey, dh_param

def new_ctx (cert=None, chain=(), key=None, proto=None, ciphers=None, dhparam=None, next_protos=None, auto_ecdh=True):
    ctx = openssl.ssl_ctx()
    if cert:
        ctx.use_cert (cert, chain)
    if key:
        ctx.use_key (key)
    if proto:
        ctx.set_options (ctx.get_options() | ssl_op_map[proto])
    if ciphers:
        ctx.set_ciphers (ciphers)
    if dhparam:
        ctx.set_tmp_dh (dhparam)
    if next_protos:
        ctx.set_next_protos (next_protos)
    if auto_ecdh:
        ctx.set_ecdh_auto (1)
    return ctx

class sock (coro.sock):

    def __init__ (self, ctx, fd=-1, verify=False, domain=coro.AF.INET):
        coro.sock.__init__ (self, fd=fd, domain=domain)
        self.ctx = ctx
        # Note: this uses SSLv23_method(), which allows it to accept V2 client hello
        #  (which are common), but still limit to V3 or TLS1 via the 'proto' arg.
        self.ssl = self.ctx.ssl()
        self.ssl.set_fd (self.fd)
        if verify:
            self.ssl.set_verify (openssl.SSL_VERIFY.PEER)

    def __repr__ (self):
        return '<openssl sock fd=%d ssl@%x @%x>' % (self.fd, id (self.ssl), id (self))

    def _non_blocking_retry (self, fun, *args):
        while 1:
            try:
                return fun (*args)
            except openssl.WantRead:
                self.wait_for_read()
            except openssl.WantWrite:
                self.wait_for_write()

    def accept (self):
        conn, addr = coro.sock.accept (self)
        try:
            # hand the fd off to a new ssl sock object...
            new = self.__class__ (self.ctx, domain=conn.domain, fd=conn.fd)
            # ...avoid having socket.pyx close the fd
            conn.fd = -1
            # using set_accept_state() makes NPN very difficult
            # new.ssl.set_accept_state()
            new.ssl_accept()
            return new, addr
        except:
            conn.close()
            raise

    def set_accept_state (self):
        return self.ssl.set_accept_state()

    def set_connect_state (self):
        return self.ssl.set_connect_state()

    def ssl_accept (self):
        self._non_blocking_retry (self.ssl.accept)

    def connect (self, addr):
        coro.sock.connect (self, addr)
        # using set_connect_state makes NPN very difficult
        # self.ssl.set_connect_state()
        return self.ssl_connect()

    def ssl_connect (self):
        self._non_blocking_retry (self.ssl.connect)

    def recv (self, block_size):
        return self._non_blocking_retry (self.ssl.read, block_size)

    read = recv

    def recv_exact (self, size):
        left = size
        r = []
        while left:
            block = self.recv (left)
            if not block:
                break
            else:
                r.append (block)
                left -= len (block)
        return ''.join (r)

    def recvfrom (self, block_size, timeout=30):
        raise SystemError("recvfrom not supported for SSL sockets")

    def send (self, data):
        return self._non_blocking_retry (self.ssl.write, data)

    write = send

    # SSL_write() makes this guarantee.
    sendall = send

    def sendto (self, data, addr):
        raise SystemError("sendto not supported for SSL sockets")

    def writev (self, list_of_data):
        _sum = 0
        for data in list_of_data:
            _sum += self._non_blocking_retry (self.ssl.write, data)
        return _sum

    def readv (self, _ignore):
        raise NotImplementedError

    def shutdown (self, how=None):
        try:
            return self._non_blocking_retry (self.ssl.shutdown)
        except OSError:
            # common with an impolite disconnect
            pass

    def close (self):
        try:
            coro.with_timeout (1, self.shutdown)
        except (openssl.Error, coro.TimeoutError):
            pass
        finally:
            coro.sock.close (self)

    def getCipher (self):
        return self.ssl.get_cipher()

    # The following are taken from #defines in /usr/include/openssl/*.h
    _protocol_str_map = {
        0x0002: 'SSLv2',  # SSL2_VERSION
        0x0300: 'SSLv3',  # SSL3_VERSION
        0x0301: 'TLSv1',  # TLS1_VERSION
    }

    def getProtocol (self):
        prot_id = self.ssl.get_protocol()
        try:
            return self._protocol_str_map[prot_id]
        except KeyError:
            return '(UNKNOWN:%x)' % (prot_id,)


import requests
import random
from threading import Thread, Lock

def proxy_validation(ip_list, mutex, thread_id):
    print(f"Thread #{thread_id} start working")
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/'
                          '21.0.1180.71'
    }
    for ip in ip_list:
        proxies = {'http': 'http://' + ip, 'https': 'https://' + ip}
        try:
            response = requests.get('https://www.bilibili.com', headers=header, proxies=proxies,
                                    timeout=random.uniform(9, 10.5))
            if response.status_code == 200:
                if mutex.acquire(2):
                    with open('usable_IP.txt', 'a') as usable:
                        ip_with_newline = ip + '\n'
                        usable.write(ip_with_newline)
                    mutex.release()
                else:
                    print("Error: failed to allocate mutex")
                    exit(1)
            else:
                print(f'IP unavailable: {ip}')
                print(f"Status code: {response.status_code}")
        except Exception as e:
            print(e.args)
            print(f'IP unavailable: {ip}')

def async_validation():
    open('usable_IP.txt', 'w')
    ip_list = []
    task_list = []
    mutex = Lock()
    with open('IP.txt', 'r') as file:
        # ip = file.readline()
        # while ip != '':
        #     ip_list.append(ip.replace('\n', ''))
        #     ip = file.readline()
        for i in range(0, 60):
            ip = file.readline()
            print("===================== ip = " + ip)
            ip_list.append(ip.replace('\n', ''))
            ip = file.readline()
    for i in range(0, 60):
        sub_ip_list = ip_list[1*i:1*(i+1)]
        task = Thread(target=proxy_validation, args=[sub_ip_list, mutex, i])
        task_list.append(task)
        task.start()

    for tasks in task_list:
        tasks.join()
    print("validation completed")

if __name__ == '__main__':
    async_validation()


import pytest

from app.databases import OperationsHistory
from app.paginate import paginate

@pytest.fixture()
def history():
    operations_history1 = OperationsHistory(
        id=1, name_user="USER", name_crypto="CRYPTO", cost="1", operation=True
    )
    operations_history2 = OperationsHistory(
        id=2, name_user="USER", name_crypto="CRYPTO", cost="1", operation=True
    )
    operations_history3 = OperationsHistory(
        id=3, name_user="USER", name_crypto="CRYPTO", cost="1", operation=True
    )
    history = [operations_history1, operations_history2, operations_history3]
    return history

def test_paginate_without_prev_page(history):
    page = 1
    post_per_page = 1
    history_page, prev_page, next_page = paginate(history, page, post_per_page)
    assert len(history_page) == 1
    assert prev_page is None
    assert next_page == 2

def test_paginate_without_next_page(history):
    page = 3
    post_per_page = 1
    history_page, prev_page, next_page = paginate(history, page, post_per_page)
    assert len(history_page) == 1
    assert prev_page == 2
    assert next_page is None

def test_paginate_with_pages(history):
    page = 2
    post_per_page = 1
    history_page, prev_page, next_page = paginate(history, page, post_per_page)
    assert len(history_page) == 1
    assert prev_page == 1
    assert next_page == 3

def test_paginate_with_one_page(history):
    page = 1
    history_page, prev_page, next_page = paginate(history, page)
    assert len(history_page) == 3
    assert prev_page is None
    assert next_page is None

def test_paginate_with_none_page(history):
    history_page, prev_page, next_page = paginate(history, None)
    assert len(history_page) == 3
    assert prev_page is None
    assert next_page is None


numeros = [1, 2, 3]
letras = ["a", "b", "c"]
palabras = ["Chancho", "Feliz", "Lunes"]
palabrasFelices = ["Feliz", "Contento", "Alegre"]
booleans = [True, False, True]
matriz = [[1, 2], [3, 4]]
ceros = [0] * 10
alfanumerico = numeros + letras
rango = list(range(1, 11))
char = list("Hola Mundo")

print(char)


import numpy as np
from graph import Graph

# Max and min time in graph
T_MAX = T_MIN = 0

# Utility functions
def __normalize(value: float, l_bound: float = 0.2) -> float:
    return l_bound + (1 - l_bound) * value

def __get_lin(t: float) -> float:
    global T_MIN, T_MAX
    return (t - T_MIN) / (T_MAX - T_MIN)

# Time strategies
def __lin(t: float) -> float:
    return __normalize(__get_lin(t))

def __exp(t: float) -> float:
    return __normalize((np.exp(3 * __get_lin(t.astype(float))) - 1) / (np.exp(3) - 1))

def __sqrt(t: float) -> float:
    return __normalize(np.sqrt(__get_lin(t.astype(float))))

# All weighting strategies
WEIGHTINGS = (__lin, __exp, __sqrt)

# All past event aggregation strategies
AGGREGATIONS = (np.min, \
                lambda x: np.quantile(x, 0.25), \
                np.median, \
                lambda x: np.quantile(x, 0.75), \
                np.max, \
                np.sum, \
                np.mean, \
                np.var)

# Get weigth of edge(s)
def __wtf(times: np.ndarray, is_multiedge: bool = False) -> np.ndarray:
    if is_multiedge:
        weight = np.fromiter((w(times) for w in WEIGHTINGS), np.ndarray)

        if times.size > 1:
            weight = np.fromiter((a(arr) for a in AGGREGATIONS for arr in weight), np.ndarray)
        else:
            weight = np.fromiter((arr for _ in AGGREGATIONS for arr in weight), np.ndarray)

    else:
        weight = np.fromiter((w(times) for w in WEIGHTINGS), float)

    return weight

# Get final vector of temporal topological features
def get_temporal_features(u: int, v: int, graph: Graph) -> np.ndarray:
    is_multigraph = graph.is_multigraph()

    vector_size = 3 * (1 + is_multigraph * 7)

    pa = np.zeros((vector_size))
    cn = np.zeros((vector_size))
    jc = np.zeros((vector_size))
    aa = np.zeros((vector_size))

    global T_MIN, T_MAX
    T_MIN = graph.min_timestamp()
    T_MAX = graph.max_timestamp()

    neighbors_u = graph.adj(u)
    neighbors_v = graph.adj(v)
    common_neighbors = neighbors_u.intersection(neighbors_v)

    edges_from_u = [graph.get_edges_between(u, z) for z in neighbors_u]
    edges_from_v = [graph.get_edges_between(u, z) for z in neighbors_v]

    times_edges_from_u = np.array( \
        [np.array([graph.get_edge_info(edgeId)[0] for edgeId in edges], float) for edges in edges_from_u if edges], \
        dtype=np.ndarray)

    times_edges_from_v = np.array( \
        [np.array([graph.get_edge_info(edgeId)[0] for edgeId in edges], float) for edges in edges_from_v if edges], \
        dtype=np.ndarray)

    sum_from_u = np.array([__wtf(time, is_multiedge=is_multigraph) for time in times_edges_from_u], float).sum(axis=0)
    sum_from_v = np.array([__wtf(time, is_multiedge=is_multigraph) for time in times_edges_from_v], float).sum(axis=0)

    pa += sum_from_u * sum_from_v

    for neighbor in common_neighbors:
        neighbors_nb = graph.adj(neighbor)
        edges_from_nb = [graph.get_edges_between(neighbor, z) for z in neighbors_nb]

        times_edges_from_nb = np.array( \
            [np.array([graph.get_edge_info(edgeId)[0] for edgeId in edges], float) for edges in edges_from_nb if edges], \
            dtype=np.ndarray)

        sum_from_nb = np.array([__wtf(time, is_multiedge=is_multigraph) for time in times_edges_from_nb], float).sum(axis=0)

        edges_to_u = graph.get_edges_between(neighbor, u)
        edges_to_v = graph.get_edges_between(neighbor, v)

        times_edges_to_u = np.array([graph.get_edge_info(edgeId)[0] for edgeId in edges_to_u], float)
        times_edges_to_v = np.array([graph.get_edge_info(edgeId)[0] for edgeId in edges_to_v], float)

        wtf_u = __wtf(times_edges_to_u, is_multiedge=is_multigraph).astype(float)
        wtf_v = __wtf(times_edges_to_v, is_multiedge=is_multigraph).astype(float)

        cn += wtf_u + wtf_v
        jc += wtf_u + wtf_v

        aa += (wtf_u + wtf_v) / np.where(np.log(1 + sum_from_nb)==0.0, 1e-15, np.log(1 + sum_from_nb))

    jc /= (sum_from_u + sum_from_v)

    return np.concatenate((aa, cn, jc, pa), axis=None)


#This script was used to create the spreadsheet for the "generic" fsb
import pandas
import os
from os.path import isfile, join

# Spalten:
#     line: transcribed line
#     file: voice line file name
#     faction: which faction voice is used
#     gender: which gender is used

genericpath = "assets/generic/"
dupl1path = f"{genericpath}/dupl/"
dupl2path = f"{genericpath}/dupl2/"
dupl3path = f"{genericpath}/dupl3/"
dupl4path = f"{genericpath}/dupl4/"
dupl5path = f"{genericpath}/dupl5/"

line = []
file = []
faction = []
gender = []
isdupl = []
inlang = []

#iterator = []

spalten = [line,file,faction,gender,isdupl]

# for i in range(0, 130):
#     iterator.append(str(i))

for i in range(0, 130):
    line.append("EMPTY")

for i in range(0, 130):
    isdupl.append("None")

for i in os.listdir(genericpath):
    if isfile(join(genericpath, i)):
        file.append(i)
        # print(len(file))

for i in range(0, 130):
    faction.append("EMPTY")

for i in range(0, 130):
    gender.append("EMPTY")

#dupl loops
for i in os.listdir(dupl1path):
    if isfile(join(dupl1path, i)):
        file.append(i)
        isdupl.append("dupl1")
        line.append("Empty")
        faction.append("Empty")
        gender.append("Empty")
        #iterator.append(str(len(iterator) + 1))
        print(len(file))

for i in os.listdir(dupl2path):
    if isfile(join(dupl2path, i)):
        file.append(i)
        isdupl.append("dupl2")
        line.append("Empty")
        faction.append("Empty")
        gender.append("Empty")
        #iterator.append(str(len(iterator) + 1))
        print(len(file))

for i in os.listdir(dupl3path):
    if isfile(join(dupl3path, i)):
        file.append(i)
        isdupl.append("dupl3")
        line.append("Empty")
        faction.append("Empty")
        gender.append("Empty")
        #iterator.append(str(len(iterator) + 1))
        print(len(file))

for i in os.listdir(dupl4path):
    if isfile(join(dupl4path, i)):
        file.append(i)
        isdupl.append("dupl4")
        line.append("Empty")
        faction.append("Empty")
        gender.append("Empty")
        #iterator.append(str(len(iterator) + 1))
        print(len(file))

for i in os.listdir(dupl5path):
    if isfile(join(dupl5path, i)):
        file.append(i)
        isdupl.append("dupl5")
        line.append("Empty")
        faction.append("Empty")
        gender.append("Empty")
        #iterator.append(str(len(iterator) + 1))
        print(len(file))

for i in file:
    inlang.append("NO")

data = {'file': file,
        'line': line,
        'faction': faction,
        'gender': gender,
        'isdupl': isdupl,
        'inlang': inlang}

print( "file: " + str(len(file)) +
      "\nline: " + str(len(line)) +
      "\nfaction: " + str(len(faction)) +
      "\ngender: " + str(len(gender)) +
      "\nisdupl: " + str(len(isdupl)))

spreadsheet = pandas.DataFrame(data)
spreadsheet.to_excel('generic_naming.xlsx')

Audio Conversion and Naming/generic_spreadsheet.py


import cv2
import numpy as np

frame = cv2.imread('banana3.png')

kernel = np.ones((5,5),np.uint8)

# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

hsv = cv2.medianBlur(hsv,7)

# define range of yellow color in HSV
lower_yellow = np.array([0,50,50])
upper_yellow = np.array([32,255,255])

# Threshold the HSV image to get only yellow colors
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)

mask = cv2.dilate(mask,kernel,iterations = 1)

# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)

cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
cv2.waitKey(0) & 0xFF

cv2.destroyAllWindows()


import logging
import os
from aiogram import Bot, types, executor
from aiogram.dispatcher import Dispatcher

API_TOKEN = os.getenv('BOT_TOKEN')
logging.basicConfig(level=logging.INFO)
bot = Bot(token=API_TOKEN)
dp= Dispatcher(bot)

@dp.message_handler(commands=['start'])
async def start(message: types.Message):
    await message.reply('Start bot')

@dp.message_handler(commands=['help'])
async def help(message: types.Message):
    await message.reply('Help')

if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)


import json

@task
def clean():
    """Clear build cache"""

    session.clean()
    Repository.clean()

@task
def distclean():
    """Clear caches and build results"""

    session.clean()
    Repository.distclean()

@task
def api():
    """Build the full api viewer into api folder"""

    build(prefix="api")
    ApiWriter(session).write("$prefix/data")

@task
def build(theme="original"):
    """Build the API viewer application"""

    # Configure fields
    session.setField("debug", False)
    session.setField("theme", theme)
    session.permutateField("es5")

    # Initialize shared objects
    assetManager = AssetManager(session).addBuildProfile()
    outputManager = OutputManager(session, assetManager, compressionLevel=2)
    fileManager = FileManager(session)

    # Deploy assets
    outputManager.deployAssets(["apibrowser.Browser"])

    # Write kernel script
    outputManager.storeKernel("$prefix/script/kernel.js", debug=True)

    # Copy files from source
    fileManager.updateFile("source/index.html", "$prefix/index.html")

    # Rewrite template as jsonp
    for tmpl in ["main", "error", "entry", "type", "params", "info", "origin", "tags"]:
        jsonTemplate = json.dumps({ "template" : open("source/tmpl/%s.mustache" % tmpl).read() })
        fileManager.writeFile("$prefix/tmpl/%s.js" % tmpl, "apiload(%s, '%s.mustache')" % (jsonTemplate, tmpl))

    # Process every possible permutation
    for permutation in session.permutate():

        # Resolving dependencies
        resolver = Resolver(session).addClassName("apibrowser.Browser")

        # Compressing classes
        outputManager.storeCompressed(resolver.getSortedClasses(), "$prefix/script/browser-$permutation.js", "new apibrowser.Browser;")

@task
def source(theme="original"):
    """Generate source"""

    # Configure fields
    session.setField("theme", theme)
    session.setField("debug", True)
    session.permutateField("es5")

    # Initialize shared objects
    assetManager = AssetManager(session).addSourceProfile()
    outputManager = OutputManager(session, assetManager, compressionLevel=0)
    fileManager = FileManager(session)

    # Write kernel script
    outputManager.storeKernel("$prefix/script/kernel.js", debug=True)

    # Rewrite template as jsonp
    for tmpl in ["main", "error", "entry", "type", "params", "info", "origin", "tags"]:
        jsonTemplate = json.dumps({ "template" : open("source/tmpl/%s.mustache" % tmpl).read() })
        fileManager.writeFile("$prefix/tmpl/%s.js" % tmpl, "apiload(%s, '%s.mustache')" % (jsonTemplate, tmpl))

    # Process every possible permutation
    for permutation in session.permutate():

        # Resolving dependencies
        resolver = Resolver(session).addClassName("apibrowser.Browser")

        # Building class loader
        outputManager.storeLoader(resolver.getSortedClasses(), "$prefix/script/browser-$permutation.js", "new apibrowser.Browser;")

    # Generate API data into source folder
    ApiWriter(session).write("$prefix/data")

@task
def server():
    """Starts built-in HTTP server"""

    Server().start()


from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.

def home(request):

    peoples=[
        {'name':'Kushagra','age':25},
        {'name':'Sohan','age':24}
    ]

    text="hi this is a sample text"
    return render(request,"home/index.html", context={'peoples':peoples,'text':text})

def success_page(request):
    print('*'*10)
    return HttpResponse("""
Hey, this is a success page.

Hey this is coming from the Django server

 hope you are loving it
""")

def test_page(request):
    print("Hi Testing")
    return HttpResponse("othiing")


from celery import Celery
from datetime import datetime, timedelta
from .tasks import schedule_post_creation

app = Celery("app")

def schedule_post(user_profile_id, content, minutes_from_now):
    scheduled_time = datetime.now() + timedelta(minutes=minutes_from_now)
    schedule_post_creation.apply_async(
        kwargs={
            "user_profile_id": user_profile_id,
            "content": content,
            "scheduled_time": scheduled_time,
        }
    )


from src.session.session import Session, acess_session
from src.const.default_header import XML_HTTP_REQ_HEADERS, POST_HEADERS
from src.const.url import DOCUMENT_WRITE_URL, IMAGE_FILTER_AJAX, UPLOAD_HOST_URL, UPLOAD_IMG_PHP
from src.const.const import GA_COOKIE
from src.useful_function.useful_function import quote, unquote, safe_get

import lxml.html
import asyncio
import aiohttp
import re

async def upload_image(board_id='api', file_path=''):
    async def get_write_info():
        url = DOCUMENT_WRITE_URL(board_id)
        async with Session().get(url) as res:
            parsed = lxml.html.fromstring(await res.text())

        csrf_token = parsed.xpath("//meta[@name='csrf-token']")[0].get("content")
        board_name = parsed.xpath("//a[@class='gall-tit-lnk']")[0].text.strip()
        r_key = parsed.xpath("//input[@name='r_key']")[0].get("value")

        return {
            'csrf_token': csrf_token,
            'board_name': board_name,
            'r_key': r_key
        }

    write_info = await get_write_info()

    header = XML_HTTP_REQ_HEADERS.copy()
    header.update({
        "Referer": DOCUMENT_WRITE_URL(board_id),
        "X-CSRF-TOKEN": write_info['csrf_token']
    })

    payload = {
        "id": board_id,
    }

    async with Session().post(IMAGE_FILTER_AJAX, headers=header, data=payload) as res:
        res_json = await res.json()

    header = POST_HEADERS.copy()
    header.update({
        "Host": UPLOAD_HOST_URL,
        "Referer": DOCUMENT_WRITE_URL(board_id)
    })

    payload = aiohttp.FormData({
        "id": board_id,
        "r_key": write_info["r_key"]
    })

    file = open(file_path, 'rb')
    file_ex = re.search(r"[a-z]{3,4}$", file_path).group()

    payload.add_field('upload[]',
                      file,
                      filename=f'beautiful4me.{file_ex}',
                      content_type=f'image/{file_ex}')

    cookies = {
        f"m_dcinside_{board_id}": board_id,
        "m_dcinside_lately": quote(f"{board_id}|{write_info['board_name']},"),
        "_ga": GA_COOKIE,
    }
    #
    async with Session().post(UPLOAD_IMG_PHP, headers=header, data=payload, cookies=cookies) as res:
        res_final = await res.text()

    file.close()

    img_data = re.search(r"(?<='img',').*(?=',0\);)", res_final).group()

    return img_data

if __name__ == '__main__':
    value = asyncio.run(upload_image('api', "C:/Users/dobbyjang/Desktop/PyDCApi/test/article.jpg"))
    print(value)


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from PythonTsa.plot_multi_ACF import multi_ACFfig
from PythonTsa.plot_multi_Q_pvalue import MultiQpvalue_plot
mda = pd.read_csv( 'USQgdpunemp.csv', header = 0)
mda = mda[['gdp', 'rate']]
dates = pd.date_range('1948-01', periods = len(mda), freq = 'Q')
mda.index = dates
mda['gdp'] = np.log(mda['gdp'])
mda.columns = ['lgdp', 'rate']
multi_ACFfig(mda, nlags = 16); plt.gcf();
plt.savefig('pyTSA_USUnempGDP_fig7-4.png', dpi = 1200,
             bbox_inches ='tight', transparent = True, legend = None)
dmda = mda.diff(1).dropna()
dmda.columns = ['dlgdp', 'drate']
dmda.plot()
plt.savefig('pyTSA_USUnempGDP_fig7-5.png', dpi = 1200,
             bbox_inches ='tight', transparent = True, legend = None) ; plt.show()
multi_ACFfig(dmda, nlags = 16);
plt.savefig('pyTSA_USUnempGDP_fig7-6.png', dpi = 1200,
            bbox_inches ='tight', transparent = True, legend = None)
qs, pv = MultiQpvalue_plot(dmda, nolags = 16);
plt.savefig('pyTSA_USUnempGDP_fig7-7.png', dpi = 1200, bbox_inches ='tight',
            transparent = True, legend = None)


from setuptools import setup
import re
import os
import ConfigParser

def read(fname):
    return open(os.path.join(os.path.dirname(__file__), fname)).read()

config = ConfigParser.ConfigParser()
config.readfp(open('tryton.cfg'))
info = dict(config.items('tryton'))
for key in ('depends', 'extras_depend', 'xml'):
    if key in info:
        info[key] = info[key].strip().splitlines()
major_version, minor_version, _ = info.get('version', '0.0.1').split('.', 2)
major_version = int(major_version)
minor_version = int(minor_version)

requires = []
for dep in info.get('depends', []):
    if not re.match(r'(ir|res|webdav)(\W|$)', dep):
        requires.append('trytond_%s >= %s.%s, < %s.%s' %
                (dep, major_version, minor_version, major_version,
                    minor_version + 1))
requires.append('trytond >= %s.%s, < %s.%s' %
        (major_version, minor_version, major_version, minor_version + 1))

setup(name='trytond_payroll',
    version=info.get('version', '0.0.1'),
    description='Tryton payroll module',
    long_description=read('README.md'),
    author='Openlabs',
    url='http://www.openlabs.co.in/',
    download_url="http://downloads.tryton.org/" + \
        info.get('version', '0.0.1').rsplit('.', 1)[0] + '/',
    package_dir={'trytond.modules.payroll': '.'},
    packages=[
        'trytond.modules.payroll',
        ],
    package_data={
        'trytond.modules.payroll': info.get('xml', []) \
            + ['tryton.cfg',],
        },
    classifiers=[
        'Development Status :: 5 - Production/Beta',
        'Environment :: Plugins',
        'Framework :: Tryton',
        'Intended Audience :: Developers',
        'Intended Audience :: Financial and Insurance Industry',
        'Intended Audience :: Legal Industry',
        'Intended Audience :: Manufacturing',
        'License :: OSI Approved :: GNU General Public License (GPL)',
        'Natural Language :: English',
        'Operating System :: OS Independent',
        'Programming Language :: Python :: 2.6',
        'Programming Language :: Python :: 2.7',
        'Topic :: Office/Business',
        ],
    license='GPL-3',
    install_requires=requires,
    zip_safe=False,
    entry_points="""
    [trytond.modules]
    payroll = trytond.modules.payroll
    """,
    )


import asyncio
import json
import random

import requests

from userbot import catub

from ..core.managers import edit_delete, edit_or_reply
from ..helpers.utils import reply_id

plugin_category = "fun"

game_code = ["ttt", "ttf", "ex", "cf", "rps", "rpsls", "rr", "c", "pc"]
game_name = [
    "Tic-Tac-Toe",
    "Tic-Tac-Four",
    "Elephant XO",
    "Connect Four",
    "Rock-Paper-Scissors",
    "Rock-Paper-Scissors-Lizard-Spock",
    "Russian Roulette",
    "Checkers",
    "Pool Checkers",
]

game = dict(zip(game_code, game_name))
category = ["classic", "kids", "party", "hot", "mixed"]

async def get_task(mode, choice):
    url = "https://psycatgames.com/api/tod-v2/"
    data = {
        "id": "truth-or-dare",
        "language": "en",
        "category": category[choice],
        "type": mode,
    }
    headers = {
        "referer": "https://psycatgames.com/app/truth-or-dare/?utm_campaign=tod_website&utm_source=tod_en&utm_medium=website"
    }
    response = requests.post(url, headers=headers, data=json.dumps(data))
    result = response.json()["results"]
    return random.choice(result)

@catub.cat_cmd(
    pattern="(task|truth|dare)(?: |$)([1-5]+)?$",
    command=("task", plugin_category),
    info={
        "header": "Get a random truth or dare task.",
        "description": "if no input is given then task will be from classic or kids category. if you want specific category then give input.",
        "note": "U need to give input as 1 for classic , 2 for kids , 3 for party , 4 for hot and 5 for mixed. if you want to give multiple catgories then use numbers without space like 12",
        "example": [
            "{tr}task",
            "{tr}task 2",
            "{tr}task 123",
        ],
    },
)
async def truth_dare_task(event):
    "Get a random task either truth or dare."
    taskmode = event.pattern_match.group(1)
    if taskmode == "task":
        catevent = await edit_or_reply(event, "Getting a random task for you.....")
        taskmode = random.choice(["truth", "dare"])
    else:
        catevent = await edit_or_reply(
            event, f"Getting a random {taskmode} task for you....."
        )
    category = event.pattern_match.group(2)
    category = int(random.choice(category)) if category else random.choice([1, 2])
    try:
        task = await get_task(taskmode, category)
        if taskmode == "truth":
            await catevent.edit(f"**The truth task for you is**\n`{task}`")
        else:
            await catevent.edit(f"**The dare task for you is**\n`{task}`")
    except Exception as e:
        await edit_delete(catevent, f"**Error while getting task**\n`{e}`", 7)

@catub.cat_cmd(
    command=("truth", plugin_category),
    info={
        "header": "Get a random truth task.",
        "description": "if no input is given then task will be from classic or kids category. if you want specific category then give input.",
        "note": "U need to give input as 1 for classic , 2 for kids , 3 for party , 4 for hot and 5 for mixed. if you want to give multiple catgories then use numbers without space like 12",
        "example": [
            "{tr}truth",
            "{tr}truth 2",
            "{tr}truth 123",
        ],
    },
)
async def truth_task(event):
    "Get a random truth task."
    # just to show in help menu as seperate

@catub.cat_cmd(
    command=("dare", plugin_category),
    info={
        "header": "Get a random dare task.",
        "description": "if no input is given then task will be from classic or kids category. if you want specific category then give input.",
        "note": "U need to give input as 1 for classic , 2 for kids , 3 for party , 4 for hot and 5 for mixed. if you want to give multiple catgories then use numbers without space like 12",
        "example": [
            "{tr}dare",
            "{tr}dare 2",
            "{tr}dare 123",
        ],
    },
)
async def dare_task(event):
    "Get a random dare task."
    # just to show in help menu as seperate

@catub.cat_cmd(
    pattern="game(?:\s|$)([\s\S]*)",
    command=("game", plugin_category),
    info={
        "header": "Play inline games",
        "description": "Start an inline game by inlinegamebot",
        "Game code & Name": game,
        "usage": "{tr}game <game code>",
        "examples": "{tr}game ttt ",
    },
)
async def igame(event):
    "Fun game by inline"
    reply_to_id = await reply_id(event)
    input_str = event.pattern_match.group(1)
    game_list = "".join(
        f"**{i}.** `{item}` :- __{game[item]}__\n"
        for i, item in enumerate(game, start=1)
    )
    if not input_str:
        await edit_delete(
            event, f"**Available Game Codes & Names :-**\n\n{game_list}", time=60
        )
        return
    if input_str not in game_code:
        catevent = await edit_or_reply(event, "`Give me a correct game code...`")
        await asyncio.sleep(1)
        await edit_delete(
            catevent, f"**Available Game Codes & Names :-**\n\n{game_list}", time=60
        )
    else:
        await edit_or_reply(
            event,
            f"**Game code `{input_str}` is selected for game:-** __{game[input_str]}__",
        )
        await asyncio.sleep(1)
        bot = "@inlinegamesbot"
        results = await event.client.inline_query(bot, input_str)
        await results[game_code.index(input_str)].click(
            event.chat_id, reply_to=reply_to_id
        )
        await event.delete()


class Solution(object):
    def findWords(self, words):
        """
        :type words: List[str]
        :rtype: List[str]
        """
        strs = ['qwertyuiop', 'asdfghjkl', 'zxcvbnm']
        m = {}
        index = 1
        for s in strs:
            for ch in s:
                m[ch] = index
            index += 1
        rtn = []
        for word in words:
            word_new = str(word).lower()
            index = m[word_new[0]]
            isOneGroup = True
            for w in word_new:
                if index != m[w]:
                    isOneGroup = False
                    break
            if isOneGroup:
               rtn.append(word)
        return rtn

print(Solution().findWords(["Hello", "Alaska", "Dad", "Peace"]))