from PySide6 import Qt
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import sys
import sqlite3
from sqlite3 import Error
from datetime import date
from reservation_page import Ui_window

class Reservation(QMainWindow):
    def __init__(self):
        super().__init__()
        self.ui = Ui_window()
        self.ui.setupUi(self)
        self.dbConnection = None
        self.initDBConnection()
        #list of information
        self.info =[]
        #check wheter user click display before confirm
        self.dis = False

        #combo box setup
        branches = ["rama 3", "Sathorn", "Ladkrabang", "Rangsit", "Siam"]
        for b in branches:
                self.ui.serviceBranch_comboBox.addItem(b)

        #model list setup
        self.showList()
        self.ui.display_button.clicked.connect(self.display)
        self.ui.confirm_button.clicked.connect(self.confirm)

    def initDBConnection(self):
        try:
            self.dbConnection = sqlite3.connect("/Users/nnevermine/Desktop/carRental.db")
            print("connected to database")
        except Error as e:
            print(e)

        return self.dbConnection

    def showList(self):
        result = self.dbConnection.cursor().execute("""SELECT carModel,available FROM carCatalog""")
        for row_no, row_data in enumerate(result):
            #show only the available car
            if(row_data[1] > 0):
                item = QListWidgetItem(row_data[0])
                self.ui.listWidget.addItem(item)
    def display(self):
        #mark that user has clicked the display button before confirm
        self.dis = True

        #car model
        model = str(self.ui.listWidget.currentItem().text())
        self.ui.model_lineEdit.setText(model)

        #price per hour
        result = self.dbConnection.cursor().execute("""SELECT car_id, pph FROM carCatalog WHERE carModel=?""",(model,))
        for row_no, row_data in enumerate(result):
            car_id = row_data[0]
            pph = row_data[1]
        self.ui.pph_lineEdit.setText(str(pph) + " baht")

        #interval
        startD = int(self.ui.pickup_dateEdit.date().day())
        startM = int(self.ui.pickup_dateEdit.date().month())
        startY = int(self.ui.pickup_dateEdit.date().year())
        start = str(startD) + "/" + str(startM) + "/" + str(startY)

        endD = int(self.ui.return_dateEdit.date().day())
        endM = int(self.ui.return_dateEdit.date().month())
        endY = int(self.ui.return_dateEdit.date().year())
        end = str(endD) + "/" + str(endM) + "/" + str(endY)

        interval = str(start) + " to " + str(end)
        self.ui.interval_lineEdit.setText(interval)

        #no. of days
        s_date = date(startY, startM, startD)
        e_date = date(endY, endM, endD)
        delta = e_date - s_date
        days = delta.days
        #return same date
        if days == 0:
            days = 1
        self.ui.days_lineEdit.setText(str(days))

        #service branch
        branch = self.ui.serviceBranch_comboBox.currentText()
        self.ui.branch_lineEdit.setText(branch)

        #price
        price = pph * days
        self.ui.price_lineEdit.setText(str(price) + " baht")

        #username
        name = self.ui.name_lineEdit.text()

        #time
        pickup_time = self.ui.pickup_timeEdit.time().toString()
        return_time = self.ui.return_timeEdit.time().toString()

        #gather all information(username, carmodel, interval, pick-up time, return time, branch, total income)
        self.info = [name,car_id,model,interval,pickup_time,return_time,branch,price]

    def confirm(self):
        #has to click display before confirm
        if self.dis == True:
            #update car avilability
            result = self.dbConnection.cursor().execute("""UPDATE carCatalog SET available = 0 WHERE car_id = ?""",(self.info[1],))
            self.dbConnection.commit()
            item = self.ui.listWidget.currentItem()
            self.ui.listWidget.takeItem(self.ui.listWidget.row(item))

            #insert data into the database
            adminTable = self.dbConnection.cursor().execute("""INSERT INTO admin(username, carId, carModel, interval, pickupTime, returnTime, branch, income)VALUES(?,?,?,?,?,?,?,?)""", tuple(self.info))
            self.dbConnection.commit()

            #insert data to userHistory
            adminTable = self.dbConnection.cursor().execute("""INSERT INTO userHistory(username, carId, carModel, interval, pickupTime, returnTime, branch, price)VALUES(?,?,?,?,?,?,?,?)""", tuple(self.info))
            self.dbConnection.commit()

            #clear lineEdits ready for other reservation
            self.ui.model_lineEdit.setText("")
            self.ui.pph_lineEdit.setText("")
            self.ui.interval_lineEdit.setText("")
            self.ui.days_lineEdit.setText("")
            self.ui.branch_lineEdit.setText("")
            self.ui.price_lineEdit.setText("")
            self.dis = False

            dialog = QMessageBox()
            dialog.setText("Reservation successful")
            dialog.exec_()


from collections import ChainMap

from defaultGeneration import DefaultValuesWrapper, DEFAULTS_VALUES_GENERATORS
from excelInputMappingRules import EXCEL_INPUT_MAPPING_RULES
from inputMappings import NonStrictInputMapping
from models.co2model import Co2Model
from models.erosionmodel import ErosionModel
from models.fertilisermodel import FertModel
from models.hmmodel import HmModel
from models.irrigationmodel import IrrigationModel
from models.lucmodel import LUCModel
from models.manuremodel import ManureModel
from models.nmodel import NModel
from models.otherorganicfertilisermodel import OtherOrganicFertModel
from models.packmodel import PackModel
from models.pmodel import PModel
from models.seedmodel import SeedModel
from outputMapping import OutputMapping

class ModelsSequence(object):
    def __init__(self, validatedInputs):
        self._intermediateValues = {}
        self.outputMapping = OutputMapping()
        self.allInputs = DefaultValuesWrapper(ChainMap(NonStrictInputMapping(validatedInputs, EXCEL_INPUT_MAPPING_RULES),
                                              self._intermediateValues, self.outputMapping.output), DEFAULTS_VALUES_GENERATORS)

    def executeSequence(self):
        self.outputMapping.mapAsIsOutput(self.allInputs)
        self.outputMapping.mapDictsToOutput(self.allInputs)
        self._computeFertiliser()
        self._computeManure()
        self._computeOtherOrganicFertiliser()
        self._computeSeed()
        self.outputMapping.mapSeeds(self.allInputs)
        if self.allInputs["cultivation_type"] != "open_ground":
            self._intermediateValues["eroded_soil"] = 0.0
        else:
            self._intermediateValues["eroded_soil"] = ErosionModel(self.allInputs).compute()["m_Erosion_eroded_soil"]
        self.outputMapping.mapIrrigationModel(IrrigationModel(self.allInputs).compute())
        self.outputMapping.mapIrrigationQuantities(self.allInputs)
        self.outputMapping.mapFertilizers(self.allInputs)
        self.outputMapping.mapOtherOrganicFertilizers(self.allInputs)
        self.outputMapping.mapCo2Model(Co2Model(self.allInputs).compute())
        self.outputMapping.mapNModel(NModel(self.allInputs).compute(), self.allInputs)
        self.outputMapping.mapPModel(PModel(self.allInputs).compute(), self.allInputs)
        self.outputMapping.mapHMModel(HmModel(self.allInputs).compute(), self.allInputs)
        self.outputMapping.mapPackModel(PackModel(self.allInputs).compute())
        self.outputMapping.mapLucModel(LUCModel(self.allInputs).compute(), self.allInputs)
        #self.outputMapping.mapUsedIntermidiateValues(self._intermediateValues)
        self.outputMapping.mapMachineries(self.allInputs)
        self.outputMapping.mapCODWasteWater(self.allInputs)
        self.outputMapping.mapPesticides(self.allInputs)
        return self.outputMapping.output;

    def _computeFertiliser(self):
        fertM = FertModel(self.allInputs)
        self._intermediateValues["ammonia_due_to_mineral_fert"] = fertM.computeNH3()
        self._intermediateValues["hm_from_mineral_fert"] = fertM.computeHeavyMetal()

    def _computeManure(self):
        manureM = ManureModel(self.allInputs)
        self._intermediateValues["nitrogen_from_all_manure"] = manureM.computeN()
        pres = manureM.computeP2O5()
        self._intermediateValues["p2o5_in_liquid_manure"] = pres[0]
        self._intermediateValues["p2o5_in_solid_manure"] = pres[1]
        self._intermediateValues["hm_from_manure"] = manureM.computeHeavyMetal();
        self._intermediateValues["ammonia_due_to_manure"] = manureM.computeNH3()

    def _computeOtherOrganicFertiliser(self):
        otherfertM = OtherOrganicFertModel(self.allInputs)
        self._intermediateValues["nitrogen_from_other_orga_fert"] = otherfertM.computeN()
        self._intermediateValues["p2o5_in_liquid_sludge"] = otherfertM.computeP2O5()
        self._intermediateValues["hm_from_other_organic_fert"] = otherfertM.computeHeavyMetal()
        self._intermediateValues["ammonia_due_to_other_orga_fert"] = otherfertM.computeNH3()

    def _computeSeed(self):
        seedM = SeedModel(self.allInputs)
        self._intermediateValues["hm_from_seed"] = seedM.computeHeavyMetal()


import os
import sys
import shutil
import numpy as np
import scipy.sparse as sp
import pickle
import copy
from operator import itemgetter
from sklearn import metrics
import torch
from typing import List, Union
import torch.utils.data

### mkdir
def mkdir(path):
    if os.path.exists(path):
        shutil.rmtree(path)
    if not os.path.exists(path):
        os.makedirs(path)

### sparse_to_tuple
def sparse_to_tuple(sparse_mx):
    if not sp.isspmatrix_coo(sparse_mx):
        sparse_mx = sparse_mx.tocoo()
    coords = np.vstack((sparse_mx.row, sparse_mx.col)).transpose()
    values = sparse_mx.data
    shape = sparse_mx.shape
    return coords, values, shape

### dropout_sparse
def dropout_sparse(x, dropout, noise_shape):
    i = x._indices()
    v = x._values()

    random_tensor = 1 - dropout
    random_tensor = random_tensor + torch.rand(noise_shape)
    dropout_mask = torch.floor(random_tensor).type(torch.bool)

    i = i[:, dropout_mask]
    v = v[dropout_mask]

    out = torch.sparse.FloatTensor(i, v, x.shape)
    out = out * (1. / (1 - dropout))

    return out

### scipy_sparse_to_torch_sparse
def scipy_sparse_to_torch_sparse(sparse_mx):
    sparse_mx = sparse_mx.tocoo()
    values = sparse_mx.data
    indices = np.vstack((sparse_mx.row, sparse_mx.col))
    i = torch.LongTensor(indices)
    v = torch.FloatTensor(values)
    shape = sparse_mx.shape
    x = torch.sparse.FloatTensor(i, v, torch.Size(shape))
    return x

