import openpyxl

def OSC_CAL(OC_MT1, OC_MT2, OC_MT3, OC_MT4,workbook_save):
    wb = openpyxl.load_workbook(workbook_save)
    sheet = wb['Sheet1']
    sheet['D17'] = OC_MT1#Osc cal 1
    sheet['D18'] = OC_MT2#OC2
    sheet['D19'] = OC_MT3#OC3
    sheet['D20'] = OC_MT4#OC4
    #print (OC_MT1, OC_MT2, OC_MT3, OC_MT4)
    wb.save(workbook_save)

def check_osc_cal(workbook_save,new_flabel):
    #print(workbook_save)

    OC_hex= open(new_flabel  + "_osc_cal.hex",'r').read()
    #print (OC_hex)
    if OC_hex[2] == '2':
        OC_MT1 = ("0x" + OC_hex[9:11])
        OC_MT2 = ("0x" + OC_hex[11:13])
        OC_MT3 = "N/A"
        OC_MT4 = "N/A"
        #print (OC_hex[2])

    elif OC_hex[2] == '3':
        OC_MT1 = ("0x" + OC_hex[9:11])
        OC_MT2 = ("0x" + OC_hex[11:13])
        OC_MT3 = ("0x" + OC_hex[13:15])
        OC_MT4 = "N/A"

    elif OC_hex[2] == '4':
        OC_MT1 = ("0x" + OC_hex[9:11])
        OC_MT2 = ("0x" + OC_hex[11:13])
        OC_MT3 = ("0x" + OC_hex[13:15])
        OC_MT4 = ("0x" + OC_hex[15:17])
    else:
        OC_MT1 = ("0x" + OC_hex[9:11])
        OC_MT2 = "N/A"
        OC_MT3 = "N/A"
        OC_MT4 = "N/A"
    OSC_CAL(OC_MT1, OC_MT2, OC_MT3, OC_MT4,workbook_save)
#check_osc_cal()


from collections import deque

class Vertex:
    def __init__(self, name, edges):
        self.name = name
        self.edges = edges

class Graph:
    def __init__(self, vertices=[]):
        if vertices:
            self.graph = {vertex.name: vertex.edges for vertex in vertices}
        else:
            self.graph = {}

    def add(self, Vertex):
        self.graph[Vertex.name] = Vertex.edges

    def get_neighbors(self, name):
        return self.graph[name]

    def bfs_recursive(self, discovered, queue):
        # Base case: if nothing left in queue, return
        if not queue:
            return
        # Recursive case
        node_name = queue.popleft() # Dequeue
        neighbors = self.get_neighbors(node_name)
        for neighbor in neighbors:
            if neighbor not in discovered:
                queue.append(neighbor)
                discovered.append(neighbor)
        self.bfs_recursive(discovered, queue)

    def bfs(self, node_name):
        queue = deque()
        discovered = []
        queue.append(node_name)
        discovered.append(node_name)
        self.bfs_recursive(discovered, queue)

vertices = [Vertex('bob', ['alice', 'george']),
            Vertex('george', [])]
g = Graph(vertices)
print(g.get_neighbors('bob'))
g.add(Vertex('alice', ['bob', 'tom']))
g.add(Vertex('tom', ['bob']))
print(g.get_neighbors('alice'))
g.bfs('alice')


import numpy as np

import settings
import evaluate.evaluate_main as ev
import utils.convert_pose as cp

def test_evaluate_pose():
    pose_pred0 = np.array([[1, 2, 3, 0, 0, 1.], [4, 5, 6, 0, 0, 1.5], [1, 2, 3, 0, 0, 1.], [4, 5, 6, 0, 0, 1.5]])
    pose_true = pose_pred0.copy()

    # scaling trajectory does not affect error
    pose_pred1 = pose_pred0.copy()
    pose_pred1[:, :3] = pose_pred1[:, :3] * 2
    print("predicted_pose\n", pose_pred1)
    pose_true = cp.pose_rvec2matr(pose_true)
    trj_err, rot_err = ev.evaluate_pose(pose_pred1, pose_true)
    print("trajectory error\n", trj_err)
    assert np.isclose(trj_err, 0).all()

    # change orientations
    pose_pred2 = pose_pred0.copy()
    rotation = np.array([0, -1, 1, 2])
    pose_pred2[:, 5] = pose_pred2[:, 5] + rotation
    print("predicted_pose\n", pose_pred2)
    trj_err, rot_err = ev.evaluate_pose(pose_pred2, pose_true)
    print("rotational error\n", rot_err)
    assert np.isclose(rot_err[1:], np.abs(rotation[[1, 0, 2, 3]])).all()

    # change orientation of origin
    pose_pred3 = pose_pred0.copy()
    rotation = np.array([1, 0, 0, 0])
    pose_pred3[:, 5] = pose_pred3[:, 5] + rotation
    print("predicted_pose\n", pose_pred3)
    trj_err, rot_err = ev.evaluate_pose(pose_pred3, pose_true)
    print("rotational error\n", rot_err)
    assert np.isclose(rot_err[1:], np.abs(rotation[0])).all()

    print("!!! test_evaluate_pose passed")

if __name__ == "__main__":
    np.set_printoptions(precision=3, suppress=True, linewidth=100)
    test_evaluate_pose()


import os.path as osp
import random
from IPython.core.pylabtools import figsize
from PIL.ImageOps import scale
from mmcv.visualization import color
import torch
import numpy as np
import math
import itertools
from core.utils.pose_aug import aug_poses_normal, aug_scale_normal
from lib.pysixd.transform import random_rotation_matrix
from lib.vis_utils.image import grid_show, heatmap
from lib.pysixd import misc
from core.utils.pose_utils import rot_from_axangle_chain

def get_normed_kps(cfg, batch, **to_float_args):
    kps_type = cfg.INPUT.KPS_TYPE
    if kps_type.lower() == "bbox":
        scale_est = batch["obj_scale_est"]
        bboxes = get_normed_bbox(scale_est.shape[0])
        batch["obj_kps"] = bboxes.to(**to_float_args)
    elif kps_type.lower() == "mean_shape":
        batch["obj_kps"] = batch["obj_mean_points"].clone()
    elif kps_type.lower() == "fps":
        # NOTE: use obj_scale_est here, train: gt_scale, test: init_scale (with noise)
        batch["obj_kps"] = norm_fps_points(batch["obj_fps_points"], batch["obj_scale_est"]).to(**to_float_args)
    elif kps_type.lower() == "axis":
        scale_est = batch["obj_scale_est"]
        num_kps = cfg.INPUT.NUM_KPS
        with_neg = cfg.INPUT.WITH_NEG_AXIS
        axises = get_normed_axis(scale_est.shape[0], num_kps, with_neg)
        batch["obj_kps"] = axises.to(**to_float_args)
    else:
        raise NotImplementedError(f"Unknown keypoints type {kps_type}")

def norm_fps_points(fps_points, scale):
    return fps_points / scale.unsqueeze(1)  # (B, V, 3)

def get_normed_axis(bs, num_kps=4, with_neg=False):
    num_per_axis = (num_kps - 1) // 3
    if with_neg:
        start = -0.5
        l = 1
    else:
        start = 0
        l = 0.5
    x_points = torch.tensor([[start + l * i / num_per_axis, 0, 0] for i in range(1, num_per_axis + 1)])
    y_points = torch.tensor([[0, start + l * i / num_per_axis, 0] for i in range(1, num_per_axis + 1)])
    z_points = torch.tensor([[0, 0, start + l * i / num_per_axis] for i in range(1, num_per_axis + 1)])
    axis = torch.cat(
        (
            x_points,
            y_points,
            z_points,
            torch.tensor([[0, 0, 0]]),  # with origin
        ),
        dim=0,
    )
    axises = torch.stack([axis for i in range(bs)], dim=0)
    return axises

def get_normed_bbox(bs):
    bbox = torch.tensor(
        [
            [1 / 2, 1 / 2, 1 / 2],
            [-1 / 2, 1 / 2, 1 / 2],
            [-1 / 2, -1 / 2, 1 / 2],
            [1 / 2, -1 / 2, 1 / 2],
            [1 / 2, 1 / 2, -1 / 2],
            [-1 / 2, 1 / 2, -1 / 2],
            [-1 / 2, -1 / 2, -1 / 2],
            [1 / 2, -1 / 2, -1 / 2],
        ]
    )
    bboxes = torch.stack([bbox for i in range(bs)], dim=0)
    return bboxes

def get_bbox_from_scale_batch(scales):
    """scale shape (B, 3)"""

    minx, maxx = -scales[:, 0] / 2, scales[:, 0] / 2
    miny, maxy = -scales[:, 1] / 2, scales[:, 1] / 2
    minz, maxz = -scales[:, 2] / 2, scales[:, 2] / 2

    bboxes = torch.stack(
        (
            torch.stack((maxx, maxy, maxz), dim=1),
            torch.stack((minx, maxy, maxz), dim=1),
            torch.stack((minx, miny, maxz), dim=1),
            torch.stack((maxx, miny, maxz), dim=1),
            torch.stack((maxx, maxy, minz), dim=1),
            torch.stack((minx, maxy, minz), dim=1),
            torch.stack((minx, miny, minz), dim=1),
            torch.stack((maxx, miny, minz), dim=1),
        ),
        dim=1,
    )  # bs, num_k, 3

    return bboxes

def aug_3d_bbox(
    batch, shift_sx=(0.8, 1.2), shift_sy=(0.8, 1.2), shift_sz=(0.8, 1.2), device="cuda", dtype=torch.float32
):
    # generate aug parameters
    ex, ey, ez = torch.rand(3)
    ex = ex * (shift_sx[1] - shift_sx[0]) + shift_sx[0]
    ey = ey * (shift_sy[1] - shift_sy[0]) + shift_sy[0]
    ez = ez * (shift_sz[1] - shift_sz[0]) + shift_sz[0]

    tensor_kwargs = {"dtype": dtype, "device": device}
    to_float_args = {"dtype": dtype, "device": device, "non_blocking": True}
    pcls_aug = []
    scales_aug = []
    for pcl, pose, scale, sym_info in zip(batch["pcl"], batch["obj_pose"], batch["obj_scale"], batch["sym_info"]):
        R = pose[:, :3]
        t = pose[:, 3]
        pcl_reproj = torch.mm(R.T, (pcl - t.view(1, 3)).T).T

        if sym_info is not None:  # y axis symmetry
            exz = (ex + ez) / 2
            ratios = torch.tensor((exz, ey, exz)).to(**tensor_kwargs)
        else:
            ratios = torch.tensor((ex, ey, ez)).to(**tensor_kwargs)

        pcl_reproj = pcl_reproj * ratios.unsqueeze(0)  # (P, 3) * (1, 3)
        scale_aug = scale * ratios
        pcl_aug = torch.mm(R, pcl_reproj.T) + t.view(3, 1)

        scales_aug.append(scale_aug)
        pcls_aug.append(pcl_aug.T)

    batch["obj_scale"] = torch.stack(scales_aug).contiguous().to(**to_float_args)
    batch["pcl"] = torch.stack(pcls_aug).contiguous().to(**to_float_args)

