from django import template

register = template.Library()

#background: -webkit-gradient(linear, 0% 0%, 0% 100%, from({{ COLOR_H1_BACK_STOP }}), to({{ COLOR_H1_BACK_START }}));
#background: -webkit-linear-gradient(top, {{ COLOR_H1_BACK_START }}, {{ COLOR_H1_BACK_STOP }});
#background: -moz-linear-gradient(top, {{ COLOR_H1_BACK_START }}, {{ COLOR_H1_BACK_STOP }});
#background: -ms-linear-gradient(top, {{ COLOR_H1_BACK_START }}, {{ COLOR_H1_BACK_STOP }});
#background: -o-linear-gradient(top, {{ COLOR_H1_BACK_START }}, {{ COLOR_H1_BACK_STOP }});

@register.simple_tag
def columned(num):
    S='-moz-column-count:'+str(num)+';\n'
    S+='-webkit-column-count:'+str(num)+';\n'
    S+='column-count:'+str(num)+';'
    return S

#def background_gradient(style,start,stop):
#    gradient='linear-gradient('+style+','+start+','+stop+')'
@register.simple_tag
def background_gradient(style,*args):
    colors=",".join(args);
    gradient='linear-gradient('+style+','+colors+')'
    S='background: '+gradient+';\n'
    # inverso rispetto agli altri, questo per style=top, cambiare se serve altro
    #S+='background: -webkit-gradient(linear, 0% 0%, 0% 100%, from('+stop+'), to('+start+'));'
    for i in ["webkit","moz","ms","o"]:
        S+='background: -'+i+'-'+gradient+';\n'
    return S

@register.simple_tag
def border_radius(radius):
    S='border-radius: '+radius+';'
    for i in ["webkit","moz"]:
        S+='\n-'+i+'-border-radius: '+radius+';'
    return S

@register.simple_tag
def box_shadow(shadow):
    S='box-shadow: '+shadow+';'
    for i in ["webkit","moz"]:
        S+='\n-'+i+'-box-shadow: '+shadow+';'
    return S

@register.simple_tag
def border_radius_pos(pos,radius):
    S=''
    if pos in ["top","left","top-left"]:
        S+='border-top-left-radius: '+radius+';\n'
        S+='-moz-border-radius-topleft: '+radius+';\n'
        S+='-webkit-bordertop-left-radius: '+radius+';\n'
    if pos in ["top","right","top-right"]:
        S+='border-top-right-radius: '+radius+';\n'
        S+='-moz-border-radius-topright: '+radius+';\n'
        S+='-webkit-bordertop-right-radius: '+radius+';\n'
    if pos in ["bottom","left","bottom-left"]:
        S+='border-bottom-left-radius: '+radius+';\n'
        S+='-moz-border-radius-bottomleft: '+radius+';\n'
        S+='-webkit-borderbottom-left-radius: '+radius+';\n'
    if pos in ["bottom","right","bottom-right"]:
        S+='border-bottom-right-radius: '+radius+';\n'
        S+='-moz-border-radius-bottomright: '+radius+';\n'
        S+='-webkit-borderbottom-right-radius: '+radius+';\n'
    return S

@register.simple_tag
def text_rotation(degree):
    S='transform: rotate('+degree+'deg);'
    for i in ["webkit","ms"]:
        S+='\n-'+i+'-transform: rotate('+degree+'deg);'
    return S

@register.simple_tag
def icon_file_manager_levels(levels,step):
    levels=int(levels)
    step=float(step)
    S=""
    S+=", ".join(map(lambda x: ".iconlevel"+unicode(x),range(0,levels)))
    S+=" {\n"
    S+="vertical-align: bottom;\n"
    S+="font-size: 1.1em;\n"
    S+="}\n\n"
    for n in range(1,levels):
        S+=".iconlevel"+unicode(n)+" {\n"
        S+="padding-left: %2.2fem;\n" % (n*step)
        S+="}\n\n"
    return S


import torch
import numpy as np

class KBinsDiscretizer:
    # simplified and modified version of KBinsDiscretizer from sklearn, see:
    # https://github.com/scikit-learn/scikit-learn/blob/7e1e6d09b/sklearn/preprocessing/_discretization.py#L21
    def __init__(self, dataset, num_bins=100, strategy="uniform"):
        self.strategy = strategy
        self.n_bins = num_bins
        self.feature_dim = dataset.shape[-1]

        # compute edges for binning
        self.bin_edges = self.__find_bin_edges(dataset)  # [feature_dim, num_bins]
        self.bin_centers = (self.bin_edges[:, 1:] + self.bin_edges[:, :-1]) * 0.5

        # for beam search, to be in the same device (for speed)
        self.bin_centers_torch = torch.from_numpy(self.bin_centers)

    def __find_bin_edges(self, X):
        if self.strategy == "uniform":
            mins, maxs = X.min(axis=0), X.max(axis=0)
            bin_edges = np.linspace(mins, maxs, self.n_bins + 1).T
        elif self.strategy == "quantile":
            quantiles = np.linspace(0, 100, self.n_bins + 1)
            bin_edges = np.percentile(X, quantiles, axis=0).T
        else:
            raise RuntimeError("Unknown strategy, should be uniform or quatile.")

        return bin_edges

    def encode(self, X, subslice=None):
        if X.ndim == 1:
            X = X[None]

        if subslice is None:
            bin_edges = self.bin_edges
        else:
            start, end = subslice
            bin_edges = self.bin_edges[start:end]

        # See documentation of numpy.isclose for an explanation of ``rtol`` and ``atol``.
        rtol = 1.0e-5
        atol = 1.0e-8

        Xt = np.zeros_like(X, dtype=np.long)
        for jj in range(X.shape[1]):
            # Values which are close to a bin edge are susceptible to numeric
            # instability. Add eps to X so these values are binned correctly
            # with respect to their decimal truncation.
            eps = atol + rtol * np.abs(X[:, jj])
            Xt[:, jj] = np.digitize(X[:, jj] + eps, bin_edges[jj][1:])

        np.clip(Xt, 0, self.n_bins - 1, out=Xt)

        return Xt

    def decode(self, Xt, subslice=None):
        if Xt.ndim == 1:
            Xt = Xt[None]

        if subslice is None:
            bin_centers = self.bin_centers
        else:
            start, end = subslice
            bin_centers = self.bin_centers[start:end]

        X = np.zeros_like(Xt, dtype=np.float64)
        for jj in range(Xt.shape[1]):
            X[:, jj] = bin_centers[jj, np.int_(Xt[:, jj])]

        return X

    def expectation(self, probs, subslice=None):
        if probs.ndim == 1:
            probs = probs[None]

        # probs: [batch_size, num_dims, num_bins]
        # bins: [1, num_dims, num_bins]
        if torch.is_tensor(probs):
            bin_centers = self.bin_centers_torch.unsqueeze(0)
        else:
            bin_centers = self.bin_centers.unsqueeze(0)

        if subslice is not None:
            start, end = subslice
            bin_centers = bin_centers[:, start:end]

        assert probs.shape[1:] == bin_centers.shape[1:]

        # expectation: [batch_size, num_dims]
        exp = (probs * bin_centers).sum(axis=-1)

        return exp

    def to(self, device):
        self.bin_centers_torch = self.bin_centers_torch.to(device)

    def eval(self):
        return self


# -*- coding: utf-8 -*- #
'''
--------------------------------------------------------------------------
# File Name:        PATH_ROOT/train.py
# Author:           JunJie Ren
# Version:          v1.0
# Created:          2021/06/14
# Description:      — — — — — — — — — — — — — — — — — — — — — — — — — — —
                            --> DD信号识别（可解释）系列代码 <--
                    -- 训练主程序，移植之前信号识别tensorflow代码至PyTorch，
                    并进行项目工程化处理
                    -- TODO train()部分代码需要模块化，特别是指标记录、数据集
                    方面
                    — — — — — — — — — — — — — — — — — — — — — — — — — — —
# Module called:    <0> PATH_ROOT/configs.py
                    <1> PATH_ROOT/dataset/RML2016.py
                    <2> PATH_ROOT/networks/MsmcNet.py
                    <3> PATH_ROOT/utils/strategy.py;plot.py
                    <4> PATH_ROOT/dataset/ACARS.py
                    — — — — — — — — — — — — — — — — — — — — — — — — — — —
# Function List:    <0> train():
                        -- 训练主程序，包含了学习率调整、log记录、收敛曲线绘制
                        ，每训练n(1)轮验证一次，保留验证集上性能最好的模型
                    <1> eval():
                        -- 验证当前训练模型在测试集中的性能
                    — — — — — — — — — — — — — — — — — — — — — — — — — — —
# Class List:       None
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# History:
       |  <author>  | <version> |   <time>   |          <desc>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   <0> | JunJie Ren |   v1.0    | 2020/06/14 | 使用PyTorch复现之前keras代码
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   <1> | JunJie Ren |   v1.1    | 2020/07/09 |    新增ACARS训练程序选项
--------------------------------------------------------------------------
'''

import os
import time

import torch
import numpy as np
import torch.nn as nn
from torchvision import transforms
from torch.autograd import Variable
from torch.utils.data import DataLoader

from configs import cfgs
from dataset.RML2016 import RMLDataset, loadNpy
from dataset.ACARS import ACARSDataset, loadNpy_acars
from networks.MsmcNet import MsmcNet_RML2016, MsmcNet_ACARS
from utils.strategy import step_lr, accuracy
from utils.plot import draw_curve