### fixed_unigram_candidate_sampler
### https://github.com/YuutoOhnuki/decagon-pytorch/blob/master/decagon-pytorch/src/decagon_pytorch/sampling.py
def fixed_unigram_candidate_sampler(
    true_classes: Union[np.array, torch.Tensor],
    num_samples: int,
    unigrams: List[Union[int, float]],
    distortion: float = 1.):

    if isinstance(true_classes, torch.Tensor):
        true_classes = true_classes.numpy()
    if true_classes.shape[0] != num_samples:
        raise ValueError('true_classes must be a 2D matrix with shape (num_samples, num_true)')
    unigrams = np.array(unigrams)

    if distortion != 1.:
        unigrams = unigrams.astype(np.float64) ** distortion
    indices = np.arange(num_samples)
    result = np.zeros(num_samples, dtype=np.int64)
    tmp = indices
    while len(tmp) > 0:
        sampler = torch.utils.data.WeightedRandomSampler(unigrams, len(indices))
        candidates = np.array(list(sampler))
        candidates = np.reshape(candidates, (len(indices), 1))
        result[indices] = candidates.T
        mask = (candidates == true_classes[indices, :])
        mask = mask.sum(1).astype(np.bool)
        tmp = indices[mask]
    return result

# ###  hinge_loss
# def hinge_loss(pos, neg, margin):
#     """Maximum-margin optimization using the hinge loss."""
#     diff = torch.relu(torch.sub(neg, pos - margin))
#     loss = torch.sum(diff)
#     return loss

###  test
def test(prefix, epo_idx, net, dp, args, log, disease):

    net.eval()
    dp.is_train = False
    dp.dropout = 0.  # disable dropout for val

    edges = pickle.load(open(args.edg_pkl_path + "{}_edges.pkl".format(prefix), "rb"))
    false_edges = pickle.load(open(args.edg_pkl_path + "{}_false_edges.pkl".format(prefix), "rb"))

    auroc_list = []
    auprc_list = []
    apk_list = []
    auroc_avg_list = []
    auprc_avg_list = []
    apk_avg_list = []
    rel_type_tmp = []
    rel_type_list = []

    print_data = []
    #for rel_type, edge_lists in edges.items():
    rel_type = (0,1)
    edge_lists = edges[rel_type]
        # rel_type_tmp.append(rel_type)  # [(0, 1)] ; [(0, 1), (1, 0)]
        # rel_type_list.append(copy.deepcopy(rel_type_tmp))  # [[(0, 1)], [(0, 1), (1, 0)]]

    i, j = rel_type
    for rt_k, edge_list in enumerate(edge_lists):
        ### pos & neg edges
        pos_edge_list = edge_list
        neg_edge_list = false_edges[rel_type][rt_k]

        ### preds result
        pos_preds_all = []
        neg_preds_all = []

        ### test per batch or in one time
        if args.te_batch:
            """
            test the data per batch
            """
            ### edges number
            n_edges = len(pos_edge_list)
            n_batchs = n_edges // args.te_batch_size
            bt_idx = 0
            while True:
                ### start, end
                bt_s = bt_idx * args.te_batch_size
                bt_e = bt_s + args.te_batch_size
                if bt_s < n_edges and bt_e >= n_edges:
                    bt_e = n_edges
                ### pos edges
                pos_edges_array = np.array(pos_edge_list[bt_s:bt_e])
                pos_edges_tensor = torch.from_numpy(pos_edges_array)
                pos_edges_tensor = pos_edges_tensor.to(args.device)
                pos_inputs = ((i, j), rt_k, pos_edges_tensor)
                pos_preds, _ = net(pos_inputs)
                pos_preds = torch.sigmoid(pos_preds)
                pos_preds = pos_preds.detach().cpu().numpy().tolist()
                pos_preds_all += pos_preds
                ### neg edges
                # neg_edges_array = np.array(neg_edge_list[bt_s:bt_e])
                # neg_edges_tensor = torch.from_numpy(neg_edges_array)
                # neg_edges_tensor = neg_edges_tensor.to(args.device)
                # neg_inputs = ((i, j), rt_k, neg_edges_tensor)
                # neg_preds, _ = net(neg_inputs)
                # neg_preds = torch.sigmoid(neg_preds)
                # neg_preds = neg_preds.detach().cpu().numpy().tolist()
                # neg_preds_all += neg_preds

                ### bt_idx ++
                bt_idx += 1
                ### break
                if bt_idx > n_batchs:
                    break
        else:
            """
            test all data in one time
            """
            ### pos edges
            pos_edges_array = np.array(pos_edge_list)
            pos_edges_tensor = torch.from_numpy(pos_edges_array)
            pos_edges_tensor = pos_edges_tensor.to(args.device)
            pos_inputs = ((i, j), rt_k, pos_edges_tensor)
            pos_preds, _ = net(pos_inputs)
            pos_preds = torch.sigmoid(pos_preds)
            pos_preds_all = pos_preds.detach().cpu().numpy().tolist()
            ### neg edges
            neg_edges_array = np.array(neg_edge_list)
            neg_edges_tensor = torch.from_numpy(neg_edges_array)
            neg_edges_tensor = neg_edges_tensor.to(args.device)
            neg_inputs = ((i, j), rt_k, neg_edges_tensor)
            neg_preds, _ = net(neg_inputs)
            neg_preds = torch.sigmoid(neg_preds)
            neg_preds_all = neg_preds.detach().cpu().numpy().tolist()

        ### all
        # preds_all = np.hstack([pos_preds_all, neg_preds_all])
        # preds_all = np.nan_to_num(preds_all)
        # labels_all = np.hstack([np.ones(len(pos_preds_all)), np.zeros(len(neg_preds_all))])

        # actual = list(range(len(pos_preds_all)))
        # predicted = []
        # for idx, score in enumerate(preds_all):
        #     predicted.append((score, idx))
#######################################################################################################
        print_data_rtk = []
        for idx, score in enumerate(pos_preds_all):
            data = [(rel_type, rt_k), edge_list[idx], pos_preds_all[idx]]
            print_data_rtk.append(data)
        print_data.append(print_data_rtk)
#######################################################################################################
    #     predicted = list(zip(*sorted(predicted, reverse=True, key=itemgetter(0))))[1]

    #     ### roc, auprc, apk
    #     auroc = metrics.roc_auc_score(labels_all, preds_all)
    #     auprc = metrics.average_precision_score(labels_all, preds_all)
    #     apk = compute_apk(actual, predicted, k=args.ap_k)
        # log.info("[{}] | Epoch: [{}/{}] | Type: [{},{},{}] |"
        #          " AUROC: {:.5f} | AUPRC: {:.5F} | AP@{}: {:.5f}".format(
        #     prefix, epo_idx + 1, args.epoch, i, j, rt_k,
        #     auroc, auprc, args.ap_k, apk))
        log.info("[{}] | Epoch: [{}/{}] | Type: [{},{},{}] ".format(prefix, epo_idx + 1, args.epoch, i, j, rt_k))

    #     ### append
    #     auroc_list.append(auroc)
    #     auprc_list.append(auprc)
    #     apk_list.append(apk)

    # ### avg
    # auroc_avg = np.mean(auroc_list)
    # auprc_avg = np.mean(auprc_list)
    # apk_avg = np.mean(apk_list)
    # auroc_avg_list.append(auroc_avg)
    # auprc_avg_list.append(auprc_avg)
    # apk_avg_list.append(apk_avg)
#######################################################################################################
    # pickle.dump(print_data, open("../../out/predict_results.pkl", "wb"))
    dis = ['all', 'covid', 'cn', 'nsclc', 'escc']
    with open("../out/predict_results_{}.txt".format(dis[disease]), "w") as presults:
        for lines in print_data: #print_data_rtk
            for line in lines: #data
                rel_type = line[0][0]
                rel_type_k = str(line[0])
                cnum = line[1][0]
                gnum = line[1][1]
                score = line[2]
                presults.write("{}\t{}\t{}\t{}\n".format(rel_type_k, cnum, gnum, score))
#######################################################################################################
    # for rel_type, auroc_avg, auprc_avg, apk_avg in zip(rel_type_list, auroc_avg_list, auprc_avg_list, apk_avg_list):

    #     log.info("[{}] | Epoch: [{}/{}] | all >>> type: {} |"
    #              " avg AUROC: {:.5f} | avg AUPRC: {:.5F} | avg AP@{}: {:.5f}".format(
    #         prefix, epo_idx + 1, args.epoch, rel_type,
    #         auroc_avg, auprc_avg, args.ap_k, apk_avg))

    # return auroc_avg_list[0], auprc_avg_list[0], apk_avg_list[0]
    log.info("[{}] | Epoch: [{}/{}]".format(prefix, epo_idx + 1, args.epoch, rel_type))

### apk
def compute_apk(actual, predicted, k=10):
    """
    Computes the average precision at k.

    This function computes the average precision at k between two lists of
    items.

    Parameters
    ----------
    actual : list
             A list of elements that are to be predicted (order doesn't matter)
    predicted : list
                A list of predicted elements (order does matter)
    k : int, optional
        The maximum number of predicted elements

    Returns
    -------
    score : double
            The average precision at k over the input lists

    """
    if len(predicted)>k:
        predicted = predicted[:k]

    score = 0.0
    num_hits = 0.0

    for i, p in enumerate(predicted):
        if p in actual and p not in predicted[:i]:
            num_hits += 1.0
            score += num_hits / (i + 1.0)

    if not actual:
        return 0.0

    return score / min(len(actual), k)

### mapk
def compute_mapk(actual, predicted, k=10):
    """
    Computes the mean average precision at k.

    This function computes the mean average precision at k between two lists
    of lists of items.

    Parameters
    ----------
    actual : list
             A list of lists of elements that are to be predicted
             (order doesn't matter in the lists)
    predicted : list
                A list of lists of predicted elements
                (order matters in the lists)
    k : int, optional
        The maximum number of predicted elements

    Returns
    -------
    score : double
            The mean average precision at k over the input lists

    """
    return np.mean([compute_apk(a,p,k) for a, p in zip(actual, predicted)])


import logging
from flask import json
from requests.auth import HTTPBasicAuth
import requests
from util import get_site_id_by_name, APIError