def aug_RT(batch, shift_tx=0.005, shift_ty=0.005, shift_tz=0.025, shift_rot=15.0, device="cuda", dtype=torch.float32):
    tensor_kwargs = {"dtype": dtype, "device": device}
    to_float_args = {"dtype": dtype, "device": device, "non_blocking": True}

    # generate aug parameters
    rx, ry, rz = torch.rand(3) * shift_rot * 2 - shift_rot
    tx = torch.rand(1) * shift_tx * 2 - shift_tx
    ty = torch.rand(1) * shift_ty * 2 - shift_ty
    tz = torch.rand(1) * shift_tz * 2 - shift_tz
    delta_r = get_rotation_torch(rx, ry, rz).to(**tensor_kwargs)
    delta_t = torch.tensor((tx, ty, tz)).to(**tensor_kwargs)

    pcls_aug = []
    Rs_aug = []
    ts_aug = []
    for pcl, pose in zip(batch["pcl"], batch["obj_pose"]):
        R = pose[:, :3]
        t = pose[:, 3]

        pcl_aug = torch.mm(delta_r, (pcl + delta_t.unsqueeze(0)).T).T
        R_aug = torch.mm(delta_r, R)
        t_aug = torch.mm(delta_r, (t + delta_t).view(3, 1))

        pcls_aug.append(pcl_aug)
        Rs_aug.append(R_aug)
        ts_aug.append(t_aug)

    Rs_aug = torch.stack(Rs_aug)
    ts_aug = torch.stack(ts_aug)
    batch["obj_pose"] = torch.cat((Rs_aug, ts_aug), dim=-1).contiguous().to(**to_float_args)
    batch["pcl"] = torch.stack(pcls_aug).contiguous().to(**to_float_args)

def get_rotation_torch(x_, y_, z_):
    x = (x_ / 180) * math.pi
    y = (y_ / 180) * math.pi
    z = (z_ / 180) * math.pi

    R_x = torch.tensor([[1, 0, 0], [0, math.cos(x), -math.sin(x)], [0, math.sin(x), math.cos(x)]], device=x_.device)
    R_y = torch.tensor([[math.cos(y), 0, math.sin(y)], [0, 1, 0], [-math.sin(y), 0, math.cos(y)]], device=y_.device)
    R_z = torch.tensor([[math.cos(z), -math.sin(z), 0], [math.sin(z), math.cos(z), 0], [0, 0, 1]], device=z_.device)

    return torch.mm(R_z, torch.mm(R_y, R_x))

def get_init_scale_train(cfg, batch, device="cuda", dtype=torch.float32):
    tensor_kwargs = {"dtype": dtype, "device": device}
    input_cfg = cfg.INPUT
    n_obj = batch["obj_scale"].shape[0]
    init_pose_type = random.choice(input_cfg.INIT_SCALE_TYPE_TRAIN)  # randomly choose one type
    if init_pose_type == "gt_noise":
        batch["obj_scale_est"] = aug_scale_normal(
            batch["obj_scale"],
            std_scale=cfg.INPUT.NOISE_SCALE_STD_TRAIN,
            min_s=cfg.INPUT.INIT_SCALE_MIN,
        )
    elif init_pose_type == "random":  # random
        scale_rand = np.zeros((n_obj, 3), dtype="float32")
        for _i in range(n_obj):
            scale_rand[_i] = np.array([random.uniform(_min, _max) for _min, _max in zip(s_min, s_max)])
            s_min = input_cfg.RANDOM_SCALE_MIN
            s_max = input_cfg.RANDOM_SCALE_MAX
        batch["obj_scale_est"] = torch.tensor(scale_rand, **tensor_kwargs)
    elif init_pose_type == "last_frame":
        batch["obj_scale_est"] = batch["last_frame_poses"][:, :3, 4]
    elif init_pose_type == "canonical":
        s_canonical = torch.tensor(input_cfg.CANONICAL_SIZE, **tensor_kwargs).reshape(1, 3)
        batch["obj_scale_est"] = s_canonical.repeat(n_obj, 1)  # [n, 3]
    else:
        raise ValueError(f"Unknown init pose type for train: {init_pose_type}")

def get_init_pose_train(cfg, batch, device="cuda", dtype=torch.float32):
    tensor_kwargs = {"dtype": dtype, "device": device}
    input_cfg = cfg.INPUT
    n_obj = batch["obj_pose"].shape[0]
    init_pose_type = random.choice(input_cfg.INIT_POSE_TYPE_TRAIN)  # randomly choose one type
    if init_pose_type == "gt_noise":
        batch["obj_pose_est"] = aug_poses_normal(
            batch["obj_pose"],
            std_rot=input_cfg.NOISE_ROT_STD_TRAIN,  # randomly choose one
            std_trans=input_cfg.NOISE_TRANS_STD_TRAIN,  # [0.01, 0.01, 0.05]
            max_rot=input_cfg.NOISE_ROT_MAX_TRAIN,  # 45
            min_z=input_cfg.INIT_TRANS_MIN_Z,  # 0.1
        )
    elif init_pose_type == "random":  # random
        poses_rand = np.zeros((n_obj, 3, 4), dtype="float32")
        for _i in range(n_obj):
            poses_rand[_i, :3, :3] = random_rotation_matrix()[:3, :3]
            t_min = input_cfg.RANDOM_TRANS_MIN
            t_max = input_cfg.RANDOM_TRANS_MAX
            poses_rand[_i, :3, 3] = np.array([random.uniform(_min, _max) for _min, _max in zip(t_min, t_max)])
        batch["obj_pose_est"] = torch.tensor(poses_rand, **tensor_kwargs)
    elif init_pose_type == "last_frame":
        assert "last_frame_poses" in batch
        batch["obj_pose_est"] = batch["last_frame_poses"][:, :3, :4]
    elif init_pose_type == "canonical":
        r_canonical = rot_from_axangle_chain(input_cfg.CANONICAL_ROT)
        t_canonical = np.array(input_cfg.CANONICAL_TRANS)
        pose_canonical = torch.tensor(
            np.hstack([r_canonical, t_canonical.reshape(3, 1)]),
            **tensor_kwargs,
        )
        batch["obj_pose_est"] = pose_canonical.repeat(n_obj, 1, 1)  # [n,3,4]
    else:
        raise ValueError(f"Unknown init pose type for train: {init_pose_type}")

def _normalize_image(im, mean, std):
    # Bx3xHxW, 3x1x1
    return (im - mean) / std

def get_out_coor(cfg, coor_x, coor_y, coor_z):
    if (coor_x.shape[1] == 1) and (coor_y.shape[1] == 1) and (coor_z.shape[1] == 1):
        coor_ = torch.cat([coor_x, coor_y, coor_z], dim=1)
    else:
        coor_ = torch.stack(
            [torch.argmax(coor_x, dim=1), torch.argmax(coor_y, dim=1), torch.argmax(coor_z, dim=1)],
            dim=1,
        )
        # set the coordinats of background to (0, 0, 0)
        coor_[coor_ == cfg.MODEL.CATRE.XYZ_HEAD.XYZ_BIN] = 0
        # normalize the coordinates to [0, 1]
        coor_ = coor_ / float(cfg.MODEL.CATRE.XYZ_HEAD.XYZ_BIN - 1)

    return coor_

def get_out_mask(cfg, pred_mask):
    # (b,c,h,w)
    # output: (b, 1, h, w)
    mask_loss_type = cfg.MODEL.CATRE.MASK_HEAD.MASK_LOSS_TYPE
    bs, c, h, w = pred_mask.shape
    if mask_loss_type == "L1":
        assert c == 1, c
        mask_max = torch.max(pred_mask.view(bs, -1), dim=-1)[0].view(bs, 1, 1, 1)
        mask_min = torch.min(pred_mask.view(bs, -1), dim=-1)[0].view(bs, 1, 1, 1)
        # [0, 1]
        out_mask = (pred_mask - mask_min) / (mask_max - mask_min)  # + 1e-6)
    elif mask_loss_type == "BCE":
        assert c == 1, c
        out_mask = torch.sigmoid(pred_mask)
    elif mask_loss_type == "CE":
        out_mask = torch.argmax(pred_mask, dim=1, keepdim=True)
    else:
        raise NotImplementedError(f"unknown mask loss type: {mask_loss_type}")
    return out_mask

def _zeros(_n, _c, _h, _w, dtype=torch.float32, device="cuda"):
    _tensor_kwargs = {"dtype": dtype, "device": device}
    return torch.zeros(_n, _c, _h, _w, **_tensor_kwargs).detach()

def _empty(_n, _c, _h, _w, dtype=torch.float32, device="cuda"):
    _tensor_kwargs = {"dtype": dtype, "device": device}
    return torch.empty(_n, _c, _h, _w, **_tensor_kwargs).detach()

def get_input_dim(cfg):
    backbone_cfg = cfg.MODEL.CATRE.BACKBONE
    if backbone_cfg.SHARED:
        return backbone_cfg.INIT_CFG.in_channels
    else:
        return backbone_cfg.INIT_CFG.in_channels // 2, backbone_cfg.INIT_CFG.in_channels // 2

def boxes_to_masks(boxes, imH, imW, device="cuda", dtype=torch.float32):
    n_obj = boxes.shape[0]
    masks = _zeros(n_obj, 1, imH, imW, device=device, dtype=dtype)  # the square region of bbox
    for _i in range(n_obj):
        x1, y1, x2, y2 = boxes[_i]
        x1 = int(min(imW - 1, max(0, x1)))
        y1 = int(min(imH - 1, max(0, y1)))
        x2 = int(min(imW - 1, max(0, x2)))
        y2 = int(min(imH - 1, max(0, y2)))
        masks[_i, 0, y1 : y2 + 1, x1 : x2 + 1] = 1.0
    return masks

def zoom_kps_batch(kps, K, K_zoom):
    invK = torch.linalg.inv(K)
    zoom_tfd_kps = invK @ K_zoom @ kps.clone().permute(0, 2, 1)
    return zoom_tfd_kps

def plot_3d(pcl1, pcl2, title):
    import matplotlib.pyplot as plt

    fig, axs = plt.subplots(1, 3, subplot_kw=dict(projection="3d"), figsize=plt.figaspect(1 / 3))
    axs[0].scatter(pcl1[:, 0], pcl1[:, 1], pcl1[:, 2], marker="o")
    axs[0].scatter(pcl2[:, 0], pcl2[:, 1], pcl2[:, 2], marker="x", color="red")

    axs[1].scatter(pcl1[:, 0], pcl1[:, 1], pcl1[:, 2], marker="o")
    axs[2].scatter(pcl2[:, 0], pcl2[:, 1], pcl2[:, 2], marker="x", color="red")

    for ax in axs:
        ax.set_xlabel("x")
        ax.set_ylabel("y")
    fig.suptitle(title)
    plt.show()

def vis_batch(cfg, batch, phase="train"):
    im_ids = batch["im_id"]
    n_obj = batch["obj_cls"].shape[0]
    Ks = batch["K"].detach().cpu().numpy()

    kpts_3d_list = batch["obj_kps"].detach().cpu().numpy()
    scale = batch["obj_scale"].detach().cpu().numpy()
    kpts_3d_list = kpts_3d_list * scale[:, None]
    kpts_3d_list = np.array([misc.get_3D_corners(kpts_3d_noise) for kpts_3d_noise in kpts_3d_list])
    pose_noise = batch["obj_pose_est"].detach().cpu().numpy()

    Rs_noise = pose_noise[:, :, :3]
    transes_noise = pose_noise[:, :, 3:]
    kpts_2d_noise = [
        misc.project_pts(kpt3d, K, R, t) for kpt3d, K, R, t in zip(kpts_3d_list, Ks, Rs_noise, transes_noise)
    ]

    poses = batch["obj_pose"].detach().cpu().numpy()
    scales = batch["obj_scale"].detach().cpu().numpy()
    pcl = batch["x"].permute(0, 2, 1).detach().cpu().numpy()
    tfd_kps = batch["tfd_kps"].permute(0, 2, 1).detach().cpu().numpy()
    nocses = batch["nocs"].detach().cpu().numpy()  # bs, 3, p
    Rs = poses[:, :, :3]
    transes = poses[:, :, 3:]
    kpts_2d_gt = [misc.project_pts(kpt3d, K, R, t) for kpt3d, K, R, t in zip(kpts_3d_list, Ks, Rs, transes)]
    # yapf: disable
    for i in range(n_obj):
        diag_len = np.linalg.norm(scales[i])
        R = Rs[i]
        t = transes[i]
        nocs_ = nocses[i] * diag_len
        nocs_ = (R @ nocs_ + t.reshape(3, 1)).T
        pcl_ = pcl[i] + transes_noise[i].reshape(1, 3)
        nocs_dist = np.linalg.norm(nocs_ - pcl_, axis=1).mean()
        plot_3d(pcl_, nocs_, f"pcl vs nocs, mean dist {nocs_dist}")
        vis_dict = {"img": (batch['img'][int(im_ids[i])].detach().cpu().numpy().transpose(1,2,0) * 255).astype('uint8')[:,:,::-1],
                    "depth": heatmap(batch['depth_obs'][int(im_ids[i])].detach().cpu().numpy().transpose(1,2,0), to_rgb=True)}
        img_vis_kpts2d_gt = misc.draw_projected_box3d(vis_dict["img"].copy(), kpts_2d_gt[i])
        vis_dict["img_vis_kpts2d_gt"] = img_vis_kpts2d_gt

        img_vis_kpts2d_noise = misc.draw_projected_box3d(vis_dict["img"].copy(), kpts_2d_noise[i])
        vis_dict["img_vis_kpts2d_noise"] = img_vis_kpts2d_noise

        show_titles = list(vis_dict.keys())
        show_ims = list(vis_dict.values())
        ncol = 2
        nrow = 2
        grid_show(show_ims, show_titles, row=nrow, col=ncol)
    # yapf: enable


