import itertools

import numpy as np
import torch as th
from ttools.training import ModelInterface

from . import utils

class ReconstructionInterface(ModelInterface):
    def __init__(self, model, args, vertex_idxs, face_idxs, junctions,
                 edge_data, vertex_t, adjacencies, junction_order,
                 template_normals, symmetries=None):
        self.model = model

        self.vertex_idxs = vertex_idxs
        self.face_idxs = face_idxs
        self.junctions = junctions
        self.edge_data = edge_data
        self.vertex_t = vertex_t
        self.junction_order = junction_order
        self.template_normals = template_normals[None]

        self.args = args

        self.n_samples_per_loop_side = int(
            np.ceil(np.sqrt(args.n_samples / face_idxs.shape[0])))

        self.optimizer = th.optim.Adam(self.model.parameters(), lr=args.lr)

        self.edge_idxs = [[0, 1, 2, 3], [3, 4, 5, 6],
                          [6, 7, 8, 9], [9, 10, 11, 0]]

        self.nonadjacent_patch_pairs = []
        self.adjacent_patch_pairs = []
        for i1, i2 in list(
                itertools.combinations(range(face_idxs.shape[0]), 2)):
            if args.wheels and (
                    i1 in [5, 11, 17, 23] or i2 in [5, 11, 17, 23]):
                continue
            if i2 in adjacencies[i1]:
                e1 = adjacencies[i1][i2]
                self.adjacent_patch_pairs.append((i1, i2, e1))
            else:
                self.nonadjacent_patch_pairs.append((i1, i2))

        self.d_points_to_tris = utils.PointToTriangleDistance.apply

        p_edge0, p_edge1, p_edge2, p_edge3 = [], [], [], []
        for i in range(self.n_samples_per_loop_side):
            for j in range(self.n_samples_per_loop_side):
                n = self.n_samples_per_loop_side

                if i > 0:
                    p_edge0.append(i + j*self.n_samples_per_loop_side)
                if i < n-1:
                    p_edge2.append(i + j*self.n_samples_per_loop_side)
                if j > 0:
                    p_edge3.append(i + j*self.n_samples_per_loop_side)
                if j < n-1:
                    p_edge1.append(i + j*self.n_samples_per_loop_side)
        self.grid_point_edges = (p_edge0, p_edge1, p_edge2, p_edge3)

        self.triangulation = []
        t_edge0, t_edge1, t_edge2, t_edge3 = [], [], [], []
        for i in range(self.n_samples_per_loop_side-1):
            for j in range(self.n_samples_per_loop_side-1):
                n = self.n_samples_per_loop_side-1

                if i > 1:
                    t_edge0.extend(
                        [len(self.triangulation), len(self.triangulation)+1])
                if i < n-2:
                    t_edge2.extend(
                        [len(self.triangulation), len(self.triangulation)+1])
                if j > 1:
                    t_edge3.extend(
                        [len(self.triangulation), len(self.triangulation)+1])
                if j < n-2:
                    t_edge1.extend(
                        [len(self.triangulation), len(self.triangulation)+1])

                self.triangulation.extend(
                    [[i + j*self.n_samples_per_loop_side,
                      i + (j+1)*self.n_samples_per_loop_side,
                      i + (j+1)*self.n_samples_per_loop_side + 1],
                     [i + j*self.n_samples_per_loop_side,
                      i + j*self.n_samples_per_loop_side + 1,
                      i + (j+1)*self.n_samples_per_loop_side + 1]])
        self.triangulation_edges = (t_edge0, t_edge1, t_edge2, t_edge3)

        _loss = Loss(args, self.triangulation_edges, self.triangulation,
                     self.grid_point_edges, self.n_samples_per_loop_side,
                     self.d_points_to_tris, self.edge_idxs,
                     self.nonadjacent_patch_pairs, self.adjacent_patch_pairs,
                     self.template_normals, symmetries)
        self._compute_losses = th.nn.DataParallel(
            _loss) if args.cuda else _loss

        if args.cuda:
            self.model.cuda()
            self._compute_losses.cuda()

    def forward(self, batch):
        ims = batch['ims']
        if self.args.cuda:
            ims = ims.cuda()

        params = self.model(ims)
        vertices, patches = utils.process_patches(
            params, self.vertex_idxs, self.face_idxs, self.edge_data,
            self.junctions, self.junction_order, self.vertex_t)

        st = th.empty(patches.shape[0], patches.shape[1],
                      self.n_samples_per_loop_side**2, 2).uniform_().to(params)

        points = utils.coons_sample(st[..., 0], st[..., 1], patches)
        normals = utils.coons_normals(st[..., 0], st[..., 1], patches)
        mtds = utils.coons_mtds(st[..., 0], st[..., 1], patches)

        return {'patches': patches, 'points': points, 'normals': normals,
                'mtds': mtds, 'st': st, 'params': params, 'vertices': vertices}

    def training_step(self, batch):
        self.model.train()
        self.optimizer.zero_grad()

        losses_dict = self._compute_losses(batch, self.forward(batch))
        loss = losses_dict['loss']
        loss.mean().backward()
        self.optimizer.step()

        return {k: v.mean().item() for k, v in losses_dict.items()}

    def init_validation(self):
        losses = ['loss', 'chamferloss', 'normalsloss', 'collisionloss',
                  'planarloss', 'templatenormalsloss', 'symmetryloss']
        ret = {loss: 0 for loss in losses}
        ret['count'] = 0
        return ret

    def validation_step(self, batch, running_data):
        self.model.eval()
        count = running_data['count']
        n = batch['ims'].shape[0]
        losses_dict = self._compute_losses(batch, self.forward(batch))
        loss = losses_dict['loss']
        chamferloss = losses_dict['chamferloss']
        normalsloss = losses_dict['normalsloss']
        collisionloss = losses_dict['collisionloss']
        planarloss = losses_dict['planarloss']
        templatenormalsloss = losses_dict['templatenormalsloss']
        symmetryloss = losses_dict['symmetryloss']
        return {
            'loss': (running_data['loss']*count +
                     loss.mean().item()*n) / (count+n),
            'chamferloss': (running_data['chamferloss']*count +
                            chamferloss.mean().item()*n) / (count+n),
            'normalsloss': (running_data['normalsloss']*count +
                            normalsloss.mean().item()*n) / (count+n),
            'collisionloss': (running_data['collisionloss']*count +
                              collisionloss.mean().item()*n) / (count+n),
            'planarloss': (running_data['planarloss']*count +
                           planarloss.mean().item()*n) / (count+n),
            'templatenormalsloss': (running_data['templatenormalsloss']*count +
                                    templatenormalsloss.mean().item()*n)
            / (count+n),
            'symmetryloss': (running_data['symmetryloss']*count
                             + symmetryloss.mean().item()*n) / (count+n),
            'count': count + n
        }

wheel_idxs = list(range(24))
no_wheel_idxs = list(range(24, 43))