def create_appliance(api_auth, parameters, contexts):
    """
    Allows users to create an appliance on a site.
    In order for them to do so, we need to know the city, site name
    model and country code.

    Works by checking if the site exists. If it exists, it gets the parameters, and with the
    parameters, it calls the SteelConnectAPI, and creates the appliance

    Parameters:
    - api_auth: SteelConnect API object, it contains authentication log in details
    - parameters: The json parameters obtained from the Dialogflow Intent. It obtains the following:
        > city: In which city the site is located in
        > country_code: The country code of the country where the site is located
        > model: The model of the appliance the user wants to create
        > site_name: the name of the site the user wants to place the appliance on

    Returns:
    - speech: A string which has the response to be read/printed to the user

    Example Prompt:
    - Make an ewok appliance for charmeleon, in Darwin, Australia

    """
    try:
        city = parameters["City"]
        site_name = parameters["SiteName"]
        model = parameters["Model"]
        country_code = parameters["Country"]["alpha-2"]
        country_name = parameters["Country"]["name"]

    except KeyError as e:
        error_string = "Error processing create Appliance intent. {0}".format(e)
        logging.error(error_string)
        return error_string

    # Get all sites and check whether site exists
    # Currently, if site doesn't exist it will let the user know that the site doesn't exist
    try:
        site_id = get_site_id_by_name(api_auth, site_name, city,country_code)
    except APIError as E:
        return str(E)

    if site_id:         #If we find a site that exists
        # Call create_appliance in SteelConnectAPI
        res = api_auth.node.create_appliance(site=site_id, model=model)

        if res.status_code == 200:          #if successful
            speech = "The {} appliance was created for the {} site in {}, {}".format(model, site_name, city, country_name)
        elif res.status_code == 400:
            speech = "Invalid parameters: {}".format(res.json()["error"]["message"])
        elif res.status_code == 404:
            speech = "Error: Organization with given id does not exist"
        elif res.status_code == 500:        #If we couldn't create the appliance
            speech = "Error: We could not create the {} appliance for the {} site in {}, {}".format(model, site_name, city, country_name)
        else:
            speech = "Error: Could not connect to SteelConnect"

        logging.debug(speech)
    else:
        speech = "The site {} does not exist in {}, {}. No appliances were created.".format(site_name, city,country_name)
    return speech


"""contains all helper functions used for deap RNN evolution code - all functions
that are not evaluation or part of the evolutionary code
"""

import numpy as np
import torch
from copy import deepcopy

from gear import Gear

# set seed number in numpy for reproducing results
seed_f = open("seed.txt", "r")
np.random.seed(int(seed_f.readlines()[0]))
seed_f.close()

def list_to_matrices(weight_list, num_in, num_hid, num_out):
	"""takes a list of weight generated by deap and converts
	it into numpy arrays that can then be entered into PyTorch
	as the parameters for an RNN to judge its fitness

	Assumes each RNN always has two weight matrices
	"""

	# define size of first weight matrix
	# size of second weight matrix follows from this
	w1_size = (num_in + num_hid)*num_hid
	w1_bias_size = num_hid
	w2_size = (num_hid*num_out)
	w2_bias_size = num_out

	# separate each of the weight into separate numpy arrays
	# resized after - returned now as 1D arrays
	w1 = np.array(weight_list[: w1_size], copy=True)
	w1_bias = np.array(weight_list[w1_size: (w1_size + w1_bias_size)], copy=True)
	w2 = np.array(weight_list[(w1_size + w1_bias_size): (w1_size + w1_bias_size + w2_size)],
			copy=True)
	w2_bias = np.array(weight_list[(w1_size + w1_bias_size + w2_size): (w1_size + \
			w1_bias_size + w2_size + w2_bias_size) ], copy=True)

	return (w1, w1_bias, w2, w2_bias)

def inject_weights(rnn, w1, w1_bias, w2, w2_bias):
	"""method that takes a pytorch rnn and sets the
	weights of its two linear units equal to w1 and
	w2 so that their fitness can be tested with the RNN
	"""

	# find needed shapes of weight matrices
	w1_shape = rnn.in2hid.weight.data.numpy().shape
	w1_bias_shape = rnn.in2hid.bias.data.numpy().shape
	w2_shape = rnn.hid2out.weight.data.numpy().shape
	w2_bias_shape = rnn.hid2out.bias.data.numpy().shape

	# reshape matrices to the proper shape
	w1 = np.reshape(w1, w1_shape)
	w1_bias = np.reshape(w1_bias, w1_bias_shape)
	w2 = np.reshape(w2, w2_shape)
	w2_bias = np.reshape(w2_bias, w2_bias_shape)

	# convert numpy arrays to tensors
	w1 = torch.from_numpy(w1).float()
	w1_bias = torch.from_numpy(w1_bias).float()
	w2 = torch.from_numpy(w2).float()
	w2_bias = torch.from_numpy(w2_bias).float()

	# set weights within the rnn equal to w1 and w2
	# types of weights must be float to avoid error with double
	rnn.in2hid.weight.data = w1
	rnn.in2hid.bias.data = w1_bias
	rnn.hid2out.weight.data = w2
	rnn.hid2out.bias.data = w2_bias

	# set all tensors in the state array equal to new weights
	rnn.state_dict()['in2hid.weight'].copy_(w1)
	rnn.state_dict()['in2hid.bias'].copy_(w1_bias)
	rnn.state_dict()['hid2out.weight'].copy_(w2)
	rnn.state_dict()['hid2out.bias'].copy_(w2_bias)

	# return the rnn with newly set weights
	return rnn

def get_rnn_output(rnn, max_it, act_exp, verbose=False):
	"""takes rnn with current weights and gets all outputs
	for the associated output circle

	Parameters:
	rnn -- the rnn being used
	max_it -- the maximum number of discrete points in the helical shape
	sigmoid_exp -- constant to multiply numbers passed into output activation
	"""

	# initialize all tracking values that are needed
	# to create a structure with the rnn
	theta_scale = 20.0
	radius_scale = 4.0
	hidden = torch.ones(1, rnn.hidden_size)
	all_positions = []
	r = 0.0
	theta = 0.0
	dr = 0.0
	dt = 0.0
	curr_t = 0 # track current t so that it does not exceed max

	# run rnn until candidate structure reaches the origin
	while (curr_t < max_it):
		# add current position into structure history
		rnn_pos = (r, theta)
		all_positions.append(rnn_pos)

		# get input and activate rnn at current timestep
		# be sure to normalize inputs before they are passed into RNN
		rnn_input = [[dr, dt]]
		outs, hidden = rnn.forward(torch.Tensor(rnn_input), hidden, act_exp)
		dr, dt = outs.data[0][0].item(), outs.data[0][1].item()

		# thickness should be scaled to minimum thickness and avoid negative thickness
		# tanh has a minimum value of -1, so add this to thickness and the minimum value
		# must also scale range of tanh to output values from min to max thickness
		#thick += (1.0 + MIN_THICKNESS)*((MAX_THICKNESS - MIN_THICKNESS)/2.0)

		# print information
		if verbose:
			print("Current R: {0}".format(str(r)))
			print("dR: {0}".format(str(dr)))
			print("dT: {0}".format(str(dt)))
			#print("Thick: {0}".format(str(thick)))

		# update the current position of the structure
		# outputs are scaled to make changes not as large
		r += dr#(dr/radius_scale)
		theta += dt#abs(dt)/theta_scale

		# increment the current time step
		curr_t += 1

	all_positions.append((r, theta))

	return all_positions

def get_RNN_output_cartesian(rnn, max_y, max_x, max_t, act_exp, verbose=False):
	"""gets RNN output for the gear tooth evolution - output starts at (0,0)
	in cartesian coordinates and moves upwards until it reaches a maximum value
	of y, forming a unique path from bottom to top that will be used as the shape
	of the gear tooth"""

	# intialize all values that need to be tracked by rnn
	x = 0.0
	y = 0.0
	dx = 0.0
	dy = 0.0
	x_scale = 5.0
	y_scale = 5.0
	curr_t = 0

	# initialize hidden state
	hidden = torch.zeros(1, rnn.hidden_size)

	# track all positions of RNN
	all_positions = []

	# run RNN until output reaches desired y position
	while(y < max_y and curr_t < max_t):
		# add current position into the positions list
		rnn_pos = (x, y)
		all_positions.append(rnn_pos)

		# form input and activte the rnn
		rnn_input = [[dx, dy]]
		outs, hidden = rnn.forward(torch.Tensor(rnn_input), hidden, act_exp)
		dx, dy = outs.data[0][0].item(), outs.data[0][1].item()

		# print out the dx and dy if it is verbose
		if(verbose):
			print("X: {0}".format(str(x)))
			print("Y: {0}".format(str(y)))
			print("dx: {0}".format(str(dx)))
			print("dy: {0}".format(str(dy)))
			input()

		# update x and y pos with rnn output
		x += (dx/x_scale)
		# x must be kept from going much too far from center
		if(x < -max_x):
			x = -max_x
		elif(x > max_x):
			x = max_x
		y += abs(dy/y_scale) # y must always move upward ? or is it ok?
		curr_t += 1

	# append the last position of the RNN
	all_positions.append((x, y))
	return all_positions

def get_hidden_input(num_r, num_c, hidden_type):
	"""creates a matrix of hidden values that are used as the initial
	hidden values for the rnn, these initital values can be zeroes, ones,
	or generated randomly

	:hidden_type is 'rand' if generated randomly, 'zero' if all zeroes, and
	'one' if all ones
	"""

	hid_mat = None

	# decide what type of initial hidden matrix to create
	if hidden_type == 'rand':
		# create hidden matrix of random values [-1, 1]
		hid_mat = 2.0*(torch.rand(num_r, num_c) - .5)
	elif hidden_type == 'zero':
		hid_mat = torch.zeros(num_r, num_c)
	elif hidden_type == 'one':
		hid_mat = torch.ones(num_r, num_c)
	else:
			print("The input hidden type is not a valid option - returning None")
	return hid_mat

def get_gear_mechanism(rnn, max_gears, min_gears, stop_thresh, rad_scale, act_exp, pos_thresh, hidden_input):
	"""method for getting output of RNN representing an entire mechanism of gears
	rnn outputs at each t a value deciding if next gear will be to left, to right,
	or attached to back, and another value dictating the pitch radius of the gear -
	also outputs a value that decides if rnn should stop at this gear"""

	# initialize all variables needed to get output
	radius = 1.0
	gear_pos_a = 1.0 # angle gear is placed at
	stop = 1.0

	# initialize the hidden layer
	hidden = get_hidden_input(1, rnn.hidden_size, hidden_input)#torch.zeros(1, rnn.hidden_size)

	# length of the outputs is the number of gears that have been added to system
	all_outputs = []

	while((len(all_outputs) < min_gears) or (len(all_outputs) < max_gears and stop < stop_thresh)):
		# must run inputs through RNN first to get values for first gear
		rnn_input = [[radius, gear_pos_a, stop]]
		outs, hidden = rnn.forward(torch.Tensor(rnn_input), hidden, act_exp)
		radius, gear_pos_a, stop = outs.data[0][0].item(), outs.data[0][1].item() \
												, outs.data[0][2].item()

		# make sure radius is positive and scale it to fit between 0 and maximum possible value
		# do not input scaled value back into RNN - large values can bias the input
		radius_scaled = (radius + 1.5)*rad_scale

		# append outputs into list
		all_outputs.append((radius_scaled, gear_pos_a, stop))

	return all_outputs