def train():
   ''' 信号调制分类训练主程序 '''
   # model
   if cfgs.model == "MsmcNet_RML2016":
      model = MsmcNet_RML2016(num_classes=cfgs.num_classes)
   elif cfgs.model == "MsmcNet_ACARS":
      model = MsmcNet_ACARS(num_classes=cfgs.num_classes)
   else :
        print('ERROR: No model {}!!!'.format(cfgs.model))
   print(model)
   '''model = torch.nn.DataParallel(model)    # 多卡预留'''
   model.cuda()

   # Dataset
   if cfgs.dataset_name == "RML2016.04c":
      x_train, y_train, x_test, y_test = loadNpy(
         cfgs.train_path,
         cfgs.test_path,
         cfgs.process_IQ
      )
      Dataset = RMLDataset
   elif cfgs.dataset_name == "ACARS":
      x_train, y_train, x_test, y_test = loadNpy_acars(
         cfgs.train_path_x,
         cfgs.train_path_y,
         cfgs.test_path_x,
         cfgs.test_path_y,
         cfgs.process_IQ
      )
      Dataset = ACARSDataset
   else :
      print('ERROR: No Dataset {}!!!'.format(cfgs.model))
   # BUG,BUG,BUG,FIXME
   transform = transforms.Compose([
                                    # transforms.ToTensor()
                                    # waiting add
                                 ])
   # Train data
   train_dataset = Dataset(x_train, y_train, transform=transform)    # RML2016.10a数据集
   dataloader_train = DataLoader(train_dataset, \
                                 batch_size=cfgs.batch_size, \
                                 num_workers=cfgs.num_workers, \
                                 shuffle=True, \
                                 drop_last=False)
   # Valid data
   valid_dataset = Dataset(x_test, y_test, transform=transform)
   dataloader_valid = DataLoader(valid_dataset, \
                              batch_size=cfgs.batch_size, \
                              num_workers=cfgs.num_workers, \
                              shuffle=True, \
                              drop_last=False)

   # log
   if not os.path.exists('./log'):
      os.makedirs('./log')
   log = open('./log/log.txt', 'a')
   log.write('-'*30+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))+'-'*30+'\n')
   log.write('model:{}\ndataset_name:{}\nnum_classes:{}\nnum_epoch:{}\nlearning_rate:{}\nsignal_len:{}\niter_smooth:{}\n'.format(
            cfgs.model, cfgs.dataset_name, cfgs.num_classes, cfgs.num_epochs,
            cfgs.lr, cfgs.signal_len, cfgs.iter_smooth))

   # load checkpoint
   if cfgs.resume:
      model = torch.load(os.path.join('./checkpoints', cfgs.checkpoint_name))

   # loss
   criterion = nn.CrossEntropyLoss().cuda()  # 交叉熵损失

   # train
   sum = 0
   train_loss_sum = 0
   train_top1_sum = 0
   max_val_acc = 0
   train_draw_acc = []
   val_draw_acc = []
   lr = cfgs.lr
   for epoch in range(cfgs.num_epochs):
      ep_start = time.time()

      # adjust lr
      # lr = half_lr(cfgs.lr, epoch)
      lr = step_lr(epoch, lr)

      # optimizer FIXME
      # optimizer = torch.optim.Adam(model.parameters(), lr=lr, betas=(0.9, 0.999), weight_decay=0.0002)
      optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
                                    lr=lr, betas=(0.9, 0.999), weight_decay=0.0002)

      model.train()
      top1_sum = 0
      for i, (signal, label) in enumerate(dataloader_train):
            input = Variable(signal).cuda().float()
            target = Variable(label).cuda().long()

            output = model(input)            # inference

            loss = criterion(output, target) # 计算交叉熵损失
            optimizer.zero_grad()
            loss.backward()                  # 反传
            optimizer.step()

            top1 = accuracy(output.data, target.data, topk=(1,))  # 计算top1分类准确率
            train_loss_sum += loss.data.cpu().numpy()
            train_top1_sum += top1[0]
            sum += 1
            top1_sum += top1[0]

            if (i+1) % cfgs.iter_smooth == 0:
               print('Epoch [%d/%d], Iter [%d/%d], lr: %f, Loss: %.4f, top1: %.4f'
                     %(epoch+1, cfgs.num_epochs, i+1, len(train_dataset)//cfgs.batch_size,
                     lr, train_loss_sum/sum, train_top1_sum/sum))
               log.write('Epoch [%d/%d], Iter [%d/%d], lr: %f, Loss: %.4f, top1: %.4f\n'
                           %(epoch+1, cfgs.num_epochs, i+1, len(train_dataset)//cfgs.batch_size,
                           lr, train_loss_sum/sum, train_top1_sum/sum))
               sum = 0
               train_loss_sum = 0
               train_top1_sum = 0

      train_draw_acc.append(top1_sum/len(dataloader_train))

      epoch_time = (time.time() - ep_start) / 60.
      if epoch % cfgs.valid_freq == 0 and epoch < cfgs.num_epochs:
            # eval
            val_time_start = time.time()
            val_loss, val_top1 = eval(model, dataloader_valid, criterion)
            val_draw_acc.append(val_top1)
            val_time = (time.time() - val_time_start) / 60.

            print('Epoch [%d/%d], Val_Loss: %.4f, Val_top1: %.4f, val_time: %.4f s, max_val_acc: %4f'
                  %(epoch+1, cfgs.num_epochs, val_loss, val_top1, val_time*60, max_val_acc))
            print('epoch time: {}s'.format(epoch_time*60))
            if val_top1[0].data > max_val_acc:
               max_val_acc = val_top1[0].data
               print('Taking snapshot...')
               if not os.path.exists('./checkpoints'):
                  os.makedirs('./checkpoints')
               torch.save(model, '{}/{}'.format('checkpoints', cfgs.checkpoint_name))

            log.write('Epoch [%d/%d], Val_Loss: %.4f, Val_top1: %.4f, val_time: %.4f s, max_val_acc: %4f\n'
                     %(epoch+1, cfgs.num_epochs, val_loss, val_top1, val_time*60, max_val_acc))
   draw_curve(train_draw_acc, val_draw_acc)
   log.write('-'*40+"End of Train"+'-'*40+'\n')
   log.close()

# validation
def eval(model, dataloader_valid, criterion):
    sum = 0
    val_loss_sum = 0
    val_top1_sum = 0
    model.eval()
    for ims, label in dataloader_valid:
        input_val = Variable(ims).cuda().float()
        target_val = Variable(label).cuda()
        output_val = model(input_val)
        loss = criterion(output_val, target_val)
        top1_val = accuracy(output_val.data, target_val.data, topk=(1,))

        sum += 1
        val_loss_sum += loss.data.cpu().numpy()
        val_top1_sum += top1_val[0]
    avg_loss = val_loss_sum / sum
    avg_top1 = val_top1_sum / sum
    return avg_loss, avg_top1

if __name__ == "__main__":
   train()


"""
Title: Explicit finger tapping sequence learning task [replication of Walker et al. 2002]
Author: Julia Wood, the University of Queensland, Australia
Code adapted from Tom Hardwicke's finger tapping task code: https://github.com/TomHardwicke/finger-tapping-task
Developed in Psychopy v2022.1.1
See my GitHub for further details: https://github.com/jrwood21
"""
import time
import pandas as pd
import numpy as np
import sys
import os
from psychopy import visual, event, core, gui, data
from pyglet.window import key
from num2words import num2words

os.chdir(os.path.abspath(''))  # change working directory to script directory
globalClock = core.Clock()  # create timer to track the time since experiment started

# define sequences for finger tapping task
targ_seq_1 = '41324'
targ_seq_2 = '42314'
prac_seq = '12344'

### set up some useful functions ###
# Function to save messages to a log file
def saveToLog(logString, timeStamp=1):
    f = open(logFile, 'a')  # open our log file in append mode so don't overwrite with each new log
    f.write(logString)  # write the string they typed
    if timeStamp != 0:  # if timestamp has not been turned off
        f.write('// logged at %iseconds' % globalClock.getTime())  # write a timestamp (very coarse)
    f.write('\n')  # create new line
    f.close()  # close and "save" the log file

# An exit function to initiate if the 'end' key is pressed
def quitExp():
    if 'logFile' in globals():  # if a log file has been created
        saveToLog('User aborted experiment')
        saveToLog('..........................................', 0)
    if 'win' in globals():  # if a window has been created
        win.close()  # close the window
    core.quit()  # quit the program

# define function to check if filename exists, then create the next available version number
def uniq_path(path):
    fn, ext = os.path.splitext(path)
    counter = 2
    while os.path.exists(path):
        path = fn + "_" + str(counter) + ext
        counter += 1
    return path