#!/usr/bin/env python3

""" This script build releasable executables for the Go CAP client """

import os
import platform
import shutil
import subprocess
import sys

from pathlib import Path
from typing import Optional

DOCKER = "docker"
TAG = "v22.4.21"
TITLE = "CAP Client Release ${TAG}"
NOTES = "Watt web interface"
UNAME_S = str(platform.uname())

def main(args: list[str]) -> None:
    """Main routine"""
    print(f"Building on {UNAME_S}....")

    assets = [build_windows(), build_linux(), build_mac()]
    assets = [asset for asset in assets if asset is not None]

    if args and args[0] != "upload":
        print()
        print(
            "Build successful. Run again as './release.sh upload' to upload assets to Github."
        )
        sys.exit(0)

        subprocess.run(
            [
                "gh",
                "release",
                "create",
                TAG,
                "--draft",
                "-n",
                NOTES,
                "-t",
                TITLE,
                assets,
            ],
            check=True,
        )

def build_linux() -> Optional[Path]:
    """Build on Linux (if running on Linux)"""
    if UNAME_S != "Linux":
        print(
            "Skipping Linux build...(must build Linux on Linux to have TurboVNC build dependencies)"
        )
        return None
    print()
    print("Building for Linux...")
    print()
    env = os.environ
    env["GOOS"] = "linux"
    subprocess.run(["go", "generate", "./..."], env=env, check=True)
    subprocess.run(
        [DOCKER, "build", ".fyne-cross/linux/", "-t", "capclient-linux"], check=True
    )
    subprocess.run(
        [
            "fyne-cross",
            "linux",
            "-name",
            "capclient",
            "-image",
            "capclient-linux:latest",
            "-env",
            "CGO_CFLAGS=-I/usr/include/ykpers-1/",
        ],
        check=True,
    )
    asset_linux = Path("fyne-cross/capclient.${TAG}_Linux.tar.xz")
    subprocess.run(
        ["mv", "fyne-cross/dist/linux-amd64/capclient.tar.xz", asset_linux], check=True
    )
    return asset_linux

def build_mac() -> Optional[Path]:
    """Build on Mac (if running on Mac)"""
    if UNAME_S != "Darwin":
        print("\nSkipping Mac build...(must build Mac on Mac)\n")
        return None
    print()
    print("\nBuilding for Mac...\n")
    print()
    turbo_home = "/Applications/TurboVNC"
    print(
        f"Note:  This script will run sudo to DELETE your {turbo_home} directory,"
        " and then (re)install TurboVNC-2.2.7 to {turbo_home}."
    )
    input(
        "\nIf you don't want this, Ctrl-C to cancel.  Otherwise, Enter to continue.\n"
    )

    env = os.environ
    env["GOOS"] = "darwin"
    subprocess.run(["go", "generate", "./..."], env=env, check=True)
    subprocess.run(
        [
            "fyne-cross",
            "darwin",
            "-name",
            "capclient",
            "--app-id",
            "com.aeolustec.capclient",
            "-env",
            "CGO_CFLAGS=-I/usr/local/include/ykpers-1",
            "-I/usr/local/include",
            "-env",
            "CGO_LDFLAGS=/usr/local/lib/libykpers-1.a",
            "/usr/local/lib/libyubikey.a",
        ],
        check=True,
    )
    asset_mac = Path("fyne-cross/Gocap.${TAG}_Mac.zip")
    subprocess.run(
        ["zip", "-r", "-j", asset_mac, "fyne-cross/dist/darwin-amd64/capclient.app"],
        check=True,
    )
    return asset_mac

def build_windows() -> Optional[Path]:
    """Build on Windows"""
    print()
    print("Building for Windows...")
    print()
    env = os.environ
    env["GOOS"] = "windows"
    subprocess.run(["go", "generate", "./..."], env=env, check=True)
    subprocess.run(
        [DOCKER, "build", ".fyne-cross/windows/", "-t", "capclient-windows"],
        check=True,
    )
    subprocess.run(
        [
            "fyne-cross",
            "windows",
            "-name",
            "capclient.exe",
            "-image",
            "capclient-windows:latest",
            "-env",
            "CGO_CFLAGS=-I/usr/include/ykpers-1/ -I/usr/share/mingw-w64/include/",
            "-env",
            "CGO_LDFLAGS=-L/usr/x86_64-w64-mingw32/lib",
        ],
        check=True,
    )
    asset_windows = Path("fyne-cross/capclient.${TAG}_Windows.zip")
    shutil.move("fyne-cross/dist/windows-amd64/capclient.exe.zip", asset_windows)
    return asset_windows

main(sys.argv)


import os
import sys
import re
import time

from aip import AipOcr

sms_code = ""
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))

class BaiduOCR(object):
    """
    百度ocr识别类，用于帮助ios设备识别投屏后的短信验证码
    """

    def __init__(self, _config, debug=False):
        from utils.logger import Log
        self.logger = Log().logger
        app_id = _config["baidu_app_id"]
        api_key = _config["baidu_api_key"]
        secret_key = _config["baidu_secret_key"]
        self.debug = debug
        if app_id == "" or api_key == "" or secret_key == "":
            self.logger.warning("请在config.yaml中配置baidu ocr相关配置")
            sys.exit(1)
        self.client = AipOcr(app_id, api_key, secret_key)

    def baidu_ocr(self, _range_, delay_time=5):
        """
        百度ocr识别数字
        :param delay_time: ocr识别延迟时间
        :param _range_: 验证码截图区域坐标(左x,左y,右x,右y)
        :return: 识别到的数字
        """

        global sms_code
        screenshot_save(_range_)
        img = open(captcha_screenshot, 'rb').read()
        ocr_ret = self.client.basicGeneral(img)

        # debug模式打印识别内容
        if self.debug:
            self.logger.info(ocr_ret)

        if "words_result" in ocr_ret:
            if len(ocr_ret["words_result"]) == 0:
                self.logger.info("暂未获取到最新验证码，%d秒后重试" % delay_time)
                time.sleep(delay_time)
                return self.baidu_ocr(_range_, delay_time)

            ocr_ret = str(ocr_ret["words_result"])

            find_all = ""
            for rule in matching_rules:
                find_all = re.findall(rule, ocr_ret)
                if len(find_all) >= 1:
                    break

            if len(find_all) >= 1:
                code = find_all[0].strip("'")
                if sms_code == code:
                    self.logger.info("暂未获取到最新验证码，%d秒后重试" % delay_time)
                    time.sleep(delay_time)
                    return self.baidu_ocr(_range_, delay_time)
                else:
                    sms_code = code

                return code
            else:
                self.logger.info("暂未获取到最新验证码，%d秒后重试" % delay_time)
                time.sleep(delay_time)
                return self.baidu_ocr(_range_, delay_time)
        else:
            self.logger.info("暂未获取到最新验证码，%d秒后重试" % delay_time)
            time.sleep(delay_time)
            return self.baidu_ocr(_range_, delay_time)

if __name__ == '__main__':
    from utils.config import get_config

    ocr_cfg = get_config("../config.yaml")["sms_captcha"]["ocr"]
    _range_ = ocr_cfg["ocr_range"]
    sms_code = BaiduOCR(ocr_cfg, True).baidu_ocr(_range_, ocr_cfg["ocr_delay_time"])
    print("百度OCR识别到的验证码是：", sms_code)
else:
    from captcha.config import *


import torch

class FFNetwork(torch.nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, num_classes, **kwargs):
        torch.nn.Module.__init__(self)

        self.input_size = input_size
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.num_classes = num_classes

        self.add_module("input", torch.nn.Linear(input_size, hidden_size))
        self.add_module("activation_input", torch.nn.Sigmoid())
        for i in range(0, num_layers):
            self.add_module("l"+str(i), torch.nn.Linear(hidden_size, hidden_size))
            self.add_module("a"+str(i), torch.nn.Sigmoid())
        self.add_module("output", torch.nn.Linear(hidden_size, num_classes))
        self.add_module("activation_output", torch.nn.Sigmoid())

    def forward(self, input):
        for module in self._modules.values():
            input = module(input)
        return input

    def forward_batch(self, batch_data):
        batch_out = self(batch_data.view(-1, batch_data.shape[1] * batch_data.shape[2]).type(torch.float32))
        return batch_out

    def evaluate_batch(self, batch_data, batch_target):
        out = self(batch_data.view(-1, batch_data.shape[1] * batch_data.shape[2]).type(torch.float32))
        return (out.max(1)[1] == (batch_target.to(batch_data.device))).sum().item()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Dec 10 21:53:41 2020

@author: heyishan
"""

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 25 20:16:38 2020

@author: heyishan
"""

import numpy as np
import pandas as pd
import plotly.express as px
import dash
import dash_table as dt
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output # control interaction
import plotly.io as pio

pio.templates.default = "seaborn"

# Read the two files
players = pd.read_csv("NBAPlayers.csv", index_col = [0])
players['Number'] = players['Number'].astype('Int64')
#players['Age'] = players['Age'].astype('Int64')
stats = pd.read_csv("playerStat.csv")

# Merge the two data frames and clean up the data
df = pd.merge(players, stats, how = "left", left_on = "Name", right_on = "Unnamed: 0")
df.Salary = df.Salary.str.split("$").str.get(1).str.replace(",", "").astype(float)
df["FG_High"] = df.FG.str.split("-").str.get(1).astype(float)
df["FG_Low"] = df.FG.str.split("-").str.get(0).astype(float)
df["FG"] = round((df["FG_High"] + df["FG_Low"])/2,2)
df["3PT_High"] = df["3PT"].str.split("-").str.get(1).astype(float)
df["3PT_Low"] = df["3PT"].str.split("-").str.get(0).astype(float)
df["3PT"] = round((df["3PT_High"] + df["3PT_Low"])/2,2)
df["FT_High"] = df.FT.str.split("-").str.get(1).astype(float)
df["FT_Low"] = df.FT.str.split("-").str.get(0).astype(float)
df["FT"] = round((df["FT_High"] + df["FT_Low"])/2,2)

df2 = df.reindex(columns = ['Name', 'Number', 'Position', 'Age', 'Height', 'Weight', 'College',
       'Salary', 'Team', 'GP', 'GS', 'MIN', 'FG', 'FG%', '3PT', '3P%',
       'FT', 'FT%', 'OR', 'DR', 'REB', 'AST', 'BLK', 'STL', 'PF', 'TO', 'PTS'])
df2 = df2.replace(np.nan, '', regex=True)

stylesheet = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=stylesheet)

server = app.server