def get_discrete_gear_mechanism(rnn, num_unique_gears, max_gears, min_gears, stop_thresh,
		rad_scale, act_exp, pos_thresh, hidden_input, verbose=False):
	"""generates output of RNN to create a gear mechanism, first n outputs of each time step
	represent the probability of each discrete type of gear being present, the one with the highest
	probability is the radius of gear that is present at that time step, there are also two other outputs,
	positition and stop, that dictate where this gear will be placed and if the RNN should continue
	outputting gears"""

	# initialize all variables needed to get output
	rnn_input = torch.ones(1, num_unique_gears + 2)

	# initialize the hidden layer
	hidden = get_hidden_input(1, rnn.hidden_size, hidden_input)

	# length of the outputs is the number of gears that have been added to system
	all_outputs = []

	while((len(all_outputs) < min_gears) or (len(all_outputs) < max_gears and stop < stop_thresh)):
		# run next forward propogation
		outs, hidden = rnn.forward_softmax(rnn_input, hidden, num_unique_gears, act_exp)

		# print out hidden state and outputs if verbose
		if verbose:
			print(f"Hidden State: {hidden}")
			print(f"Output State: {outs}")
			input()

		# output of this step becomes input for next step
		rnn_input = outs
		stop = outs.data[0][num_unique_gears+1].item()

		# get the current gear type/size
		gear_type = np.argmax(outs.data[0][:num_unique_gears].numpy())

		# append outputs into list
		all_outputs.append((gear_type, outs.data[0][num_unique_gears].item(), outs.data[0][num_unique_gears+1].item()))

	return all_outputs

def get_gear_ratio(outputs, pos_thresh):
	"""method for finding the gear ratio of a set of gears that is generated
	by the rnn - assumes that the first gear in the list is the input and
	the last gear in the list is the output"""

	# set radius to the intial value
	radius = outputs[0][0]
	ratio = 1.0

	# go through each gear and update the ratio by multiplying with current ratio
	for gear_ind in range(1, len(outputs)):
		gear = outputs[gear_ind]
		nxt_radius = gear[0]
		direction = gear[1]
		if(direction < pos_thresh[0] or direction > pos_thresh[1]):
			ratio *= radius/nxt_radius
		# if gear is attached to back only need to update radius
		radius = nxt_radius

	return ratio

def get_centers_and_radii(outputs, pos_thresh, output_min):
	"""takes a list of outputs of form (radius, position output, stop) and
	transforms it into a list of center locations and radii - any values below
	pos_thresh for position output are scaled between 0 and 360 degrees for placement
	relative to the last gear in the list, anything greater or equal represents gear
	being attached to back of previous gear

	each element of result has form (position, radius, z_position)
	"""

	# find how much positions should be scaled to get to 2*pi
	total_range = pos_thresh - output_min # range is from -1 to pos thresh for tanh
	scale_factor = 2*np.pi/total_range

	# third element of position tuple is a z dimension that tells you if gear is attached to back of another
	z = 0

	# instantiate resulting list - first circle always at origin
	result = [((0, 0), outputs[0][0], z)]

	# go through each gear and find position relative to previous gear
	for curr, last in zip(outputs[1:], outputs):
		# if position greater than pos_thresh, gear is attached to back of previous
		if(curr[1] > pos_thresh):
			# increment z because gears are now placed behind the others
			z += 1
			result.append((result[-1][0], curr[0], z))

		else:
			angle = (curr[1] - output_min)*scale_factor
			distance = curr[0] + last[0]
			last_pos = result[-1][0]

			# must handle each quadrant specifically depending on angle
			if(angle <= np.pi/2.0):
				x_change = distance*np.cos(angle)
				y_change = distance*np.sin(angle)
			elif(angle <= np.pi):
				angle = np.pi - angle
				x_change = -distance*np.cos(angle)
				y_change = distance*np.sin(angle)
			elif(angle <= 1.5*np.pi):
				angle = angle - np.pi
				x_change = -distance*np.cos(angle)
				y_change = -distance*np.sin(angle)
			else:
				angle = 2*np.pi - angle
				x_change = distance*np.cos(angle)
				y_change = -distance*np.sin(angle)

			# update the position with change in x and y relative to last pos
			pos = (last_pos[0] + x_change, last_pos[1] + y_change)
			result.append((pos, curr[0], z))

	return result

def check_intersect_amount(mechanism):
	"""takes a list of circles (defined as a tuple with center position and the radii)
	and returns a sum of the amount of intersecting radius within the mechanism - two
	gears are overlapping if they are in the same z dimension and would collide with each
	other"""

	# perform nested loop and check if each pair of circles intersects
	total_intersection = 0.0
	for i in enumerate(mechanism):
		left_c = i[1]
		right_ind = i[0] + 1
		while(right_ind < len(mechanism)):
			# grab current circle to test for intersection
			right_c = mechanism[right_ind]

			# find distance between centers and sum of radii
			center_dist = np.sqrt(np.square(right_c.pos[0] - left_c.pos[0]) \
				+ np.square(right_c.pos[1] - left_c.pos[1]))
			radii_sum = right_c.radius + left_c.radius

			# if sum of radii is greater than the distance between centers
			# then these two circles intersect if at same z position
			if(radii_sum > center_dist and left_c.pos[2] == right_c.pos[2]):
				total_intersection += np.square(radii_sum - center_dist)
			right_ind += 1

	# only reaches this point if no circles intersect
	return total_intersection

def check_intersect(mechanism):
	"""takes a list of circles (defined as a tuple with center position and the radii)
	and returns true if any circles intersect and false if not circles intersect"""

	# perform nested loop and check if each pair of circles intersects
	for i in enumerate(mechanism):
		left_c = i[1]
		right_ind = i[0] + 1
		while(right_ind < len(mechanism)):
			# grab current circle to test for intersection
			right_c = mechanism[right_ind]

			# find distance between centers and sum of radii
			center_dist = np.sqrt(np.square(right_c.pos[0] - left_c.pos[0]) \
				+ np.square(right_c.pos[1] - left_c.pos[1]))
			radii_sum = right_c.radius + left_c.radius

			# if sum of radii is greater than the distance between centers
			# then these two circles intersect if at same z position
			if(radii_sum > center_dist and left_c.pos[2] == right_c.pos[2]):
				return True
			right_ind += 1

	# only reaches this point if no circles intersect
	return False

def check_conflicting_gear_axis(mechanism, hole_size):
	"""finds the amount of overlapping radius of gear mechanisms that cannot be created
	because the center axis of the gear would intersect with the body of another gear

	:param hole_size: the size of the hole that runs through center of gears

	:returns: the amount of overlap that is created by conflicting axis
	"""

	# store the total numeric value for conflicting gear axis
	total_conflict = 0.0
	for l_ind in range(len(mechanism)):
		center = mechanism[l_ind].pos[0]
		rad = mechanism[l_ind].radius
		for r_ind in range(len(mechanism)):
			# check for axis conflicts with every possible pair of gears
			if(l_ind != r_ind):
				o_center = mechanism[r_ind].pos[0]
				left_bound = center - rad - hole_size
				right_bound = center + rad + hole_size
				if(left_bound <= o_center < center):
					total_conflict += np.square(o_center - left_bound)
				elif(center < o_center <= right_bound):
					total_conflict += np.square(right_bound - o_center)
	return total_conflict

def create_mechanism_representation(all_outputs, pos_thresh, output_min):
	"""uses a list of gear RNN outputs to create a more understandable representation for
	the mechanism, each gear is represented with (radius, position, previous gear, next gears,
	ratio) so that all information for each gear in the mechanism is readily available

	this method converts the raw RNN output into the above form - stored as a Gear object
	"""

	# populate mechanism with the first gear
	# ratio set to 1.0 by default when gear is instantiated
	r = all_outputs[0][0]
	init_x = np.cos(np.pi/4)*r
	init_y = np.sin(np.pi/4)*r
	mechanism = [Gear(r, (init_x, init_y, 0), 0)]

	# go through all outputs and create a gear object for each one
	for index, curr in enumerate(all_outputs[1:]):
		prev_gear = mechanism[-1] # previous gear is always last outputted mechanism

		# must set padding to true if space should be inserted between gears for 3D printing
		new_pos = get_gear_pos_linear(prev_gear.pos, curr[1], prev_gear.radius, curr[0],
					pos_thresh, output_min)
		mechanism.append(Gear(curr[0], new_pos, len(mechanism) - 1))

		# add index of current into list of nxt gears for gear it attaches to
		prev_gear.next_gears.append(index + 1)

		# find ratio of current gear - only changes if not attached to front/back
		new_ratio = prev_gear.ratio*(prev_gear.radius/mechanism[-1].radius)
		if(-pos_thresh <= curr[1] <= pos_thresh ):
			mechanism[-1].ratio = new_ratio
		else:
			mechanism[-1].ratio = prev_gear.ratio

	return mechanism

def create_discrete_mechanism(all_outputs, gear_radii, pos_thresh, output_min):
	"""creates mechanism using RNN output based on discrete gear radius
	options

	:param all_outputs: the list of outputs created by RNN
	:param gear_radii: the list of gear radius options
	"""

	r = gear_radii[all_outputs[0][0]]
	mechanism = [Gear(r, (r, r, 0), 0)]
	for index, curr in enumerate(all_outputs[1:]):
		prev_gear = mechanism[-1]

		# get position for the next gear
		new_pos = get_gear_pos_linear(prev_gear.pos, curr[1], prev_gear.radius, gear_radii[curr[0]], \
				pos_thresh, output_min)
		mechanism.append(Gear(gear_radii[curr[0]], new_pos, len(mechanism) - 1))
		prev_gear.next_gears.append(index + 1)

		# find ratio of the current gear
		new_ratio = prev_gear.ratio*(prev_gear.radius/mechanism[-1].radius)
		if(-pos_thresh <= curr[1] <= pos_thresh ):
			mechanism[-1].ratio = new_ratio
		else:
			mechanism[-1].ratio = prev_gear.ratio

	return mechanism