# Finger tapping task function
def fingerTapping(n_trials, tap_targetSequence, sequenceType):
    ## Intro screen ##
    saveToLog('Presenting introduction screen') # save info to log
    win.setColor('#000000', colorSpace='hex')  # set background colour to black
    win.flip()  # display
    generalText.setText(
        'TASK INSTRUCTIONS\n\nPlace the fingers of your LEFT hand on the keys 1, 2, 3, and 4. You will be shown a sequence of 5 digits %(sequence)s, and the computer will start counting down until you start. \n\nOnce the countdown has completed and the screen turns green, type %(sequence)s over and over as QUICKLY and as ACCURATELY as possible. \n\nYou will have 30 seconds to type %(sequence)s as many times as possible. Stop when the screen turns red again. You will get 30 seconds to rest before the next trial. \n\nPress the spacebar when you are ready for the countdown to begin.' % {'sequence': tap_targetSequence})
    generalText.draw()
    win.flip()  # display
    event.waitKeys(keyList=["space"])  # wait for a spacebar press before continuing
    event.clearEvents()  # clear the event buffer

    win.flip()  # blank the screen first
    trials = range(1, n_trials + 1)
    saveToLog('Running finger tapping task. %i trials with target sequence %s' % (len(trials), tap_targetSequence))  # save info to log

    for thisTrial in trials: # begin rest block
        win.setColor('#ff0000', colorSpace='hex')  # set background colour to red
        win.flip()  # display
        if thisTrial == 1:  # if this is first trial
            restClock = core.CountdownTimer(10) # start timer counting down from 10
        else:  # for all other trials
            saveToLog('Resting')  # save info to log
            restClock = core.CountdownTimer(30)  # start timer counting down from 30
        sequenceText.setText(tap_targetSequence)  # set up sequence text
        sequenceText.setAutoDraw(True)  # display sequence text continuously
        timerText.setAutoDraw(True)  #  display timer text continuously
        win.flip()
        while restClock.getTime() > 0:  # loop continues until trial timer ends
            count = restClock.getTime()  # get current time from clock
            timerText.setText(num2words(np.ceil(count)))  # set timer text to the current time
            win.flip()  # display timer text
            if event.getKeys(['end']):  # checks for the key 'end' on every refresh so user can quit at any point
                quitExp()  # initiate quit routine

        # begin tapping task
        saveToLog('Trial: %i' % thisTrial) # save info to log
        win.setColor('#89ba00', colorSpace='hex')  # set background colour to green
        win.flip()  # display the green background
        tap_stream = []  # clear previous sequence keypresses from the stream
        event.clearEvents()  # this makes sure the key buffer is cleared, otherwise old key presses might be recorded
        trialClock = core.CountdownTimer(30)  # start timer counting down from 30
        timerText.setText('Tap as fast as you can!')  # set timer text to the current time
        win.flip()  # display the text

        k = 0  # set up marker index
        endTrial = False  # a trigger to end the trial when True (deployed when the timer runs out)
        while endTrial == False:  # while trigger has not been deployed
            # display incremental markers across the screen from left to right as the user presses accepted keys
            if k == 0:  # start at beginning of marker index
                # start markers incrementing from left to right and append key presses to tap_stream
                while k < len(listOfMarkers) - 1 and endTrial == False:  # until the markers reach the far side of the screen
                    if trialClock.getTime() <= 0:  # if timer has run out
                        endTrial = True  # deploy the trigger to end the trial
                        break  # and break out of this loop
                    elif event.getKeys(['end']):  # if user presses end key
                        if thisTrial == 1 and not metaData['practice mode']: # during trial 1: save partial data collected from trial 1
                            quit_dict = {'stream': [tap_stream],
                                         'trial': thisTrial}
                            quit_df = pd.DataFrame(quit_dict, index=[0])
                            fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_" + str(metaData['participant allocation']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '_quitExp_trial1' + '.csv'
                            if os.path.exists(fileName):
                                fileName = uniq_path(fileName)
                            quit_df.to_csv(fileName)
                            saveToLog('User pressed end key during trial 1. Experiment aborted with %s seconds of trial 1 remaining' % trialClock.getTime())
                            saveToLog('Trial 1 data saved with filename: %s' %fileName)
                        elif thisTrial > 1 and not metaData['practice mode']: # or during a later trial: save partial and complete trial data collected
                            quit_dict = {'stream': [tap_stream],
                                         'trial': thisTrial}
                            quit_df = pd.DataFrame(quit_dict, index=[0])
                            fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_" + str(metaData['participant allocation']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '_quitExp' + '.csv'
                            if os.path.exists(fileName):
                                fileName = uniq_path(fileName)
                            quit_df.to_csv(fileName)
                            saveToLog('User pressed end key during trial %s' % thisTrial)
                            saveToLog('Experiment aborted with %s seconds of this trial remaining' % trialClock.getTime())
                            saveToLog('Partial trial data saved with filename: %s' %fileName)
                            fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_" + str(metaData['participant allocation']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '_quitExp_trials' + '.csv'
                            if os.path.exists(fileName):
                                fileName = uniq_path(fileName)
                            store_out.to_csv(fileName)
                            saveToLog('Data from complete trials saved with filename: %s' %fileName)
                        quitExp()  # AND quit the program
                    elif event.getKeys('1'):  # checks for key on every refresh
                        listOfMarkers[k].setAutoDraw(True)  # turn this marker on
                        win.flip()  # display
                        tap_stream.append(1)  # record the key press
                        k += 1  # move on to the next marker
                    elif event.getKeys('2'):  # checks for key on every refresh
                        listOfMarkers[k].setAutoDraw(True)  # turn this marker on
                        win.flip()  # display
                        tap_stream.append(2)  # record the key press
                        k += 1  # move on to the next marker
                    elif event.getKeys('3'):  # checks for key on every refresh
                        listOfMarkers[k].setAutoDraw(True)  # turn this marker on
                        win.flip()  # display
                        tap_stream.append(3)  # record the key press
                        k += 1  # move on to the next marker
                    elif event.getKeys('4'):  # checks for key on every refresh
                        listOfMarkers[k].setAutoDraw(True)  # turn this marker on
                        win.flip()  # display
                        tap_stream.append(4)  # record the key press
                        k += 1  # move on to the next marker

            # start markers incrementing from right to left and append keypresses to tap_stream:
            elif k == len(listOfMarkers) - 1 and endTrial == False:
                while k > 0:
                    if trialClock.getTime() <= 0:  # if timer has run out
                        endTrial = True  # deploy the trigger to end the trial
                        break  # and break out of this loop
                    elif event.getKeys(['end']):   # if user presses end key
                        if thisTrial == 1 and not metaData['practice mode']: # during trial 1: save partial data collected from trial 1
                            quit_dict = {'stream': [tap_stream],
                                         'trial': thisTrial}
                            quit_df = pd.DataFrame(quit_dict, index=[0])
                            fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_" + str(metaData['participant allocation']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '_quitExp_trial1' + '.csv'
                            if os.path.exists(fileName):
                                fileName = uniq_path(fileName)
                            quit_df.to_csv(fileName)
                            saveToLog('User pressed end key during trial 1. Experiment aborted with %s seconds of trial 1 remaining' % trialClock.getTime())
                            saveToLog('Trial 1 data saved with filename: %s' %fileName)
                        elif thisTrial > 1 and not metaData['practice mode']: # or during a later trial: save partial and complete trial data collected
                            quit_dict = {'stream': [tap_stream],
                                         'trial': thisTrial}
                            quit_df = pd.DataFrame(quit_dict, index=[0])
                            fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_" + str(metaData['participant allocation']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '_quitExp' + '.csv'
                            if os.path.exists(fileName):
                                fileName = uniq_path(fileName)
                            quit_df.to_csv(fileName)
                            saveToLog('User pressed end key during trial %s' % thisTrial)
                            saveToLog('Experiment aborted with %s seconds of this trial remaining' % trialClock.getTime())
                            saveToLog('Partial trial data saved with filename: %s' %fileName)
                            fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_" + str(metaData['participant allocation']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '_quitExp_trials' + '.csv'
                            if os.path.exists(fileName):
                                fileName = uniq_path(fileName)
                            store_out.to_csv(fileName)
                            saveToLog('Data from complete trials saved with filename: %s' %fileName)
                        quitExp()  # AND quit the program
                    elif event.getKeys('1'):  # checks for key on every refresh
                        listOfMarkers[k].setAutoDraw(False)  # turn this marker off
                        win.flip()  # display contents of video buffer
                        tap_stream.append(1)  # record the key press
                        k -= 1  # move on to the next marker
                    elif event.getKeys('2'): #checks for key on every refresh
                        listOfMarkers[k].setAutoDraw(False)  # turn this marker off
                        win.flip()  # display contents of video buffer
                        tap_stream.append(2)  # record the key press
                        k -= 1  # move on to the next marker
                    elif event.getKeys('3'): #checks for key on every refresh
                        listOfMarkers[k].setAutoDraw(False)  # turn this marker off
                        win.flip()  # display contents of video buffer
                        tap_stream.append(3)  # record the key press
                        k -= 1  # move on to the next marker
                    elif event.getKeys('4'): #checks for key on every refresh
                        listOfMarkers[k].setAutoDraw(False)  # turn this marker off
                        win.flip()  # display contents of video buffer
                        tap_stream.append(4)  # record the key press
                        k -= 1  # move on to the next marker

        # turn off all markers during the rest block
        for marker in listOfMarkers:  # for each marker
            marker.setAutoDraw(False)  # turn off

        win.setColor('#ff0000', colorSpace='hex')  # set background colour to red
        win.flip()  # display red background

        output = patternDetect(stream_in=tap_stream, targetSequence_in=tap_targetSequence)  # run the pattern detector to calculate correct sequences, errors and accuracy

        #  gather all relevant data for this trial
        newRow = {'participant': metaData['participant'],
                  'allocation': metaData['participant allocation'],
                  'session': metaData['session number'],
                  'session_time': metaData['session time'],
                  'target_sequence': tap_targetSequence,
                  'sequence_type': sequenceType,
                  'trial': thisTrial, # record which trial number
                  'stream': [tap_stream], # stream of key presses entered by participant
                  'n_correct': output['n_correct']}
#                  'errors': output['errors'], # Unhash these lines if you want them to be reported in the csv output file.
#                  'accuracy': output['accuracy']}

        # store all trial data in df. Each trial is stored in a new row
        if thisTrial == 1:
            store_out = pd.DataFrame(newRow, index=[0])
        elif thisTrial > 1:
            store_out = store_out.append(newRow, ignore_index=True)

    # after all trials are complete:
    sequenceText.setAutoDraw(False)  # turn off the sequence text
    timerText.setAutoDraw(False)  # turn off the timer text
    win.flip()  # clear the display

    return store_out

# Function for analysing the response stream
def patternDetect(stream_in, targetSequence_in):
    # pre-load some variables
    det_targetSequence = list(map(int, list(targetSequence_in))) # convert target sequence to list of integers
    det_stream = list(stream_in) # convert stream of key presses to a list
    n_correct = float(0) # store for number of correct sequences per trial
    '''
    Define stores for error tracking. I did not use these metrics in my study design, but I have left them in the code, in case
    they are appropriate for other experimental designs. Redefine, remove or ignore them as necessary for your study design.
    '''
    contiguousError = 0 # store for cumulative errors
    errors = float(0) # store for errors
    # note that n_correct + errors = total sequences

    i = 0  # start pattern detection at first element of keypress stream:
    while i < len(det_stream):  # search through every item in stream
        # for all key presses up to the final 5 (or any other target sequence length)
        if i <= len(det_stream) - len(det_targetSequence):
            # for any value in the stream where it + the next 4 keypresses match the target sequence:
            if det_stream[i:(i + len(det_targetSequence))] == det_targetSequence:
                n_correct += 1  # record a correct pattern completed
                i += len(det_targetSequence)  # adjust position to skip forward by length of targetSequence

                # Then add any accumulated errors to the total error count and clear the contiguous error count
                if contiguousError >= 1:  # check if there are contiguous errors we have not yet accounted for
                    errors += 1 # add an error to the total count
                    contiguousError = 0 # reset contiguous error count

            # otherwise, if the next sequence length of items in the stream does not match the target sequence:
            elif det_stream[i:(i + len(det_targetSequence))] != det_targetSequence:
                contiguousError += 1  # record a 'contiguous error'
                i += 1  # adjust index forward by 1

                # when contiguous error count reaches 5 incorrect keypresses in a row (i.e., the correct sequence doesn't follow 5 keypresses in a row)
                # OR if the final item of the stream does not match the target sequence:
                if contiguousError == 5 or i == len(det_stream):
                    errors += 1 # add an error to the total count
                    contiguousError = 0 # reset contiguous error count

        # now deal with last items of the stream (a special case, see 'method' above)
        else:
            # get last items
            lastItems = det_stream[i:]
            # get subset of target sequence of same length as last items
            sequenceSubset = det_targetSequence[:len(lastItems)]

            # Addition of PARTIAL correct sequences at end of stream:
            while lastItems != None:  # while there are additional items left to check
                if lastItems == sequenceSubset:  # if lastItems match target sequence subset
                    n_correct += float(len(lastItems)) / float(len(det_targetSequence))  # record fractional sequence

                    if contiguousError >= 1:  # check if there are errors we have not yet recorded
                        errors += 1  # add an error to total
                        contiguousError = 0  # reset contiguous error count
                    lastItems = None  # force failure of inner while loop by updating lastItems
                    i = len(det_stream)  # force failure of outer while loop by updating i
                else:  # if lastItems do not match target sequence
                    contiguousError += 1  # add 1 to contiguous error count

                    # when contiguous error count reaches 5 incorrect keypresses in a row or if this is final item
                    if contiguousError == 5 or len(lastItems) == 1:
                        errors += 1  # add an error to total
                        contiguousError = 0  # reset contiguous error count
                    if len(lastItems) == 1:  # if this is the final item
                        lastItems = None  # force failure of inner while loop by updating lastItems
                        i = len(det_stream)  # force failure of outer while loop by updating i
                    else:  # else if there are still items left to check
                        lastItems = lastItems[1:]  # drop the first item from lastItems
                        sequenceSubset = sequenceSubset[:-1]  # drop the last item from the sequence subset

    # integrity check
    if n_correct == 0:
        print('Issue with this stream - n_correct is zero')
        accuracy = float('nan')
    else:
        accuracy = 1 - errors / n_correct  # calculate accuracy
        # NOTE: this accuracy definition matches Hardwicke et al. 2016. I did not use this metric in my study design, but I have
        # left the code in the script case it is suitable for other study designs. Remove, redefine or ignore as necessary.

    return {'n_correct': n_correct, 'errors': errors, 'accuracy': accuracy}