fig01 = px.bar(df, x="Name", y="Age")
fig02 = px.bar(df, x="Name", y="HeightNum")
fig03 = px.bar(df, x="Name", y="WeightNum")
fig04 = px.bar(df, x="Name", y="SalaryNum")
fig11 = px.bar(df, x="Name", y="PTS")
fig12 = px.bar(df, x="Name", y="TO")
fig13 = px.bar(df, x="Name", y="PF")
fig14 = px.bar(df, x="Name", y="STL")
fig15 = px.bar(df, x="Name", y="BLK")
fig16 = px.bar(df, x="Name", y="AST")
fig17 = px.bar(df, x="Name", y="REB")
fig18 = px.bar(df, x="Name", y="FT%")
fig19 = px.bar(df, x="Name", y="3P%")
fig20 = px.bar(df, x="Name", y="FG%")

markdown_text = "Want to discover some interesting facts about your favorite NBA teams? You've come to the right place!"
markdown_text1 = "Below are some graphs that show the information and perfomance for players on each team. \n Update the graphs by selecting different teams."
markdown_text2 = "Click on the stat that you're interested in."

app.layout = html.Div([
    # Create a header and style it

    html.H1('Explore your favorite NBA Teams!', style={'textAlign': 'center'}, id="top"),
    dcc.Markdown(children=markdown_text),
    html.Div([html.H4("Choose your favorite teams: "),
              dcc.Dropdown(options=[{'label': 'Atlanta Hawks', 'value': 'Atlanta Hawks'},
                                    {'label': 'Boston Celtics', 'value': 'Boston Celtics'},
                                    {'label': 'Brooklyn Nets', 'value': 'Brooklyn Nets' },
                                    {'label': 'Charlotte Hornets', 'value': 'Charlotte Hornets'},
                                    {'label': 'Chicago Bulls', 'value': 'Chicago Bulls'},
                                    {'label': 'Cleveland Cavaliers', 'value': 'Cleveland Cavaliers'},
                                    {'label': 'Dallas Mavericks', 'value': 'Dallas Mavericks'},
                                    {'label': 'Denver Nuggets', 'value': 'Denver Nuggets'},
                                    {'label': 'Detroit Pistons', 'value': 'Detroit Pistons'},
                                    {'label': 'Golden State Warriors', 'value': 'Golden State Warriors'},
                                    {'label': 'Houston Rockets', 'value': 'Houston Rockets'},
                                    {'label': 'Indiana Pacers', 'value': 'Indiana Pacers'},
                                    {'label': 'Los Angeles Clippers', 'value': 'Los Angeles Clippers'},
                                    {'label': 'Los Angeles Lakers', 'value': 'Los Angeles Lakers'},
                                    {'label': 'Memphis Grizzlies', 'value': 'Memphis Grizzlies'},
                                    {'label': 'Miami Heat', 'value': 'Miami Heat'},
                                    {'label': 'Milwaukee Bucks', 'value': 'Milwaukee Bucks'},
                                    {'label': 'Minnesota Timberwolves', 'value': 'Minnesota Timberwolves'},
                                    {'label': 'New Orleans Pelicans', 'value': 'New Orleans Pelicans'},
                                    {'label': 'New York Knicks', 'value': 'New York Knicks'},
                                    {'label': 'Oklahoma City Thunder', 'value': 'Oklahoma City Thunder'},
                                    {'label': 'Orlando Magic', 'value': 'Orlando Magic'},
                                    {'label': 'Philadelphia 76ers', 'value': 'Philadelphia 76ers'},
                                    {'label': 'Phoenix Suns', 'value': 'Phoenix Suns'},
                                    {'label': 'Portland Trail Blazers', 'value': 'Portland Trail Blazers'},
                                    {'label': 'Sacramento Kings', 'value': 'Sacramento Kings'},
                                    {'label': 'San Antonio Spurs', 'value': 'San Antonio Spurs'},
                                    {'label': 'Toronto Raptors', 'value': 'Toronto Raptors'},
                                    {'label': 'Utah Jazz', 'value': 'Utah Jazz'},
                                    {'label': 'Washington Wizards', 'value': 'Washington Wizards'}],
                           id='my-dropdown',
                           multi = True,
                           style={'width': '300px'},
                           placeholder="Select a team"),
            html.H2('Player Stats', style={'textAlign': 'center'}),
            dt.DataTable(id='my_table',
                         columns=[{"name": i, "id": i} for i in df2.columns.values],
                         style_cell={'textAlign': 'left', 'border': '1px solid grey'},
                         sort_action='native',
                         style_table={'overflowY': 'auto'},
                         style_header={'backgroundColor': 'white','fontWeight': 'bold'},
                         data=df2.to_dict("rows")),
            html.Br(),

            html.H2('Team Stats Visualization', style={'textAlign': 'center'}),
            dcc.Markdown(children=markdown_text1),
            dcc.Markdown(children=markdown_text2),
            html.A("Personal Information", href = "#personal-info"),
            html.Br(),
            html.A("Age", href="#Age-graph"),
            html.Br(),
            html.A("Height", href="#Height-graph"),
            html.Br(),
            html.A("Weight", href="#Weight-graph"),
            html.Br(),
            html.A("Salary", href="#Salary-graph"),
            html.Br(),
            html.Br(),
            html.A("Performance", href = "#performance"),
            html.Br(),
            html.A("Points", href="#PTS-graph"),
            html.Br(),
            html.A("Turnover", href="#TO-graph"),
            html.Br(),
            html.A("Fouls", href="#PF-graph"),
            html.Br(),
            html.A("Steals", href="#STL-graph"),
            html.Br(),
            html.A("Blocks", href="#BLK-graph"),
            html.Br(),
            html.A("Assists", href="#AST-graph"),
            html.Br(),
            html.A("Rebounds", href="#REB-graph"),
            html.Br(),
            html.A("Free Throw %", href="#FT%-graph"),
            html.Br(),
            html.A("Three-pointers %", href="#3P%-graph"),
            html.Br(),
            html.A("Field Goals %", href="#FG%-graph"),
            html.Br(),

            html.H3('Personal Information', style={'textAlign': 'center'}, id="personal-info"),
            dcc.Graph(id='Age-graph', figure=fig01),
            dcc.Graph(id='Height-graph', figure=fig02),
            dcc.Graph(id='Weight-graph', figure=fig03),
            dcc.Graph(id='Salary-graph', figure=fig04),
            html.H3('Performance', style={'textAlign': 'center'}, id="performance"),
            dcc.Graph(id='PTS-graph', figure=fig11),
            dcc.Graph(id='TO-graph', figure=fig12),
            dcc.Graph(id='PF-graph', figure=fig13),
            dcc.Graph(id='STL-graph', figure=fig14),
            dcc.Graph(id='BLK-graph', figure=fig15),
            dcc.Graph(id='AST-graph', figure=fig16),
            dcc.Graph(id='REB-graph', figure=fig17),
            dcc.Graph(id='FT%-graph', figure=fig18),
            dcc.Graph(id='3P%-graph', figure=fig19),
            dcc.Graph(id='FG%-graph', figure=fig20),
            html.A('Data Source:'),
            html.A("https://www.espn.com/nba/", href="https://www.espn.com/nba/"),
            html.Br(),
            html.A("Back to top", href="#top")
    ])
])

@app.callback(
    Output(component_id='my_table', component_property='data'),
    #Output(component_id='my-graph', component_property='figure'),
    [Input(component_id='my-dropdown', component_property='value')]

)

def display_table(value):
    if value is not None:
        if type(value) == "str":
            dff = df2[df2['Team']==value]
        else:
            dff = df2[df2['Team'].isin(value)]
        dff = dff.sort_values(by = "Name")
    else:
        dff = df2
    return dff.to_dict('records')

@app.callback(
    Output(component_id='Age-graph', component_property='figure'),
    Output(component_id='Height-graph', component_property='figure'),
    Output(component_id='Weight-graph', component_property='figure'),
    Output(component_id='Salary-graph', component_property='figure'),
    Output(component_id='PTS-graph', component_property='figure'),
    Output(component_id='TO-graph', component_property='figure'),
    Output(component_id='PF-graph', component_property='figure'),
    Output(component_id='STL-graph', component_property='figure'),
    Output(component_id='BLK-graph', component_property='figure'),
    Output(component_id='AST-graph', component_property='figure'),
    Output(component_id='REB-graph', component_property='figure'),
    Output(component_id='FT%-graph', component_property='figure'),
    Output(component_id='3P%-graph', component_property='figure'),
    Output(component_id='FG%-graph', component_property='figure'),
    [Input(component_id='my-dropdown', component_property='value')]

)

def display_graph(value):
    if value is not None:
        if type(value) == "str":
            df_team = df[df.Team == value]
        else:
            df_team = df[df.Team.isin(value)]
    else:
        df_team = df
    df_team = df_team.sort_values(by = "Name")
    fig01 = px.bar(df_team, x="Name", y="Age", title="Age", color = "Team", text = "Age",
                   labels={"Name": "Player Name"})
    fig02 = px.bar(df_team, x="Name", y="HeightNum", title = "Height ", color = "Team",
                   labels={"Name": "Player Name", "HeightNum": "Height (inches) "}, text = "HeightNum")
    fig03 = px.bar(df_team, x="Name", y="WeightNum", title = "Weight ", color = "Team",
                   labels={"Name": "Player Name", "WeightNum": "Weight (lbs)"}, text = "WeightNum")
    fig04 = px.bar(df_team, x="Name", y="SalaryNum", title = "Salary", color = "Team",
                   labels={"Name": "Player Name", "SalaryNum": "Salary"}, text = "SalaryNum")
    fig11 = px.bar(df_team, x="Name", y="PTS", title = "Average Points per Game", color = "Team",
                   labels={"Name": "Player Name", "PTS": "PTS (per game)"}, text = "PTS")
    fig12 = px.bar(df_team, x="Name", y="TO", title = "Average Turnover per Game", color = "Team",
                   labels={"Name": "Player Name", "TO": "TO (per game)"}, text = "TO")
    fig13 = px.bar(df_team, x="Name", y="PF", title = "Average Fouls per Game", color = "Team",
                   labels={"Name": "Player Name", "PF": "PF (per game)"}, text = "PF")
    fig14 = px.bar(df_team, x="Name", y="STL", title = "Average Steals per Game", color = "Team",
                   labels={"Name": "Player Name", "STL": "STL (per game)"}, text = "STL")
    fig15 = px.bar(df_team, x="Name", y="BLK", title = "Average Blocks per Game", color = "Team",
                   labels={"Name": "Player Name", "BLK": "BLK (per game)"}, text = "BLK")
    fig16 = px.bar(df_team, x="Name", y="AST", title = "Average Assists per Game", color = "Team",
                   labels={"Name": "Player Name", "AST": "AST (per game)"}, text = "AST")
    fig17 = px.bar(df_team, x="Name", y="REB", title = "Average Rebounds per Game", color = "Team",
                   labels={"Name": "Player Name", "REB": "REB (per game)"}, text = "PF")
    fig18 = px.bar(df_team, x="Name", y="FT%", title = "Free Throw Percentage", color = "Team",
                   labels={"Name": "Player Name"} , text = "FT%")
    fig19 = px.bar(df_team, x="Name", y="3P%", title = "3-Point Field Goal Percentage", color = "Team",
                   labels={"Name": "Player Name"} , text = "3P%")
    fig20 = px.bar(df_team, x="Name", y="FG%", title = "Field Goal Percentage", color = "Team",
                   labels={"Name": "Player Name"} , text = "FG%")

    fig01.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig02.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig03.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig04.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig11.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig12.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig13.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig14.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig15.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig16.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig17.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig18.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig19.update_traces(texttemplate='%{text:.2s}', textposition='outside')
    fig20.update_traces(texttemplate='%{text:.2s}', textposition='outside')

    fig01.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
    fig02.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
    fig03.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
    fig04.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
    fig11.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
    fig01.update_layout(height=600)
    fig02.update_layout(height=600)
    fig03.update_layout(height=600)
    fig04.update_layout(height=600)
    fig11.update_layout(height=600)
    fig12.update_layout(height=600)
    fig13.update_layout(height=600)
    fig14.update_layout(height=600)
    fig15.update_layout(height=600)
    fig16.update_layout(height=600)
    fig17.update_layout(height=600)
    fig18.update_layout(height=600)
    fig19.update_layout(height=600)
    fig20.update_layout(height=600)

    return fig01, fig02, fig03, fig04, fig11, fig12, fig13, fig14, fig15, fig16, fig17, fig18, fig19, fig20