def find_novelty(curr_vec, other_vecs, k=1):
	"""pass in a numpy vector characterizing gear mechanism and find the average distance between
	it and all other vectors in matrix other_vecs - returns average distance from the rest
	of the vectors

	Paramters
	curr_vec: the vector for which novelty is being found
	other_vecs: all other vectors in the population
	k: the number of distances for which average is being taken
	"""

	# find difference between elements of vector and all other vectors
	# square difference to avoid negative values
	difference = other_vecs - curr_vec
	difference = np.square(difference)

	# find total difference for each vector and grab average of values
	summed_rows = np.sum(difference, axis=1)
	summed_rows = np.reshape(summed_rows, (1, -1))
	sorted_dists = np.sort(summed_rows[0, :])

	# take average of k closest solutions, disclude the first element because it is dist from self
	avg_dist = np.mean(sorted_dists[: k])
	return avg_dist

def get_mechanism_vector(mechanism):
	"""this method creates a charactaristic vector to describe a mechanism
	based on positioning, ratios, and size"""

	# create lists that can be populated with all mechanism data
	x = []
	r = []
	total_gear = len(mechanism)

	# populate all of the lists
	for gear in mechanism:
		x.append(gear.pos[0])
		#z.append(gear.pos[2])
		r.append(gear.radius)

	# convert arrays to np arrays
	x = np.array(x)
	#z = np.array(z)
	r = np.array(r)

	# find the average ratio between each gear
	ratios = np.array([1.0])
	if(len(mechanism) > 1):
		ratios = (r[:-1]/r[1:])

	# construct the vector of items to characterize mechanism
	#vec = np.array([np.mean(x), np.var(x), np.mean(ratios), np.var(ratios), \
	#				np.mean(r), np.var(r), len(mechanism)])
	vec = np.array([np.var(x), np.mean(ratios), np.var(ratios), \
					np.mean(r), np.var(r), len(mechanism)])

	return vec

def get_gear_pos(previous_pos, angle, prev_rad, curr_rad, pos_thresh, output_min, padding=1.0):
	"""this method outputs the position of a single gear based on the position
	of the gear it attaches to and it's angular RNN output
	"""

	# find how much positions should be scaled to get to 2*pi
	total_range = -2.0*(1.0 - pos_thresh) - 2.0*output_min # range is from -pos_thresh to pos thresh for tanh
	scale_factor = 2.0*np.pi/total_range

	# attack to the back of the previous gear
	if(angle > pos_thresh):
		# just increment z dimension
		pos = (previous_pos[0], previous_pos[1], previous_pos[2] + 1)
	# attach to front of previous gear
	elif(angle < -pos_thresh):
		# just decrement z dimension
		pos = (previous_pos[0], previous_pos[1], previous_pos[2] - 1)

	else:
		angle = (angle + pos_thresh)*scale_factor
		distance = curr_rad + prev_rad

		# must handle each quadrant specifically depending on angle
		if(angle <= np.pi/2.0):
			x_change = distance*np.cos(angle)
			y_change = distance*np.sin(angle)
		elif(angle <= np.pi):
			angle = np.pi - angle
			x_change = -distance*np.cos(angle)
			y_change = distance*np.sin(angle)
		elif(angle <= 1.5*np.pi):
			angle = angle - np.pi
			x_change = -distance*np.cos(angle)
			y_change = -distance*np.sin(angle)
		else:
			angle = 2*np.pi - angle
			x_change = distance*np.cos(angle)
			y_change = -distance*np.sin(angle)

		# update the position with change in x and y relative to last pos
		pos = (previous_pos[0] + x_change, previous_pos[1] + y_change, previous_pos[2])

		# add space between gear centers in x-y dimensions if padding set to true
		# makes 3D printing easier by separating gears more
		pos = (pos[0]*padding, pos[1]*padding, pos[2])

	return pos

def get_gear_pos_linear(previous_pos, angle, prev_rad, curr_rad, pos_thresh, output_min, padding=1.0):
	"""this method outputs the position of a single gear based on the position
	of the gear it attaches to and it's angular RNN output - instead of placing at any
	angle around previous gear, this method places it linearly to the right of previous
	gear or fixes it to front or back

	return: a tuple (x, y, z) that gives position of gear
	"""

	# attack to the back of the previous gear
	if(angle > pos_thresh):
		# just increment z dimension
		pos = (previous_pos[0], previous_pos[1], previous_pos[2] + 1)
	# attach to front of previous gear
	elif(angle < -pos_thresh):
		# just decrement z dimension
		pos = (previous_pos[0], previous_pos[1], previous_pos[2] - 1)
	# place gear to the right of previous
	else:
		x_delta = curr_rad + prev_rad
		# update the position with change in x and y relative to last pos
		pos = ((previous_pos[0] + x_delta)*padding, previous_pos[1], previous_pos[2])

	return pos

def check_bounding_box(ind, x_bound, y_bound):
	"""finds the total amount of gears that lie out of the desired boudning
	box for gear system and adds all x and y distances outside of the desired
	bounding box

	:param ind: list of gears contained in the mechanism
	:param x_bound: maximum allowed length of the mechanism
	"""

	# find lowest allowed x and y values
	lower_x = ind[0].pos[0] - ind[0].radius
	upper_x = ind[0].pos[0] + x_bound

	# only check individuals after the first
	total_outside = 0.0
	for g in ind[1: ]:
		# find the amount the gear lies out of x bound
		x = g.pos[0]
		r = g.radius
		if((x - r)  < lower_x):
			total_outside += np.square((x - r) - lower_x)
		elif(x > upper_x):
			total_outside += np.square(x - upper_x)

		"""
		y = g.pos[1]
		if((y - r) < lower_y):
			total_outside += np.square((y - r) - lower_y)
		elif((y + r) > y_bound):
			total_outside += np.square((y + r) - y_bound)
		"""
	return total_outside

def dominates(ind1, ind2):
	"""outputs true if ind1 dominates ind2, false o/w"""

	# get fitness vectors for each individual
	one_fit = ind1.fitness.values
	two_fit = ind2.fitness.values

	# feasible solutions dominate infeasible solutions
	if(one_fit[2] <= 0 and two_fit[2] > 0):
		return True

	# if both infeasible dominates if CV is less than other
	# if CV less than other, other must be nonzero!
	elif(one_fit[2] < two_fit[2]):
		return True

	# if both feasible check for traditional domination
	elif(one_fit[2] <= 0 and two_fit[2] <= 0):
		# minimize hidden nodes and maximize novelty
		if(one_fit[0] > two_fit[0] and one_fit[1] < two_fit[1]):
			return True

	# only reaches this point if doesn't dominate
	return False

def get_crowding_distance(ind1, ind2):
	"""finds the crowding distance between two individuals
	based on the first two values in fitness vector"""

	crowd_dist = 0.0
	crowd_dist += np.square(ind1.fitness.values[0] - ind2.fitness.values[0])
	crowd_dist += np.square(ind1.fitness.values[1] - ind2.fitness.values[1])
	return crowd_dist

def get_3DP_layout(mechanism, bed_width, padding_ratio):
	"""takes a list of gears (mechanism) and alters the positions of the gears
	to be placed into a grid for easy 3D printing

	bed_width: size of the 3D printing bed, used to configure how the gears are
	laid out in a grid to fit on the 3D printer
	padding_ratio: the amount to multiply the distance between gears by to create
	enough padding between them to 3D print

	return: both old and newly positioned mechanism lists
	"""

	# create a deepcopy of the original mechanism to return
	og_mech = deepcopy(mechanism)

	# find maximum radius of all gears
	max_r = max(mechanism, key=lambda g: g.radius).radius

	ind = 1
	x = padding_ratio*mechanism[ind - 1].radius
	y = padding_ratio*max_r
	# update position to new 3DP position
	mechanism[ind - 1].pos = (x, y, 0)
	# place each gear from mechanism into a grid
	while(ind < len(mechanism)):
		curr_rad = mechanism[ind].radius
		prev_rad = mechanism[ind - 1].radius
		x_delta = padding_ratio*(curr_rad + prev_rad)

		# continue adding gear in current row
		if((x_delta + x + curr_rad) < bed_width):
			x += x_delta
			mechanism[ind].pos = (x, y, 0)
		# create new row for gears
		else:
			x = padding_ratio*mechanism[ind].radius
			y += padding_ratio*2*max_r
			mechanism[ind].pos = (x, y, 0)
		ind += 1

	return (mechanism, og_mech)

def get_mech_and_vec(ind, rnn, num_in, num_out, num_unique_gears, max_gears, min_gears, stop_threshold,
		radius_scale, act_exp, placement_thresh, gear_radii, output_min, verbose=False):
	"""takes in a set of weights, uses it to activate and rnn and returns the
	outputs, mechanism, and vector for that set of weights"""

	# get rnn output with weights from ind
	w1, w1_bias, w2, w2_bias = list_to_matrices(ind, num_in, ind.h_nodes, num_out)
	rnn = inject_weights(rnn, w1, w1_bias, w2, w2_bias)
	output = get_discrete_gear_mechanism(rnn, num_unique_gears, max_gears, min_gears, stop_threshold, \
				radius_scale, act_exp, placement_thresh, 'one', verbose=verbose)

	# generate vector and mechanism representation for rnn output
	mech = create_discrete_mechanism(output, gear_radii, placement_thresh, output_min)
	vec = get_mechanism_vector(mech)

	return (output, mech, vec)

def eval_useless_gears(mech):
	"""determines the number of useless coaxial gears that were used in the
	mechanism - this could be 3 or coaxial gears in a row, a coaxial gear at
	the end of the mechanism, or a system of gears all at the origin"""

	CV = 0.0
	# check if all gears are coaxial at origin
	if(np.var(np.array([g.pos[0] for g in mech])) == 0.0):
		CV += len(mech) - 1

	# check if there are 3 coaxial gear in a row
	index = 2
	while(index < len(mech)):
		if(mech[index].pos[0] == mech[index - 1].pos[0] and \
				mech[index].pos[0] == mech[index - 2].pos[0]):
			CV += 1
		index += 1

	# check if there are multiple coaxial gears on output beam
	if(len(mech) > 1 and mech[0].pos[0] == mech[1].pos[0]):
		CV += 1

	# check if an extra coaxial gear is added at end for no reason
	if(len(mech) > 1 and mech[-1].pos[0] == mech[-2].pos[0]):
		CV += 1

	# check if there are any coaxial gears of the same size
	for first_g, sec_g in zip(mech[:], mech[1:]):
		if(first_g.radius == sec_g.radius and first_g.pos[2] != sec_g.pos[2]):
			CV += 1

	return CV