class Loss(th.nn.Module):
    def __init__(self, args, triangulation_edges, triangulation,
                 grid_point_edges, n_samples_per_loop_side, d_points_to_tris,
                 edge_idxs, nonadjacent_patch_pairs, adjacent_patch_pairs,
                 template_normals, symmetries):
        super(Loss, self).__init__()
        self.args = args
        self.triangulation_edges = triangulation_edges
        self.triangulation = triangulation
        self.grid_point_edges = grid_point_edges
        self.d_points_to_tris = d_points_to_tris
        self.edge_idxs = edge_idxs
        self.nonadjacent_patch_pairs = nonadjacent_patch_pairs
        self.adjacent_patch_pairs = adjacent_patch_pairs
        self.symmetries = symmetries

        linspace = th.linspace(0, 1, n_samples_per_loop_side)
        s_grid, t_grid = th.meshgrid(linspace, linspace)
        self.s_grid = th.nn.Parameter(s_grid.flatten(), requires_grad=False)
        self.t_grid = th.nn.Parameter(t_grid.flatten(), requires_grad=False)
        self.template_normals = th.nn.Parameter(
            template_normals, requires_grad=False)

    def forward(self, batch, fwd_data):
        patches = fwd_data['patches']  # [b, n_patches, 12, 3]
        points = fwd_data['points']
        normals = fwd_data['normals']
        mtds = fwd_data['mtds']
        vertices = fwd_data['vertices']

        target_points = batch['points'].to(points)  # [b, n_points, 3]
        target_normals = batch['normals'].to(normals)
        if self.args.wheels:
            wheel_target_points = batch['wheel_points'].to(points)
            wheel_target_normals = batch['wheel_normals'].to(normals)

        b, n_patches, _, _ = patches.shape

        st = fwd_data['st']

        if self.symmetries is not None:
            xs, ys = self.symmetries
            xs_ = vertices[:, xs]
            ys_ = vertices[:, ys] * vertices.new_tensor([[[-1, 1, 1]]])
            symmetryloss = th.sum((xs_ - ys_)**2, dim=-1).mean()
        else:
            symmetryloss = patches.new_zeros(1)

        if self.args.wheels:
            mtds = mtds.view(b, -1)

            wheel_points = points[:, wheel_idxs]
            no_wheel_points = points[:, no_wheel_idxs]

            wheel_normals = normals[:, wheel_idxs]
            no_wheel_normals = normals[:, no_wheel_idxs]

            wheel_chamferloss_a, wheel_chamferloss_b, wheel_normalsloss_a, \
                wheel_normalsloss_b = utils.compute_chamfer_losses(
                    wheel_points, wheel_normals, wheel_target_points,
                    wheel_target_normals, self.args.w_normals > 0)
            no_wheel_chamferloss_a, no_wheel_chamferloss_b, \
                no_wheel_normalsloss_a, no_wheel_normalsloss_b = \
                utils.compute_chamfer_losses(no_wheel_points, no_wheel_normals,
                                             target_points, target_normals,
                                             self.args.w_normals > 0)

            chamferloss_a = th.cat(
                [wheel_chamferloss_a, no_wheel_chamferloss_a], dim=1)
            normalsloss_a = th.cat(
                [wheel_normalsloss_a, no_wheel_normalsloss_a], dim=1)

            ratio = batch['ratio']
            n_wheel_pts = wheel_target_points.shape[1]
            n_no_wheel_pts = target_points.shape[1]
            n_pts = n_wheel_pts + n_no_wheel_pts
            ratio_wheel = ratio * n_pts/n_wheel_pts
            ratio_no_wheel = (1-ratio) * n_pts/n_no_wheel_pts

            chamferloss_a = th.sum(mtds*chamferloss_a, dim=-1) / mtds.sum(-1)
            chamferloss_b = ratio_wheel * \
                wheel_chamferloss_b.mean(
                    1) + ratio_no_wheel * no_wheel_chamferloss_b.mean(1)
            chamferloss = ((chamferloss_a+chamferloss_b).mean() / 2).view(1)

            normalsloss_a = th.sum(mtds*normalsloss_a, dim=-1) / mtds.sum(-1)
            normalsloss_b = ratio_wheel * \
                wheel_normalsloss_b.mean(
                    1) + ratio_no_wheel * no_wheel_normalsloss_b.mean(1)
            normalsloss = ((normalsloss_a+normalsloss_b).mean() / 2).view(1)

        elif self.args.seperate_turbines:
            turbine_idxs = [x for x in range(76) if x not in [72, 73, 74, 75]]
            no_turbine_idxs = [x for x in range(76)
                               if x not in [10, 12, 14, 17, 19, 20, 21, 24, 25,
                                            27, 28, 29, 30, 31, 32, 33, 34,
                                            66]]

            turbine_points = points[batch['turbines']]
            turbine_points = turbine_points[:, turbine_idxs]
            no_turbine_points = points[batch['turbines']]
            no_turbine_points = no_turbine_points[:, no_turbine_idxs]

            turbine_normals = normals[batch['turbines']]
            turbine_normals = turbine_normals[:, turbine_idxs]
            no_turbine_normals = normals[batch['turbines']]
            no_turbine_normals = no_turbine_normals[:, no_turbine_idxs]

            turbine_mtds = mtds[batch['turbines']]
            turbine_mtds = turbine_mtds[:, turbine_idxs]
            no_turbine_mtds = mtds[batch['turbines']]
            no_turbine_mtds = no_turbine_mtds[:, no_turbine_idxs]

            turbine_patches = patches[batch['turbines']]
            turbine_patches = turbine_patches[:, turbine_idxs]
            no_turbine_patches = patches[batch['turbines']]
            no_turbine_patches = no_turbine_patches[:, no_turbine_idxs]

            turbine_target_points = target_points[batch['turbines']]
            no_turbine_target_points = target_points[batch['turbines']]

            turbine_target_normals = target_normals[batch['turbines']]
            no_turbine_target_normals = target_normals[batch['turbines']]

            if turbine_points.shape[0] > 0:
                turbine_mtds = turbine_mtds.view(turbine_mtds.shape[0], -1)
                turbine_chamferloss_a, turbine_chamferloss_b, \
                    turbine_normalsloss_a, turbine_normalsloss_b = \
                    utils.compute_chamfer_losses(turbine_points,
                                                 turbine_normals,
                                                 turbine_target_points,
                                                 turbine_target_normals,
                                                 self.args.w_normals > 0)
                turbine_chamferloss_a = th.sum(
                    turbine_mtds*turbine_chamferloss_a,
                    dim=-1) / turbine_mtds.sum(-1)
                turbine_chamferloss_b = turbine_chamferloss_b.mean(1)
                turbine_chamferloss = (
                    (turbine_chamferloss_a +
                     turbine_chamferloss_b).mean() / 2).view(1)
                turbine_normalsloss_a = th.sum(
                    turbine_mtds*turbine_normalsloss_a,
                    dim=-1) / turbine_mtds.sum(-1)
                turbine_normalsloss_b = turbine_normalsloss_b.mean(-1)
                turbine_normalsloss = (
                    (turbine_normalsloss_a +
                     turbine_normalsloss_b).mean() / 2).view(1)
            else:
                turbine_chamferloss = turbine_normalsloss = points.new_zeros(1)

            if no_turbine_points.shape[0] > 0:
                no_turbine_mtds = no_turbine_mtds.view(
                    no_turbine_mtds.shape[0], -1)
                no_turbine_chamferloss_a, no_turbine_chamferloss_b, \
                    no_turbine_normalsloss_a, no_turbine_normalsloss_b = \
                    utils.compute_chamfer_losses(no_turbine_points,
                                                 no_turbine_normals,
                                                 no_turbine_target_points,
                                                 no_turbine_target_normals,
                                                 self.args.w_normals > 0)
                no_turbine_chamferloss_a = th.sum(
                    no_turbine_mtds*no_turbine_chamferloss_a,
                    dim=-1) / no_turbine_mtds.sum(-1)
                no_turbine_chamferloss_b = no_turbine_chamferloss_b.mean(1)
                no_turbine_chamferloss = (
                    (no_turbine_chamferloss_a +
                     no_turbine_chamferloss_b).mean() / 2).view(1)
                no_turbine_normalsloss_a = th.sum(
                    no_turbine_mtds*no_turbine_normalsloss_a,
                    dim=-1) / no_turbine_mtds.sum(-1)
                no_turbine_normalsloss_b = no_turbine_normalsloss_b.mean(-1)
                no_turbine_normalsloss = (
                    (no_turbine_normalsloss_a +
                     no_turbine_normalsloss_b).mean() / 2).view(1)
            else:
                no_turbine_chamferloss = no_turbine_normalsloss = \
                    points.new_zeros(1)

            ratio_turbine = turbine_points.shape[0] / b
            chamferloss = ratio_turbine*turbine_chamferloss + \
                (1-ratio_turbine)*no_turbine_chamferloss
            normalsloss = ratio_turbine*turbine_normalsloss + \
                (1-ratio_turbine)*no_turbine_normalsloss

            del turbine_normals, turbine_target_normals, no_turbine_normals, \
                no_turbine_target_normals, turbine_points, \
                turbine_target_points, no_turbine_points, \
                no_turbine_target_points
        else:
            mtds = mtds.view(b, -1)

            chamferloss_a, chamferloss_b, normalsloss_a, normalsloss_b = \
                utils.compute_chamfer_losses(
                    points, normals, target_points, target_normals,
                    self.args.w_normals > 0)
            chamferloss_a = th.sum(mtds*chamferloss_a, dim=-1) / mtds.sum(-1)
            chamferloss_b = chamferloss_b.mean(1)
            chamferloss = ((chamferloss_a+chamferloss_b).mean() / 2).view(1)
            normalsloss_a = th.sum(mtds*normalsloss_a, dim=-1) / mtds.sum(-1)
            normalsloss_b = normalsloss_b.mean(-1)
            normalsloss = ((normalsloss_a+normalsloss_b).mean() / 2).view(1)

        mtds = mtds.view(b, n_patches, -1)

        if self.args.w_templatenormals:
            templatenormalsloss = th.sum(
                (self.template_normals - normals)**2, dim=-1)
            templatenormalsloss = th.sum(
                mtds*templatenormalsloss, dim=-1) / mtds.sum(-1)
        else:
            templatenormalsloss = th.zeros_like(chamferloss)

        del target_normals, normals, target_points

        if self.args.w_planar > 0:
            planarloss = utils.planar_patch_loss(st, points, mtds)
        else:
            planarloss = th.zeros_like(chamferloss)

        del points, mtds

        if self.args.w_collision > 0:
            collisionloss = chamferloss.new_zeros([b, 0])
            grid_points = utils.coons_sample(self.s_grid, self.t_grid, patches)
            triangles = grid_points[:, :, self.triangulation]

            i1s, i2s, e1s = zip(*self.adjacent_patch_pairs)
            points1 = grid_points[:, i1s]
            point_idxs = th.tensor([self.grid_point_edges[e]
                                    for e in e1s]).to(points1.device)
            point_idxs = point_idxs[None, :, :, None].expand(b, -1, -1, 3)
            points1 = th.gather(points1, 2, point_idxs)
            points2 = grid_points[:, i2s]

            triangles1 = triangles[:, i1s]
            triangle_idxs = th.tensor(
                [self.triangulation_edges[e] for e in e1s]
            ).to(triangles1.device)
            triangle_idxs = triangle_idxs[None, :, :,
                                          None, None].expand(b, -1, -1, 3, 3)
            triangles1 = th.gather(triangles1, 2, triangle_idxs)
            triangles2 = triangles[:, i2s]

            idxs = utils.bboxes_intersect(
                points1, points2, dim=2).any(0).nonzero().squeeze(1)
            n_adjacent_intersections = idxs.shape[0]

            if n_adjacent_intersections > 0:
                points1 = points1[:, idxs].view([-1] + list(points1.shape[2:]))
                points2 = points2[:, idxs].view([-1] + list(points2.shape[2:]))
                triangles1 = triangles1[:, idxs].view(
                    [-1] + list(triangles1.shape[2:]))
                triangles2 = triangles2[:, idxs].view(
                    [-1] + list(triangles2.shape[2:]))
                d1 = self.d_points_to_tris(points1, triangles2)
                d2 = self.d_points_to_tris(points2, triangles1)
                d = th.min(d1, d2).view(b, -1)
                collisionloss = th.cat(
                    [collisionloss, th.exp(-(d/self.args.sigma_collision)**2)],
                    dim=1)

            i1s, i2s = zip(*self.nonadjacent_patch_pairs)
            idxs = utils.bboxes_intersect(
                grid_points[:, i1s], grid_points[:, i2s], dim=2
            ).any(0).nonzero().squeeze(1)
            n_nonadjacent_intersections = idxs.shape[0]
            i1s = th.tensor(i1s).to(grid_points.device)[idxs]
            i2s = th.tensor(i2s).to(grid_points.device)[idxs]

            if n_nonadjacent_intersections > 0:
                points1 = grid_points[:, i1s].view(
                    [-1] + list(grid_points.shape[2:]))
                points2 = grid_points[:, i2s].view(
                    [-1] + list(grid_points.shape[2:]))
                triangles1 = triangles[:, i1s].view(
                    [-1] + list(triangles.shape[2:]))
                triangles2 = triangles[:, i2s].view(
                    [-1] + list(triangles.shape[2:]))
                d1 = self.d_points_to_tris(points1, triangles2)
                d2 = self.d_points_to_tris(points2, triangles1)
                d = th.min(d1, d2).view(b, -1)
                collisionloss = th.cat(
                    [collisionloss, th.exp(-(d/self.args.sigma_collision)**2)],
                    dim=1)

            del triangles

            if n_adjacent_intersections + n_nonadjacent_intersections > 0:
                collisionloss = collisionloss.sum(-1).mean()
            else:
                collisionloss = th.zeros_like(chamferloss)
        else:
            collisionloss = th.zeros_like(chamferloss)

        loss = chamferloss + self.args.w_normals*normalsloss + \
            self.args.w_collision*collisionloss + \
            self.args.w_planar*planarloss + \
            self.args.w_templatenormals*templatenormalsloss + \
            self.args.w_symmetry*symmetryloss

        return {
            'loss': loss,
            'chamferloss': chamferloss,
            'normalsloss': normalsloss,
            'collisionloss': collisionloss,
            'planarloss': planarloss,
            'templatenormalsloss': templatenormalsloss,
            'symmetryloss': symmetryloss,
        }


# Keys
from libqtile.lazy import lazy
from libqtile.config import Key

# Mouse
from libqtile.config import Click, Drag

# Groups
from libqtile.config import Group, Match

# Layouts
from libqtile import layout

# Screens
from libqtile import bar, widget
from libqtile.config import Screen

# Screens/Extras
from qtile_extras import widget
from qtile_extras.widget.decorations import PowerLineDecoration

# Startup
import os
from scripts import *
from themes import current_theme as theme

widget_defaults = dict(
    font = font_family,
    fontsize = 15,
    padding = 10,
)

extension_defaults = widget_defaults.copy()