if __name__ == '__main__':
    app.run_server(debug=True)


import cStringIO as StringIO

import cgi, time, urlparse
from urllib import unquote

from zope.interface import implements
# Twisted Imports
from twisted.internet import defer
from twisted.python import log, failure

# Sibling Imports
from twisted.web2 import http, iweb, fileupload, responsecode
from twisted.web2 import http_headers, context
from twisted.web2.filter.range import rangefilter
from twisted.web2 import error

from twisted.web2 import version as web2_version
from twisted import __version__ as twisted_version

VERSION = "Twisted/%s TwistedWeb/%s" % (twisted_version, web2_version)
_errorMarker = object()

def defaultHeadersFilter(request, response, ctx):
    if not response.headers.hasHeader('server'):
        response.headers.setHeader('server', VERSION)
    if not response.headers.hasHeader('date'):
        response.headers.setHeader('date', time.time())
    return response
defaultHeadersFilter.handleErrors = True

def preconditionfilter(request, response, ctx):
    newresponse = http.checkPreconditions(request, response)
    if newresponse is not None:
        return newresponse
    return response

def doTrace(request):
    request = iweb.IRequest(request)
    txt = "%s %s HTTP/%d.%d\r\n" % (request.method, request.uri,
                                    request.clientproto[0], request.clientproto[1])

    l=[]
    for name, valuelist in request.headers.getAllRawHeaders():
        for value in valuelist:
            l.append("%s: %s\r\n" % (name, value))
    txt += ''.join(l)

    return http.Response(
        responsecode.OK,
        {'content-type': http_headers.MimeType('message', 'http')},
        txt)

def parsePOSTData(request):
    if request.stream.length == 0:
        return defer.succeed(None)

    parser = None
    ctype = request.headers.getHeader('content-type')

    if ctype is None:
        return defer.succeed(None)

    def updateArgs(data):
        args = data
        request.args.update(args)

    def updateArgsAndFiles(data):
        args, files = data
        request.args.update(args)
        request.files.update(files)

    def error(f):
        f.trap(fileupload.MimeFormatError)
        raise http.HTTPError(responsecode.BAD_REQUEST)

    if ctype.mediaType == 'application' and ctype.mediaSubtype == 'x-www-form-urlencoded':
        d = fileupload.parse_urlencoded(request.stream)
        d.addCallbacks(updateArgs, error)
        return d
    elif ctype.mediaType == 'multipart' and ctype.mediaSubtype == 'form-data':
        boundary = ctype.params.get('boundary')
        if boundary is None:
            return failure.Failure(fileupload.MimeFormatError("Boundary not specified in Content-Type."))
        d = fileupload.parseMultipartFormData(request.stream, boundary)
        d.addCallbacks(updateArgsAndFiles, error)
        return d
    else:
        raise http.HTTPError(responsecode.BAD_REQUEST)

class StopTraversal(object):
    """
    Indicates to Request._handleSegment that it should stop handling
    path segments.
    """
    pass

class Request(http.Request):
    """
    vars:
    site

    scheme
    host
    port
    path
    params
    querystring

    args
    files

    prepath
    postpath

    @ivar path: The path only (arguments not included).
    @ivar args: All of the arguments, including URL and POST arguments.
    @type args: A mapping of strings (the argument names) to lists of values.
                i.e., ?foo=bar&foo=baz&quux=spam results in
                {'foo': ['bar', 'baz'], 'quux': ['spam']}.
    """
    implements(iweb.IRequest)

    site = None
    _initialprepath = None
    responseFilters = [rangefilter, preconditionfilter,
                       error.defaultErrorHandler, defaultHeadersFilter]

    def __init__(self, *args, **kw):
        if kw.has_key('site'):
            self.site = kw['site']
            del kw['site']
        if kw.has_key('prepathuri'):
            self._initialprepath = kw['prepathuri']
            del kw['prepathuri']

        # Copy response filters from the class
        self.responseFilters = self.responseFilters[:]
        self.files = {}
        self.resources = []
        http.Request.__init__(self, *args, **kw)

    def addResponseFilter(self, f, atEnd=False):
        if atEnd:
            self.responseFilters.append(f)
        else:
            self.responseFilters.insert(0, f)

    def unparseURL(self, scheme=None, host=None, port=None,
                   path=None, params=None, querystring=None, fragment=None):
        """Turn the request path into a url string. For any pieces of
        the url that are not specified, use the value from the
        request. The arguments have the same meaning as the same named
        attributes of Request."""

        if scheme is None: scheme = self.scheme
        if host is None: host = self.host
        if port is None: port = self.port
        if path is None: path = self.path
        if params is None: params = self.params
        if querystring is None: query = self.querystring
        if fragment is None: fragment = ''

        if port == http.defaultPortForScheme.get(scheme, 0):
            hostport = host
        else:
            hostport = host + ':' + str(port)

        return urlparse.urlunparse((
            scheme, hostport, path,
            params, querystring, fragment))

    def _parseURL(self):
        if self.uri[0] == '/':
            # Can't use urlparse for request_uri because urlparse
            # wants to be given an absolute or relative URI, not just
            # an abs_path, and thus gets '//foo' wrong.
            self.scheme = self.host = self.path = self.params = self.querystring = ''
            if '?' in self.uri:
                self.path, self.querystring = self.uri.split('?', 1)
            else:
                self.path = self.uri
            if ';' in self.path:
                self.path, self.params = self.path.split(';', 1)
        else:
            # It is an absolute uri, use standard urlparse
            (self.scheme, self.host, self.path,
             self.params, self.querystring, fragment) = urlparse.urlparse(self.uri)

        if self.querystring:
            self.args = cgi.parse_qs(self.querystring, True)
        else:
            self.args = {}

        path = map(unquote, self.path[1:].split('/'))
        if self._initialprepath:
            # We were given an initial prepath -- this is for supporting
            # CGI-ish applications where part of the path has already
            # been processed
            prepath = map(unquote, self._initialprepath[1:].split('/'))

            if path[:len(prepath)] == prepath:
                self.prepath = prepath
                self.postpath = path[len(prepath):]
            else:
                self.prepath = []
                self.postpath = path
        else:
            self.prepath = []
            self.postpath = path
        #print "_parseURL", self.uri, (self.uri, self.scheme, self.host, self.path, self.params, self.querystring)

    def _fixupURLParts(self):
        hostaddr, secure = self.chanRequest.getHostInfo()
        if not self.scheme:
            self.scheme = ('http', 'https')[secure]

        if self.host:
            self.host, self.port = http.splitHostPort(self.scheme, self.host)
        else:
            # If GET line wasn't an absolute URL
            host = self.headers.getHeader('host')
            if host:
                self.host, self.port = http.splitHostPort(self.scheme, host)
            else:
                # When no hostname specified anywhere, either raise an
                # error, or use the interface hostname, depending on
                # protocol version
                if self.clientproto >= (1,1):
                    raise http.HTTPError(responsecode.BAD_REQUEST)
                self.host = hostaddr.host
                self.port = hostaddr.port

    def process(self):
        "Process a request."
        self._requestContext = context.RequestContext(tag=self, parent=self.site.context)

        try:
            self.checkExpect()
            resp = self.preprocessRequest()
            if resp is not None:
                self._cbFinishRender(resp).addErrback(self._processingFailed)
                return
            self._parseURL()
            self._fixupURLParts()
        except:
            failedDeferred = self._processingFailed(failure.Failure())
            return

        d = self._getChild(self.site.resource, self.postpath)
        d.addCallback(lambda res, ctx: res.renderHTTP(ctx), self._requestContext)
        d.addCallback(self._cbFinishRender)
        d.addErrback(self._processingFailed)

    def preprocessRequest(self):
        """Do any request processing that doesn't follow the normal
        resource lookup procedure. "OPTIONS *" is handled here, for
        example. This would also be the place to do any CONNECT
        processing."""

        if self.method == "OPTIONS" and self.uri == "*":
            response = http.Response(responsecode.OK)
            response.headers.setHeader('allow', ('GET', 'HEAD', 'OPTIONS', 'TRACE'))
            return response
        # This is where CONNECT would go if we wanted it
        return None

    def _getChild(self, res, path):
        """Create a PageContext for res, call res.locateChild, and pass the
        result on to _handleSegment."""

        self.resources.append(res)

        if not path:
            return defer.succeed(res)

        return defer.maybeDeferred(
            res.locateChild, self._requestContext, path
        ).addCallback(
            self._handleSegment, res, path
        )

    def _handleSegment(self, result, res, path):
        """Handle the result of a locateChild call done in _getChild."""
        newres, newpath = result
        # If the child resource is None then display a error page
        if newres is None:
            raise http.HTTPError(responsecode.NOT_FOUND)

        # If we got a deferred then we need to call back later, once the
        # child is actually available.
        if isinstance(newres, defer.Deferred):
            return newres.addCallback(
                lambda actualRes: self._handleSegment(
                    (actualRes, newpath), res, path))

        if newpath is StopTraversal:
            # We need to rethink how to do this.
            #if newres is res:
                return res
            #else:
            #    raise ValueError("locateChild must not return StopTraversal with a resource other than self.")

        newres = iweb.IResource(newres)
        if newres is res:
            assert not newpath is path, "URL traversal cycle detected when attempting to locateChild %r from resource %r." % (path, res)
            assert len(newpath) < len(path), "Infinite loop impending..."

        # We found a Resource... update the request.prepath and postpath
        for x in xrange(len(path) - len(newpath)):
            self.prepath.append(self.postpath.pop(0))

        return self._getChild(newres, newpath)

    def _processingFailed(self, reason):
        if reason.check(http.HTTPError) is not None:
            # If the exception was an HTTPError, leave it alone
            d = defer.succeed(reason.value.response)
        else:
            # Otherwise, it was a random exception, so give a
            # ICanHandleException implementer a chance to render the page.
            def _processingFailed_inner(reason):
                handler = iweb.ICanHandleException(self._requestContext, default=self)
                return handler.renderHTTP_exception(self._requestContext, reason)
            d = defer.maybeDeferred(_processingFailed_inner, reason)

        d.addCallback(self._cbFinishRender)
        d.addErrback(self._processingReallyFailed, reason)
        return d

    def _processingReallyFailed(self, reason, origReason):
        log.msg("Exception rendering error page:", isErr=1)
        log.err(reason)
        log.msg("Original exception:", isErr=1)
        log.err(origReason)

        body = ("<title>Internal Server Error</title>"
                "
Internal Server Error
An error occurred rendering the requested page. Additionally, an error occured rendering the error page.")

        response = http.Response(
            responsecode.INTERNAL_SERVER_ERROR,
            {'content-type': http_headers.MimeType('text','html'),
             'content-length': len(body)},
            body)
        self.writeResponse(response)

    def _cbFinishRender(self, result):
        def filterit(response, f):
            if (hasattr(f, 'handleErrors') or
                (response.code >= 200 and response.code < 300 and response.code != 204)):
                return f(self, response, self._requestContext)
            else:
                return response

        response = iweb.IResponse(result, None)
        if response:
            d = defer.Deferred()
            for f in self.responseFilters:
                d.addCallback(filterit, f)
            d.addCallback(self.writeResponse)
            d.callback(response)
            return d

        resource = iweb.IResource(result, None)
        if resource:
            self.resources.append(resource)
            d = defer.maybeDeferred(resource.renderHTTP, self._requestContext)
            d.addCallback(self._cbFinishRender)
            return d

        raise TypeError("html is not a resource or a response")

    def renderHTTP_exception(self, ctx, reason):
        log.msg("Exception rendering:", isErr=1)
        log.err(reason)

        body = ("<title>Internal Server Error</title>"
                "
Internal Server Error
An error occurred rendering the requested page. More information is available in the server log.")

        return http.Response(
            responsecode.INTERNAL_SERVER_ERROR,
            {'content-type': http_headers.MimeType('text','html'),
             'content-length': len(body)},
            body)

class Site:
    def __init__(self, resource):
        """Initialize.
        """
        self.context = context.SiteContext()
        self.resource = iweb.IResource(resource)

    def __call__(self, *args, **kwargs):
        return Request(site=self, *args, **kwargs)

    def remember(self, obj, inter=None):
        """Remember the given object for the given interfaces (or all interfaces
        obj implements) in the site's context.

        The site context is the parent of all other contexts. Anything
        remembered here will be available throughout the site.
        """
        self.context.remember(obj, inter)

__all__ = ['Request', 'Site', 'StopTraversal', 'VERSION', 'defaultHeadersFilter', 'doTrace', 'parsePOSTData', 'preconditionfilter']


from rest_framework.test import APITestCase
from rest_framework import status
from django.urls import reverse
from .factories import *

# I wrote this code
# Test cases for Post API
class PostViewTestCase(APITestCase):
    def setUp(self):
        # Create test users
        self.user1 = UserFactory()
        self.user2 = UserFactory()

        # Create test data, such as posts, comments, and likes
        self.post = Post.objects.create(user=self.user1, title='Test Post', content='This is a test post')
        self.comment = Comment.objects.create(user=self.user1, post=self.post, content='Test Comment')
        self.like = Like.objects.create(user=self.user1, post=self.post)

    def test_view_post(self):
        url = reverse('api-post', args=[self.post.id])
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['title'], self.post.title)
        self.assertEqual(response.data['content'], self.post.content)

    def test_list_post_comments(self):
        url = reverse('api-post-comments', args=[self.post.id])
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)
        self.assertEqual(response.data[0]['content'], self.comment.content)
        self.assertEqual(response.data[0]['user'], self.comment.user.id)

    def test_like_post(self):
        url = reverse('api-like-post', args=[self.post.id])
        data = {'user': self.user1.id, 'post': self.post.id}
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