def gen_openSCAD_beams(mech, gear_dists, hole_r, slot_len, slot_ht, slot_t, dist_from_cent, init_offset, slot_hole_len, slot_hole_ht):
	"""generates SCAD commands for the locations of the holes for slots
	within the insert that will be used to hold beams within the 3D printed
	car"""

	# return result as a large string containing all CAD commands
	commands = "difference(){\n"

	# add commands for the actual slot fillers
	commands += "union(){\n"
	commands += f"translate([{dist_from_cent}, 0, 0])cube([{slot_len}, {slot_ht}, {slot_t}]);\n"
	commands += f"translate([{dist_from_cent - slot_hole_len}, 0, 0])cube([{slot_len + 2*slot_hole_len}, {slot_hole_ht}, {slot_t}]);\n"
	commands += "}\n"

	hole = f"cylinder(10, {hole_r}, {hole_r}, $fn=20);"
	pos = dist_from_cent + init_offset

	# go through each gear and add command for its beam hole in slot
	index = 0
	while(index < len(mech)):
		commands += f"translate([{pos}, 0, -1]){hole}\n"
		# find the distance between beam holes for this hole and the next
		if(index < len(mech) - 1):
			gear_one = min(mech[index].radius, mech[index + 1].radius)
			gear_two = max(mech[index].radius, mech[index + 1].radius)
			# check if gears are coaxial
			if(mech[index].pos[0] != mech[index + 1].pos[0]):
				pos_delta = gear_dists[(gear_one, gear_two)]
			else:
				pos_delta = 0
			pos += pos_delta
		index += 1
	commands += "}\n"
	return commands

if __name__ == '__main__':
	""" main function for quick tests"""

	get_gear_pos(None, None, .75, -1)


import unittest
import json
import indx
import datetime as dt

with open('testdata.json', 'r') as f:
    test_data = json.load(f)

class TestIndxFns(unittest.TestCase):

    def test_prep_data(self):
        test_dates = [dt.date(*i) for i in
                      [(2015, 1, 1),
                      (2015, 3, 14),
                      (2016, 11, 7),
                      (2016, 8, 9)]]

        for date in test_dates:
            funds = sum([int(project['raised_fx']['GBP'])
                         for project in test_data
                         if project['end_time'] == str(date)
                         and project['status'][0] == 's'])
            ind = (date - test_dates[0]).days
            self.assertEqual(funds, indx.prep_data(
                test_data, dt.date(2015, 1, 1), dt.date(2016, 12, 31))[0][ind])

    def test_index(self):
        start_date = dt.date(2015, 7, 2)
        end_date = dt.date(2016, 10, 1)
        n_days = (end_date - start_date).days
        data = indx.prep_data(test_data, dt.date(2015, 1, 1),
                              dt.date(2016, 12, 31))
        index_should = sum([int(project['raised_fx']['GBP'])
                           for project in test_data
                           if dt.datetime.strptime(
                            project['end_time'], '%Y-%m-%d').date()
                            >= start_date
                           and dt.datetime.strptime(
                            project['end_time'], '%Y-%m-%d').date()
                            < end_date
                           and project['status'][0] == 's'])
        self.assertEqual(index_should,
                         indx.index(data, end_date, n_days))

    def test_index_over_time(self):
        data = indx.prep_data(test_data, dt.date(2015, 1, 1),
                              dt.date(2016, 12, 31))
        iot = indx.index_over_time(data, dt.date(2015, 3, 12),
                                   dt.date(2015, 5, 20), 3)
        iot_should = indx.index(data, dt.date(2015, 3, 18), 3)
        self.assertEqual(iot[0][2], iot_should)

if __name__ == '__main__':
    unittest.main()