### Collect and store meta-data about the experiment session ###
expName = 'Explicit finger tapping sequence task'  # define experiment name
date = time.strftime("%d %b %Y %H:%M:%S", time.localtime())  # get date and time
metaData = {'participant': '',
            'session number': [1, 2],
            'session time': ['pm-a', 'pm-b', 'am'],
            'practice mode': False,
            'use automated counter-balancing': True,
            'researcher': 'JW',
            'location': '304, Seddon North, UQ, Brisbane'}  # set up info for infoBox gui
infoBox = gui.DlgFromDict(dictionary=metaData,
                          title=expName,
                          order=['participant', 'session number', 'session time',
                                 'practice mode','use automated counter-balancing'])  # display gui to get info from user
if not infoBox.OK:  # if user hit cancel
    quitExp()  # quit

# check if participant dir exists, and if not, create one:
if not os.path.isdir('data'):
    os.mkdir('data')
if not os.path.isdir('data' + os.path.sep + 'fingertapping'):
    os.mkdir('data' + os.path.sep + 'fingertapping')
p_dir = 'data' + os.path.sep + 'fingertapping' + os.path.sep + 'P' + str(metaData['participant'])
if not os.path.isdir(p_dir):
    os.mkdir(p_dir)

if not metaData['practice mode']:  # if this is not practice mode:
    if metaData['use automated counter-balancing']:  # and user has chosen to use automated counter-balancing:
        cb = {'participant allocation': ['AJX', 'AJY', 'AKX', 'AKY',
                                         'BJX', 'BJY', 'BKX', 'BKY']}  # set up info for infoBox gui
        infoBox = gui.DlgFromDict(dictionary=cb,
                                  title='Choose counter-balancing parameters')  # display gui to get info from user
        metaData.update({'participant allocation': cb['participant allocation']})
        if not infoBox.OK:  # if user hit cancel
            quitExp()  # quit

    elif not metaData['use automated counter-balancing']: # or if user has chosen to manually select sequence type:
        seq_dict = {'use sequence': ['sequence_1', 'sequence_2'],
                    'number of trials': ''}
        infoBox = gui.DlgFromDict(dictionary=seq_dict,
                                  title='Select sequence to run experiment')  # display gui to get info from user
        metaData.update({'participant allocation': 'manual_selection',
                         'sequence type': '%s' % seq_dict['use sequence'],
                         'number of trials': '%s' % seq_dict['number of trials']})
        if not infoBox.OK:  # if user hit cancel
            quitExp()  # quit

    # build filename for this participant's data
    fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_" + str(metaData['participant allocation']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '.csv'

    # is this an existing participant? If so we will create a new file name to store the data under
    if os.path.exists(fileName):  # if they are an existing participant
        # confirm that user knows sessions already exist for this participant's current session and time and advise filename will be different:
        myDlg = gui.Dlg()
        myDlg.addText(
            "This participant has existing files for this session time in the directory! Click ok to continue or cancel to abort. \n\n NOTE: if you choose to continue, files will be stored under a different file name.")
        myDlg.show()  # show dialog and wait for OK or Cancel
        if not myDlg.OK:  # if the user pressed cancel
            quitExp()

        # redefine file name by iteratively appending a number so that existing files are not overwritten
        fileName = uniq_path(fileName)

    metaData.update({'expName': expName, 'date': date})  # record the experiment date and name in the metaData

    # check if logfile exists for this participant. If not, create one:
    logFile = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_" + str(metaData['participant allocation']) +'_log.txt'
    if not os.path.exists(logFile):
        with open(logFile, 'w') as fp:
            pass

    # save metaData to log
    saveToLog('..........................................', 0)
    saveToLog('experiment: %s' % (metaData['expName']), 0)
    saveToLog('researcher: %s' % (metaData['researcher']), 0)
    saveToLog('location: %s' % (metaData['location']), 0)
    saveToLog('date: %s' % (metaData['date']), 0)
    saveToLog('participant: %s' % (metaData['participant']), 0)
    saveToLog('session: %s' % (metaData['session number']), 0)
    saveToLog('session time: %s' % (metaData['session time']), 0)
    saveToLog('participant allocation: %s' % (metaData['participant allocation']), 0)
    saveToLog('                                            ', 0)

else:  # otherwise, if it is practice mode:
    logFile = p_dir + os.path.sep + 'P' + str(metaData['participant']) + '_practice_log.txt'
    if not os.path.exists(logFile):
        with open(logFile, 'w') as fp:
            pass

    # ask user to define number of trials
    prac_dict = {'number of trials': ''}
    infoBox = gui.DlgFromDict(dictionary=prac_dict,
                              title='enter number of trials')  # display gui to get info from user
    if not infoBox.OK:  # if user hit cancel
        quitExp()  # quit

    # build filename for this participant's practice data
    fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '_PRACTICE' + '.csv'
    # is this an existing participant? If so we will create a new file name to store the data under
    if os.path.exists(fileName):  # if existing participant
        # check user knows sessions already exist for this participant's current session and time:
        myDlg = gui.Dlg()
        myDlg.addText(
            "This participant has existing files for this session time in the directory! Click ok to continue or cancel to abort. \n\n NOTE: if you choose to continue, files will be stored under a different file name.")
        myDlg.show()  # show dialog and wait for OK or Cancel
        if not myDlg.OK:  # if the user pressed cancel
            quitExp()

        # redefine file name by iteratively appending a number so that the original files are not overwritten
        fileName = uniq_path(fileName)

    metaData.update({'participant allocation': 'practice'})

    # save metaData to log
    saveToLog('..........................................', 0)
    saveToLog('experiment: %s' % (expName), 0)
    saveToLog('researcher: %s' % (metaData['researcher']), 0)
    saveToLog('location: %s' % (metaData['location']), 0)
    saveToLog('date: %s' % (date), 0)
    saveToLog('participant: %s' % (metaData['participant']), 0)
    saveToLog('session: %s' % (metaData['session number']), 0)
    saveToLog('session time: %s' % (metaData['session time']), 0)
    saveToLog('participant allocation: %s' % (metaData['participant allocation']), 0)
    saveToLog('                                            ', 0)

### Prepare stimuli etc ###
win = visual.Window(size=(1920, 1080), fullscr=True, screen=0, allowGUI=False, allowStencil=False, ## UPDATE SIZE TO MATCH YOUR CURRENT MONITOR SETTINGS
                    monitor='testMonitor', color=(-1,-1,-1), colorSpace='rgb', units='pix') # setup the Window
generalText = visual.TextStim(win=win, ori=0, name='generalText', text='', font=u'Arial', pos=[0, 0], height=35,
                              wrapWidth=920, color=(1,1,1), colorSpace='rgb', opacity=1, depth=0.0)  # general text
sequenceText = visual.TextStim(win=win, ori=0, name='sequenceText', text='', font=u'Arial', pos=[0, 250], height=90,
                               wrapWidth=None, color=(1,1,1), colorSpace='rgb', opacity=1, depth=0.0)  # sequence text
timerText = visual.TextStim(win=win, ori=0, name='sequenceText', text='', font=u'Arial', pos=[0, -130], height=40,
                            wrapWidth=800, color=(1,1,1), colorSpace='rgb', opacity=1, depth=0.0)  # timer text

# set up the markers that increment across the screen - generate enough so that they cover the full range of the window
listOfMarkers = []  # store for white markers
windowSize = list(win.size) # get window size
for i in range(int(-windowSize[0] / 2), int(windowSize[0] / 2), int(windowSize[0] / 40)):  # generate markers to cover whole screen
    i += 25  # add a slight horizontal adjustment to ensure markers do not go off screen
    listOfMarkers.append(visual.Circle(win, radius=15, edges=32, pos=[i, 0], fillColor='white'))  # generate the markers

# for monitoring key state (only need this if using markers)
keys = key.KeyStateHandler()
win.winHandle.push_handlers(keys)

saveToLog('Set up complete') # save info to log
### set-up complete ###

### run the experiment ###
if metaData['practice mode']:  # if user has chosen practice mode
    res = fingerTapping(n_trials=int(prac_dict['number of trials']), tap_targetSequence = prac_seq, sequenceType ='practice')  # run practice sequence

elif not metaData['practice mode']: # if it is not practice mode
    if not metaData['use automated counter-balancing']: # AND the user has chosen to manually select the sequence type:
        if seq_dict['use sequence'] == 'sequence_1': # EITHER run task with sequence 1:
            res = fingerTapping(n_trials=int(seq_dict['number of trials']), tap_targetSequence = targ_seq_1, sequenceType = 'sequence_1')
        elif seq_dict['use sequence'] == 'sequence_2': # OR run task with sequence 2:
            res = fingerTapping(n_trials=int(seq_dict['number of trials']), tap_targetSequence = targ_seq_2, sequenceType = 'sequence_2')

    elif metaData['use automated counter-balancing']: # OR if user has selected to use automated counter balancing:
        # NOTE: these allocations are specific to my study (each letter represents one type of grouping/randomisation variable). Adapt groupings to suit individual experiments
        ####### X ORDER
        if ((metaData['participant allocation'] == 'AJX') or (metaData['participant allocation'] == 'BJX') or (metaData['participant allocation'] == 'AKX') or (metaData['participant allocation'] == 'BKX')):
            # session 1
            if int(metaData['session number']) == 1:
                if metaData['session time'] == 'pm-a':
                    res = fingerTapping(n_trials = 12, tap_targetSequence = targ_seq_1, sequenceType='sequence_1')  # sequence 1
                elif metaData['session time'] == 'pm-b' or 'am':
                    res = fingerTapping(n_trials = 4, tap_targetSequence = targ_seq_1, sequenceType='sequence_1') # wordlist 1
            # session 2
            elif int(metaData['session number']) == 2:
                if metaData['session time'] == 'pm-a':
                    res = fingerTapping(n_trials = 12, tap_targetSequence = targ_seq_2, sequenceType='sequence_2')  # sequence 2
                elif metaData['session time'] == 'pm-b' or 'am':
                    res = fingerTapping(n_trials = 4, tap_targetSequence = targ_seq_2, sequenceType='sequence_2')  # sequence 2

        ####### Y ORDER
        elif ((metaData['participant allocation'] == 'AJY') or (metaData['participant allocation'] == 'BJY') or (metaData['participant allocation'] == 'AKY') or (metaData['participant allocation'] == 'BKY')):
            # session 1
            if int(metaData['session number']) == 1:
                if metaData['session time'] == 'pm-a':
                    res = fingerTapping(n_trials = 12, tap_targetSequence = targ_seq_2, sequenceType='sequence_2')  # sequence 2
                elif metaData['session time'] == 'pm-b' or 'am':
                    res = fingerTapping(n_trials = 4, tap_targetSequence = targ_seq_2, sequenceType='sequence_2')  # sequence 2
            # session 2
            elif int(metaData['session number']) == 2:
                if metaData['session time'] == 'pm-a':
                    res = fingerTapping(n_trials = 12, tap_targetSequence = targ_seq_1, sequenceType='sequence_1')  # sequence 1
                elif metaData['session time'] == 'pm-b' or 'am':
                    res = fingerTapping(n_trials = 4, tap_targetSequence= targ_seq_1, sequenceType='sequence_1')  # sequence 1