# I wrote this code


from setuptools import setup, find_packages
import os

requirements = [
    'colorama',
]

init_fn = os.path.join(os.path.dirname(__file__), 'pjprobe', '__init__.py')
with open(init_fn) as f:
    for l in f.readlines():
        if '__version__' in l:
            exec(l)
            break

setup(
    name='pjprobe',
    version=__version__,
    install_requires=requirements,
    python_requires='>=3.7',
    packages=find_packages(),
    author="DelinQu",
    author_email="delinqu.cs@gmail.com",
    entry_points={
        'console_scripts': [
            'pjprobe = pjprobe.pjprobe:main',
        ]
    },
)


#!/usr/bin/python

# Plot the number of transcripts against expression value, use counts matrix as input

import os
import getopt
import sys
import shlex
import numpy as np
from subprocess import call, Popen, PIPE
import matplotlib.pyplot as plt

def usage():
	print("Usage:")
	print("	python plot_transcripts_filtering.py -i [isoforms.matrix] -r [start,stop,step] -o [outDir]\n")
	print("Input:")
	print("	-i / --matrix file containing the counts matrix (isoforms or genes)")
	print("	-r / --range for filtering range (format: start,stop,step) (default:0,6,0.5)")
	print("output:")
	print("	-o / --outputDir for output directory (default: current directory)")
	print("	-n / --noplot to skip the plot generation")
	print("")
	print("-h / --help for help")
	print("-v / --verbose to activate verbose mode")

# Default values
outDir = "./"
matrix = None
start = 0
stop = 6
step = 0.5
verbose = False
noplot = False

################################## GET OPTS ##################################################
try:
    opts, args = getopt.getopt(sys.argv[1:], "hi:r:o:vn", ["help", "matrix=", "range=", "outputDir=", "verbose", "noplot"])
except getopt.GetoptError as err:
	# will print something like "option -a not recognized"
    print(str(err))
	# print help information and exit:
    usage()
    sys.exit(2)

for o, a in opts:
	if o in ("-i", "--matrix"):
		matrix = a
	elif o in ("-r", "--range"):
		start,stop,step = a.split(",")
		start = float(start)
		stop = float(stop)
		step = float(step)
	elif o in ("-o", "--outputDir"):
		outDir = a
	elif o in ("-h", "--help"):
		usage()
		sys.exit()
	elif o in ("-v", "--verbose"):
		verbose = True
	elif o in ("-n", "--noplot"):
		noplot = True
	else:
		assert False, "unhandled option"

# Check Input
if(matrix == None):
	print("Please provide a count matrix as input (option -i / --matrix)\n")
	usage()
	sys.exit()

if(outDir == None):
	print("Please provide output directory (option -o / --outputDir)\n")
	usage()
	sys.exit()

if not(isinstance(start,(int, float))):
	print("Check your range, 'start' is not an int or float !\n")
	sys.exit()

if not(isinstance(stop, (int, float))):
	print("Check your range, 'stop' is not an int or float !\n")
	sys.exit()

if not(isinstance(step, (int, float))):
	print("Check your range, 'step' is not an int or float !\n")
	sys.exit()

if not(os.path.isdir(outDir)):
	print(str(outDir)+" is not a directory !\n")
	sys.exit()

if not(os.path.exists(matrix)):
	print(str(matrix)+" does not exists !\n")
	sys.exit()

################################## PLOT ########################################################
thresholds = list()
nbIsoforms = list()

# We need to create the plot now to add the text as we go along the filtering in the loop below
if(noplot == False):
	plt.figure(figsize=(20,10))

if(verbose == True):
	print(matrix)

#For each TPM thresholds in 'range'
for tpmThreshold in np.arange(start, stop+step, step):
	if(verbose == True):
		print("Current Threshold: " + str(tpmThreshold))

	# First, remove header line from the matrix
	cmd1 = "tail -n +2 " + str(matrix)
	p1 = Popen(shlex.split(cmd1), shell=False, stdout=PIPE)

	# Then keep the line only if max_expressed(Transcript) > current_threshold
	cmd2 = "awk \'{max=$2; for(i=2;i<=NF;i++) if($i>max) max=$i; if(max >= " + str(tpmThreshold) + ") {print max};}\'"
	p2 = Popen(shlex.split(cmd2), shell=False, stdin=p1.stdout, stdout=PIPE)

	# Finally get the number of transcript for the result
	cmd3 = "wc -l"
	result = Popen(shlex.split(cmd3), shell=False, stdin=p2.stdout, stdout=PIPE).communicate()[0]
	# Popen is outputing bytes, so we use "decode()" to change it to string
	result = result.decode()

	# 'thresholds' and 'nbIsoforms' works in parallel: thresholds[i] corresponds to nbIsoforms[i]
	thresholds.append(tpmThreshold)
	nbIsoforms.append(result)

	#Plot coordinates in the plot next to the dots
	strResult = str(result).replace("\n", "")

	if(noplot == False):
		plt.text(tpmThreshold, result, "("+strResult+")")

	if(verbose == True):
		print("Number of transcripts: " + strResult + "\n")

# Saving output as txt file
textOutputFile = outDir + "/Nb_transcripts_"+ os.path.basename(matrix)+".txt"

if(verbose == True):
		print("Saving txt output in:" + textOutputFile + "\n")

index = 0
with open(textOutputFile, "w") as outTxtFile:
	outTxtFile.write("Threshold\tNumber_Isoforms_Left\n")
	while index < len(thresholds):
		outTxtFile.write(str(thresholds[index])+"\t"+str(nbIsoforms[index]))
		index = index + 1

# If noplot NOT activated, we plot the figure
if(noplot == False):
	# Print the plot using the lists created in the previous for loop
	plt.scatter(thresholds, nbIsoforms, color='dodgerblue', s=40)
	plt.xlabel('Expression level')
	plt.ylabel('Number of isoforms > expression')
	plt.xlim(start, stop+1)
	plt.title(os.path.basename(matrix))

	# Saving graph
	graphFile = outDir + "/Nb_transcripts_"+ os.path.basename(matrix)+".png"
	if(verbose == True):
		print("Saving graph :" + graphFile + "\n")
	plt.savefig(graphFile, bbox_inches='tight')


# file:         request_validation.py
# description:  Utility functions to verify required API request parameters

from flask import request

def required_query_params(request, parameters):
  """Validate that a set of query parameters are present in a request"""
  for expected_param in parameters:
    received_param = request.args.get(expected_param)
    if received_param is None:
      message = { 'message': 'required query parameter \'{0}\' is missing'.format(expected_param) }
      status_code = 400 # 400 status = bad request, missing parameter
      return message, status_code


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('sap_success_factors', '0015_auto_20180510_1259'),
    ]

    operations = [
        migrations.AddField(
            model_name='sapsuccessfactorsenterprisecustomerconfiguration',
            name='additional_locales',
            field=models.TextField(default='', help_text='A comma-separated list of additional locales.', verbose_name='Additional Locales', blank=True),
        ),
    ]


import functools
import logging

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
from torch.cuda.amp import autocast, GradScaler

from codebase.torchutils.distributed import world_size
from codebase.torchutils.metrics import AccuracyMetric, AverageMetric, EstimatedTimeArrival
from codebase.torchutils.common import GradientAccumulator
from codebase.torchutils.common import ThroughputTester, time_enumerate

_logger = logging.getLogger(__name__)

scaler = None

def _run_one_epoch(is_training: bool,
                   epoch: int,
                   model: nn.Module,
                   loader: data.DataLoader,
                   criterion: nn.modules.loss._Loss,
                   optimizer: optim.Optimizer,
                   scheduler: optim.lr_scheduler._LRScheduler,
                   use_amp: bool,
                   accmulated_steps: int,
                   device: str,
                   memory_format: str,
                   log_interval: int):
    phase = "train" if is_training else "eval"
    model.train(mode=is_training)

    global scaler
    if scaler is None:
        scaler = GradScaler(enabled=use_amp and is_training)

    gradident_accumulator = GradientAccumulator(steps=accmulated_steps, enabled=is_training)

    time_cost_metric = AverageMetric("time_cost")
    loss_metric = AverageMetric("loss")
    accuracy_metric = AccuracyMetric(topk=(1, 5))
    eta = EstimatedTimeArrival(len(loader))
    speed_tester = ThroughputTester()

    if is_training and scheduler is not None:
        scheduler.step(epoch)

    lr = optimizer.param_groups[0]['lr']
    _logger.info(f"{phase.upper()} start, epoch={epoch:04d}, lr={lr:.6f}")

    for time_cost, iter_, (inputs, targets) in time_enumerate(loader, start=1):
        inputs = inputs.to(device=device, non_blocking=True, memory_format=memory_format)
        targets = targets.to(device=device, non_blocking=True)

        with torch.set_grad_enabled(mode=is_training):
            with autocast(enabled=use_amp and is_training):
                outputs = model(inputs)
                loss: torch.Tensor = criterion(outputs, targets)

        gradident_accumulator.backward_step(model, loss, optimizer, scaler)

        time_cost_metric.update(time_cost)
        loss_metric.update(loss)
        accuracy_metric.update(outputs, targets)
        eta.step()
        speed_tester.update(inputs)

        if iter_ % log_interval == 0 or iter_ == len(loader):
            _logger.info(", ".join([
                phase.upper(),
                f"epoch={epoch:04d}",
                f"iter={iter_:05d}/{len(loader):05d}",
                f"fetch data time cost={time_cost_metric.compute()*1000:.2f}ms",
                f"fps={speed_tester.compute()*world_size():.0f} images/s",
                f"{loss_metric}",
                f"{accuracy_metric}",
                f"{eta}",
            ]))
            time_cost_metric.reset()
            speed_tester.reset()

    _logger.info(", ".join([
        phase.upper(),
        f"epoch={epoch:04d} {phase} complete",
        f"{loss_metric}",
        f"{accuracy_metric}",
    ]))

    return {
        f"{phase}/lr": lr,
        f"{phase}/loss": loss_metric.compute(),
        f"{phase}/top1_acc": accuracy_metric.at(1).rate,
        f"{phase}/top5_acc": accuracy_metric.at(5).rate,
    }