# Key Bindings ------------------------------------------
keys = [
    # Switch between windows
    Key([modifier], "left", lazy.layout.left(), desc="Move focus to left"),
    Key([modifier], "right", lazy.layout.right(), desc="Move focus to right"),
    Key([modifier], "down", lazy.layout.down(), desc="Move focus down"),
    Key([modifier], "up", lazy.layout.up(), desc="Move focus up"),
    Key(["mod1"], "Tab", lazy.layout.next(), desc="Move window focus to other window"),
    # Key(["mod1"], "Tab", lazy.spawn(os.path.join(home_dir, ".config/rofi/launchers/type-3/launcher.sh")), desc="Spawn launcher"),

    # Move windows between left/right columns or move up/down in current stack.
    Key([modifier, "shift"], "left", lazy.layout.shuffle_left(), desc="Move window to the left"),
    Key([modifier, "shift"], "right", lazy.layout.shuffle_right(), desc="Move window to the right"),
    Key([modifier, "shift"], "down", lazy.layout.shuffle_down(), desc="Move window down"),
    Key([modifier, "shift"], "up", lazy.layout.shuffle_up(), desc="Move window up"),

    # Grow windows. If current window is on the edge of screen and direction
    Key([modifier, "control"], "left", lazy.layout.grow_left(), desc="Grow window to the left"),
    Key([modifier, "control"], "right", lazy.layout.grow_right(), desc="Grow window to the right"),
    Key([modifier, "control"], "down", lazy.layout.grow_down(), desc="Grow window down"),
    Key([modifier, "control"], "up", lazy.layout.grow_up(), desc="Grow window up"),
    Key([modifier], "n", lazy.layout.normalize(), desc="Reset all window sizes"),

    # Toggle between split and unsplit sides of stack.
    # Split = all windows displayed
    # Unsplit = 1 window displayed, like Max layout, but still with multiple stack panes
    Key([modifier], "Return", lazy.spawn(terminal), desc="Launch terminal"),
    Key([modifier, "shift"], "Return", lazy.layout.toggle_split(), desc="Toggle between split and unsplit sides of stack"),

    # Toggle between different layouts
    Key([modifier], "q", lazy.window.kill(), desc="Kill focused window"),
    Key([modifier], "Tab", lazy.next_layout(), desc="Toggle between layouts"),
    Key([modifier, "control"], "r", lazy.reload_config(), desc="Reload the config"),
    Key([modifier], "r", lazy.spawn(os.path.join(home_dir, ".config/rofi/launchers/type-7/launcher.sh")), desc="Spawn launcher"),
    Key([modifier, "shift"], "q", lazy.spawn(os.path.join(home_dir, ".config/rofi/powermenu/type-5/powermenu.sh")), desc="Shutdown Qtile"),

    # Spawn default file explorer
    Key([modifier], "e", lazy.spawn(explorer), desc="Spawn file explorer"),

    # Raise, lower and mute volume
    Key([], "XF86AudioRaiseVolume", lazy.spawn("amixer set Master 5%+"), desc="Increase volume using amixer"),
    Key([], "XF86AudioLowerVolume", lazy.spawn("amixer set Master 5%-"), desc="Decrease volume using amixer"),
    Key([], "XF86AudioMute", lazy.spawn("amixer set Master toggle"), desc="Mute volume using amixer"),

    # Key to increase and decrease screen brightness using brightnessctl
    Key([], "XF86MonBrightnessUp", lazy.spawn("brightnessctl set +5%"), desc="Increase brightness using brightnessctl"),
    Key([], "XF86MonBrightnessDown", lazy.spawn("brightnessctl set 5%-"), desc="Decrease brightness using brightnessctl"),

    # Key to toggle between Brazilian Portuguese ABNT2 and US English
    Key(["mod1"], "Shift_L", lazy.function(toggle_keyboard_layout), desc="Toggle keyboard layout between BR ABNT2 and US"),

    # Printscreen
    Key([], "Print", lazy.spawn("scrot")),
    Key([modifier, "shift"], "s", lazy.spawn("scrot -s")),

    Key([modifier], "f", lazy.window.toggle_floating()),
]

# Mouse Bindings --------------------------------------
mouse = [
    Drag([modifier], "Button1", lazy.window.set_position_floating(), start=lazy.window.get_position()),
    Drag([modifier], "Button3", lazy.window.set_size_floating(), start=lazy.window.get_size()),
    Click([modifier], "Button2", lazy.window.bring_to_front()),
]

# Layouts ---------------------------------------------
layouts = [
    layout.Columns(margin=(0, 3, 3, 3), border_focus='#a1b5ec', border_width=2),
    layout.Max(),
]

# Groups -----------------------------------------------
group_icon = "\uf111 "
group_icon_selected = "\uebb4 "
group_hotkeys = "123"

for hotkey in group_hotkeys:
    keys.extend([
        # mod1 + letter of group = switch to group
        Key(
            [modifier],
            hotkey,
            lazy.group[hotkey].toscreen(),
            desc=f"Switch to group {hotkey}",
        ),

        # mod1 + shift + letter of group = switch to & move focused window to group
        Key(
            [modifier, "shift"],
            hotkey,
            lazy.window.togroup(hotkey, switch_group=False),
            desc=f"Switch to & move focused window to group {hotkey}",
        )
    ])

groups = [Group(hotkey, label=group_icon) for hotkey in group_hotkeys]

# Screens --------------------------------------------
screens = []
num_screens = 2  # Change this value to the number of screens you want

powerline_forward_slash = {
    "decorations": [
        PowerLineDecoration(
            path="forward_slash"
        )
    ]
}

powerline_rounded_left = {
    "decorations": [
        PowerLineDecoration(
            path="rounded_left"
        )
    ]
}

powerline_rounded_right = {
    "decorations": [
        PowerLineDecoration(
            path="rounded_right"
        )
    ]
}

for _ in range(num_screens):
    screen = Screen(
        top=bar.Bar(
            [
                widget.Image(
                    background = theme["base"],
                    filename = os.path.join(images_dir, "icons/arch-linux-icon.png"),
                    scale = True,
                    margin_y = 9,
                ),

                widget.GroupBox(
                    background = theme["base"],
                    highlight_method = 'block',
                    inactive="#FFFFFF",
                    foreground="#FFFFFF",
                    **powerline_rounded_left,
                ),

                widget.Spacer(
                    background = "#00000000",
                    **powerline_rounded_right,
                ),

                # Current volume, uses amixer
                widget.Volume(
                    fmt = '\uf028   {}',
                    background = theme["base"],
                    font = font_family_bold,
                    **powerline_rounded_right,
                ),

                # Current battery
                widget.Battery(
                    format = '{char}   {percent:2.0%}',
                    background = theme["base"],
                    font = font_family_bold,

                    unknown_char = "\U000f0091",    # Material Design icon for unknown battery state
                    discharge_char = "\U000f0083",  # Material Design icon for discharging battery
                    charge_char = "\U000f0084",     # Material Design icon for charging battery
                    full_char = "\U000f0079",       # Material Design icon for full battery (same as charging)

                    low_percentage = 0.15,
                    low_foreground = "FF0000",
                    **powerline_rounded_right,
                ),

                # Current time
                widget.Clock(
                    background = theme["base"],
                    format="\uf43a   %H:%M  ",
                    font=font_family_bold,
                ),
            ],
            40,
            background = "#00000000",
            margin=(5, 10, 15, 10),
        ),
    )
    screens.append(screen)

# General Configuration Variables ---------------------

# A function which generates group binding hotkeys. It takes a single argument, the DGroups object, and can use that to set up dynamic key bindings.
# A sample implementation is available in 'libqtile/dgroups.py' called `simple_key_binder()`, which will bind groups to "mod+shift+0-10" by default.
dgroups_key_binder = None

# A list of Rule objects which can send windows to various groups based on matching criteria.
dgroups_app_rules = []  # type: list

# Controls whether or not focus follows the mouse around as it moves across windows in a layout.
follow_mouse_focus = True

# When clicked, should the window be brought to the front or not.
# If this is set to "floating_only", only floating windows will get affected (This sets the X Stack Mode to Above.)
bring_front_click = False

# If true, the cursor follows the focus as directed by the keyboard, warping to the center of the focused window.
# When switching focus between screens, If there are no windows in the screen, the cursor will warp to the center of the screen.
cursor_warp = False

# The default floating layout to use. This allows you to set custom floating rules among other things if you wish.
floating_layout = layout.Floating(
    float_rules=[
        # Run the utility of `xprop` to see the wm class and name of an X client.
        *layout.Floating.default_float_rules,
        Match(wm_class="confirmreset"),  # gitk
        Match(wm_class="makebranch"),  # gitk
        Match(wm_class="maketag"),  # gitk
        Match(wm_class="ssh-askpass"),  # ssh-askpass
        Match(title="branchdialog"),  # gitk
        Match(title="pinentry"),  # GPG key password entry
    ]
)

# If a window requests to be fullscreen, it is automatically fullscreened.
# Set this to false if you only want windows to be fullscreen if you ask them to be.
auto_fullscreen = False

# Behavior of the _NET_ACTIVATE_WINDOW message sent by applications
#
# urgent: urgent flag is set for the window
# focus: automatically focus the window
# smart: automatically focus if the window is in the current group
# never: never automatically focus any window that requests it
focus_on_window_activation = "smart"

# Controls whether or not to automatically reconfigure screens when there are changes in randr output configuration.
reconfigure_screens = True

# If things like steam games want to auto-minimize themselves when losing
# focus, should we respect this or not?
auto_minimize = True

# XXX: Gasp! We're lying here. In fact, nobody really uses or cares about this
# string besides java UI toolkits; you can see several discussions on the
# mailing lists, GitHub issues, and other WM documentation that suggest setting
# this string if your java app doesn't work correctly. We may as well just lie
# and say that we're a working one by default.
#
# We choose LG3D to maximize irony: it is a 3D non-reparenting WM written in
# java that happens to be on java's whitelist.
#wmname = "LG3D"

# When using the Wayland backend, this can be used to configure input devices.
wl_input_rules = None


from Game import Game
import socket
import threading
import re

class Server:
    """
        Class Implementing the Game Server
    """
    def __init__(self, port):
        """
            __init__(Server, int) -> None
            Initializes the Game Server
        """
        self.game = Game("arena.txt")
        self.lock = threading.Lock()    # To control concurrent access to the game
        self.connections = []   # List of incoming connections, each connection is a client_thread
        self.soc = None  # Socket to be used for communication
        self.port = port    # Port number on which to listen
        self.started = False  # Status of the server
        self.can_recieve_commands = False

    def start_server(self):
        """
            start_server(Server) -> None
            Starts the server and prepares it to accept new connections
        """
        assert not self.started, "Server has already been started"
        self.soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Open a socket
        self.soc.bind((socket.gethostname(), self.port)) # Bind the  socket
        self.soc.listen(5)   # Start listening, max 5 pending connection requests
        self.started = True
        connect_thread = threading.Thread(target = self.connect)
        connect_thread.start()

        key = "0"
        while key != "1":
            key = input("Enter 1 to start the game: ")
            if key == "1":
                self.can_recieve_commands = True
                self.start_game()

    def stop_server(self):
        """
            stop_server(Server) -> None
            Stops the server and closes all the connections
        """
        self.started = False

    def connect(self):
        """
            connect(Server) -> None
            Keeps on listening for new connections and connects to them as they are available
        """
        while self.started:
            (client_socket, address) = self.soc.accept()
            client = ClientThread(self, client_socket, address)
            self.connections.append(client)

    def start_game(self):
        """
            start_game(Server) ->
            Starts the game on this server
        """
        self.game.start_game()
        self.send_arena()

    def send_arena(self):
        """
            send_arena(Server) -> None
            Calls send_arena function on all the clients
        """
        for connection in self.connections:
            connection.send_arena()

class ClientThread:
    """
        ClientThread abstracts the thread for each client
    """
    def __init__(self, server, socket, addr):
        """
            __init__(ClientThread, Server, socket, address) -> None
            Initializes the client thread
        """
        self.server = server
        self.soc = socket
        self.address = addr
        self.recieved = ""  # This is a dirty solution, fix this!
        self.connected = False  # Part of the dirty solution
        self.from_listening = False # Part of dirty solution
        self.id = -1    # Id for this client in the game
        self.add_client_to_game()    # Adds this client to the game

    def add_client_to_game(self):
        """
            add_client_to_game(ClientThread) -> None
            Adds this client to the Game
        """
        self.soc.send("__TYPE__")
        type = self.soc.recv(1024)

        if (self.server.game.is_valid_type(type)):
            self.send_arena()    # Send Initial Arena
            self.server.lock.acquire()  # Acquire Lock
            pos = self.get_initial_position()   # Get initial position from the client
            self.id = self.server.game.init_player(pos, type) # Request to add player
            self.server.lock.release()  # Release the lock
            self.connected = True
            t = threading.Thread(target = self.start_listening)
            t.start()

    def send_arena(self):
        """
            send_arena(ClientThread) -> None
            Sends the arena to the client
        """
        self.server.lock.acquire()
        self.can_recieve_commands = False
        self.soc.send("__ARENA__" + str(len(str(self.server.game))))   # Send arena command
        if (not self.connected or self.from_listening):
            self.recieved = self.soc.recv(1024);
        while (self.recieved != "__READY__"):   # Wait to recieve ready
            continue    # Ready will be recieved by start_listening
        assert (self.recieved == "__READY__"), "Invalid Protocol: " + recieved
        self.recieved = ""  # Clear Recieved
        self.soc.send(str(self.server.game)) # Send the arena
        self.can_recieve_commands = True
        self.server.lock.release()

    def get_initial_position(self):
        """
            get_initial_positon(ClientThread) -> (int, int)
            Recieves the initial requested position from the client
        """
        self.soc.send("__POSITION__")    # Send position Command
        position = self.soc.recv(1024)   # Wait for position
        nums = filter(None, re.split("[(), ]", position))
        return (int(nums[0]), int(nums[1]))

    def start_listening(self):
        """
            start_listening(ClientThread) -> None
            Start listening for move requests
        """
        while True:
            if self.can_recieve_commands:
                command = self.soc.recv(1024)
                if command.startswith("__READY__"):
                    self.recieved = command
                    continue
                self.server.lock.acquire()
                self.server.game.move(self.id, command)
                self.server.lock.release()
                self.from_listening = True
                self.server.send_arena()
                self.from_listening = False