## End screen ##
saveToLog('Presenting end screen')  # save info to log
win.setColor('#000000', colorSpace='hex')  # set background colour to black
win.flip()
generalText.setText(u'Thank you. That is the end of this section. Please inform the researcher you have finished.')
generalText.draw()
win.flip()  # present video buffer
event.waitKeys(keyList=['end']) # wait for the end key to be pressed before continuing
event.clearEvents() # clear the event buffer

saveToLog('Experiment presentation over')  # save info to log
### Finished running the experiment ###

### Save and clean up ###
win.close()

'''
Save the data as a csv file. The loop below also checks if saving is not possible, usually because the file is already open, and asks user to close if this is the case
if this does not resolve the situation, attempt is made to save the data with a different filename.
'''
while True:
    try:
        res.to_csv(fileName)
        saveToLog('Data saved with file name: %s' % fileName) # save info to log
        break
    except: # if cannot save data, likely because file is already open, ask user to close
        saveToLog('Problem encountered saving data - requesting user close open data files...') # save info to log
        myDlg = gui.Dlg()
        myDlg.addText(
                "Unable to store data. Try closing open excel files and then click ok. Press cancel to attempt data storage to new file.")
        myDlg.show()  # show dialog and wait for OK or Cancel
        if not myDlg.OK:  # if the user pressed cancel
            fileName = p_dir + os.path.sep + 'P' + str(metaData['participant']) + "_ProblemSaving_" + str(metaData['participant allocation']) + '_S' + str(metaData['session number']) + '_' + str(metaData['session time']) + '.csv'
            saveToLog('Attempting to save data with different filename: %s' %fileName) # save info to log
            try:
                res.to_csv(fileName)
                print('Data was saved with a different filename: %s' %fileName)
                saveToLog('Data saved with file name: %s' % fileName) # save info to log
                break
            except:
                saveToLog('Major error: Data could not be saved') # save info to log
                quitExp() # quit the experiment

t = globalClock.getTime() # get run time of experiment
saveToLog('Total experiment runtime was %i seconds' % t) # record runtime to log
saveToLog('..........................................', 0)

# Shut down:
core.quit()


from typing import Union, Tuple

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import numpy as np
from gym import Env
from gym.spaces import Box

from ..agent import Agent
from . import ReplayBuffer
from .actor import Actor
from .critic import Critic
from .polyak_update import polyak_update

class TD3Agent(Agent):

    def __init__(self, name, env: Env,
                 discounting_factor: float = 0.99,
                 batch_size: int = 32,
                 buffer_size: int = 50000,
                 start_learning: int = 1000,
                 learning_rate_actor: float = 0.0005,
                 learning_rate_critic: float = 0.001,
                 polyak_tau: float = 0.01,
                 hidden_sizes_s: Union[int, Tuple[int, ...]] = 128,
                 hidden_sizes_a: Union[int, Tuple[int, ...]] = 128,
                 hidden_sizes_shared: Union[int, Tuple[int, ...]] = 256,
                 hidden_sizes_actor: Union[int, Tuple[int, ...]] = (128, 128),
                 policy_noise: float = 0.2,
                 noise_clip: float = 0.5,
                 max_grad_norm: float = 0.5,
                 exploration_noise: float = 0.1,
                 policy_update_frequency: int = 10,
                 target_update_frequency: int = 10
                 ):
        super().__init__(name, 'TD3', env)
        assert isinstance(self._env.action_space, Box), "Action space must be of type Box"
        self._device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        self._gamma = discounting_factor
        self._memory = ReplayBuffer(buffer_size, self._device)
        self.q1 = Critic(self.observation_shape,
                         self.action_shape,
                         hidden_sizes_s,
                         hidden_sizes_a,
                         hidden_sizes_shared,
                         self._device)
        self.q2 = Critic(self.observation_shape,
                         self.action_shape,
                         hidden_sizes_s,
                         hidden_sizes_a,
                         hidden_sizes_shared,
                         self._device)
        self.q1_target = Critic(self.observation_shape,
                                self.action_shape,
                                hidden_sizes_s,
                                hidden_sizes_a,
                                hidden_sizes_shared,
                                self._device)
        self.q2_target = Critic(self.observation_shape,
                                self.action_shape,
                                hidden_sizes_s,
                                hidden_sizes_a,
                                hidden_sizes_shared,
                                self._device)
        self.pi = Actor(self.observation_shape,
                        self.action_shape,
                        hidden_sizes_actor,
                        self._device)
        self.pi_target = Actor(self.observation_shape,
                        self.action_shape,
                        hidden_sizes_actor,
                        self._device)

        self.q1_target.load_state_dict(self.q1.state_dict())
        self.q2_target.load_state_dict(self.q2.state_dict())
        self.pi_target.load_state_dict(self.pi.state_dict())
        self.q1_target.train(False)
        self.q2_target.train(False)
        self.pi_target.train(False)
        self._q_optimizer = optim.Adam(list(self.q1.parameters()) + list(self.q2.parameters()), lr=learning_rate_critic)
        self._pi_optimizer = optim.Adam(list(self.pi.parameters()), lr=learning_rate_actor)
        self._batch_size = batch_size
        self._start_learning = max(start_learning, batch_size)
        self._policy_noise = policy_noise
        self._noise_clip = noise_clip
        self._max_grad_norm = max_grad_norm
        self._exploration_noise = exploration_noise
        self._policy_update_frequency = policy_update_frequency
        self._target_update_frequency = target_update_frequency
        self._tau = polyak_tau
        self._q_loss = torch.Tensor([0.0], device=self._device)
        self._pi_loss = torch.Tensor([0.0], device=self._device)
        self._a_limits = torch.Tensor(self._env.action_space.low, device=self._device),\
                         torch.Tensor(self._env.action_space.high, device=self._device)

    def find_action(self, observation, in_eval=False):
        with torch.no_grad():
            a = self.pi(torch.tensor(observation, dtype=torch.float, device=self._device)).detach().numpy()
            if not in_eval:
                a += np.random.normal(0, self._exploration_noise, size=self.action_shape)
                a = a.clip(self._env.action_space.low, self._env.action_space.high)
        return a.tolist()

    def learn(self, observation, action, reward, next_observation, global_step):
        self._memory.put((observation, action, reward, next_observation))

        if self._memory.size() > self._start_learning:
            s, a, r, s_prime = self._memory.sample(self._batch_size)
            with torch.no_grad():
                clipped_noise = torch.randn_like(a, device=self._device) * self._policy_noise
                clipped_noise = clipped_noise.clamp(-self._noise_clip, self._noise_clip)
                a_prime = self.pi_target(s_prime) + clipped_noise
                a_prime = a_prime.clamp(*self._a_limits)
                qf1_next_target = self.q1_target(s_prime, a_prime)
                qf2_next_target = self.q2_target(s_prime, a_prime)
                min_qf_next_target = torch.min(qf1_next_target, qf2_next_target)
                next_q_value = r + self._gamma * min_qf_next_target

            q1_l = F.mse_loss(self.q1(s, a), next_q_value)
            q2_l = F.mse_loss(self.q2(s, a), next_q_value)
            self._q_loss = 0.5 * (q1_l + q2_l)
            # optimize the model
            self._q_optimizer.zero_grad()
            self._q_loss.backward()
            nn.utils.clip_grad_norm_(list(self.q1.parameters()) + list(self.q2.parameters()), self._max_grad_norm)
            self._q_optimizer.step()

            if (global_step + 1) % self._policy_update_frequency == 0:
                self._pi_loss = -self.q1(s, self.pi(s)).mean()
                self._pi_optimizer.zero_grad()
                self._pi_loss.backward()
                nn.utils.clip_grad_norm_(list(self.pi.parameters()), self._max_grad_norm)
                self._pi_optimizer.step()

            if (global_step + 1) % self._target_update_frequency == 0:
                polyak_update(self.q1.parameters(), self.q1_target.parameters(), self._tau)
                polyak_update(self.q2.parameters(), self.q2_target.parameters(), self._tau)
                polyak_update(self.pi.parameters(), self.pi_target.parameters(), self._tau)

    def get_log_dict(self):
        return {
            'loss/q_loss': self._q_loss.item(),
            'loss/pi_loss': self._pi_loss.item()
        }


from django.conf.urls import include, url
from provisioner.views import ProvisionStatus, login

urlpatterns = [
    url(r'^$', ProvisionStatus, name='home'),
    url(r'login.*', login),
    url(r'^events/', include('events.urls')),
    url(r'^provisioner/', include('provisioner.urls')),
]


from flask import Flask, render_template, request, redirect, session, flash
from mysqlconnection import MySQLConnector
import re, md5
app = Flask(__name__)
app.secret_key = "MySessionSecretKey1"
mysql = MySQLConnector( app, "the_wall")
email_regex = re.compile(r'^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]+$')

@app.route( "/" )
def lr():
    # session['user_id'] = False
    if session['user_id']:
        return redirect( "/wall" )
    return render_template( "index.html" )

# VIEW MESSAGES AND COMMENTS
@app.route( "/wall" )
def wall():
    if not session['user_id']:
        return render_template( "index.html" )

    query = "SELECT first_name, id FROM users WHERE id = :id"
    q_p = { 'id': session['user_id'] }
    user = {}
    user = mysql.query_db( query, q_p )[0]

    query = "SELECT first_name, last_name, message, DATE_FORMAT(messages.created_at, '%M %d, %Y') AS message_date, messages.id, user_id FROM messages JOIN users ON users.id = messages.user_id ORDER BY messages.created_at DESC"
    messages = mysql.query_db( query )

    query = "SELECT users.first_name, users.last_name, comments.message_id, comment, DATE_FORMAT(comments.created_at, '%M %d, %Y') AS comment_date FROM comments JOIN users ON comments.user_id = users.id ORDER BY comments.created_at ASC"
    comments = mysql.query_db( query )

    return render_template( "wall.html", user = user, messages = messages, comments = comments )