train_one_epoch = functools.partial(_run_one_epoch, is_training=True)
evaluate_one_epoch = functools.partial(_run_one_epoch, is_training=False)


from sklearn import mixture

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from sklearn.preprocessing import StandardScaler
import time
from collections import Counter
import copy

import matplotlib_utils as mu
import pandas_utils as pu
import dimensionality_reduction_utils as dr

from os import sys
sys.path.append("/notebooks/Neurosignal_Final/PRML/")
sys.path.append("/neuron_mesh_tools/Neurosignal_Final/PRML/")
#from prml.rv import VariationalGaussianMixture

# =------------- Functions to Help with Plotting -------------- #

def plot_BIC_and_Likelihood(gmm_data,
                       fig_width=12,
                       fig_height=5,
                           title_suffix = ""):
    """
    Pupose

    """
    cluster_values = list(gmm_data.keys())
    cluster_labels = "Number of Clusters"

    fig1,_ = plt.subplots(1,2)

    fig1 = mu.plot_graph(
        title = "Average Log Likelihood Of Data vs. Number of Clusters\n" + title_suffix,
        y_values = [gmm_data[K]["log_likelihood"] for K in cluster_values],
        x_values = cluster_values,
        x_axis_label = cluster_labels,
        y_axis_label = "Average Log Likelihood of Data (Per Sample)",
        figure = fig1,
        ax_index = 0,
    )

    fig1 = mu.plot_graph(
        title = "BIC vs. Number of Clusters\n" + title_suffix,
        y_values = [gmm_data[K]["bic_value"] for K in cluster_values],
        x_values = cluster_values,
        x_axis_label = cluster_labels,
        y_axis_label = "BIC (Bayesian Information Criterion)",
        figure = fig1,
        ax_index = 1
    )

    fig1.set_tight_layout(True)
    fig1.set_size_inches(fig_width, fig_height)
    return fig1

# ----------------- Functions for analysis ------------------- #
def gmm_analysis(X_train,
                possible_K = list(range(2,8)),
                 reg_covar = 0.00001,
                init_params = "kmeans",
                covariance_type = "full",
                 pca_obj = None,
                 scaler_obj = None,
                 column_titles = None,
                 model_type="mixture", #other type is "variational"
                 verbose=True
                ):

    """
    Purpose: Will perform gmm analysis for a specified different
    number of clusters and save the models and relevant data for further analysis

    """
    if column_titles is None:
        columns_picked = X_train.columns
    else:
        columns_picked = column_titles

    if type(X_train) == pd.DataFrame:
        X_train = X_train.to_numpy()

    scaled_original_results = dict()

    for K in possible_K:
        if verbose:
            print(f"\n\n------Working on clusters K={K}-----")
        st_time = time.time()
        scaled_original_results[K] = dict()

        reg_covar_local = copy.copy(reg_covar)
        #1) Training the GMM
        while reg_covar_local <= 0.1:
            try:
                if model_type == "mixture":
                    if verbose:
                        print("Using mixture model")
                    gmm = mixture.GaussianMixture(n_components=K,
                                                  covariance_type=covariance_type,
                                                 reg_covar=reg_covar,
                                                 init_params=init_params)
                elif model_type == "variational":
                    if verbose:
                        print("Using variational model")
                    raise Exception("Currently not implemented")
                    #gmm = VariationalGaussianMixture(n_components=K)
                else:
                    print("Not right model")
                    raise Exception(f"The gmm model was not picked as mixture or variational : {model_type}")

                gmm.fit(X_train)

            except Exception as e:
                print(f"Exception occured = {str(e)}")
                print(f"Errored on gmm for reg_cov = {reg_covar_local}")
                reg_covar_local = reg_covar_local*10
            else:
                break

        if reg_covar_local >= 1:
            raise Exception(f"No gmm converged and reg_cov was {reg_covar_local}")

        if model_type == "mixture":
            bic_value = gmm.bic(X_train)
            average_log_likelihood_train = gmm.score(X_train)
            current_means = gmm.means_
        else:
            bic_value = 0
            average_log_likelihood_train = 0
            current_means = gmm.mu

        # Getting the Average Log likelihood:

        scaled_original_results[K]["model"] = gmm
        scaled_original_results[K]["log_likelihood"] = average_log_likelihood_train
        scaled_original_results[K]["bic_value"] = bic_value
        scaled_original_results[K]["reg_covar"] = reg_covar

        if not pca_obj is None:
            if verbose:
                print("reversing the pca transformation")
            current_means = pca_obj.inverse_transform(current_means)

        if not scaler_obj is None:
            if verbose:
                print("reversing the normalizing transformation")
            current_means = scaler_obj.inverse_transform(current_means)

        recovered_means = pd.DataFrame(current_means)
        recovered_means.columns = columns_picked

        scaled_original_results[K]["recovered_means"] = recovered_means

        if verbose:
            if model_type == "mixture":
                print(f"Convergence status = {gmm.converged_}")
            print(f"Total time for GMM = {time.time() - st_time}")

    return scaled_original_results

def gmm_classification(gmm_model,curr_data,
                       classification="hard",
                       verbose=True,
                       return_counts=True,
                      ):
    """
    Purpose: Will use the gaussian model passed to
    classify the data points as to which
    cluster they belong

    """
    if type(gmm_model) == mixture.GaussianMixture:
        probs = gmm_model.predict_proba(curr_data)
    elif type(gmm_model) == VariationalGaussianMixture:
        raise Exception("Currently not implemented")
        #probs = gmm_model.classify_proba(curr_data.to_numpy())
    else:
        raise Exception(f"The gmm model was not a mixture or Variational model: {type(gmm_model)}")

    if classification == "soft":
        count_values = np.sum(probs,axis=0)
    elif classification == "hard":
        gmm_class = np.argmax(probs,axis=1)
        counter_obj = Counter(gmm_class)
        count_values = []
        for clust_idx in range(gmm_model.n_components):
            if clust_idx in counter_obj.keys():
                count_values.append(counter_obj[clust_idx])
            else:
                count_values.append(0)
        count_values = np.array(count_values)
    if verbose:
        sorted_cluster_values = np.flip(np.argsort(count_values))
        print(f"Classification: {dict([(k,np.round(count_values[k],2)) for k in sorted_cluster_values])}")

    return count_values

def category_classifications(model,labeled_data,
                                       return_dataframe=True,
                                       verbose = False,
                                       classification_types = ["hard","soft"]):
    total_hard = []
    total_soft = []

    labeled_data_classification = dict()
    dicts_for_classif_df = []

    for c_type in classification_types:

        if verbose:
            print(f"\nclassification_type={c_type}")
        labeled_data_classification[c_type]=dict()

        for k,v in labeled_data.items():

            if verbose:
                print(f"{k}")

            curr_class = gmm_classification(model,v,classification=c_type,verbose=verbose)
            labeled_data_classification[c_type][k] = curr_class

            classifier_dict = dict()
            classifier_dict["classification"]=c_type
            classifier_dict["category"]=k
            classifier_dict["n_clusters"] = model.n_components
            classif_dict_up = dict([(f"cl_{i}",np.round(bb,1)) for i,bb in enumerate(curr_class)])
            classifier_dict.update(classif_dict_up)

            dicts_for_classif_df.append(classifier_dict)

    if return_dataframe:
        # Print out the classification Numbers in Easy to See Dataframe
        df_class = pd.DataFrame.from_dict(dicts_for_classif_df)
        df_class.style.set_caption(f"Clustering Numbers By Neuroscience Category for K = {model.n_components}")
        df_class = df_class.sort_values(by=['category'])
        #print(df_class.to_markdown())

        return labeled_data_classification,df_class
    else:
        return labeled_data_classification

def clustering_stats(data,clust_perc=0.80):
    """
    Will computer different statistics about the clusters
    formed that will be later shown or plotting

    Metrics: For each category and classification type
    1) highest_cluster identify
    2) highest_cluster_percentage
    3) n clusters needed to encompass clust_perc % of the category
    4) Purity statistic

    """
    # categories = ["Apical","Basal","Axon"]
    # classifications = ["hard","soft"]
    # clust_perc = 0.8

    classifications = list(data.keys())
    categories = list(data[classifications[0]].keys())

    stats_dict_by_classification = dict()

    for curr_classification in classifications:
        stats_dict = dict()

        total_per_cluster_by_category = [data[curr_classification][c] for c in categories]
        total_per_cluster = np.sum(total_per_cluster_by_category,axis=0)
        for curr_category in categories:
            local_stats_dict = dict()

            count_data = data[curr_classification][curr_category]

            """
            Statistics to find:
            1) The cluster with the most of that label and the % in that cluster
            2) The number of clusters needed to comprise 80% of labeled group
            3) The purity measurements

            Pseudocode:
            1) get the total number items put in each cluster across all categories
            2) For each cluster:
            a. Multiply the perc in that cluster * (curent number in that cluster/total number in that cluster)

            """

            sorted_labels = np.flip(np.argsort(count_data))
            highest_cluster_perc = count_data[sorted_labels[0]]/np.sum(count_data)

            local_stats_dict["highest_cluster"]  = sorted_labels[0]
            local_stats_dict["highest_cluster_perc"] = highest_cluster_perc

            sorted_labels_cumsum_perc = np.cumsum(count_data[sorted_labels]/np.sum(count_data))
            perc_per_cluster = count_data/np.sum(count_data)

            n_clusters = np.digitize(clust_perc,sorted_labels_cumsum_perc)+1
            local_stats_dict[f"n_clusters_{np.floor(clust_perc*100)}"] = n_clusters

            #find the purity metric

            purity = np.sum(perc_per_cluster[total_per_cluster != 0]*count_data[total_per_cluster != 0]/total_per_cluster[total_per_cluster != 0])

            local_stats_dict["purity"] = purity

            stats_dict[curr_category] = local_stats_dict

        # measure the purity of each cluster
        max_per_cluster = cluster_purity = np.max(total_per_cluster_by_category,axis=0)
        cluster_purity = [m/t_c if t_c > 0 else 0 for m,t_c in zip(max_per_cluster,total_per_cluster)]

        stats_dict_by_classification[curr_classification] = dict(cluster_purity= cluster_purity,stats_dict=stats_dict)
    return stats_dict_by_classification

def cluster_stats_dataframe(labeled_data_classification):
    """
    Purpose: Just want to visualize the soft and the hard assignment (and show they are not that different)

    Pseudocode:
    1)

    """

    ret_stats = clustering_stats(labeled_data_classification)

    dict_for_df = []

    for cl_type,cl_data in ret_stats.items():
        k = len(cl_data["cluster_purity"])
        curr_stats_dict = cl_data["stats_dict"]

        for cat_name,cat_stats_dict in curr_stats_dict.items():
            cat_local_dict = dict()
            cat_local_dict["category"] = cat_name
            cat_local_dict["classification"] = cl_type
            cat_local_dict["n_clusters"] = k
            cat_local_dict.update(cat_stats_dict)

            dict_for_df.append(cat_local_dict)

    df = pd.DataFrame.from_dict(dict_for_df)
    return df.sort_values(by=['category'])