class Solution:
    def rotate(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        length = len(nums)
        k %= length;
        # 时间复杂度: O(N*K)，空间复杂度: O(1)
        # if k != 0:
        #     for i in range(k):
        #         pre = nums[length-1]
        #         for j in range(length):
        #             tmp = nums[j]
        #             nums[j] = pre
        #             pre = tmp

        # 时间复杂度: O(N)，空间复杂度: O(1)
        if k != 0:
            self.reverse(nums, 0, length - 1)
            self.reverse(nums, 0, k - 1)
            self.reverse(nums, k, length - 1)

    def reverse(self, nums, start, end):
        while start < end:
            tmp = nums[start]
            nums[start] = nums[end]
            nums[end] = tmp
            start += 1
            end -= 1


from pysot.models.backbone import PeleeNet7a
import torch

# converted_model_file = '../../pretrained_models/peleenet21a_tracking.pth'
# state_dict = torch.load('../../pretrained_models/peleenet21a.pth')
state_dict = torch.load('/home/rwang/workspace/PeleeNetV2/weights/pnet17v1_7387_cpu.pth.tar')['state_dict']
converted_model_file = '../pretrained_models/peleenet17a_tracking.pth'

model = PeleeNet7a()
t = {k:v for k,v in state_dict.items() if k in model.state_dict()}
model.load_state_dict(t)
torch.save(model.state_dict(), converted_model_file)


import math

def circleArea(r):
    if r <= 0:
        return False
    elif type(r) is str:
        return False
    else:
        answer = math.pi * (float(r) * float(r))
        return round(answer, 2)

'''
if __name__ == '__main__':
    circleArea(-100)
    circleArea(0)
    circleArea("assfgdawd")
    circleArea(123432)
    circleArea(123456.4567)
'''


import librosa
import os
import numpy as np

path = "./"
items = 0
solves = []

def formatSol(id):
  tmp = [0,0,0,0]
  if id > 4:
    raise ValueError ("Wrong label!")
  else:
    tmp[id - 1] += 1
  solves.append(tmp)

with open(path + "music/solve.txt", "r") as indiv:
  for each in indiv:
    tmp = False
    solId = 0
    point = 0
    for i in each:
      if i == " " or i == "\n":
        pass
      elif i == ":":
        tmp = True
      elif tmp:
        solId *= 10
        solId += int(i)
      else:
        point *= 10
        point += int(i)
    formatSol(solId)

mfccdata = []

def setmfcc(id):
  audiopath = path + "music/" + str(id) + ".mp3"
  audio, sr = librosa.load(audiopath)
  mfccdata.append(librosa.feature.mfcc(audio))

for i in range(300):
  setmfcc(i + 1)
  print(i + 1)

resq = open(path + "res-q.txt", "w")
for each in mfccdata:
  resq.writelines(np.array_str(each) + "\n")
resq.close()

print(mfccdata[0].shape)


import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
import logging
import json

from singular_api_client.helpers import CohortMetric, SkanEventsResponse, SkanEvent
from .params import Format, Dimensions, DiscrepancyMetrics, TimeBreakdown, CountryCodeFormat, Metrics
from .exceptions import ArgumentValidationException, APIException, UnexpectedAPIException
from .helpers import ReportStatusResponse, CustomDimension, CohortMetricsResponse, \
    DataAvailabilityResponse
from .version import __version__

logger = logging.getLogger("singular_client")

class SingularClient(object):
    """
    Client for Singular Reporting API
    See:
        - https://github.com/singular-labs/singular_api_client
        - https://developers.singular.net/v2.0/reference
    """
    BASE_API_URL = "https://api.singular.net/api/"
    DEFAULT_HTTP_TIMEOUT = 60 * 5

    def __init__(self, api_key, http_timeout=DEFAULT_HTTP_TIMEOUT, user_agent='Singular API Client v%s' % __version__):
        self.api_key = api_key
        self.user_agent = user_agent
        session = requests.Session()
        retry = Retry(
            connect=5,
            backoff_factor=0.5,
            status_forcelist=(500, 502, 503, 504),
            method_whitelist=('GET', 'POST')
        )
        adapter = HTTPAdapter(max_retries=retry)
        session.mount('http://', adapter)
        session.mount('https://', adapter)
        self.default_http_timeout = http_timeout
        self.session = session

    def create_async_report(self, start_date, end_date,
                            format=Format.JSON,
                            dimensions=(Dimensions.APP, Dimensions.OS, Dimensions.SOURCE),
                            metrics=(Metrics.ADN_COST, Metrics.ADN_IMPRESSIONS),
                            discrepancy_metrics=(DiscrepancyMetrics.ADN_CLICKS, DiscrepancyMetrics.ADN_INSTALLS),
                            cohort_metrics=None,
                            cohort_periods=None,
                            source=None,
                            app=None,
                            display_alignment=True,
                            time_breakdown=TimeBreakdown.ALL,
                            country_code_format=CountryCodeFormat.ISO3,
                            filters=None,
                            **kwargs
                            ):
        """
        Use this endpoint to run custom queries in the Singular platform for aggregated statistics without keeping
         a live connection throughout the request

        :param start_date: "YYYY-mm-dd" format date
        :param end_date: "YYYY-mm-dd" format date
        :param format: Format for returned results, for example Format.CSV
        :param dimensions: A list of dimensions, for example [Dimensions.APP, Dimensions.Source]
        :param metrics: A list of metrics, for example [Metrics.ADN_IMPRESSIONS, Metrics.ADN_COST]
        :param discrepancy_metrics: List of metrics that may help detect discrepancies between Ad Networks
         and Attribution providers, for example [DiscrepancyMetrics.ADN_CLICKS, DiscrepancyMetrics.ADN_INSTALLS]
        :param cohort_metrics: list of cohorted metrics by name or ID; A full list can be retrieved through
         the Cohorted Metrics endpoint
        :param cohort_periods: list of cohorted periods; A full list can be retrieved through the Cohorted Metrics
          endpoint
        :param source: optional list of source names to filter by
        :param app: optional list of app names to filter by
        :param display_alignment: When set to True, results will include an alignment row to account for any difference
         between campaign and creative statistics
        :param time_breakdown: Break results by the requested time period, for example TimeBreakdown.DAY
        :param country_code_format: Country code formatting option, for example CountryCodeFormat.ISO3
        :param filters: a JSON encoded list of filters. Can be used to apply more complex filters than simply filtering
          by app or source. The relation between different elements of the list is an AND relation.
          A full list of the dimensions you can filter by and potential values can be retrieved from the
          `get_reporting_filters` endpoint.
        :return: report_id
        """

        query_dict = self._build_reporting_query(start_date, end_date, format, dimensions, metrics,
                                                 discrepancy_metrics, cohort_metrics, cohort_periods, app,
                                                 source, display_alignment, time_breakdown, country_code_format,
                                                 filters, **kwargs)

        response = self._api_post("v2.0/create_async_report", data=query_dict)
        parsed_response = response.json()
        return parsed_response["value"]["report_id"]

    def create_async_skadnetwork_raw_report(self, start_date, end_date,
                                            format=Format.JSON,
                                            dimensions=(Dimensions.APP, Dimensions.SOURCE,
                                                        Dimensions.SKAN_CAMPAIGN_ID, Dimensions.SKAN_CONVERSION_VALUE),
                                            metrics=(Metrics.SKAN_INSTALLS,),
                                            source=None,
                                            app=None,
                                            time_breakdown=TimeBreakdown.ALL,
                                            country_code_format=CountryCodeFormat.ISO3,
                                            filters=None,
                                            skadnetwork_date_type=None,
                                            **kwargs
                                            ):
        """
        Use this endpoint to run custom queries in the Singular platform for aggregated skadnetwork raw data without
         keeping a live connection throughout the request

        :param start_date: "YYYY-mm-dd" format date
        :param end_date: "YYYY-mm-dd" format date
        :param format: Format for returned results, for example Format.CSV
        :param dimensions: A list of dimensions, for example [Dimensions.APP, Dimensions.Source, Dimensions.SKAN_CAMPAIGN_ID]
        :param metrics: A list of metrics, for example [Metrics.SKAN_INSTALLS]
        :param source: optional list of source names to filter by
        :param app: optional list of app names to filter by
        :param time_breakdown: Break results by the requested time period, for example TimeBreakdown.DAY
        :param country_code_format: Country code formatting option, for example CountryCodeFormat.ISO3
        :param filters: a JSON encoded list of filters. Can be used to apply more complex filters than simply filtering
          by app or source. The relation between different elements of the list is an AND relation.
          A full list of the dimensions you can filter by and potential values can be retrieved from the
          `get_reporting_filters` endpoint.
        :param skadnetwork_date_type: the type of date you want the report to be based on:
            - "skan_postback_date" (default) - the date the SKAN postback was sent by the device.
            - "estimated_install_date" - the install date as calculated by
        :return: report_id
        """

        query_dict = self._build_skan_reporting_query(start_date, end_date, format, dimensions, metrics,
                                                      app, source, time_breakdown, country_code_format,
                                                      filters, skadnetwork_date_type, None, **kwargs)

        response = self._api_post("v2.0/create_async_skadnetwork_raw_report", data=query_dict)
        parsed_response = response.json()
        return parsed_response["value"]["report_id"]

    def create_async_skadnetwork_report(self, start_date, end_date,
                                        format=Format.JSON,
                                        dimensions=(Dimensions.APP, Dimensions.SOURCE,
                                                    Dimensions.SKAN_CAMPAIGN_ID, Dimensions.SKAN_CONVERSION_VALUE),
                                        metrics=(Metrics.SKAN_INSTALLS,),
                                        discrepancy_metrics=[],
                                        source=None,
                                        app=None,
                                        time_breakdown=TimeBreakdown.ALL,
                                        country_code_format=CountryCodeFormat.ISO3,
                                        filters=None,
                                        skadnetwork_date_type=None,
                                        skan_events=None,
                                        **kwargs
                                        ):
        """
        Use this endpoint to run custom queries in the Singular platform for aggregated skadnetwork data without
         keeping a live connection throughout the request

        :param start_date: "YYYY-mm-dd" format date
        :param end_date: "YYYY-mm-dd" format date
        :param format: Format for returned results, for example Format.CSV
        :param dimensions: A list of dimensions, for example [Dimensions.APP, Dimensions.Source, Dimensions.SKAN_CAMPAIGN_ID]
        :param metrics: A list of metrics, for example [Metrics.SKAN_INSTALLS]
        :param discrepancy_metrics: List of metrics that may help detect discrepancies between Ad Networks
         and Attribution providers, for example [DiscrepancyMetrics.TRACKER_INSTALLS]
        :param source: optional list of source names to filter by
        :param app: optional list of app names to filter by
        :param time_breakdown: Break results by the requested time period, for example TimeBreakdown.DAY
        :param country_code_format: Country code formatting option, for example CountryCodeFormat.ISO3
        :param filters: a JSON encoded list of filters. Can be used to apply more complex filters than simply filtering
          by app or source. The relation between different elements of the list is an AND relation.
          A full list of the dimensions you can filter by and potential values can be retrieved from the
          `get_reporting_filters` endpoint.
        :param skadnetwork_date_type: the type of date you want the report to be based on:
            - "skan_postback_date" (default) - the date the SKAN postback was sent by the device.
            - "estimated_install_date" - the install date as calculated by
        :param skan_events: list of skan events by name or ID; A full list can be retrieved through
            the Skan Events endpoint
        :return: report_id
        """

        query_dict = self._build_skan_reporting_query(start_date, end_date, format, dimensions, metrics,
                                                      app, source, time_breakdown, country_code_format,
                                                      filters, skadnetwork_date_type, skan_events,
                                                      discrepancy_metrics=discrepancy_metrics,
                                                      **kwargs)

        response = self._api_post("v2.0/create_async_skadnetwork_report", data=query_dict)
        parsed_response = response.json()
        return parsed_response["value"]["report_id"]

    def get_report_status(self, report_id):
        """
        This endpoint returns the status of a given report.
          If a report has failed, an error message is returned. If the report completes, a download url is returned
          together with the status.

        :param report_id: id generated by the create_async_report method
        :return: return the status of the report
        :rtype: ReportStatusResponse
        """
        params = {"report_id": report_id}
        response = self._api_get("v2.0/get_report_status", params=params)
        parsed_response = response.json()
        self._verify_legacy_error(parsed_response)
        return ReportStatusResponse(parsed_response["value"])

    def get_custom_dimensions(self):
        """
        Use this endpoint to return all the custom dimensions configured for your account by name and ID.
          Dimension IDs can then be used in Reporting API queries to group the data using Custom Dimensions

        :return: list of `CustomDimension` instances
        :rtype: list[CustomDimension]
        """
        response = self._api_get("custom_dimensions")
        parsed_response = response.json()
        self._verify_legacy_error(parsed_response)
        return CustomDimension.parse_list(parsed_response["value"]["custom_dimensions"])

    def get_cohort_metrics(self):
        """
        Use this endpoint to return all cohorted metrics and cohort periods configured for your account

        :return: a new `CohortMetricsResponse` instance
        :rtype: CohortMetricsResponse
        """
        response = self._api_get("cohort_metrics")
        parsed_response = response.json()
        self._verify_legacy_error(parsed_response)
        return CohortMetricsResponse(parsed_response["value"])

    def get_skan_events(self):
        """
        Use this endpoint to return all skan events for your account

        :return: a new `SkanEventsResponse` instance
        :rtype: SkanEventsResponse
        """
        response = self._api_get("v2.0/skan_events")
        parsed_response = response.json()
        self._verify_legacy_error(parsed_response)
        return SkanEventsResponse(parsed_response["value"])

    def data_availability_status(self, data_date, format=Format.JSON, display_non_active_sources=False):
        """
        Use this endpoint to determine whether for a given day, data is available for each of your data data sources.
         This data can then be used to determine whether to pull data.

        :param data_date: You can only select a single day. The API will check whether there is data for this day.
            Date format: "YYYY-mm-dd"
        :param format: Format for returned results, for example Format.CSV
        :type format: str
        :param display_non_active_sources: Active source is defined as a source that has data in the last 30 days
        :type display_non_active_sources: bool
        :return: DataAvailabilityResponse if format==Format.JSON, or unicode if format==Format.CSV
        :rtype: DataAvailabilityResponse | unicode
        """

        self._verify_param("format", format, Format)
        query_dict = dict(data_date=data_date, format=format,
                          display_non_active_sources=self._bool(display_non_active_sources))

        response = self._api_get("v2.0/data_availability_status", params=query_dict)
        if format == Format.JSON:
            parsed_response = response.json()
            self._verify_legacy_error(parsed_response)
            return DataAvailabilityResponse(parsed_response["value"])
        elif format == Format.CSV:
            return response.text
        else:
            raise ArgumentValidationException("unsupported format")

    def get_reporting_filters(self):
        """
        This endpoint returns all available filters and their respective available options.
        Please note that filters can differ between users, per the configured.

        example response:
        {
            "dimensions": [
              {
                "name": "os",
                "display_name": "OS",
                "values": [
                    {"name": 4, "display_name": "Android"},
                  {"name": 1, "display_name": "iOS"}
                ],
              },
              {
                "name": "source",
                "display_name": "Source",
                "values": [
                  {"name": "adwords", "display_name": "AdWords"}
                ]
              }
            ]
          }

        :return: dictionary of available filters and their respected values
        :rtype: dict[str, list[dict]]
        """
        response = self._api_get("v2.0/reporting/filters")
        parsed_response = response.json()
        self._verify_legacy_error(parsed_response)
        return parsed_response["value"]

    @staticmethod
    def _bool(value):
        if value:
            return "true"
        else:
            return "false"

    @classmethod
    def _build_reporting_query(cls, start_date, end_date, format, dimensions, metrics, discrepancy_metrics,
                               cohort_metrics, cohort_periods, app, source, display_alignment, time_breakdown,
                               country_code_format, filters, **kwargs):
        """
        build reporting query format that can be used by either the `create_async_report` or `reporting` endpoints
        """
        cls._verify_param("format", format, Format)
        cls._verify_param("time_breakdown", time_breakdown, TimeBreakdown)
        cls._verify_param("country_code_format", country_code_format, CountryCodeFormat)

        if filters is None:
            filters = []

        if (cohort_metrics or cohort_periods) and (not cohort_metrics or not cohort_periods):
            raise ArgumentValidationException("`cohort_metrics` must be used with `cohort_periods`")

        dimensions_request = ",".join(dimensions)
        metrics_request = ",".join(metrics)
        discrepancy_metrics_request = ",".join(discrepancy_metrics)
        query_dict = dict(
            start_date=start_date,
            end_date=end_date,
            dimensions=dimensions_request,
            metrics=metrics_request,
            discrepancy_metrics=discrepancy_metrics_request,
            display_alignment=display_alignment,
            format=format,
            time_breakdown=time_breakdown,
            country_code_format=country_code_format,
        )
        if source is not None:
            if not isinstance(source, list):
                sources = [source]
            else:
                sources = source
            filters.append({"dimension": "source", "operator": "in", "values": sources})
        if app is not None:
            if not isinstance(app, list):
                apps = [app]
            else:
                apps = app
            filters.append({"dimension": "app", "operator": "in", "values": apps})
        if cohort_metrics:
            if isinstance(cohort_metrics, list):
                cohort_metrics = [(i.name if isinstance(i, CohortMetric) else i) for i in cohort_metrics]
                cohort_metrics = ",".join(cohort_metrics)
            query_dict.update({'cohort_metrics': cohort_metrics})
        if cohort_periods:
            if isinstance(cohort_periods, list):
                cohort_periods = ",".join(cohort_periods)
            query_dict.update({'cohort_periods': cohort_periods})
        if filters:
            query_dict["filters"] = json.dumps(filters)

        query_dict.update(kwargs)
        return query_dict

    @classmethod
    def _build_skan_reporting_query(cls, start_date, end_date, format, dimensions, metrics, app, source, time_breakdown,
                                    country_code_format, filters, skadnetwork_date_type, skan_events,
                                    discrepancy_metrics=[],
                                    **kwargs):
        query_dict = cls._build_reporting_query(start_date, end_date, format, dimensions, metrics, discrepancy_metrics,
                                                None, None, app, source, None, time_breakdown,
                                                country_code_format, filters, **kwargs)

        if skadnetwork_date_type:
            query_dict.update({'skadnetwork_date_type': skadnetwork_date_type})
        if skan_events:
            if isinstance(skan_events, list):
                skan_events = [(event.name if isinstance(event, SkanEvent) else event) for event in skan_events]
                skan_events = ",".join(skan_events)
            query_dict.update({'skan_events': skan_events})

        return query_dict

    @staticmethod
    def _verify_param(param_name, value, base_class):
        expected_values = base_class.__ALL_OPTIONS__
        if value not in expected_values:
            raise ArgumentValidationException("unexpected %s value %s, expected one of %s" %
                                              (param_name, repr(value), repr(expected_values)))

    @staticmethod
    def _verify_legacy_error(parsed_response):
        if parsed_response["status"] != 0:
            raise APIException("API request failed: %s" % parsed_response["value"])

    def _api_get(self, endpoint, params=None):
        return self._api_request("GET", endpoint, params=params)

    def _api_post(self, endpoint, data=None, json=None):
        return self._api_request("POST", endpoint, data=data, json=json)

    def _api_request(self, method, endpoint, **kwargs):
        url = self.BASE_API_URL + endpoint
        headers = {"Authorization": self.api_key,
                   'User-Agent': self.user_agent}

        response = self.session.request(method, url,
                                        headers=headers,
                                        timeout=self.default_http_timeout,
                                        **kwargs)

        logger.info("%(method)s %(url)s, kwargs = %(kwargs)s --> code = %(code)s" %
                    dict(method=method, url=url, kwargs=repr(kwargs), code=response.status_code))

        if not response.ok:
            if response.status_code is None or response.status_code >= 500 < 600:
                raise UnexpectedAPIException("%s failed with code = %s, payload = %s" % (
                    endpoint, response.status_code, response.text))
            else:
                raise APIException("%s failed with code = %s, payload = %s" % (
                    endpoint, response.status_code, response.text))

        return response


import cv2
import numpy as np
import matplotlib.pyplot as plt
import glob
import os

data_dir = 'D:\\img'
all_image_data_path = sorted(glob.glob(os.path.join(data_dir,"*")))
total_data = list(all_image_data_path)
data_length = len(total_data)
print(data_length)
for i in range(1, 65, 4):
    img1 = cv2.imread(total_data[i], 1)
    img2 = cv2.imread(total_data[i+1], 1)
    img3 = cv2.imread(total_data[i+2], 1)
    img4 = cv2.imread(total_data[i+3], 1)

    img1 = cv2.resize(img1, (480,282))
    img2 = cv2.resize(img2, (480,282))
    img3 = cv2.resize(img3, (480,282))
    img4 = cv2.resize(img4, (480,282))

    addh1 = cv2.hconcat([img1, img2])
    addh2 = cv2.hconcat([img3, img4])
    addv = cv2.vconcat([addh1, addh2])

    cv2.imwrite('D:/img/{}.jpg'.format(i), addv)
    i = 4*i+1

    # cv2.imshow('imgv',addv)
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()


from apps.clients import client_login
from django.db import connection
from django.core.cache import cache
from apps.dashboard import dictfetchall
from django.shortcuts import render_to_response
from django.template import RequestContext, loader, Context
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.db.models import Q
from django.db import IntegrityError
from django.contrib import messages
from django.contrib.auth import authenticate, login as auth_login, logout as logout_login
from forms import MailCreateForm, SMSCreateForm, SmileForm
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_protect
from django.forms.models import modelformset_factory, formset_factory
from custom_user.models import EmailUser
from apps.ladies.models import Lady
from apps.clients.models import Client
from apps.mails.models import Mail
from . import sendMail
from apps.dashboard.forms import EmailUserForm
from apps.dashboard import custom_pagination
from django.core.exceptions import PermissionDenied
from apps.workers import get_groups
from apps.dashboard.middleware.http import Http403
from apps.workers.models import Worker
import datetime
import json

@client_login
def send_mail(request):
    form = MailCreateForm(request.POST or None)
    to = request.GET.get('to', '')
    subject = request.POST.get('subject', '')
    content = request.POST.get('content', '')
    payment = request.GET.get('payment', '')
    client = get_object_or_404(Client, user=request.user)

    try:
        lady = Lady.objects.get(pk=to)
    except Exception:
        lady = None

    if request.method == 'POST':
        if form.is_valid():
            if lady is not None:
                if payment == 'free':
                    result = sendMail(subject=subject, content=content, fr=client, to=lady, free=True)
                else:
                    result = sendMail(subject=subject, content=content, fr=client, to=lady)
                message = result['message']
                messages.add_message(request, messages.SUCCESS, message)
                return HttpResponseRedirect('/ladies')
            else:
                message = 'Lady error!'
                messages.add_message(request, messages.ERROR, message)

    return render_to_response('send_mail.html', locals(), context_instance=RequestContext(request))

@client_login
def send_smile(request):
    to = request.GET.get('to', '')
    client = get_object_or_404(Client, user=request.user)
    subject = 'Smile'
    form = SmileForm(request.POST or None)

    try:
        lady = Lady.objects.get(pk=to)
    except Exception:
        lady = None
    if request.method == 'POST':
        if form.is_valid():
            if lady is not None:
                smile = request.POST.get('smile', '')
                content = '

' % (smile, smile,)
                new_message = Mail(subject=subject, fr=client.id, to=to, content=content, type='smile', type_send='client')
                new_message.save()
                message = 'Smile send!'
                messages.add_message(request, messages.SUCCESS, message)
                return HttpResponseRedirect('/ladies')
            else:
                message = 'Lady error!'
                messages.add_message(request, messages.ERROR, message)

    return render_to_response('send_smile.html', locals(), context_instance=RequestContext(request))

@client_login
def send_sms(request):
    form = SMSCreateForm(request.POST or None)
    subject = 'SMS'
    to = request.GET.get('to', '')
    content = request.POST.get('content', '')
    client = get_object_or_404(Client, user=request.user)

    try:
        lady = Lady.objects.get(pk=to)
    except Exception:
        lady = None

    if request.method == 'POST':
        if form.is_valid():
            if lady is not None:
                new_sms = Mail(subject=subject, fr=client.id, to=to, content=content, type='sms', type_send='client')
                if client.sms_credits < 1:
                    new_sms.active = False
                    new_sms.save()
                    message = 'Error! Not SMS credits'
                    messages.add_message(request, messages.ERROR, message)
                else:
                    client.sms_credits -= 1
                    client.save()
                    new_sms.active = True
                    new_sms.save()
                    message = 'SMS send'
                    messages.add_message(request, messages.ERROR, message)
                    return HttpResponseRedirect('/ladies')
            else:
                message = 'Lady error!'
                messages.add_message(request, messages.ERROR, message)

    return render_to_response('send_sms.html', locals(), context_instance=RequestContext(request))

@client_login
@csrf_protect
def load_inbox(request):
    data = dict()
    if request.is_ajax():
        client_id = int(request.POST.get('client_id', 0))
        count_to_page = int(request.POST.get('per_page', 15))
        page = int(request.POST.get('page', 1))
        sort = int(request.POST.get('sort', 1))
        type_load = str(request.POST.get('type', 'inbox'))

        if client_id:
            if sort == 1:
                sort_q = 'ORDER BY `date_send` DESC'
            elif sort == 2:
                sort_q = 'ORDER BY `first_name` ASC'
            elif sort == 3:
                sort_q = 'ORDER BY `ladies_id` ASC'
            else:
                sort_q = 'ORDER BY `birthday` ASC'

            if type_load == 'inbox':
                try:
                    with connection.cursor() as c:
                        c.execute('''SELECT `mails`.`id`, `ladies`.`id` AS `ladies_id`, `subject`, `fr`, `date_send`, `date_open`, `type`, `type_send`, `attachment`, `first_name`, `last_name`, `image_lady` FROM `mails` INNER JOIN `ladies` ON `mails`.`fr` = `ladies`.`id` WHERE `mails`.`active`=1 AND `to`=%s %s LIMIT %s OFFSET %s;''' % (str(client_id), sort_q, str(count_to_page), str((page-1)*count_to_page)))
                        mails = dictfetchall(c)
                    with connection.cursor() as k:
                        k.execute('''SELECT COUNT(`id`) FROM `mails` WHERE `active`=1 AND `to`=%s;''' % str(client_id))
                        count_mails = k.fetchone()[0]
                except Exception:
                    count_mails = 0
                    mails = None
            else:
                try:
                    with connection.cursor() as c:
                        c.execute('''SELECT `mails`.`id`, `ladies`.`id` AS `ladies_id`, `subject`, `fr`, `date_send`, `date_open`, `type`, `attachment`, `first_name`, `last_name`, `image_lady` FROM `mails` INNER JOIN `ladies` ON `mails`.`to` = `ladies`.`id` WHERE `mails`.`active`=1 AND `fr`=%s %s LIMIT %s OFFSET %s;''' % (str(client_id), sort_q, str(count_to_page), str((page-1)*count_to_page)))
                        mails = dictfetchall(c)
                    with connection.cursor() as k:
                        k.execute('''SELECT COUNT(`id`) FROM `mails` WHERE `active`=1 AND `fr`=%s;''' % str(client_id))
                        count_mails = k.fetchone()[0]
                except Exception:
                    count_mails = 0
                    mails = None

            if mails:
                for item in mails:
                    item['name'] = u'%s %s.' % (item['first_name'], item['last_name'][0])
                    item['date_send'] = item['date_send'].isoformat()
                    try:
                        item['date_open'] = item['date_open'].isoformat()
                    except AttributeError:
                        item['date_open'] = None

                if count_mails > count_to_page:
                    paginations_data = custom_pagination(page, count_mails, count_to_page)
                else:
                    paginations_data = []

                per_page_list = []
                if count_mails > 15:
                    per_page_list = [15]
                    if count_mails > 25:
                        per_page_list = [15, 25]
                    elif count_mails > 50:
                        per_page_list = [15, 25, 50]
                    elif count_mails > 100:
                        per_page_list = [15, 25, 50, 100]

                data = {'status': True, 'mails': mails, 'paginations_data': paginations_data, 'count_mails': count_mails, 'per_page_list': per_page_list}

    return HttpResponse(json.dumps(data), content_type="application/json")