# POST A MESSAGE TO START A DISCUSSION
@app.route( "/post_message", methods = ['POST'] )
def post_message():
    query = "INSERT INTO messages( message, user_id, created_at, updated_at ) VALUES( :message, :user_id, NOW(), NOW() )"
    q_p = {
        'message': request.form['message'],
        'user_id': session['user_id']
    }
    mysql.query_db( query, q_p )
    flash( "Your message has been posted" )
    return redirect( "/wall" )

# POST A COMMENT IN RESPONCE TO A MESSAGE
@app.route( "/post_comment/<message_id>", methods = ['POST'])
def post_comment( message_id ):
    query = "INSERT INTO comments( comment, user_id, message_id, created_at, updated_at ) VALUES( :comment, :user_id,:message_id, NOW(), NOW() )"
    q_p = {
        'comment': request.form['comment'],
        'user_id': session['user_id'],
        'message_id': message_id
    }
    mysql.query_db( query, q_p )

    return redirect( "/wall" )

# DELETE MESSAGE
@app.route( "/delete_message" )
def delete_message():
    flash ("delete command received!")
    return redirect( "/wall" )

# LOGIN
@app.route( "/authorization", methods = ["POST"] )
def authorization():
    # EMAIL VALIDATION
    if not email_regex.match( request.form['email'] ):
        flash( "Invalid email" )
    else:
        query = "SELECT * FROM users WHERE users.email = :email LIMIT 1"
        q_p = { 'email': request.form['email'] }
        user = mysql.query_db( query, q_p )
        if not user:
            flash( "Email " + request.form['email'] + " is not registered with any user" )
        else:
            pw_h = md5.new( request.form['pw'] ).hexdigest()
            if user[0]['password'] != pw_h: # PASSWORD VALIDATION
                flash( "Wrong password" )
            else:  # SUCCESSFUL LOGIN
                session['user_id']= user[0]['id']
                return redirect( "/wall" )

    return redirect( "/" )

# SIGN UP
@app.route( "/signup", methods = ["POST"] )
def signup():
    error = False

    # FORM INPUT VALIDATIONS
    # VALIDATE FIRST NAME
    if len( request.form['first_name'] ) < 2: # NAME LENGTH
        error = True
        flash( "First name is too short" )
    elif not str.isalpha( str( request.form['first_name'] ) ): # NAME CONVENTIONS
        error = True
        flash( "Invalid characters in the first name" )

    # VALIDATE LAST NAME
    if len( request.form['last_name'] ) < 2: # NAME LENGTH
        error = True
        flash( "Last name is too short" )
    elif not str.isalpha( str( request.form['last_name'] ) ): # NAME CONVENTIONS
        error = True
        flash( "Invalid characters in the last name" )

    # VALIDATE EMAIL
    if not email_regex.match( request.form['email'] ): # EMAIL CONVENTIONS
        error = True
        flash( "Invalid email" )
    else: # CHECK IF EMAIL IS ALREADY IN USE
        # email = request.form['email']
        query = "SELECT email FROM users WHERE users.email = :email LIMIT 1"
        q_p = { 'email': request.form['email'] }
        existing_email = mysql.query_db( query, q_p )
        if existing_email:
            error = True
            flash( "Email " + request.form['email'] + " is already in use" )

    # VALIDATE PASSWORD CONVENTIONS AND REPEAT
    if len( str( request.form['pw'] ) ) < 8:
        error = True
        flash( "Password should be at least 8 characters long")
    elif request.form['pw'] != request.form['rpt_pw']:
        error = True
        flash( "Repeat password does not match")

    if error:
        return redirect( "/" )

    else: # ADD NEW USER INTO THE DATABASE
        query = "INSERT INTO users( first_name, last_name, email, password, created_at, updated_at ) VALUES( :first_name, :last_name, :email, :pw_h, NOW(), NOW() )"
        q_p = {
            'first_name': request.form['first_name'],
            'last_name': request.form['last_name'],
            'email': request.form['email'],
            'pw_h': md5.new( request.form['pw'] ).hexdigest()
        }
        mysql.query_db( query, q_p )

        flash( "Your user account has been saved" )

        # FETCH THE NEW USER ID FROM THE DATABASE FOR SESSION LOGIN
        query = "SELECT id FROM users WHERE email = :email LIMIT 1"
        q_p = { 'email': request.form['email'] }
        session['user_id']= mysql.query_db( query, q_p )[0]['id']

    return redirect( "/wall" )

@app.route( "/logout", methods = ["POST"])
def logout():
    session['user_id'] = False
    return redirect( "/" )

app.run( debug = True )


#!/usr/bin/env python3

"""Tool to update Conan dependencies to the latest"""

import argparse
import json
import os
import re
import subprocess

def main():
    """
    Read Conan dependencies, look for updates, and update the conanfile.py with updates
    """
    parser = argparse.ArgumentParser()
    parser.add_argument("--repo", help="Repo name of the package to update", required=True)
    command_args = parser.parse_args()

    fullpath = os.path.join(os.getcwd(), command_args.repo)

    with open(os.path.join(fullpath, "conanfile.py"),
        "r", encoding="utf-8", newline="") as conan_file:
        conan_file_content = conan_file.read()

        packages = []
        package_strings = re.findall(r'requires\("(.*?)/(.*?)@', conan_file_content)

        for package_string in package_strings:
            package = {
                "name": package_string[0],
                "version": package_string[1],
            }
            packages.append(package)

        for package in packages:
            conan_inspect_output = subprocess.run("conan inspect . --format json",
                cwd=f"conan-recipes/recipes/{package['name']}",
                shell=True, check=True, stdout=subprocess.PIPE)
            conan_inspect_json = json.loads(conan_inspect_output.stdout.decode("utf-8"))
            package["latest_version"] = conan_inspect_json["version"]

            old_package = f"{package['name']}/{package['version']}"
            new_package = f"{package['name']}/{package['latest_version']}"

            if old_package != new_package and old_package in conan_file_content:
                conan_file_content = conan_file_content.replace(old_package, new_package)

                print("Replace:")
                print(f"  {old_package}")
                print("With:")
                print(f"  {new_package}")
                print()

    with open(os.path.join(fullpath, "conanfile.py"),
        "w", encoding="utf-8", newline="") as conan_file:
        conan_file.write(conan_file_content)

if __name__ == "__main__":
    main()


from flask import request
from mobile_endpoint.backends.manager import get_dao

from mobile_endpoint.case.case_processing import process_cases_in_form

from mobile_endpoint.extensions import requires_auth
from mobile_endpoint.form.form_processing import create_xform, get_instance_and_attachments, get_request_metadata
from mobile_endpoint.views import ota_mod
from mobile_endpoint.views.response import get_open_rosa_response

@ota_mod.route('/receiver/<domain>', methods=['POST'])
@requires_auth
def form_receiver(domain):
    return _receiver(domain, backend='sql')

@ota_mod.route('/couch-receiver/<domain>', methods=['POST'])
@requires_auth
def couch_receiver(domain):
    return _receiver(domain, backend='couch')

@ota_mod.route('/mongo-receiver/<domain>', methods=['POST'])
@requires_auth
def mongo_receiver(domain):
    return _receiver(domain, backend='mongo')

def _receiver(domain, backend):
    dao = get_dao(backend)
    instance, attachments = get_instance_and_attachments(request)
    request_meta = get_request_metadata(request)
    request_meta['domain'] = domain

    xform_lock = create_xform(instance, attachments, request_meta, dao)

    with xform_lock as xform:
        case_result = None
        if xform.doc_type == 'XFormInstance':
            case_result = process_cases_in_form(xform, dao)

        dao.commit_atomic_submission(xform, case_result)

    return get_open_rosa_response(xform, None, None)


import numpy as np
import torch
import random
import time

smp = torch.nn.Softmax(dim=0)
smt = torch.nn.Softmax(dim=1)

def get_T_global_min(args, record, max_step = None, T0 = None, p0 = None, lr = 0.1, NumTest = None, all_point_cnt = 15000):

    if max_step is None:
        max_step = args.max_iter
    if NumTest is None:
        NumTest =  args.G

    KINDS = args.num_classes
    all_point_cnt = np.min((all_point_cnt,int(len(record)*0.9)))
    print(f'Sample {all_point_cnt} instances in each round')
    p_estimate = [[] for _ in range(3)]
    p_estimate[0] = torch.zeros(KINDS)
    p_estimate[1] = torch.zeros(KINDS, KINDS)
    p_estimate[2] = torch.zeros(KINDS, KINDS, KINDS)
    for idx in range(NumTest):
        print(idx, flush=True)
        sel_loc = np.random.permutation(record.shape[1])[:3]
        record_sel = record[:, sel_loc]
        # print(f'sel_loc is {sel_loc}')
        cnt_y_3 = count_y_known2nn(KINDS, record_sel, all_point_cnt)
        for i in range(3):
            cnt_y_3[i] /= all_point_cnt
            p_estimate[i] = p_estimate[i] + cnt_y_3[i] if idx != 0 else cnt_y_3[i]

    for j in range(3):
        p_estimate[j] = p_estimate[j] / NumTest

    args.device = set_device()
    loss_min, E_calc, P_calc, T_init = calc_func(KINDS, p_estimate, False, args.device, max_step, T0, p0, lr = lr)

    E_calc = E_calc.cpu().numpy()
    P_calc = P_calc.cpu().numpy()
    return E_calc, P_calc

def error(T, T_true):
    error = np.sum(np.abs(T-T_true)) / np.sum(np.abs(T_true))
    return error

def set_device():
    if torch.cuda.is_available():
        _device = torch.device("cuda")
    else:
        _device = torch.device("cpu")
    print(f'Current device is {_device}', flush=True)
    return _device

def distCosine(x, y):
    """
    :param x: m x k array
    :param y: n x k array
    :return: m x n array
    """
    xx = np.sum(x ** 2, axis=1) ** 0.5
    x = x / xx[:, np.newaxis]
    yy = np.sum(y ** 2, axis=1) ** 0.5
    y = y / yy[:, np.newaxis]
    dist = 1 - np.dot(x, y.transpose())  # 1 - cosine distance
    return dist