def plot_advanced_stats_per_k(advanced_stats_per_k,
                             stats_to_plot = ["highest_cluster_perc","purity"],
                              title_suffix="",
                             fig_width = 12,
                              fig_height = 5):
    """
    Purpose: plotting the highest cluster and purity as a function of k

    Pseudocode:
    0) Get all the possible categories, n_clusters
    0) Sort by n_clusters
    1) Iterate through all the stats we want to plot
        2) Iterate through all of the categories
            -- for all n_clusters
            a. Restrict by category and n_clusters and pull down the statistic
            b. Add to list
            --
            c. Save full list in dictionary

        3) Plot the stat using the category dictionary (using the ax index id)

    """

    advanced_stats_df = pd.concat(list(advanced_stats_per_k.values()))

    unique_categories = np.unique(advanced_stats_df["category"].to_numpy())
    unique_n_clusters = np.unique(advanced_stats_df["n_clusters"].to_numpy())
    stats_to_plot = ["highest_cluster_perc","purity"]

    cluster_labels = "Number of Clusters"

    fig, _ = plt.subplots(1,len(stats_to_plot))

    for j,st in enumerate(stats_to_plot):
        st_cat_dict = dict()
        for cat in unique_categories:
            cat_list = []
            for k in unique_n_clusters:
                curr_st = advanced_stats_df.query(f"category=='{cat}' & n_clusters=={k}")[st].to_numpy()
                if len(curr_st) != 1:
                    raise Exception("Stat was not of size 1")
                cat_list.append(curr_st[0])
            st_cat_dict[cat] = cat_list

            fig = mu.plot_graph(
                title = f"{st} vs. Number of Clusters\n" + title_suffix,
                y_values = cat_list,
                x_values = unique_n_clusters,
                x_axis_label = cluster_labels,
                y_axis_label = f"{st}",
                figure = fig,
                ax_index = j,
                label=cat
            )
    fig.set_tight_layout(True)
    fig.set_size_inches(fig_width, fig_height)
    return fig

def gmm_pipeline(df,
                title_suffix,
                labeled_data_indices=None,
                 category_column=None,
                 columns_picked=None,
                 possible_K = list(range(2,8)),
                 print_tables = None, #clusters will print the clustering tables fro
                 apply_normalization=True,
                 apply_pca = True,
                 pca_whiten=True,
                 plot_sqrt_eigvals=True,
                 n_components_pca = None,
                 classification_types = ["hard"],#["hard","soft"]
                 model_type = "mixture",
                 verbose=True,

                ):
    """
    Will carry out all of the clustering analysis and
    advanced stats analysis on a given dataset

    Arguments:
    A data table with all of the labeled data
    """
    # ------- Initializing variables --------- #

    if labeled_data_indices is None:
        category_col = df[category_column].to_numpy()
        unique_labels = np.unique(category_col)
        labeled_data_indices = dict([(k,np.where(category_col==k)[0]) for k in unique_labels])
        df = pu.delete_columns(df,[category_column])

    if print_tables is None:
        print_tables = possible_K

    # -------- Part 0: Preprocessing (Column restriction, Normalization, PCA) ----------- #
    if verbose:
        print(f"# -------- Part 0: Preprocessing (Column restriction, Normalization, PCA) ----------- #")

    if columns_picked is None:
        columns_picked = list(df.columns)
    else:
        if verbose:
            print(f"Restricting to columns : {columns_picked}")
        df = df[columns_picked]

    # Scaling the Data
    if apply_normalization:
        if verbose:
            print(f"Applying Normalization")

        scaler_obj = StandardScaler()
        df_data_scaled = scaler_obj.fit_transform(df)

        #df_data_reversed = scaler.inverse_transform(df_data_scaled,copy=True)

        data_df_normalized = pd.DataFrame(df_data_scaled)
        #add on the columns
        data_df_normalized.columns = df.columns
        df = data_df_normalized
    else:
        scaler_obj = None

    # Applying pca to the data
    if apply_pca:

        if n_components_pca is None:
            n_components_pca=len(columns_picked)

        if verbose:
            print(f"Applying pca with {n_components_pca} components")

        data_analyzed = dr.pca_analysis(df.to_numpy(),
                                    n_components=n_components_pca,
                                    whiten=pca_whiten,
                                    plot_sqrt_eigvals=plot_sqrt_eigvals)

        if verbose:
            print(f'Explained Variance = {data_analyzed["percent_variance_explained_up_to_n_comp"]}')
            dr.plot_variance_explained(data_analyzed)

        df_pca = pd.DataFrame(data_analyzed["data_proj"])
        df_pca.columns = [f"PC_{j}" for j in range(n_components_pca)]
        df = df_pca

        pca_obj = data_analyzed["pca_obj"]

    else:
        pca_obj = None

    # -------- Part 1: GMM clustering with different Number of Clusters ----------- #
    if verbose:
        print(f"# -------- Part 1: GMM clustering with different Number of Clusters ----------- # ")

    X_train = df
    scaled_original_results = gmm.gmm_analysis(X_train,
                    scaler_obj=scaler_obj,
                    pca_obj=pca_obj,
                     possible_K = possible_K,
                    column_titles=columns_picked,
                    model_type = model_type)

    if model_type == "mixture":
        fig1 = gmm.plot_BIC_and_Likelihood(scaled_original_results,title_suffix=title_suffix)
        mu.display_figure(fig1)

    # --------- Part 2: computing the advanced statistics on the clustering ------- #
    if verbose:
        print(f"# --------- Part 2: computing the advanced statistics on the clustering ------- # ")

    advanced_stats_per_k = dict()
    labeled_data = dict([(kk,df.iloc[vv]) for kk,vv in labeled_data_indices.items()])

    for curr_K in scaled_original_results.keys():
        if verbose:
            print(f"\n\n----Working on Advanced Statistics for n_clusters = {curr_K}----\n")

        model = scaled_original_results[curr_K]["model"]

        labeled_data_classification,df_class=gmm.category_classifications(
                                    model,
                                    labeled_data,
                                    classification_types=classification_types)
        if curr_K in print_tables:
            print("Recovered Means From Clustering")
            pu.display(scaled_original_results[curr_K]["recovered_means"])
            print("\n")
            print(f"Clustering Numbers By Neuroscience Category for K = {model.n_components}")
            pu.display_df(df_class)
            print("\n")

        cl_stats_df = gmm.cluster_stats_dataframe(labeled_data_classification)

        if curr_K in print_tables:
            print(f"Clustering Advanced Statistics By Neuroscience Category for K = {curr_K}")
            pu.display_df(cl_stats_df)

        column_restriction = ["category","highest_cluster_perc","purity","n_clusters"]
        cl_stats_restricted = cl_stats_df.query("classification=='hard'")[column_restriction]

        advanced_stats_per_k[curr_K] = cl_stats_restricted

    # -------- Part 3: Plotting the Advanced Cluster Statistics -------------- #
    if verbose:
        print(f"# -------- Part 3: Plotting the Advanced Cluster Statistics -------------- # ")
    fig_current = gmm.plot_advanced_stats_per_k(advanced_stats_per_k,title_suffix=title_suffix)
    mu.display_figure(fig_current)

import gmm


import math
import gym
from gym import spaces, logger
from gym.utils import seeding
import numpy as np
import random
import xlrd
from datetime import datetime
import os.path
import os
from openpyxl.reader.excel import load_workbook
from tkinter import _flatten

class Environ():

    def __init__(self):

        #设置参数
        self.C = 6     #边缘的最大存储容量
        self.U = 5     #边缘覆盖范围内的用户数量
        self.N = 10    #视频的数量
        self.l = 1.0   #本地到服务器的单位延迟
        self.p = 1.0   #本地到服务器的单位流量成本

        self.alpha = 0.8  #对延迟的关注度

        self.seed()
        self.state = None

        self.min_action = np.zeros(self.N)
        self.max_action = np.ones(self.N)

        self.steps = 0
        self._max_episode_steps = 12  #暂设
        self.steps_beyond_done = None

        self.min_observation = [-1 for _ in range(self.C + self._max_episode_steps * self.U)]
        self.min_observation = np.array(self.min_observation)
        self.min_observation = np.append(self.min_observation, 0)
        self.max_observation = [self.N-1 for _ in range(self.C + self._max_episode_steps * self.U)]
        self.max_observation = np.array(self.max_observation)
        self.max_observation = np.append(self.max_observation, 11)

        self.action_space = spaces.Box(
            low=self.min_action,
            high=self.max_action
        )
        self.observation_space = spaces.Box(
            low=self.min_observation,
            high=self.max_observation
        )

        #choice中用类似队列的形式来记录已存储的视频下标
        self.start = 0
        self.length = 0
        self.choice = [-1 for _ in range(self.C)]

    def seed(self, seed=None):
        self.np_random, seed = seeding.np_random(seed)
        return [seed]

    def step(self, action):

        #判断动作是否符合规范
        assert np.array(action) in self.action_space,"%r (%s) invalid" % (action, type(action))
        sum = 0
        for i in range(len(action)):
            sum = sum + action[i]
        assert sum == 1 , "%r (%s) invalid" % (action, "每次只缓存一个视频")

        uservideo = [[3,3,3,5,5,5,6,6,2,2,9,9],
                 [2,2,0,0,0,4,4,1,1,8,8,8],
                 [7,7,7,4,4,3,3,6,6,6,2,2],
                 [4,4,4,2,2,2,8,8,8,5,5,5],
                 [3,3,3,2,2,6,6,4,4,0,0,0]]
        uservideo = np.array(uservideo)
        uservideoOne = uservideo.flatten()

        done = self.steps >= self._max_episode_steps
        done = bool(done)
        ind = -1  #做的动作，缓存的那个视频，得到其下标
        for i in range(self.N):
            if action[i] == 1:
                ind = i

        if not done:
            #edge缓存的视频没有被缓存过
            if ind not in self.choice:
                if self.length < self.C:
                    self.length += 1
                elif self.length == self.C:
                    self.start = (self.start + 1) % self.C
                else:
                    raise RuntimeError()
                self.choice[(self.start + self.length - 1) % self.C] = ind

            #5个用户的奖赏
            userReward = [0]*self.U
            for i in range(self.U):
                for j in range(self.N):
                    if j in uservideo[i]:
                        if j in self.choice:  #如果用户观看的视频在边缘里的话，奖赏更高，给一个正值奖赏
                            userReward[i] += 5
                        else:  #如果用户观看的视频不在边缘里的话，延迟更高，奖赏更低
                            userReward[i] += -(self.alpha * self.l + (1-self.alpha) * self.p)

            reward = 0.0
            print("self.steps,uservideo,action,self.choice,userReward:",self.steps,uservideo,action,self.choice,userReward)
            for i in range(self.U):
                reward = reward + userReward[i]
            self.steps += 1

        elif self.steps_beyond_done is None:
            # Pole just fell!
            self.steps_beyond_done = 0
            reward = -(self.alpha * self.l + (1-self.alpha) * self.p)
        else:
            if self.steps_beyond_done == 0:
                logger.warn("""
You are calling 'step()' even though this environment has already returned
done = True. You should always call 'reset()' once you receive 'done = True'
Any further steps are undefined behavior.
                """)
            self.steps_beyond_done += 1
            reward = -(self.alpha * self.l + (1-self.alpha) * self.p)

        self.state = np.append(self.choice,uservideoOne)
        #original_time = datetime.now()
        a = random.randint(0, self._max_episode_steps-1)
        self.state = np.append(self.state,a)

        return np.array(self.state), reward, done, {}

    def reset(self):
        #边缘中已经缓存了哪些视频
        self.Choice = [-1 for _ in range(self.C)]
        resetChoiceNum = np.random.randint(self.C+1)    #边缘中已缓存视频的数量
        resetChoiceIndex = random.sample(range(0,self.N),resetChoiceNum)      #边缘中已缓存视频的下标
        for i in range(resetChoiceNum):
            self.Choice[i] = resetChoiceIndex[i]

        #用户观看的视频情况
        resetUservideo = [[random.randint(-1, self.N-1) for j in range(self._max_episode_steps)] for i in range(self.U)]
        resetUservideo = np.array(resetUservideo)
        resetUservideoOne = resetUservideo.flatten()

        self.state = np.append(self.Choice,resetUservideoOne)
        #original_time = datetime.now()
        a = random.randint(0, self._max_episode_steps-1)
        self.state = np.append(self.state,a)

        return np.array(self.state)