if __name__ == "__main__":
    server = Server(8694)
    server.start_server()


#
# python3 rl/rl_daily/env_buy_only.py
# tensorboard --logdir logs
#

import numpy as np
import gym
from gym import spaces

import pandas as pd
import pandas_ta  # for TA magic

from stable_baselines3 import PPO
from stable_baselines3 import A2C
from stable_baselines3.common.vec_env import DummyVecEnv
from stable_baselines3.common.evaluation import evaluate_policy
from stable_baselines3.common.noise import ActionNoise
from gym.envs.registration import EnvSpec
from stable_baselines3.common.env_checker import check_env

from os import path

from plotly.subplots import make_subplots

INITIAL_DEPOSIT = 3000    # The agent starts with $3000 deposit
ORDER_FEES = 1            # $1 for execution of each order
STATE_DATA = 100
PROFIT_PERIOD = 20

ACTIONS = {0: 0, 1: 0, 2: 0}

class ProfitEnv(gym.Env):
    df = None
    current_index = 0
    last_bought_position = 0
    last_bought_price = 0
    stop_loss = 0
    take_profit = 0
    budget = 0
    number_of_shares_bought = 0
    total_deals = 0
    metadata = {'render.modes': ['human']}
    ticker = ''
    mode = ''
    sell_signals = None
    buy_signals = None
    hold_signals = None
    sum_profit = 0
    tickers = None
    initial_tickers = []
    failures = 0
    spec = EnvSpec(id='ProfitEnv-v0', max_episode_steps=2000, reward_threshold=5000)
    total_rewards = 0
    done = False

    _max_episode_steps = 2000  # PROFIT_PERIOD * 10  # get profit in 50 days

    def __init__(self, tickers_list: list = None, mode='learn'):
        super(ProfitEnv, self).__init__()

        self.mode = mode

        self.action_space = spaces.Discrete(2)  # hold or buy only

        # Current price: Low, High, Open, Close
        # EMA3, EMA7, EMA20, EMA70, EMA200, SMA50, SMA200,
        # Bollinger_low, Bollinger_up, RSI, SuperTrend,
        # MACD, MACD_signal, ATR, current profit,
        self.observation_space = spaces.Box(low=-1, high=1, shape=(STATE_DATA, 23), dtype=np.float32)   # shape=(1, 20)

        self.tickers = tickers_list.copy()
        self.initial_tickers = tickers_list.copy()

        self.ticker = self.tickers.pop()
        self.get_data(self.ticker)

        self.reset()

    def prepare_data(self):
        k_period = 100
        k_indicator = {i: 0 for i in range(200)}
        k2_indicator = {i: 0 for i in range(200)}

        try:
            self.df.ta.ema(length=3, append=True, col_names=('EMA3',))
            self.df.ta.ema(length=7, append=True, col_names=('EMA7',))
            self.df.ta.ema(length=20, append=True, col_names=('EMA20',))

            self.df.ta.sma(length=50, append=True, col_names=('SMA50',))
            self.df.ta.sma(length=200, append=True, col_names=('SMA200',))

            self.df.ta.rsi(append=True, col_names=('RSI',))
            self.df['RSI'] /= 100

            self.df.ta.atr(append=True, col_names=('ATR',))
            self.df['ATR'] /= 100

            self.df.ta.bbands(col_names=('L', 'M', 'U', 'B', 'P'), append=True)   # length=34,

            self.df.ta.macd(append=True, col_names=('MACD', 'MACD_hist', 'MACD_signal'))

            self.df.ta.supertrend(append=True, length=10, multiplier=3.0,
                                  col_names=('S_trend', 'S_trend_d', 'S_trend_l', 'S_trend_s',))

            # Calculate our own metrics:

            self.df['K2'] = (self.df['High'] - self.df['Low']) / self.df['L']
            self.df['K'] = (self.df['EMA20'] - self.df['EMA7']) / self.df['Close'] - 0.01

            self.df['diff1'] = self.df['EMA7'] / self.df['SMA50'] - 1
            self.df['diff2'] = (self.df['EMA7'] - self.df['EMA3']) / self.df['L']

            """
            for i in range(200, len(self.df['Close'])):
                # Integral-based metrics
                diff = self.df['SMA200'].values[i - k_period:i] - self.df['EMA7'].values[i - k_period:i]

                prob_up = diff[diff > 0].sum()
                prob_down = abs(diff[diff < 0].sum())

                k_indicator[i] = prob_up / (prob_up + prob_down)

                diff = self.df['EMA7'].values[i - k_period:i] - self.df['EMA3'].values[i - k_period:i]
                prob_up = diff[diff > 0].sum()
                prob_down = abs(diff[diff < 0].sum())

                k2_indicator[i] = prob_up / (prob_up + prob_down)

            self.df['W'] = k_indicator.values()
            self.df['W2'] = k2_indicator.values()
            """
        except Exception as e:
            print(f'WRONG DATA {self.ticker} {e}')
            exit(1)

        # self.df = self.df.replace([np.inf, -np.inf], np.nan)

        low_50 = {i: 0 for i in range(50)}
        high_50 = {i: 0 for i in range(50)}
        for i in range(50, len(self.df['Close'])):
            low_50[i] = self.df[i - 50:i]['Low'].min()
            high_50[i] = self.df[i - 50:i]['High'].max()

        low_30 = {i: 0 for i in range(30)}
        high_30 = {i: 0 for i in range(30)}
        for i in range(30, len(self.df['Close'])):
            low_30[i] = self.df[i - 30:i]['Low'].min()
            high_30[i] = self.df[i - 30:i]['High'].max()

        self.df['low_30'] = low_30.values()
        self.df['low_50'] = low_50.values()
        self.df['high_30'] = high_30.values()
        self.df['high_50'] = high_50.values()

        self.df = self.df[200:].copy().fillna(0)

    def get_state(self):
        states = []

        for i in range(self.current_index - STATE_DATA, self.current_index):
            state = []

            scaled_parameters = [
                'Low', 'High', 'Open', 'Close', 'EMA3', 'EMA7', 'EMA20',
                'SMA50', 'SMA200', 'L', 'U',
            ]

            for parameter in scaled_parameters:
                state.append(self.df[parameter].values[i])

            parameters = ['RSI', 'MACD', 'MACD_signal', 'ATR', 'S_trend_d', 'K', 'K2',
                          'low_30', 'low_50', 'high_30', 'high_50']   # 'S_trend_d', 'MACD', 'MACD_signal', 'ATR',
            for parameter in parameters:
                state.append(self.df[parameter].values[i])

            # Our own moving average crossover for daily trades
            # state.append(self.df['diff1'].values[i])
            # state.append(self.df['diff2'].values[i])

            # state.append(self.df['W'].values[i])
            # state.append(self.df['W2'].values[i])

            state.append(self.last_bought_price)  # add the info about purchased price to the state

            state = np.array(state, dtype=np.float32).flatten()

            states.append(state)

        return np.array(states)   # states[0]  # np.array(states)  # states

    def step(self, action):
        # actions: 0 - hold, 1 - buy, 2 - sell

        reward = 0  # to motivate purchases
        profit = 0

        current_price = self.df['Close'].values[self.current_index]

        if self.number_of_shares_bought > 0:
            if self.df['Low'].values[self.current_index] < self.stop_loss:
                reward = -1

                # Sell by stop loss in 3% down
                self.last_bought_price = 0
                self.last_bought_position = 0
                self.number_of_shares_bought = 0

                self.sell_signals[self.current_index] = True

            elif current_price > self.take_profit:
                profit = (current_price - self.last_bought_price) / self.last_bought_price

                self.last_bought_price = 0
                self.last_bought_position = 0
                self.number_of_shares_bought = 0

                reward = 1

                self.sell_signals[self.current_index] = True

        if action == 1:
            if self.number_of_shares_bought == 0:
                # bet_size = min(self.budget, 20000)  # limit size of every deal

                number_of_shares = 100  #  bet_size // current_price

                self.last_bought_price = current_price
                self.last_bought_position = self.current_index
                self.number_of_shares_bought = number_of_shares
                self.total_deals += 1

                self.buy_signals[self.current_index] = True

                reward = 0.01

        if action == 0:
            self.hold_signals[self.current_index] = True
            reward = 0

        self.current_index += 1
        # (self.current_index > 100 and self.total_rewards < 3) or
        done = bool(self.current_index >= len(self.df['Close']) - PROFIT_PERIOD)
        self.done = done

        if done and len(self.tickers) > 0:
            done = False

            ticker = self.tickers.pop()

            self.get_data(ticker)
            self.prepare_data()
            self.reset(cleanup_budget=False)
        elif not self.tickers and self.mode != 'test':
            self.tickers = self.initial_tickers.copy()

        budget = self.budget + self.last_bought_price * self.number_of_shares_bought
        if budget < 500:
            self.budget = 3000

        if self.mode != 'test':
            self.total_rewards += reward

        ACTIONS[action] += 1

        return self.get_state(), reward, done, {}

    def get_data(self, ticker):
        file_name = f'rl/data/daily_{ticker}.xlsx'
        self.ticker = ticker

        if path.exists(file_name):
            self.df = pd.read_excel(file_name, index_col=0)  # , header=[0, 1]
        else:
            self.df = pd.DataFrame()
            self.df = self.df.ta.ticker(ticker, period='700d', interval='1h')
            self.prepare_data()

            self.df.index = self.df.index.strftime('%m/%d/%Y %H:%M')
            self.df.to_excel(file_name, index=True, header=True)

        scaled_parameters = [
            'Low', 'High', 'Open', 'Close', 'EMA3', 'EMA7', 'EMA20',
            'SMA50', 'SMA200', 'L', 'U'
        ]

        for parameter in scaled_parameters:
            self.df[parameter] = self.df[parameter] / self.df[parameter].values[0]  # self.df['SMA200'] - 1

        # self.df = self.df.replace([np.inf, -np.inf], np.nan)

    def reset(self, cleanup_budget=True):

        print(self.total_rewards, self.current_index)

        if cleanup_budget:
            self.budget = INITIAL_DEPOSIT
        else:
            if self.last_bought_position > 0:
                self.budget += self.last_bought_price * self.number_of_shares_bought

        self.current_index = STATE_DATA  # we start from the Day #5 in the data set to have a history
        self.last_bought_position = 0
        self.last_bought_price = 0
        self.number_of_shares_bought = 0
        self.sum_profit = 0

        self.buy_signals = {i: False for i in range(len(self.df))}
        self.sell_signals = {i: False for i in range(len(self.df))}
        self.hold_signals = {i: False for i in range(len(self.df))}

        self.failures = 0
        self.total_rewards = 0
        self.done = False

        return self.get_state()

    def draw(self):
        df = self.df

        graph = make_subplots(rows=1, cols=1)
        graph.update_layout(title=self.ticker, xaxis_rangeslider_visible=False)

        graph.add_candlestick(open=df['Open'], high=df['High'], low=df['Low'], close=df['Close'])

        graph.add_scatter(y=df['SMA50'], mode='lines', name='SMA50',
                          line={'color': 'magenta'})
        # graph.add_scatter(y=df['SMA200'], mode='lines', name='SMA200',
        #                   line={'color': 'blue', 'width': 3})

        buy_signals = [i for i, (index, row) in enumerate(df.iterrows()) if row['buy_signals'] == True]
        graph.add_scatter(x=buy_signals, y=df['Close'].values[buy_signals], name='Buy Signal', mode='markers',
                          marker_symbol='triangle-up', marker_color='#00FE35', marker_size=15, row=1, col=1)

        sell_signals = [i for i, (index, row) in enumerate(df.iterrows()) if row['sell_signals'] == True]
        graph.add_scatter(x=sell_signals, y=df['Close'].values[sell_signals], name='Sell Signal', mode='markers',
                          marker_symbol='triangle-down', marker_color='#D62728', marker_size=15, row=1, col=1)

        hold_signals = [i for i, (index, row) in enumerate(df.iterrows()) if row['hold_signals'] == True]
        graph.add_scatter(x=hold_signals, y=df['Close'].values[hold_signals], name='HOLD Signal', mode='markers',
                          marker_symbol='hash', marker_color='#555555', marker_size=15, row=1, col=1)

        graph.show()

    def render(self, mode='human', close=False):
        if self.total_deals > 0 and self.total_deals % 100 == 0:
            total_budget = self.budget
            if self.last_bought_position > 0:
                total_budget += self.last_bought_price * self.number_of_shares_bought

            message = f"""
            Current budget: ${total_budget:.1f}
            Profit: {100 * (total_budget / INITIAL_DEPOSIT - 1):.0f}%
            Total Deals: {self.total_deals}
            """
            print(message)

        if self.total_rewards > 50:
            self.df['buy_signals'] = self.buy_signals.values()
            self.df['sell_signals'] = self.sell_signals.values()
            self.df['hold_signals'] = self.hold_signals.values()
            self.draw()

            exit()