def count_real(KINDS, T, P, mode, _device = 'cpu'):
    # time1 = time.time()
    P = P.reshape((KINDS, 1))
    p_real = [[] for _ in range(3)]

    p_real[0] = torch.mm(T.transpose(0, 1), P).transpose(0, 1)
    # p_real[2] = torch.zeros((KINDS, KINDS, KINDS)).to(_device)
    p_real[2] = torch.zeros((KINDS, KINDS, KINDS))

    temp33 = torch.tensor([])
    for i in range(KINDS):
        Ti = torch.cat((T[:, i:], T[:, :i]), 1)
        temp2 = torch.mm((T * Ti).transpose(0, 1), P)
        p_real[1] = torch.cat([p_real[1], temp2], 1) if i != 0 else temp2

        for j in range(KINDS):
            Tj = torch.cat((T[:, j:], T[:, :j]), 1)
            temp3 = torch.mm((T * Ti * Tj).transpose(0, 1), P)
            temp33 = torch.cat([temp33, temp3], 1) if j != 0 else temp3
        # adjust the order of the output (N*N*N), keeping consistent with p_estimate
        t3 = []
        for p3 in range(KINDS):
            t3 = torch.cat((temp33[p3, KINDS - p3:], temp33[p3, :KINDS - p3]))
            temp33[p3] = t3
        if mode == -1:
            for r in range(KINDS):
                p_real[2][r][(i+r+KINDS)%KINDS] = temp33[r]
        else:
            p_real[2][mode][(i + mode + KINDS) % KINDS] = temp33[mode]

    temp = []       # adjust the order of the output (N*N), keeping consistent with p_estimate
    for p1 in range(KINDS):
        temp = torch.cat((p_real[1][p1, KINDS-p1:], p_real[1][p1, :KINDS-p1]))
        p_real[1][p1] = temp
    return p_real

def func(KINDS, p_estimate, T_out, P_out, N,step, LOCAL, _device):
    eps = 1e-2
    eps2 = 1e-8
    eps3 = 1e-5
    loss = torch.tensor(0.0).to(_device)       # define the loss

    P = smp(P_out)
    # loss = loss + 0.1*torch.norm(P.view(-1) - torch.tensor([0.51441996, 0.34073234, 0.08246922, 0.06237848]))
    # loss = loss + 0.1 * torch.norm(P[3]-0.1) +  0.1 * torch.norm(P[2]-0.1)
    # P = P_out
    T = smt(T_out)

    mode = random.randint(0, KINDS-1)
    mode = -1
    # Borrow p_ The calculation method of real is to calculate the temporary values of T and P at this time: N, N*N, N*N*N
    p_temp = count_real(KINDS, T.to(torch.device("cpu")), P.to(torch.device("cpu")), mode, _device)

    weight = [1.0,1.0,1.0]
    # weight = [2.0,1.0,1.0]

    for j in range(3):  # || P1 || + || P2 || + || P3 ||
        p_temp[j] = p_temp[j].to(_device)
        loss += weight[j] * torch.norm(p_estimate[j] - p_temp[j]) #/ np.sqrt(N**j)

    if step > 100 and LOCAL and KINDS != 100:
        loss += torch.mean(torch.log(P+eps))/10

    return loss

def calc_func(KINDS, p_estimate, LOCAL, _device, max_step = 501, T0=None, p0 = None, lr = 0.1):
    # init
    # _device =  torch.device("cpu")
    N = KINDS
    eps = 1e-8
    if T0 is None:
        T = 1 * torch.eye(N) - torch.ones((N,N))
        # T[-1] = torch.ones(N)
    else:
        T = T0

    if p0 is None:
        P = torch.ones((N, 1), device = None) / N + torch.rand((N,1), device = None)*0.1     # P：0-9 distribution
        # P[2:] -= 5.0
        # P =  torch.tensor([0.4,0.4,0.1,0.1])
    else:
        P = p0

    T = T.to(_device)
    P = P.to(_device)
    p_estimate = [item.to(_device) for item in p_estimate]
    print(f'using {_device} to solve equations')

    T.requires_grad = True
    P.requires_grad = True

    optimizer = torch.optim.Adam([T, P], lr = lr)

    # train
    loss_min = 100.0
    T_rec = torch.zeros_like(T)
    P_rec = torch.zeros_like(P)

    time1 = time.time()
    for step in range(max_step):
        if step:
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        loss = func(KINDS, p_estimate, T, P, N,step, LOCAL, _device)
        if loss < loss_min and step > 5:
            loss_min = loss.detach()
            T_rec = T.detach()
            P_rec = P.detach()
        # if step % 100 == 0:
        #     print('loss {}'.format(loss))
        #     print(f'step: {step}  time_cost: {time.time() - time1}')
        #     print(f'T {np.round(smt(T.cpu()).detach().numpy()*100,1)}', flush=True)
        #     print(f'P {np.round(smp(P.cpu().view(-1)).detach().numpy()*100,1)}', flush=True)
        #     # print(f'P {np.round((P.cpu().view(-1)).detach().numpy()*100,1)}', flush=True)
        #     time1 = time.time()

    return loss_min, smt(T_rec).detach(), smp(P_rec).detach(), T_rec.detach()

def count_y(KINDS, feat_cord, label, cluster_sum):
    # feat_cord = torch.tensor(final_feat)
    cnt = [[] for _ in range(3)]
    cnt[0] = torch.zeros(KINDS)
    cnt[1] = torch.zeros(KINDS, KINDS)
    cnt[2] = torch.zeros(KINDS, KINDS, KINDS)
    feat_cord = feat_cord.cpu().numpy()
    dist = distCosine(feat_cord, feat_cord)
    max_val = np.max(dist)
    am = np.argmin(dist,axis=1)
    for i in range(cluster_sum):
        dist[i][am[i]] = 10000.0 + max_val
    min_dis_id = np.argmin(dist,axis=1)
    for i in range(cluster_sum):
        dist[i][min_dis_id[i]] = 10000.0 + max_val
    min_dis_id2 = np.argmin(dist,axis=1)
    for x1 in range(cluster_sum):
        cnt[0][label[x1]] += 1
        cnt[1][label[x1]][label[min_dis_id[x1]]] += 1
        cnt[2][label[x1]][label[min_dis_id[x1]]][label[min_dis_id2[x1]]] += 1

    return cnt

def count_y_known2nn(KINDS, label_list, cluster_sum=None):

    if cluster_sum is not None:
        sample = np.random.choice(range(label_list.shape[0]), cluster_sum, replace=False)
        label_list = label_list[sample]

    cnt = [[] for _ in range(3)]
    cnt[0] = torch.zeros(KINDS)
    cnt[1] = torch.zeros(KINDS, KINDS)
    cnt[2] = torch.zeros(KINDS, KINDS, KINDS)

    for i in range(cluster_sum):
        cnt[0][label_list[i][0]] += 1
        cnt[1][label_list[i][0]][label_list[i][1]] += 1
        cnt[2][label_list[i][0]][label_list[i][1]][label_list[i][2]] += 1

    return cnt


from django.shortcuts import render, reverse, redirect
from django.views.generic import View
from django.views.generic.edit import CreateView
import requests
import re

count = 6
# Create your views here.
def home(request):
    template_name = 'home.html'
    return render(request, template_name=template_name)

def getPainting(request):
    template_name = 'arts.html'
    prelink = "https://drive.google.com/uc?export=view&id="
    if request.method == "POST":
        global count
        # request.POST['id']
        imgid = count + 1
        name = request.POST['name']
        link = request.POST['link']
        linkid = re.search(r"\bd\/\w+[^/]([A-Za-z0-9-_])*", link)
        link = prelink + linkid.group()[2:]
        requests.post('https://kvdvse6qr3.execute-api.ap-south-1.amazonaws.com/img/image',
                         json = {'imgId':f'{imgid}',
                                 'altText': f'{name}',
                                 'imgUrl': f'{link}'})

    allImages = requests.get("https://kvdvse6qr3.execute-api.ap-south-1.amazonaws.com/img/images")

    return render(request, template_name=template_name, context = { 'images': allImages.json()['images'] })

# class getPaintingView(View):
#     template_name = 'arts.html'
#     def get(self, request):
#         return render(request, self.template_name)

#     def post(self, request):
#         print(request)

# class addPaintingView(CreateView):
#     template_name = 'addArt.html'
#     def get(self, request):
#         return render(request, self.template_name)


import numpy as np
import os

import torch
from typing import List, Tuple
from tqdm import tqdm
from datetime import datetime, timedelta
import pickle
import matplotlib.pyplot as plt
# -------------------- Colorize ------------------------------------------
"""A set of common utilities used within the environments. These are
not intended as API functions, and will not remain stable over time.
"""
import numpy as np
import matplotlib.colors as colors

color2num = dict(gray=30,
                 red=31,
                 green=32,
                 yellow=33,
                 blue=34,
                 magenta=35,
                 cyan=36,
                 white=37,
                 crimson=38)

def colorize(string, color, bold=False, highlight=False):
    """Return string surrounded by appropriate terminal color codes to
    print colorized text.  Valid colors: gray, red, green, yellow,
    blue, magenta, cyan, white, crimson
    """

    # Import six here so that `utils` has no import-time dependencies.
    # We want this since we use `utils` during our import-time sanity checks
    # that verify that our dependencies (including six) are actually present.
    import six

    attr = []
    num = color2num[color]
    if highlight:
        num += 10
    attr.append(six.u(str(num)))
    if bold:
        attr.append(six.u('1'))
    attrs = six.u(';').join(attr)
    return six.u('\x1b[%sm%s\x1b[0m') % (attrs, string)

def calc_iou(times_gt, time):
    a_s, a_e = times_gt
    b_s, b_e = time
    if b_s > a_e or a_s > b_e:
        return 0
    else:
        o_s = max(a_s,b_s)
        o_e = min(a_e,b_e)
        intersection = o_e - o_s
        u_s = min(a_s,b_s)
        u_e = max(a_e,b_e)
        union = u_e - u_s
        return intersection/float(union)

def green(s):
    return colorize(s, 'green', bold=True)

def blue(s):
    return colorize(s, 'blue', bold=True)

def red(s):
    return colorize(s, 'red', bold=True)

def magenta(s):
    return colorize(s, 'magenta', bold=True)

def colorize_mat(mat, hsv):
    """
    Colorizes the values in a 2D matrix MAT
    to the color as defined by the color HSV.
    The values in the matrix modulate the 'V' (or value) channel.
    H,S (hue and saturation) are held fixed.

    HSV values are assumed to be in range [0,1].

    Returns an uint8 'RGB' image.
    """
    mat = mat.astype(np.float32)
    m, M = np.min(mat), np.max(mat)
    v = (mat - m) / (M - m)
    h, s = hsv[0] * np.ones_like(v), hsv[1] * np.ones_like(v)
    hsv = np.dstack([h, s, v])
    rgb = (255 * colors.hsv_to_rgb(hsv)).astype(np.uint8)
    return rgb