with open('smp500.txt', 'r') as f:
    TICKERS = f.readlines()

TICKERS = [t.replace('\n', '') for t in TICKERS if '^' not in t and '/' not in t and '.' not in t]

TICKERS.remove('GOOG')
TICKERS.remove('TSLA')

TICKERS = ['USDJPY=X']
non_vectorized_env = ProfitEnv(TICKERS[:1].copy())  # :100
# wrapped_env = gym.wrappers.Monitor(non_vectorized_env, './results', force=True)
env = DummyVecEnv([lambda: non_vectorized_env])

state = env.reset()

# check_env(non_vectorized_env)

model = PPO('MlpPolicy', env, verbose=False, tensorboard_log='logs')  # learning_rate=0.0001
model.learn(total_timesteps=500000, progress_bar=True)

# non_vectorized_env = ProfitEnv(TICKERS[:1].copy(), mode='test')
# env = gym.wrappers.Monitor(non_vectorized_env, './results', force=True)
env.reset()
# env = DummyVecEnv([lambda: wrapped_env])

evaluate_policy(model, env, n_eval_episodes=1, render=True)


"""
Create a function that takes two arguments. Both arguments are integers, a and b. Return True if one of them is 10 or if their sum is 10.
Examples
a,b = 9, 10 ➞ True
a,b = 9, 9 ➞ False
a,b = 1, 9 ➞ True

"""
a = int(input())
b = int(input())
if a or b == 10:
    print(True)
elif a + b == 10:
    print (True)
else:
    print (False)
# + (a==0 or b==10) * True + (a+b==10) * True + (a> 10 and b> 10) * False


#!/usr/bin/env python2.7

from datetime import datetime, timedelta

from epidata.EpidataLiteStreamingContext import EpidataLiteStreamingContext
import sys
import numpy
import pandas
import sqlite3
from sqlite3 import Error

import unittest

ec = EpidataLiteStreamingContext()

database = "/Users/lujiajun/Documents/epidata-intern/data/epidata_development.db"

def create_connection(db_file):
    conn = None
    try:
        conn = sqlite3.connect(db_file, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES)
    except Error as e:
        print(e)

    return conn

con = create_connection(database)

class Base(unittest.TestCase):

    def assertEqualRows(self, one, two):
        self.maxDiff = None
        # if not isinstance(one, Column):
        self.assertEqual(one, two)

    def assertEqualDataFrames(self, one, two):
        self.assertEqual(one.count(), two.count())
        for i, j in zip(one, two):
            self.assertEqualRows(i, j)

class EpidataContextTests(Base):
    # def test_simple_query_test(self):
    #     # create a database connection
    #     cur = con.cursor()
    #     cur.execute("select * from measurements_original where key2 = 'Test-1'")
    #     rows = cur.fetchall()
    #
    #     for row in rows:
    #         print(row)

    def test_simpleTest(self):

        ec.printSomething('god')
        trans = ec.createTransformations("Identity", ["Meas-1"], {})
        print(trans)
        ec.createStream("measurements_original", "measurements_cleansed", trans)
        print("Start stream")
        ec.startStream()
        print("Enter 'Q' to stop streaming")
        # data = input("Enter a number to quit")
        # while data:
        #     data = input("Enter a number to quit")
        ec.stopStream()

if __name__ == "__main__":
    # NOTE Fixtures are added externally, by IPythonSpec.scala.
    unittest.main()


from models import Model
from models.comment import Comment
from models.base_model import SQLModel

class Weibo(SQLModel):
    """
    微博类
    """
    def __init__(self, form):
        super().__init__(form)
        self.content = form.get('content', '')
        # 和别的数据关联的方式, 用 user_id 表明拥有它的 user 实例
        self.user_id = form.get('user_id', None)

    @classmethod
    def add(cls, form, user_id):
        w = Weibo(form)
        w.user_id = user_id
        w.new(w)

    @classmethod
    def update(cls, form):
        weibo_id = int(form['id'])
        w = Weibo.one(id=weibo_id)
        w.title = form['content']
        w.save()

    def comments(self):
        cs = Comment.all(weibo_id=self.id)
        return cs


import random
from functools import wraps
from time import time

import numpy as np

REAL_COUNTS_LIST = 'real_counts_list'

ESTIMATED_COUNTS_LIST = 'estimated_counts_list'

CHANGES = 'changes_'

def timing(f):
    # a decorator for function timinf
    @wraps(f)
    def wrap(*args, **kw):
        ts = time()
        result = f(*args, **kw)
        te = time()
        # print('func:%r args:[%r, %r] took: %2.4f sec' % \
        #       (f.__name__, args, kw, te - ts))
        print('func:%r took: %2.4f sec' % \
              (f.__name__, te - ts))
        return result

    return wrap

def set_random_seed(random_seed):
    # set a random seed for both random and numpy
    random.seed(random_seed)
    np.random.seed(random_seed)


import datetime
import journal_scan
import os
import finance_tracker
import pirate_massacre
import threading
import time
import web_server
from pytz import UTC

pirate_scanner = None
finance_scanner = None
book_mark = None

def all_scanners():
    return [pirate_scanner, finance_scanner]

mutex = threading.Lock()

# There appears to be a bug in the bookmark system. Until that's fixed we'll rebuild
# the complete scanner every time a request is made
rebuild_scanner_on_request = False

def build_scanners():
    global pirate_scanner
    global finance_scanner
    global book_mark
    global mutex

    mutex.acquire()
    pirate_scanner = pirate_massacre.PirateMassacreScanner()
    finance_scanner = finance_tracker.FinanceTracker()
    mutex.release()

    # Wing missions last around 7 days, so we only need to scan that far back
    start_date = datetime.datetime.now(UTC) - datetime.timedelta(8)
    book_mark = journal_scan.scan_journal_files_in_date_range(all_scanners(), start_date, None)

    print("Scanners rebuilt.")

def strfdelta(tdelta, fmt):
    d = {"days": tdelta.days}
    d["hours"], rem = divmod(tdelta.seconds, 3600)
    d["minutes"], d["seconds"] = divmod(rem, 60)
    return fmt.format(**d)

def build_remaining_time_str(expiry):
    now = UTC.localize(datetime.datetime.utcnow())
    if(expiry < now):
        return 'EXPIRED!'
    else:
        message = "Expires in "
        remaining = expiry - now
        if remaining.days > 0:
            message += strfdelta(remaining, '{days}D {hours}H {minutes}MIN')
        else:
            message += strfdelta(remaining, '{hours}H {minutes}MIN')
        return message

rep_classes = {
    "HOSTILE": "FactionRepBad",
    "UNFRIENDLY": "FactionRepBad",
    "NEUTRAL": "FactionRepNeutral",
    "FRIENDLY": "FactionRepGood",
    "ALLIED": "FactionRepGood"
}

def get_reputation_class(rep_string):
    if rep_string not in rep_classes:
        return "FactionRepNeutral"
    return rep_classes[rep_string]

class PirateMassacreHandler(web_server.Handler):
    def get_handler(self, request):
        if request == "/mission_report":
            return self.get_mission_report
        elif request == "/finance_report":
            return self.get_finance_report
        elif request == "/rebuild":
            return self.get_rebuild
        return None

    def get_mission_report(self):
        if pirate_scanner == None:
            return

        if rebuild_scanner_on_request:
            build_scanners()

        global mutex
        mutex.acquire()
        report = pirate_scanner.build_report()
        mutex.release()

        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

        content = ""

        content += f'