# -------------------- / Colorize ------------------------------------------

def gpu_initializer(gpu_id):
    os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_id)
    global device
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print('Using device: ', device)
    return device


# -*- coding: utf-8 -*-
from django.contrib import admin

from adminsortable2.admin import SortableAdminMixin, SortableInlineAdminMixin
from modeltranslation.admin import (
    TranslationAdmin, TranslationTabularInline, TranslationStackedInline,
    TabbedTranslationAdmin
)

from .models import (
    SiteSettings, FooterSettings, NavigationMenu, NavigationLinks
)

class HeaderSettingsAdminMixin(object):
    """
    Mixin класс для разделения сео данных в админ панели
    """
    def get_fieldsets(self, request, obj=None):
        seo_fields = ['left_side_title_en', 'left_side_title_ru',
                      'right_side_title_en', 'right_side_title_ru',
                      'right_side_description_en', 'right_side_description_ru',
                      'button_text_en', 'button_text_ru',
                      'button_link_en', 'button_link_ru']
        if self.fieldsets:
            return self.fieldsets
        fields = [
            x for x in self.get_fields(request, obj) if not x in seo_fields
        ]
        return [
            (None, {'fields': fields}), ('HeaderSettings', {
                'fields': seo_fields
            })
        ]

@admin.register(SiteSettings)
class SiteSettingsAdmin(admin.ModelAdmin):
    fields = ('favicon', 'logo', 'preloader')

@admin.register(FooterSettings)
class FooterSettingsAdmin(TabbedTranslationAdmin):
    class Media:
        js = (
            'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js',
            'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js',
            'modeltranslation/js/tabbed_translation_fields.js',
        )
        css = {
            'screen': ('modeltranslation/css/tabbed_translation_fields.css',),
        }

class NavigationLinksTabularInline(
        SortableInlineAdminMixin, TranslationStackedInline):
    model = NavigationLinks
    extra = 0

@admin.register(NavigationMenu)
class NavigationMenuAdmin(TabbedTranslationAdmin):
    list_display = ['name', 'menu_type']
    inlines = (NavigationLinksTabularInline,)

    class Media:
        js = (
            'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js',
            'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js',
            'modeltranslation/js/tabbed_translation_fields.js',
            'js/admin/admin_navigation_menu.js',
        )
        css = {
            'screen': ('modeltranslation/css/tabbed_translation_fields.css',),
        }


#!/usr/bin/env python
"""
Pymodbus Synchronous Client Example to showcase Device Information
--------------------------------------------------------------------------

This client demonstrates the use of Device Information to get information
about servers connected to the client. This is part of the MODBUS specification,
and uses the MEI 0x2B 0x0E request / response.
"""
# --------------------------------------------------------------------------- #
# import the various server implementations
# --------------------------------------------------------------------------- #
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
# from pymodbus.client.sync import ModbusUdpClient as ModbusClient
# from pymodbus.client.sync import ModbusSerialClient as ModbusClient

# --------------------------------------------------------------------------- #
# import the request
# --------------------------------------------------------------------------- #
from pymodbus.mei_message import ReadDeviceInformationRequest
from pymodbus.device import ModbusDeviceIdentification

# --------------------------------------------------------------------------- #
# configure the client logging
# --------------------------------------------------------------------------- #
import logging
FORMAT = ('%(asctime)-15s %(threadName)-15s '
          '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)

UNIT = 0x1

def run_sync_client():
    # ------------------------------------------------------------------------#
    # choose the client you want
    # ------------------------------------------------------------------------#
    # make sure to start an implementation to hit against. For this
    # you can use an existing device, the reference implementation in the tools
    # directory, or start a pymodbus server.
    #
    # If you use the UDP or TCP clients, you can override the framer being used
    # to use a custom implementation (say RTU over TCP). By default they use
    # the socket framer::
    #
    #    client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    #
    # It should be noted that you can supply an ipv4 or an ipv6 host address
    # for both the UDP and TCP clients.
    #
    # There are also other options that can be set on the client that controls
    # how transactions are performed. The current ones are:
    #
    # * retries - Specify how many retries to allow per transaction (default=3)
    # * retry_on_empty - Is an empty response a retry (default = False)
    # * source_address - Specifies the TCP source address to bind to
    #
    # Here is an example of using these options::
    #
    #    client = ModbusClient('localhost', retries=3, retry_on_empty=True)
    # ------------------------------------------------------------------------#
    client = ModbusClient('localhost', port=5020)
    # from pymodbus.transaction import ModbusRtuFramer
    # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
    # client = ModbusClient(method='binary', port='/dev/ptyp0', timeout=1)
    # client = ModbusClient(method='ascii', port='/dev/ptyp0', timeout=1)
    # client = ModbusClient(method='rtu', port='/dev/ptyp0', timeout=1,
    #                       baudrate=9600)
    client.connect()

    # ------------------------------------------------------------------------#
    # specify slave to query
    # ------------------------------------------------------------------------#
    # The slave to query is specified in an optional parameter for each
    # individual request. This can be done by specifying the `unit` parameter
    # which defaults to `0x00`
    # ----------------------------------------------------------------------- #
    log.debug("Reading Device Information")
    information = {}
    rr = None

    while not rr or rr.more_follows:
        next_object_id = rr.next_object_id if rr else 0
        rq = ReadDeviceInformationRequest(read_code=0x03, unit=UNIT,
                                          object_id=next_object_id)
        rr = client.execute(rq)
        information.update(rr.information)
        log.debug(rr)

    print("Device Information : ")
    for key in information.keys():
        print(key, information[key])

    # ----------------------------------------------------------------------- #
    # You can also have the information parsed through the
    # ModbusDeviceIdentificiation class, which gets you a more usable way
    # to access the Basic and Regular device information objects which are
    # specifically listed in the Modbus specification
    # ----------------------------------------------------------------------- #
    di = ModbusDeviceIdentification(info=information)
    print('Product Name : ', di.ProductName)

    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()

if __name__ == "__main__":
    run_sync_client()


import random , sys , traceback
from time import sleep
from selenium import webdriver
import datetime

c=1;

browser = webdriver.Chrome('D:\\Python\\Bot Insta\\chromedriver')
browser.get('https://google.com')
while c== 1:
    c=0
    try:
        browser.find_element_by_xpath('/html/body/ytd-app/div/div/ytd-masthead/div[3]/div[1]/ytd-topbar-logo-renderer/a/div[1]').click()
        print('am rulat ')
    except:
        c=1
        sleep(2)
        print('sunte in exceptie ')

print('gata')
# while browser.find_element_by_xpath('/html/body/ytd-app/div/div/ytd-masthead/div[3]/div[1]/ytd-topbar-logo-renderer/a/div[1]')==[]:
#     print("nu e bine nu gasim ce trebuie ")
#     sleep(2)
# print('am gasit')

#browser.close()
#browser.quit()


from django.urls import path
from .views import *

urlpatterns = [
    path('', PostList.as_view(), name="post_list_url"),
    path("search/", Search.as_view(), name='search_form_url'),
    path("filter/<int:pk>", DateFilter.as_view(), name='date_filter_url'),
    path("<slug:category>/", PostList.as_view(), name='post_by_category_url'),
    path("<slug:category>/<slug:slug>/", PostDetail.as_view(), name='post_detail_url'),
]


import typing as T
import asyncio
import logging
import inspect
from functools import lru_cache
from . import types
from . import transport as _transport
from . import errors
from . import stub
from . import utils
from . import spec

logger = logging.getLogger('pjrpc.server')

class Service:
    """Receive request, routing, process and response to server"""

    def _method_predicate(self, meth):
        return inspect.iscoroutinefunction(meth) or callable(meth)

    @lru_cache(maxsize=1024)
    def _get_func(self, f_name: str):
        for name, func in inspect.getmembers(self, self._method_predicate):
            if name == f_name:
                return func

        raise errors.MethodNotFoundError()

    def _check_args(self, args: T.Dict[str, T.Type], func: T.Callable):
        #TODO: check default value
        annotations = func.__annotations__

        for k, v in args.items():
            if k in annotations:
                if type(v) is not annotations[k]:
                    raise errors.InvalidParamError()

    async def __call__(
        self,
        request: types.Request,
    ) -> T.Union[spec.ErrorResponseMessage, spec.SuccessResponseMessage]:

        target = self._get_func(request.method)
        params = request.params or {}

        self._check_args(params, target)

        if not inspect.iscoroutinefunction(target):
            target = utils.to_async()(target)

        ret = await target(**params)

        if not isinstance(request, spec.Notification):
            return utils.make_response_from_data(
                id=request.id,
                result=ret,
            )

class Server:

    def __init__(
        self,
        app_path: str,
        host: str = '127.0.0.1',
        port: int = 6969,
        compress: bool = False,
    ):

        self._app_cls = utils.load_app_from_string(app_path)
        self._host = host
        self._port = port
        self._stub = stub.Stub(compress)
        self._loop = asyncio.get_event_loop()
        self._futures = {}

    async def connection_handler(
        self,
        reader: asyncio.StreamReader,
        writer: asyncio.StreamWriter,
    ):
        transport = _transport.ServerTransport(reader, writer, interval=2, alive=5)

        async def dispatch_request(request):
            if isinstance(request, list):
                async def batch_request(requests):
                    app = self._app_cls()

                    tasks = []
                    for request in requests:
                        if isinstance(request, spec.Notification):
                            self._loop.create_task(app(request))
                        else:
                            f = self._loop.create_task(app(request))
                            tasks.append(f)

                    if len(tasks) == 0:
                        return None

                    responses = asyncio.wait(tasks)
                    return responses

                return await batch_request(request)

            return await self._app_cls()(request)

        def on_request_done(fut):
            err = fut.exception()
            if err:
                ret = utils.make_response_from_data(
                    error={'code': err.code, 'message': err.message})
            else:
                ret = fut.result()
            self._loop.create_task(transport.send_message(self._stub.pack(ret)))

        async for in_data in transport.messages():
            try:
                request = self._stub.unpack(in_data)

            except errors.ParseError as error:
                err_resp = utils.make_response_from_data(
                    error={'code': error.code, 'message': error.message})
                out_data = self._stub.pack(err_resp)
                self._loop.create_task(transport.send_message(out_data))

            f = self._loop.create_task(dispatch_request(request))
            f.add_done_callback(on_request_done)

    def protocol_factory(self):
        reader = asyncio.StreamReader(limit=1024, loop=self._loop)
        protocol = asyncio.StreamReaderProtocol(
            reader, self.connection_handler, loop=self._loop)
        return protocol

    async def start(self):
        server = await self._loop.create_server(self.protocol_factory, self._host, self._port)

        async with server:
            logger.info('Server is starting on port %d ...', self._port)
            await server.serve_forever()