Tracking {report["MissionCount"]}/20 missions for a potential {"{:,}".format(report["TotalReward"])} credit reward. ({"{:,}".format(report["TotalWingReward"])} credits in wing missions.)
'
        for system_entry in report['MissionsBySystem']:
            system_name = system_entry['Name']
            system = report['Systems'][system_name]
            content += (f'
{system.name}
')
            for faction_entry in system_entry["Factions"]:
                faction_name = faction_entry['Name']
                faction = report['Factions'][faction_name]

                rep_string = faction.get_reputation_string()
                rep_class = get_reputation_class(rep_string)

                icons = ""
                if faction.government == 'Anarchy':
                    icons += '🏴☠' # pirate flag
                if faction.state in ["War", "CivilWar"]:
                    icons += '⚔' # crossed swords

                content += f'
{faction.name}{icons}
{rep_string}

'
                missions = faction_entry["Missions"]
                if len(missions) > 0:
                    for mission in missions:
                        kills = mission.total_kills - mission.remaining_kills
                        content += '
'

                        message = 'Kill {} for {:,} credits'.format(mission.target_faction, mission.reward)
                        if mission.wing:
                            message += ' WING '
                        message += ' — '

                        if mission.remaining_kills > 0:
                            message += f' {kills}/{mission.total_kills} ({mission.remaining_kills} remain)'
                            message += ' — '
                            message += build_remaining_time_str(mission.expiry)
                        else:
                            message += ' DONE!'

                        content += message
                        content += '
'
                else:
                    content += '
'
                    content += 'None'
                    if faction_entry['HasMissionsInOtherSystem']:
                        content +=' (have mission in other system)'
                    content += '
'

        self.wfile.write(bytes(content, "utf-8"))

    def get_finance_report(self):
        if finance_scanner == None:
            return

        global mutex
        mutex.acquire()
        report = finance_scanner.build_report_json()
        mutex.release()

        self.send_response(200)
        self.send_header("Content-type", "text/json")
        self.end_headers()

        content = report
        self.wfile.write(bytes(content, "utf-8"))

    def get_rebuild(self):
        build_scanners()

        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()

        content = "Scanners Rebuilt"
        self.wfile.write(bytes(content, "utf-8"))

def main_loop():
    if rebuild_scanner_on_request:
        return

    global mutex
    global pirate_scanner
    global book_mark

    while True:
        time.sleep(0.5)

        mutex.acquire()
        book_mark = journal_scan.resume_from_book_mark(
            all_scanners(),
            book_mark)
        mutex.release()

if __name__ == "__main__":
    args = web_server.parse_args("Run a web server showing a live stream of your pirate massacre missions grouped by system.")

    build_scanners()

    public_path = os.path.join(
        os.path.dirname(
            os.path.realpath(__file__)
        ), "Public")

    web_server.start(args, PirateMassacreHandler, public_path)

    main_loop()


import unittest

from pyanaconda.core.constants import SOURCE_TYPE_RPM_OSTREE, SOURCE_TYPE_RPM_OSTREE_CONTAINER, \
    SOURCE_TYPE_FLATPAK, PAYLOAD_TYPE_RPM_OSTREE
from pyanaconda.modules.payloads.base.initialization import TearDownSourcesTask
from pyanaconda.modules.payloads.constants import SourceType
from pyanaconda.modules.payloads.payload.rpm_ostree.flatpak_installation import InstallFlatpaksTask
from pyanaconda.modules.payloads.payload.rpm_ostree.installation import InitOSTreeFsAndRepoTask, \
    ChangeOSTreeRemoteTask, PullRemoteAndDeleteTask, DeployOSTreeTask, SetSystemRootTask, \
    PrepareOSTreeMountTargetsTask, CopyBootloaderDataTask, TearDownOSTreeMountTargetsTask, \
    ConfigureBootloader
from pyanaconda.modules.payloads.payload.rpm_ostree.rpm_ostree import RPMOSTreeModule
from pyanaconda.modules.payloads.payload.rpm_ostree.rpm_ostree_interface import RPMOSTreeInterface
from pyanaconda.modules.payloads.payloads import PayloadsService
from pyanaconda.modules.payloads.payloads_interface import PayloadsInterface
from pyanaconda.modules.payloads.source.factory import SourceFactory
from tests.unit_tests.pyanaconda_tests import check_instances

from tests.unit_tests.pyanaconda_tests.modules.payloads.payload.module_payload_shared import \
    PayloadKickstartSharedTest

class RPMOSTreeInterfaceTestCase(unittest.TestCase):
    """Test the RPM OSTree DBus module."""

    def setUp(self):
        self.module = RPMOSTreeModule()
        self.interface = RPMOSTreeInterface(self.module)

    def test_type(self):
        """Test the Type property."""
        assert self.interface.Type == PAYLOAD_TYPE_RPM_OSTREE

    def test_default_source_type(self):
        """Test the DefaultSourceType property."""
        assert self.interface.DefaultSourceType == SOURCE_TYPE_RPM_OSTREE

    def test_supported_sources(self):
        """Test the SupportedSourceTypes property."""
        assert self.interface.SupportedSourceTypes == [
            SOURCE_TYPE_RPM_OSTREE,
            SOURCE_TYPE_RPM_OSTREE_CONTAINER,
            SOURCE_TYPE_FLATPAK,
        ]

class RPMOSTreeKickstartTestCase(unittest.TestCase):
    """Test the RPM OSTree kickstart commands."""

    def setUp(self):
        self.maxDiff = None
        self.module = PayloadsService()
        self.interface = PayloadsInterface(self.module)
        self.shared_ks_tests = PayloadKickstartSharedTest(
            payload_service=self.module,
            payload_service_intf=self.interface
        )

    def _check_properties(self, expected_source_type):
        payload = self.shared_ks_tests.get_payload()
        assert isinstance(payload, RPMOSTreeModule)

        if expected_source_type is None:
            assert not payload.sources
        else:
            sources = payload.sources
            assert 1 == len(sources)
            assert sources[0].type.value == expected_source_type

    def test_ostree_kickstart(self):
        ks_in = """
        ostreesetup --osname="fedora-atomic" --remote="fedora-atomic-28" --url="file:///ostree/repo" --ref="fedora/28/x86_64/atomic-host" --nogpg
        """
        ks_out = """
        # OSTree setup
        ostreesetup --osname="fedora-atomic" --remote="fedora-atomic-28" --url="file:///ostree/repo" --ref="fedora/28/x86_64/atomic-host" --nogpg
        """
        self.shared_ks_tests.check_kickstart(ks_in, ks_out)
        self._check_properties(SOURCE_TYPE_RPM_OSTREE)

    def test_ostree_container_kickstart(self):
        ks_in = """
        ostreecontainer --stateroot="fedora-coreos" --transport="repository" --remote="fedora" --url="quay.io/fedora/coreos:stable" --no-signature-verification
        """
        ks_out = """
        # OSTree container setup
        ostreecontainer --stateroot="fedora-coreos" --remote="fedora" --no-signature-verification --transport="repository" --url="quay.io/fedora/coreos:stable"
        """
        self.shared_ks_tests.check_kickstart(ks_in, ks_out)
        self._check_properties(SOURCE_TYPE_RPM_OSTREE_CONTAINER)

    def test_priority_kickstart(self):
        ks_in = """
        ostreesetup --osname="fedora-iot" --url="https://compose/iot/" --ref="fedora/iot"
        url --url="https://compose/Everything"
        """
        ks_out = """
        # OSTree setup
        ostreesetup --osname="fedora-iot" --remote="fedora-iot" --url="https://compose/iot/" --ref="fedora/iot"
        """
        self.shared_ks_tests.check_kickstart(ks_in, ks_out)
        self._check_properties(SOURCE_TYPE_RPM_OSTREE)

    def test_ostreecontainer_priority_kickstart(self):
        ks_in = """
        url --url="https://compose/Everything"
        ostreecontainer --stateroot="fedora-coreos" --remote="fedora" --url="quay.io/fedora/coreos:stable"
        """
        ks_out = """
        # OSTree container setup
        ostreecontainer --stateroot="fedora-coreos" --remote="fedora" --url="quay.io/fedora/coreos:stable"
        """
        self.shared_ks_tests.check_kickstart(ks_in, ks_out)
        self._check_properties(SOURCE_TYPE_RPM_OSTREE_CONTAINER)

class RPMOSTreeModuleTestCase(unittest.TestCase):
    """Test the RPM OSTree module."""

    def setUp(self):
        self.maxDiff = None
        self.module = RPMOSTreeModule()

    def test_get_kernel_version_list(self):
        """Test the get_kernel_version_list method."""
        assert self.module.get_kernel_version_list() == []

    def test_install_with_tasks(self):
        """Test the install_with_tasks method."""
        assert self.module.install_with_tasks() == []

        rpm_source = SourceFactory.create_source(SourceType.RPM_OSTREE)
        self.module.set_sources([rpm_source])

        tasks = self.module.install_with_tasks()
        check_instances(tasks, [
            InitOSTreeFsAndRepoTask,
            ChangeOSTreeRemoteTask,
            PullRemoteAndDeleteTask,
            DeployOSTreeTask,
            SetSystemRootTask,
            CopyBootloaderDataTask,
            PrepareOSTreeMountTargetsTask,
        ])

        rpm_container_source = SourceFactory.create_source(SourceType.RPM_OSTREE_CONTAINER)
        self.module.set_sources([rpm_container_source])

        tasks = self.module.install_with_tasks()
        check_instances(tasks, [
            InitOSTreeFsAndRepoTask,
            ChangeOSTreeRemoteTask,
            DeployOSTreeTask,
            SetSystemRootTask,
            CopyBootloaderDataTask,
            PrepareOSTreeMountTargetsTask,
        ])

        flatpak_source = SourceFactory.create_source(SourceType.FLATPAK)
        self.module.set_sources([rpm_source, flatpak_source])

        tasks = self.module.install_with_tasks()
        check_instances(tasks, [
            InitOSTreeFsAndRepoTask,
            ChangeOSTreeRemoteTask,
            PullRemoteAndDeleteTask,
            DeployOSTreeTask,
            SetSystemRootTask,
            CopyBootloaderDataTask,
            PrepareOSTreeMountTargetsTask,
            InstallFlatpaksTask,
        ])

    def test_collect_mount_points(self):
        """Collect mount points from successful tasks."""
        rpm_source = SourceFactory.create_source(SourceType.RPM_OSTREE)
        self.module.set_sources([rpm_source])
        tasks = self.module.install_with_tasks()

        for task in tasks:
            # Fake the task results.
            task_id = task.__class__.__name__
            task._set_result([
                "/path/{}/1".format(task_id),
                "/path/{}/2".format(task_id)
            ])

            # Fake the task run.
            task.succeeded_signal.emit()

        assert self.module._internal_mounts == [
            "/path/PrepareOSTreeMountTargetsTask/1",
            "/path/PrepareOSTreeMountTargetsTask/2"
        ]

    def test_container_collect_mount_points(self):
        """Collect mount points from successful tasks with ostreecontainer."""
        rpm_source = SourceFactory.create_source(SourceType.RPM_OSTREE_CONTAINER)
        self.module.set_sources([rpm_source])
        tasks = self.module.install_with_tasks()

        for task in tasks:
            # Fake the task results.
            task_id = task.__class__.__name__
            task._set_result([
                "/path/{}/1".format(task_id),
                "/path/{}/2".format(task_id)
            ])

            # Fake the task run.
            task.succeeded_signal.emit()

        assert self.module._internal_mounts == [
            "/path/PrepareOSTreeMountTargetsTask/1",
            "/path/PrepareOSTreeMountTargetsTask/2"
        ]

    def test_post_install_with_tasks(self):
        """Test the post_install_with_tasks method."""
        assert self.module.post_install_with_tasks() == []

        rpm_source = SourceFactory.create_source(SourceType.RPM_OSTREE)
        self.module.set_sources([rpm_source])

        tasks = self.module.post_install_with_tasks()
        check_instances(tasks, [
            ChangeOSTreeRemoteTask,
            ConfigureBootloader,
        ])

    def test_container_post_install_with_tasks(self):
        """Test the post_install_with_tasks method with ostreecontainer."""
        assert self.module.post_install_with_tasks() == []

        rpm_source = SourceFactory.create_source(SourceType.RPM_OSTREE_CONTAINER)
        self.module.set_sources([rpm_source])

        tasks = self.module.post_install_with_tasks()
        check_instances(tasks, [
            ChangeOSTreeRemoteTask,
            ConfigureBootloader,
        ])

    def test_tear_down_with_tasks(self):
        """Test the tear_down_with_tasks method."""
        rpm_source = SourceFactory.create_source(SourceType.RPM_OSTREE)

        self.module.set_sources([rpm_source])
        self.module._add_internal_mounts(["/path/1", "/path/2"])

        tasks = self.module.tear_down_with_tasks()

        check_instances(tasks, [
            TearDownSourcesTask,
            TearDownOSTreeMountTargetsTask
        ])

        assert tasks[0]._sources == [rpm_source]
        assert tasks[1]._internal_mounts == ["/path/1", "/path/2"]

    def test_container_tear_down_with_tasks(self):
        """Test the tear_down_with_tasks method with ostreecontainer."""
        rpm_source = SourceFactory.create_source(SourceType.RPM_OSTREE_CONTAINER)

        self.module.set_sources([rpm_source])
        self.module._add_internal_mounts(["/path/1", "/path/2"])

        tasks = self.module.tear_down_with_tasks()

        check_instances(tasks, [
            TearDownSourcesTask,
            TearDownOSTreeMountTargetsTask
        ])

        assert tasks[0]._sources == [rpm_source]
        assert tasks[1]._internal_mounts == ["/path/1", "/path/2"]


import yfinance as yf

class IndexArbitrageNative:
    def __init__(self, basket_tickers, basket_weights):
        self.basket_tickers = basket_tickers
        self.basket_weights = basket_weights

    def calculate_fair_value(self, spy_price, basket_prices):
        # Calculate the fair value of the index futures contract
        fair_value = sum(price * weight for price, weight in zip(basket_prices, self.basket_weights))
        return fair_value

    def check_arbitrage_opportunity(self):
        # Fetch the latest prices of the basket of stocks and SPY
        basket_data = yf.download(self.basket_tickers, period='1d')['Adj Close']
        spy_data = yf.download('SPY', period='1d')['Adj Close']

        # Extract the latest prices from the fetched data
        basket_prices = [basket_data[ticker][-1] for ticker in self.basket_tickers]
        spy_price = spy_data[-1]

        # Calculate the fair value of the index futures contract
        fair_value = self.calculate_fair_value(spy_price, basket_prices)

        # Check if there is an arbitrage opportunity
        if spy_price < fair_value:
            return {
                'opportunity': 'buy_spy',
                'spy_price': spy_price,
                'basket_prices': basket_prices
            }
        elif spy_price > fair_value:
            return {
                'opportunity': 'sell_spy',
                'spy_price': spy_price,
                'basket_prices': basket_prices
            }
        else:
            return {
                'opportunity': 'no_arbitrage',
                'spy_price': spy_price,
                'basket_prices': basket_prices
            }


from h2o_wave import ui, data, Q
from .common import global_nav
from .synthetic_data import *

async def show_grey_dashboard(q: Q):
    q.page['meta'] = ui.meta_card(box='', layouts=[
        ui.layout(
            breakpoint='xs',
            min_width='800px',
            zones=[
                ui.zone('header', size='76px'),
                ui.zone('title'),
                ui.zone('body', size='1000px', zones=[
                    ui.zone('top', direction=ui.ZoneDirection.ROW, size='25%'),
                    ui.zone('middle', direction=ui.ZoneDirection.ROW, size='25%'),
                    ui.zone('middle2', direction=ui.ZoneDirection.ROW, size='25%'),
                    ui.zone('bottom', direction=ui.ZoneDirection.ROW, size='25%'),
                ]),
                ui.zone('footer', size='80px'),
            ]
        )
    ])

    q.page['header'] = ui.header_card(box='header', title='H2O Wave Demo', subtitle='Grey Dashboard',
                                      image='https://wave.h2o.ai/img/h2o-logo.svg',
                                      items=[ui.tabs(name='Dashboards', value='#dashboards/grey',
                                                     items=global_nav),])
    q.page['section'] = ui.section_card(
        box='title',
        title=next(sample_title),
        subtitle=next(sample_caption),
        items=[
            ui.label(label='Start:'),
            ui.date_picker(name='target_date', label='', value='2020-12-20'),
            ui.label(label='End:'),
            ui.date_picker(name='target_date', label='', value='2020-12-25'),
        ],
    )

    stock_dates = generate_time_series(10000)
    stock_prices = generate_random_walk()

    q.page['small'] = ui.small_stat_card(
        box=ui.box('top', order=1),
        title=next(sample_term),
        value=next(sample_dollars),
    )
    q.page['small_series'] = ui.small_series_stat_card(
        box=ui.box('top', order=2),
        title=next(sample_term),
        value=next(sample_dollars),
        plot_category='date',
        plot_value='price',
        plot_data=data(
            fields=['date', 'price'],
            rows=[(next(stock_dates), next(stock_prices)) for i in range(30)],
            pack=True,
        ),
    )
    q.page['small_series_interval'] = ui.small_series_stat_card(
        box=ui.box('top', order=3),
        title=next(sample_term),
        value=next(sample_dollars),
        plot_category='date',
        plot_value='price',
        plot_type=ui.SmallSeriesStatCardPlotType.INTERVAL,
        plot_data=data(
            fields=['date', 'price'],
            rows=[(next(stock_dates), next(stock_prices)) for i in range(30)],
            pack=True,
        ),
    )
    q.page['wide_series'] = ui.wide_series_stat_card(
        box=ui.box('middle', order=1),
        title=next(sample_term),
        value=next(sample_dollars),
        aux_value=next(sample_percent),
        plot_category='date',
        plot_value='price',
        plot_data=data(
            fields=['date', 'price'],
            rows=[(next(stock_dates), next(stock_prices)) for i in range(30)],
            pack=True,
        ),
    )
    q.page['wide_bar'] = ui.wide_bar_stat_card(
        box=ui.box('middle', order=2),
        title=next(sample_term),
        value=next(sample_dollars),
        aux_value=next(sample_percent),
        progress=random.random(),
    )
    q.page['wide_gauge'] = ui.wide_gauge_stat_card(
        box=ui.box('middle', order=3),
        title=next(sample_term),
        value=next(sample_dollars),
        aux_value=next(sample_percent),
        progress=random.random(),
    )
    q.page['tall_series'] = ui.tall_series_stat_card(
        box=ui.box('middle2', order=1),
        title=next(sample_term),
        value=next(sample_dollars),
        aux_value=next(sample_percent),
        plot_category='date',
        plot_value='price',
        plot_data=data(
            fields=['date', 'price'],
            rows=[(next(stock_dates), next(stock_prices)) for i in range(30)],
            pack=True,
        ),
    )
    q.page['tall_gauge'] = ui.tall_gauge_stat_card(
        box=ui.box('middle2', order=2),
        title=next(sample_term),
        value=next(sample_dollars),
        aux_value=next(sample_percent),
        progress=random.random(),
    )
    q.page['large'] = ui.large_stat_card(
        box=ui.box('bottom', order=1),
        title=next(sample_term),
        value=next(sample_dollars),
        aux_value=next(sample_percent),
        caption=next(sample_caption),
    )
    q.page['large_bar'] = ui.large_bar_stat_card(
        box=ui.box('bottom', order=2),
        title=next(sample_term),
        value=next(sample_dollars),
        value_caption=next(sample_term),
        aux_value=next(sample_dollars),
        aux_value_caption=next(sample_term),
        progress=random.random(),
        caption=next(sample_caption),
    )

    q.page['footer'] = ui.footer_card(box='footer', caption='(c) 2021 H2O.ai. All rights reserved.')

    await q.page.save()


import sys

def f(M,N):
    li = [False,False,True]+[i%2 for i in range(3,N+1)]
    for n in range(3, N+1, 2):
        if li[n]:
            li[n*n::n] = [False]*(N//n-n+1)
    return li[M:]

M, N = map(int, sys.stdin.readline().split())
li = f(M,N)
print("\n".join([str(n) for n, t in zip(range(M,N+1),li) if t]))


import numpy as np
from skopt import Optimizer

y_best = float('inf')
x_best = np.zeros(0)
x_list = []
y_list = []

def solve(objective,
          x0,
          lower_bounds,
          upper_bounds,
          dim,
          eval_constraints,
          max_evals):
    global x_best,x_list,y_best,y_list
    y_best = float('inf')
    x_best = np.zeros(0)
    bounds = []
    for i in range(dim):
        bounds.append((lower_bounds[i], upper_bounds[i]))
    opt = Optimizer(bounds,acq_func="LCB")

    for t in range(int(max_evals-eval_constraints)):
        suggested = opt.ask()
        y = objective(suggested)
        opt.tell(suggested, y)
        x_list.append(suggested)
        y_list.append(y)
        if y_best > y:
            y_best = y
            x_best = suggested


from fastapi import FastAPI, Query
from datetime import datetime
from pytz import utc

app = FastAPI()

@app.get("/api")
async def get_info(
    slack_name: str = Query(..., title="Slack Name"),
    track: str = Query(..., title="Track"),
):
    # Get current day of the week
    current_day = datetime.now(utc).strftime('%A')

    # Get current UTC time
    current_utc_time = datetime.now(utc).strftime('%Y-%m-%dT%H:%M:%SZ')

    # GitHub file and repo URLs
    github_file_url = "https://github.com/preciousajorgba/HNGX/blob/main/task1.py"
    github_repo_url = "https://github.com/preciousajorgba/HNGX"

    # Response JSON
    response_data = {
        "slack_name": slack_name,
        "current_day": current_day,
        "utc_time": current_utc_time,
        "track": track,
        "github_file_url": github_file_url,
        "github_repo_url": github_repo_url,
        "status_code": 200
    }

    return response_data

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)


import dataclasses
from typing import Any, Optional

from flask import jsonify

from ...exceptions.exceptions import ResourceExistsException
from ..models.video_model import Video
from ..repositories.unit_of_work import BaseUnitfWork
from .querie_mixin import QueryMixin
from .use_case import UseCase

class AddVideoUseCase(UseCase):
    def __init__(self, unit_of_work: Optional[BaseUnitfWork] = None) -> None:
        super().__init__(unit_of_work)

    def execute(self, data: dict[str, Any]) -> dict[str, Any]:
        with self.unit_of_work as uow:
            video = Video(
                video_id=data["video_id"],
                video_title=data["video_title"],
                channel_title=data["channel_title"],
                video_description=data["video_description"],
                video_thumbnail=data["video_thumbnail"],
                video_duration=data["video_duration"],
                views_count=data["views_count"],
                likes_count=data["likes_count"],
                comments_count=data["comments_count"],
                published_at=data["published_at"],
                channel_id=data["channel_id"],
            )
            uow.repository.add(video)
        return dataclasses.asdict(video)

class GetVideoUseCase(UseCase):
    def __init__(self, unit_of_work: Optional[BaseUnitfWork] = None) -> None:
        super().__init__(unit_of_work)

    def execute(self, data: dict[str, Any]) -> dict[str, Any]:
        with self.unit_of_work as uow:
            video_id = data["video_id"]
            video = uow.repository.get_by_id(video_id)
        return dataclasses.asdict(video)

class DeleteVideoUseCase(UseCase):
    def __init__(self, unit_of_work: Optional[BaseUnitfWork] = None) -> None:
        super().__init__(unit_of_work)

    def execute(self, data: dict[str, Any]) -> dict[str, Any]:
        with self.unit_of_work as uow:
            video_id = data["video_id"]
            video = uow.repository.get_by_id(video_id)
            uow.repository.delete(video_id)
        return dataclasses.asdict(video)

class UpdateVideoUseCase(UseCase):
    def __init__(self, unit_of_work: Optional[BaseUnitfWork] = None) -> None:
        super().__init__(unit_of_work)

    def execute(self, data: dict[str, Any]) -> dict[str, Any]:
        with self.unit_of_work as uow:
            id = int(data["id"])
            video = uow.repository.get_by_id(id)
            if data.get("channel_title"):
                video.channel_title = data.get("channel_title")
            if data.get("comments_count"):
                video.comments_count = data.get("comments_count")
            if data.get("likes_count"):
                video.likes_count = data.get("likes_count")
            if data.get("video_description"):
                video.video_description = data.get("video_description")
            if data.get("video_duration"):
                video.video_duration = data.get("video_duration")
            if data.get("video_id"):
                video.video_id = data.get("video_id")
            if data.get("video_thumbnail"):
                video.video_thumbnail = data.get("video_thumbnail")
            if data.get("video_title"):
                video.video_title = data.get("video_title")
            if data.get("views_count"):
                video.views_count = data.get("views_count")
            if data.get("published_at"):
                video.published_at = data.get("published_at")
            uow.repository.update(video)
        return dataclasses.asdict(video)

class GetVideosUseCase(UseCase):
    def __init__(self, unit_of_work: Optional[BaseUnitfWork] = None) -> None:
        super().__init__(unit_of_work)

    def execute(self, data: dict[str, Any]) -> dict[str, Any]:
        with self.unit_of_work as uow:
            sort_field = "id"
            limit = 10
            offset = 0
            sort_order = "ASC"
            if data.get("sort_field"):
                sort_field = data.get("sort_field")
            if data.get("limit"):
                limit = data.get("limit")
            if data.get("offset"):
                offset = data.get("offset")
            if data.get("sort_order"):
                sort_order = data.get("sort_order")
            videos = uow.repository.list_all(sort_field=sort_field, limit=limit, offset=offset, sort_order=sort_order)
        return jsonify(videos)

class AddManyVideoUseCase(UseCase):
    def __init__(self, unit_of_work: Optional[BaseUnitfWork] = None) -> None:
        super().__init__(unit_of_work)

    def execute(self, data: dict[str, Any]) -> dict[str, Any]:
        with self.unit_of_work as uow:
            video_data_list = data["videos"]
            videos_added: int = 0
            for video_data in video_data_list:
                print(video_data)
                video = Video(
                    video_id=video_data["video_id"],
                    video_title=video_data["video_title"],
                    video_description=video_data["video_description"],
                    video_thumbnail=video_data["video_thumbnail"],
                    video_duration=video_data["video_duration"],
                    views_count=video_data["views_count"],
                    likes_count=video_data["likes_count"],
                    comments_count=video_data["comments_count"],
                    published_at=video_data["published_at"],
                    channel_id=video_data["channel_id"],
                )
                try:
                    uow.repository.add(video)
                    videos_added += 1
                except ResourceExistsException:
                    pass
        return {"Videos Added": videos_added}

class QueryVideoUseCase(QueryMixin, UseCase):
    def __init__(self, unit_of_work: Optional[BaseUnitfWork] = None) -> None:
        super().__init__(unit_of_work)

    def execute(self, data: dict[str, Any]) -> dict[str, Any]:
        with self.unit_of_work as uow:
            videos = []
            video_data_list = uow.repository.query(self.generate_query(data))
            if video_data_list:
                for video_data in video_data_list:
                    d = {}
                    for i, item in enumerate(video_data):
                        d[data["fields"][i]] = item
                    videos.append(d)
        return jsonify(videos)


#!/usr/bin/env python3
# coding: utf-8

import mysql.connector
from mysql.connector import errorcode
# -tc- ne pas utiliser l'étoile dans un import. La pep8 dit de l'éviter
from config import *
from constant import *

# -tc- plutôt qu'une fonction qui voys connecte et vous
# -tc- déconnecte de base immédiatement, définir une classe
# -tc- Database représentant la connection.
def database():

    cnx = mysql.connector.connect(**DB_CONFIG)
    cursor = cnx.cursor(buffered=True)

    try:
        cursor.execute("DROP DATABASE IF EXISTS {}".format(DB_CONFIG["database"]))
        print("database is deleted")
    except mysql.connector.Error as err:
        print("Failed delete database: {}".format(err))
        exit(1)

    # -tc- Quel intérêt ici de créer une fonction dans la fonction?
    def create_database(cursor):
        try:
            cursor.execute(
                "CREATE DATABASE {} DEFAULT CHARACTER SET 'utf8mb4'".format(
                    DB_CONFIG["database"]
                )
            )
        except mysql.connector.Error as err:
            print("Failed creating database: {}".format(err))
            exit(1)

    try:
        cursor.execute("USE {}".format(DB_CONFIG["database"]))
    except mysql.connector.Error as err:
        print("Database {} does not exists.".format(DB_CONFIG["database"]))
        if err.errno == errorcode.ER_BAD_DB_ERROR:
            create_database(cursor)
            print("Database {} created successfully.".format(DB_CONFIG["database"]))
            cnx.database = DB_CONFIG["database"]
        else:
            print(err)
            exit(1)

    for table_name in TABLES:
        table_description = TABLES[table_name]
        try:
            print("Creating table {}: ".format(table_name), end="")
            cursor.execute(table_description)
        except mysql.connector.Error as err:
            if err.errno == errorcode.ER_TABLE_EXISTS_ERROR:
                print("already exists.")
            else:
                print(err.msg)
        else:
            print("OK")

    cursor.close()
    cnx.close()


print("merhaba")
print(2*6)
print(10//3)
print(-15//4)
maasAli=5000
maasAhmet=400
vergi=0.27
#yorum satiri hastagle baslıyor
print(maasAli-(maasAli*vergi))
print(maasAhmet-(maasAhmet*vergi))
num=10
num +=10
print(num)
ad="Ali"
soyad=" Ak"
adsoyad=ad+soyad
tc=2345678
dyil=2000
adres="adres mah "
yas=26
sipa1=110
sipa2=1100.5
sipa3=356.95
tot=sipa1+sipa2+sipa3
print("total=",tot)


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

# 本文件的目的，在于pyest测试时导入，可以定位到工程文件代码，直接 import
# 后面的注释部分，请严格按照真实的项目名、路径进行替换

TESTS_FOLDER_DIR = os.path.dirname(os.path.abspath(__file__))
FATHER_DIR = os.path.dirname(TESTS_FOLDER_DIR)

PROJECT_DIR = os.path.join(FATHER_DIR, "/src")

# 将项目工程加入到import 检索路径中
sys.path.insert(0, PROJECT_DIR)

print(f"tests folder dir is {TESTS_FOLDER_DIR}")
print(f"father folder dir is {FATHER_DIR}")
print(f"prject folder dir is {PROJECT_DIR}")


marks = [1, 2, 3, 4, 5, 3, 4, 5, 2, 1]
sun = 0
nun = 0
for i in marks:
    nun += 1
    if i > 2:
        sun += 1
print(marks)
print(nun)
print((sun/ nun) * 100)


alunos = {}
i = 0
sala = []

def entrarnome():
    return str(input('\nEntre com o nome do aluno >>> '))

def entrarnota():
    while True:
        n = float(input(f'Entre com a média do aluno: '))
        if n < 0 or n > 10:
            print('\n\033[1;31mERRO! Entrada inválida! Tente novamente!\033[m\n')
        else:
            return n

while True:
    alunos['nome'] = entrarnome()
    alunos['média'] = entrarnota()
    if alunos['média'] >= 7:
        alunos['situação'] = 'Aprovado'
    elif alunos['média'] >= 5:
        alunos['situação'] = 'Recuperação'
    else:
        alunos['situação'] = 'Reprovado'
    sala.append(alunos.copy())
    while True:
        op = str(input('Deseja inserir outro aluno [S/N] ? >>> ')).upper()
        if op != 'S' and op != 'N':
            print('\n\033[1;31mERRO! Entrada inválida! Tente novamente!\033[m\n')
        else:
            break
    if op == 'N':
        break

print('\n                          Tabela dos alunos           ')
print('---------------------------------------------------------------------')
print('              Nome              |      Média      |     Situação     ')
print('---------------------------------------------------------------------\n')
for i in range(0, len(sala)):
    print('{:^32}|{:^17}|{:^18}'.format(sala[i]['nome'], round(sala[i]['média'], 2), sala[i]['situação']))
print('\n---------------------------------------------------------------------')


from collections import deque
def solution(time, r):

    answer = []
    wait = deque()
    pyo = deque()

    t = 0
    while t <= max(time):
        for idx,i in enumerate(time):
            if i == t:
                wait.append(idx)
                pyo.append(r[idx])
        if len(wait) == 1:
            answer.append(wait.popleft())

        for idx2,w in enumerate(wait):
            if min(pyo) == r[w]:
                wait.pop(idx2)
        t+=1
    return answer

solution([0,3,1,0],[0,1,2,3])
# [0,1,3,0]	[0,1,2,3]	[0, 1, 3, 2]
# [7,6,8,1]	[0,1,2,3]	[3, 1, 0, 2]


#!/usr/bin/python3
import re

files = [ 'games120.col',
          'miles250.col',
          'miles500.col',
          'miles750.col',
          'miles1000.col',
          'miles1500.col',
          'le450_5b.col',
          'le450_15b.col',
          'le450_25b.col',
          'ran10_100_a.bliss',
          'ran10_100_b.bliss',
          'ran10_100_c.bliss',
          'ran10_100_d.bliss',
          ]

## for each file above
max_budgets = [ 9, 7, 8, 8, 7, 5, 19, 17, 10, 12, 12, 13, 12 ]

repeat_times = 5
time_out_min = 60

wait_seconds = 60

test_graph_dir = '../test_graphs/'

out_dir = './table2output/'

results_time = {}
results_sol = {}
for f,max_budget in zip(files, max_budgets):
    for budget in range(max_budget+1):
        results_time[f, budget] = []
        results_sol[f, budget] = []
        for i in range(repeat_times):
            with open(out_dir+f+'.budget%d'%budget+'.run%d'%i, 'r') as out_file:
                out_file_str = out_file.read()
                ## get objective value
                match = re.search('Best Solution:  Value = \d*', out_file_str)
                if match == None:
                    ## do something to get best obj vale
                    ## find all incumbent updates
                    match = re.findall('inc=\d\d*', out_file_str)
                    ## get the very last one
                    last_reported_inc = match.pop()
                    ## get the objective value
                    obj_val = re.search('\d\d*', last_reported_inc).group(0)
                else:
                    obj_val_line = match.group(0)
                    obj_val = re.search('\d\d*', obj_val_line).group(0)
                results_sol[f,budget].append(int(obj_val))

                ## get run time
                match = re.search('Average search time \(Wall clock\)\s*\d*\.\d seconds.', out_file_str)
                if match == None:
                    time = 'NaN'
                else:
                    time_line = match.group(0)
                    time = re.search('\d\d*\.\d', time_line).group(0)
                results_time[f,budget].append(float(time))


import csv
import ijson  # type: ignore
from pylegend._typing import (
    PyLegendSequence,
    PyLegendOptional,
    TYPE_CHECKING
)
if TYPE_CHECKING:
    from pylegend.core.tds.tds_frame import PyLegendTdsFrame  # pragma: no cover
from pylegend.core.tds.result_handler.result_handler import ResultHandler
from pylegend.core.request.response_reader import ResponseReader

__all__: PyLegendSequence[str] = [
    "ToCsvFileResultHandler"
]

class ToCsvFileResultHandler(ResultHandler[None]):

    def __init__(self, file_or_writer, parse_float_as_decimal: bool = False) -> None:  # type: ignore
        self.__file: PyLegendOptional[str] = file_or_writer if isinstance(file_or_writer, str) else None
        self.__csv_writer = None if isinstance(file_or_writer, str) else file_or_writer
        self.__parse_float_as_decimal = parse_float_as_decimal

    def handle_result(self, frame: "PyLegendTdsFrame", result: ResponseReader) -> None:
        if self.__file is None:
            self.__write_result(self.__csv_writer, frame, result, self.__parse_float_as_decimal)
        else:
            with open(self.__file, 'w', newline='') as csvfile:
                csv_writer = csv.writer(csvfile)
                self.__write_result(csv_writer, frame, result, self.__parse_float_as_decimal)

    @staticmethod
    def __write_result(  # type: ignore
            csv_writer,
            frame,
            result,
            parse_as_decimal
    ) -> None:
        csv_writer.writerow([col.get_name() for col in frame.columns()])
        for next_row in ijson.items(result, "result.rows.item.values", use_float=not parse_as_decimal):
            csv_writer.writerow(next_row)
        return


import re

a, b = [int(x) for x in re.findall(r'\d+', open('d15.txt').read())]

def getnext(x, mul, modulo):
    x = mul * x % 2147483647
    while x % modulo != 0: x = mul * x % 2147483647
    return x

def judge(x, y, rounds, p2 = False):
    res = 0
    for _ in range(rounds):
        if p2: m1 = 4; m2 = 8
        else: m1 = 1; m2 = 1
        x = getnext(x, 16807, m1)
        y = getnext(y, 48271, m2)
        xb = bin(x)[2:].zfill(16)[-16:]
        yb = bin(y)[2:].zfill(16)[-16:]
        if xb == yb: res += 1
    return res

# P1
print(judge(a, b, 40_000_000))

# P2
print(judge(a, b, 5_000_000, True))


#!/usr/bin/python

import sys
import os

file = sys.argv[1]
output = sys.argv[2]

import libtorrent as lt

fs = lt.file_storage()
lt.add_files( fs, file )

ct = lt.create_torrent( fs, 5000 )

#ct.add_tracker("http://tracker.openbittorrent.com/announce", 0)
#ct.add_tracker("udp://tracker.openbittorrent.com:80/announce", 0)
ct.add_tracker("http://tracker.publicbt.com/announce", 0)
ct.add_tracker("udp://tracker.publicbt.com:80/announce", 0)

ct.set_creator("iftd")

lt.set_piece_hashes( ct, os.path.dirname(file))

bt_str = lt.bencode( ct.generate() )

fd = open(output, "wb" )
fd.write( bt_str )
fd.close()