# mainMTLgender2.py
# genderLoss와 ageLoss 합치기 : 로직
#
#
#   1. minimize w1/L1 + w2/L2 -> L1>L2 -> w1=1, w2=0
#                                L1<L2 -> w1=0, w2=1
#   2. 만약 L1, L2이고 L2 = L21 + L22 + L23로 구성된다면?
#                     동시에 minimize하고 싶다면?
#                     만약 L2가 결정되어 있다면(계수가 정해져 있다면),
#                     w1,w2는 w1/L1 + w2/L2로 결정하고,
#                     L2 내에서는 w21/L21 + w22/L22 + w23/L23으로 결정할 수 있을 듯...
import os
import time
import json
import argparse
import torch
import torchvision
import random
import numpy as np
from data import FaceDataset
from tqdm import tqdm
from torch import nn
from torch import optim
from collections import OrderedDict
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torch.optim import lr_scheduler
from torchvision.models.resnet import resnet34
from torchvision.models.resnet import resnet152
from torchvision.models.resnet import ResNet
from mean_variance_loss import MeanVarianceLoss
from mean_variance_loss import MeanVarianceLoss2
from mean_variance_loss import MeanVarianceLossMTL
from mean_variance_loss import MeanVarianceLossMTL2
import cv2
#from torchsummary import summary

from torch.utils.tensorboard import SummaryWriter

#LAMBDA_1 = 0.2
#LAMBDA_2 = 0.05
START_AGE = 0
END_AGE = 69
VALIDATION_RATE= 0.1

random.seed(2019)
np.random.seed(2019)
torch.manual_seed(2019)

#DEV_CUDA = 'cuda:1'
# change DEV_CUDA in mean_varaince_loss.py

def ResNet34(num_classes):

    model = resnet34(pretrained=True)
    model.fc = nn.Sequential(
        nn.BatchNorm1d(512),
        nn.Dropout(0.5),
        nn.Linear(512, num_classes),
    )
    model.fcGender = nn.Sequential(
        nn.BatchNorm1d(512),
        nn.Dropout(0.5),
        nn.Linear(512, 1),
        nn.Sigmoid()
    )
    #model.lossRatio = nn.Sequential(
    #    nn.Linear(512, 3), # fc(softmax, mean, variance) + gender
    #    nn.Softmax(dim=1)
    #)
    model.lossRatioAll = nn.Sequential(
        nn.Linear(512, 1), # fc(age) + gender
        nn.Sigmoid()
    )
    model.lossRatioAge = nn.Sequential(
        nn.Linear(512, 3), # fc(softmax, mean, variance)
        nn.Softmax(dim=1)
    )
    return model

def ResNet152(num_classes):

    model = resnet152(pretrained=True)
    model.fc = nn.Sequential(
        nn.BatchNorm1d(2048),
        nn.Dropout(0.5),
        nn.Linear(2048, num_classes),
    )
    model.fcGender = nn.Sequential(
        nn.BatchNorm1d(2048),
        nn.Dropout(0.5),
        nn.Linear(2048, 1),
        nn.Sigmoid()
    )
    #model.lossRatio = nn.Sequential(
    #    nn.Linear(2048, 3), # fc(softmax, mean, variance) + gender
    #    nn.Softmax(dim=1)
    #)
    model.lossRatioAll = nn.Sequential(
        nn.Linear(2048, 1), # fc(age) + gender
        nn.Sigmoid()
    )
    model.lossRatioAge = nn.Sequential(
        nn.Linear(2048, 3), # fc(softmax, mean, variance)
        nn.Softmax(dim=1)
    )
    return model

def ResNet50(num_classes):

    model = resnet50(pretrained=True)
    model.fc = nn.Sequential(
        nn.BatchNorm1d(2048),
        nn.Dropout(0.5),
        nn.Linear(2048, num_classes),
    )
    model.fcGender = nn.Sequential(
        nn.BatchNorm1d(2048),
        nn.Dropout(0.5),
        nn.Linear(2048, 1),
        nn.Sigmoid()
    )
    #model.lossRatio = nn.Sequential(
    #    nn.Linear(2048, 3), # fc(softmax, mean, variance) + gender
    #    nn.Softmax(dim=1)
    #)
    model.lossRatioAll = nn.Sequential(
        nn.Linear(2048, 1), # fc(age) + gender
        nn.Sigmoid()
    )
    model.lossRatioAge = nn.Sequential(
        nn.Linear(2048, 3), # fc(softmax, mean, variance)
        nn.Softmax(dim=1)
    )
    return model

def train(train_loader, model, criterion1, criterion2, criterionGender,\
          optimizer, optimizerwAll, optimizerwAge, epoch, result_directory):

    #global LAMBDA_1, LAMBDA_2

    model.train()
    running_loss = 0.
    running_mean_loss = 0.
    running_variance_loss = 0.
    running_softmax_loss = 0.
    running_gender_loss = 0.

    running_w_mean = 0.
    running_w_variance = 0.
    running_w_softmax = 0.
    running_w_gender = 0.
    interval = 5
    for i, sample in enumerate(train_loader):
        images = sample['image'].cuda()
        labels = sample['label'].cuda()
        labels2 = sample['label2'].cuda()

        output, outputGender, lRAll, lRAge = model(images)

        # Age
        mean_loss, variance_loss = criterion1(output, labels)
        softmax_loss = criterion2(output, labels)
        # Gender
        lossGender = criterionGender(outputGender, labels2)

        # 각 component의 loss 구하기
        l1 = mean_loss.item()
        l2 = variance_loss.item()
        # criterion2 = torch.nn.CrossEntropyLoss().cuda(), model.forward(x) -> nn.Linear(x)
        l3 = softmax_loss.item()
        lGender = lossGender.item()
        lAge = model.loss_lambda1 * l1 + model.loss_lambda2 * l2 + 1 * l3 # loss weight에 따라 변하지 않는 고유 loss?
        lTotal = lGender + lAge
        print("l1, l2, l3, lGender, lAge, lTotal = ", l1, l2, l3, lGender, lAge, lTotal)

        # loss weights parameter를 포함한 loss function sum w/L 구하기
        lRAll_ = lRAll[:,0].mean()
        losswAll = lRAll_/lAge + (1-lRAll_)/lGender

        losswAge = (lRAge[:,0].mean()/(model.loss_lambda1*l1)) + \
                   (lRAge[:,1].mean()/(model.loss_lambda2*l2)) + \
                   (lRAge[:,2].mean()/l3)

        #print("lR", lR)

        if (np.isnan(l1) or np.isnan(l2) or np.isnan(l3) or np.isinf(l1) or np.isinf(l2) or np.isinf(l3) \
            or np.isnan(lGender) or np.isinf(lGender) or np.isnan(lAge) or np.isinf(lAge)):
            print('one of l1, l2, l3, lGender is inf or nan!!!')
            import sys
            sys.exit()

        optimizerwAll.zero_grad()
        losswAll.backward(retain_graph = True)
        optimizerwAll.step()

        lRAll_ = lRAll.mean(axis=0).detach()
        lRAll_ = lRAll_*0.8 + 0.1 # at least 0.1 with 2 tasks

        optimizerwAge.zero_grad()
        losswAge.backward(retain_graph = True)
        optimizerwAge.step()

        lRAge_ = lRAge.mean(axis=0).detach()
        lRAge_ = lRAge_*0.7 + 0.1 # at least 0.1 with 2 tasks

        optimizer.zero_grad() #lRAll_ or lRAll_[0]?
        loss = (lRAll_* \
                 (lRAge_[0] * model.loss_lambda1* mean_loss + \
                  lRAge_[1] * model.loss_lambda2 * variance_loss + \
                  lRAge_[2] * softmax_loss) + \
                (1 - lRAll_) * \
                  (lossGender)).mean()
        print('loss weights(mean, variance, softmax, sigmoid) = ', \
              lRAll_.item() * lRAge_[0].item(), lRAll_.item() * lRAge_[0].item(), lRAll_.item() * lRAge_[0].item(), \
              (1-lRAll_).item)
        loss.backward()
        optimizer.step()

        #running_loss += loss.data
        running_loss += l1 + l2 + l3 + lGender # to match val_loss
        running_mean_loss += mean_loss.data
        running_variance_loss += variance_loss.data
        running_softmax_loss += softmax_loss.data
        running_gender_loss += lossGender.data

        running_w_mean += lRAll_.data*lRAge_[0].data
        running_w_variance += lRAll_.data*lRAge_[1].data
        running_w_softmax += lRAll_.data*lRAge_[2].data
        running_w_gender += (1-lRAll_.data)

        if (i + 1) % interval == 0:
            print('[%d, %5d] mean_loss: %.3f, variance_loss: %.3f, softmax_loss: %.3f, gender_loss: %.3f, loss: %.3f'
                  % (epoch, i, running_mean_loss / interval,
                     running_variance_loss / interval,
                     running_softmax_loss / interval,
                     running_gender_loss /interval,
                     running_loss / interval))
            with open(os.path.join(result_directory, 'log'), 'a') as f:
                f.write('[%d, %5d] mean_loss: %.3f, variance_loss: %.3f, softmax_loss: %.3f, gender_loss: %.3f, loss: %.3f\n'
                        % (epoch, i, running_mean_loss / interval,
                           running_variance_loss / interval,
                           running_softmax_loss / interval,
                           running_gender_loss / interval,
                           running_loss / interval))

    return running_mean_loss/len(train_loader), running_variance_loss/len(train_loader), \
           running_softmax_loss/len(train_loader), running_gender_loss/len(train_loader), running_loss/len(train_loader), \
           running_w_mean/len(train_loader), running_w_variance/len(train_loader), running_w_softmax/len(train_loader), \
           running_w_gender/len(train_loader)

## RETURN of evaluate
#    return mean_loss_val / len(val_loader),\    # mean
#        variance_loss_val / len(val_loader),\   # variance
#        softmax_loss_val / len(val_loader),\    # soft-max
#        loss_val / len(val_loader),\            # total loss
#        mae / len(val_loader)                   # mae

## POSSIBLE WAYS TO constrain lossRatio1, lossRatio2, lossRatio3
#  1. weight decay
#  2. hard constraints on logit(p)
#  3. hard constraints on p

## ISSUES?
#  1. initial losses have different scales?!!!
#  2.

def evaluate(val_loader, model, criterion1, criterion2, criterionGender):
    model.cuda()
    model.eval()
    loss_val = 0.
    mean_loss_val = 0.
    variance_loss_val = 0.
    softmax_loss_val = 0.
    gender_loss_val = 0.
    mae = 0.
    acc_gen = 0.
    with torch.no_grad():
        for i, sample in enumerate(val_loader):
            image = sample['image'].cuda()
            label = sample['label'].cuda()
            label2 = sample['label2'].cuda()
            label2 = label2.reshape(-1,1)

            #output, outputGender, lRAll, lRAge = model(images)
            #
            output, outputGender, _, __ = model(image)
            mean_loss, variance_loss = criterion1(output, label)
            softmax_loss = criterion2(output, label)
            lossGender = criterionGender(outputGender, label2)

            acc_gen += ((outputGender > 0.5 and label2 == 1) or (outputGender < 0.5 and label2 == 0) )*1.
            #acc_gen += (lossGender < 0.30102999566)*1.

            loss = mean_loss + variance_loss + softmax_loss + lossGender
            loss_val += loss.data
            mean_loss_val += mean_loss.data
            variance_loss_val += variance_loss.data
            softmax_loss_val += softmax_loss.data
            gender_loss_val += lossGender.data
            m = nn.Softmax(dim=1)
            output_softmax = m(output)
            a = torch.arange(START_AGE, END_AGE + 1, dtype=torch.float32).cuda()
            mean = (output_softmax * a).sum(1, keepdim=True).cpu().data.numpy()
            pred = np.around(mean)
            mae += np.absolute(pred - sample['label'].cpu().data.numpy())

    return mean_loss_val / len(val_loader),\
        variance_loss_val / len(val_loader),\
        softmax_loss_val / len(val_loader),\
        gender_loss_val/len(val_loader),\
        loss_val / len(val_loader),\
        mae / len(val_loader),\
        acc_gen / len(val_loader)

def test(test_loader, model):
    model.cuda()
    model.eval()
    mae = 0.
    acc_gen = 0.
    with torch.no_grad():
        for i, sample in enumerate(test_loader):
            image = sample['image'].cuda()
            label = sample['label'].cuda()
            label2 = sample['label2'].cuda()
            label2 = label2.reshape(-1,1)
            output, outputGender, _, __ = model(image)
            #lossGender =  criterionGender(outputGender, label2)
            m = nn.Softmax(dim=1)
            output = m(output)
            a = torch.arange(START_AGE, END_AGE + 1, dtype=torch.float32).cuda()
            mean = (output * a).sum(1, keepdim=True).cpu().data.numpy()
            pred = np.around(mean)
            mae += np.absolute(pred - sample['label'].cpu().data.numpy())
            acc_gen += ((outputGender > 0.5 and label2 == 1) or (outputGender < 0.5 and label2 == 0) )*1.
    return mae / len(test_loader), acc_gen/len(test_loader)

def predict(model, image):

    model.eval()
    with torch.no_grad():
        image = image.astype(np.float32) / 255.
        image = np.transpose(image, (2,0,1))
        img = torch.from_numpy(image).cuda()
        output, _, __ = model(img[None]) # age, gender, lossRatio
        m = nn.Softmax(dim=1)
        output = m(output)
        a = torch.arange(START_AGE, END_AGE + 1, dtype=torch.float32).cuda()
        mean = (output * a).sum(1, keepdim=True).cpu().data.numpy()
        pred = np.around(mean)[0][0]
    return pred

def get_image_list(image_directory, leave_sub, validation_rate):

    train_val_list = []
    test_list = []
    for fn in os.listdir(image_directory):
        if not('ipynb' in fn): # filtering!
            filepath = os.path.join(image_directory, fn)
            subject = int(fn[:3])
            if subject == leave_sub:
                test_list.append(filepath)
            else:
                train_val_list.append(filepath)
    num = len(train_val_list)
    index_val = np.random.choice(num, int(num * validation_rate), replace=False)
    train_list = []
    val_list = []
    for i, fp in enumerate(train_val_list):
        if i in index_val:
            val_list.append(fp)
        else:
            train_list.append(fp)

    return train_list, val_list, test_list

def get_args():

    parser = argparse.ArgumentParser()
    parser = argparse.ArgumentParser()
    parser.add_argument('-b', '--batch_size', type=int, default=16)
    parser.add_argument('-l', '--loss_type', type=int, default=1)
    parser.add_argument('-i', '--image_directory', type=str)
    parser.add_argument('-ls', '--leave_subject', type=int)
    parser.add_argument('-lr', '--learning_rate', type=float)
    parser.add_argument('-l1', '--lambda1', type=float, default=0.2)
    parser.add_argument('-l2', '--lambda2', type=float, default=0.05)
    parser.add_argument('-e', '--epoch', type=int, default=0)
    parser.add_argument('-r', '--resume', type=str, default=None)
    parser.add_argument('-rd', '--result_directory', type=str, default=None)
    parser.add_argument('-pi', '--pred_image', type=str, default=None)
    parser.add_argument('-pm', '--pred_model', type=str, default=None)
    parser.add_argument('-cu', '--cuda', type=int, default=0)
    parser.add_argument('-C', '--CNN', type=str, default='resnet34')
    parser.add_argument('-m', '--meta', type=str, default=None)
    parser.add_argument('-p', '--parallel', type=int, default=0)

    return parser.parse_args()

def main():

    import sys
    sys.path.append('../../utils-max/')
    # Here = max/Research/AgeEstimation
    #        max/utils-max/
    import newprint
    from newprint import print0, print2, print

    args = get_args()
    #if args.cuda == 1:
    #    DEV_CUDA = 'cuda:1'
    #Does not work properly.
    #  RuntimeError: Expected tensor for argument #1 'input' to have the same device as tensor for argument #2 'weight'; but device 0does not equal 1 #(while checking arguments for cudnn_convolution)
    if args.cuda:
        torch.cuda.set_device(args.cuda)
    LAMBDA_1 = args.lambda1
    LAMBDA_2 = args.lambda2

    def forward(self, x):
        # See note [TorchScript super()]
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)

        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)

        x = self.avgpool(x)
        xout = torch.flatten(x, 1)

        y = self.fc(xout)
        gender = self.fcGender(xout)
        #lossR = self.lossRatio(xout)
        lossRAll = self.lossRatioAll(xout)
        lossRAge = self.lossRatioAge(xout)

        return y,gender,lossRAll, lossRAge

    ResNet.forward = forward

    if args.CNN == 'resnet34':
        model = ResNet34(END_AGE - START_AGE + 1)
    elif args.CNN == 'resnet50':
        model = ResNet50(END_AGE - START_AGE + 1)
    elif args.CNN == 'resnet152':
        model = ResNet152(END_AGE - START_AGE + 1)
    else:
        raise ValueError("CNN model not found", args.CNN)

    import os

    if args.meta is not None:
        if not os.path.isfile(args.meta):
            raise ValueError('meta file DOES NOT exist. --meta ' + args.meta)

    model.cuda()

    model.loss_lambda1 = args.lambda1
    model.loss_lambda2 = args.lambda2

    if args.epoch > 0:
        import pandas as pd
        datMeta = pd.read_csv(args.meta, index_col=0, dtype = {'id':'str'})
        batch_size = args.batch_size
        if args.result_directory is None:
            args.result_directory = 'result-DMTLgender2-'+ args.CNN + \
                                    '-l'+str(args.loss_type) + \
                                    f'-lr={int(args.learning_rate*100000):06d}' + \
                                    f'-l1={int(args.lambda1*1000):04d}' + \
                                    f'-l2={int(args.lambda2*1000):04d}' + \
                                    f'-e{args.epoch:06d}'
            print('result_directory = ', args.result_directory)
            #raise ValueError('stop')

        if args.result_directory is not None:
        #else:
            while os.path.isdir(args.result_directory):
                args.result_directory = args.result_directory + "_"
            if not os.path.exists(args.result_directory):
                os.mkdir(args.result_directory)
        print('result_directory modified to = ', args.result_directory)
        writer_train = SummaryWriter(args.result_directory+'train') # tensorboard
        writer_val = SummaryWriter(args.result_directory+'val') # tensorboard
        writer_test = SummaryWriter(args.result_directory+'test') # tensorboard

        train_filepath_list, val_filepath_list, test_filepath_list\
            = get_image_list(args.image_directory, args.leave_subject, VALIDATION_RATE)
        transforms_train = torchvision.transforms.Compose([
            torchvision.transforms.ToPILImage(),
            torchvision.transforms.RandomApply(
                [torchvision.transforms.RandomAffine(degrees=10, shear=16),
                 torchvision.transforms.RandomHorizontalFlip(p=1.0),
                ], p=0.5),
            torchvision.transforms.Resize((256, 256)),
            torchvision.transforms.RandomCrop((224, 224)),
            torchvision.transforms.ToTensor()
        ])
        train_gen = FaceDataset(train_filepath_list, transforms_train, datMeta=datMeta)
        train_loader = DataLoader(train_gen, batch_size=batch_size, shuffle=True, pin_memory=True, num_workers=8)

        transforms = torchvision.transforms.Compose([
            torchvision.transforms.ToPILImage(),
            torchvision.transforms.Resize((224, 224)),
            torchvision.transforms.ToTensor()
        ])
        val_gen = FaceDataset(val_filepath_list, transforms, datMeta=datMeta)
        val_loader = DataLoader(val_gen, batch_size=1, shuffle=False, pin_memory=True, num_workers=8)

        test_gen = FaceDataset(test_filepath_list, transforms, datMeta=datMeta)
        test_loader = DataLoader(test_gen, batch_size=1, shuffle=False, pin_memory=True, num_workers=8)

        #https://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object-instance

        #optimizer = optim.SGD(model.parameters(), lr = args.learning_rate, momentum=0.9, weight_decay=1e-4)

        #optimizerw = optim.SGD(model.lossRatio.parameters(), lr = args.learning_rate, momentum=0.9, weight_decay=1e-2)

        optimizerwAll = optim.SGD(model.lossRatioAll.parameters(), lr = args.learning_rate, momentum=0.9, weight_decay=1e-2)
        optimizerwAge = optim.SGD(model.lossRatioAge.parameters(), lr = args.learning_rate, momentum=0.9, weight_decay=1e-2)

        lparameters = [model.conv1, model.bn1, model.relu, model.maxpool, \
                       model.layer1, model.layer2, model.layer3, model.layer4, \
                       model.avgpool, model.fc, model.fcGender]

        params = []

        for i, layer in enumerate(lparameters):
            #print(i, layer)
            for p in layer.parameters():
                params.append(p)

        optimizer = torch.optim.SGD(params, lr=args.learning_rate, momentum=0.9, weight_decay=1e-4)

        if args.loss_type == 1:
            criterion1 = MeanVarianceLossMTL(START_AGE, END_AGE).cuda()
        elif args.loss_type == 2:
            criterion1 = MeanVarianceLossMTL2(START_AGE, END_AGE).cuda()
        else:
            raise ValueError('loss_type should be either 1 or 2')
        criterion2 = torch.nn.CrossEntropyLoss().cuda()

        criterionGender = torch.nn.BCELoss().cuda()  # with Sigmoid output

        # scheduler = lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.1)
        scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[40, 60], gamma=0.1)
        schedulerwAll = lr_scheduler.MultiStepLR(optimizerwAll, milestones=[40, 60], gamma=0.1)
        schedulerwAge = lr_scheduler.MultiStepLR(optimizerwAge, milestones=[40, 60], gamma=0.1)

        for param in model.parameters():
            param.requires_grad = False
        for param in model.fc.parameters():
            param.requires_grad = True
        for param in model.lossRatioAll.parameters():
            param.requires_grad = True
        for param in model.lossRatioAge.parameters():
            param.requires_grad = True

        best_val_mae = np.inf
        best_val_loss = np.inf
        best_mae_epoch = -1
        best_loss_epoch = -1
        for epoch in range(args.epoch):
            if epoch == 10:
                for param in model.parameters():
                    param.requires_grad = True
            scheduler.step(epoch)
            schedulerwAll.step(epoch)
            schedulerwAge.step(epoch)

            mean_loss_train, variance_loss_train, softmax_loss_train, gender_loss_train, loss_train, lR1, lR2, lR3, lRGender = \
                train(train_loader, model, criterion1, criterion2, criterionGender, optimizer, optimizerwAll, optimizerwAge, epoch, args.result_directory)

            ## torch.isnan, torch.isinf
            mean_loss, variance_loss, softmax_loss, gender_loss, loss_val, mae, acc_gen = evaluate(val_loader, model, \
                                                                                criterion1, criterion2, criterionGender)
            mae_test, acc_gen_test  = test(test_loader, model)
            print('epoch: %d, mean_loss: %.3f, variance_loss: %.3f, softmax_loss: %.3f, gender_loss: %.3f, loss: %.3f, mae: %3f, acc_gen: %3f' %
                (epoch, mean_loss, variance_loss, softmax_loss, gender_loss, loss_val, mae, acc_gen))
            print('epoch: %d, test_mae: %3f, test_acc_gen: %3f' % (epoch, mae_test, acc_gen_test))
            with open(os.path.join(args.result_directory, 'log'), 'a') as f:
                f.write('epoch: %d, mean_loss: %.3f, variance_loss: %.3f, softmax_loss: %.3f, gender_loss: %.3f, loss: %.3f, mae: %3f, acc_gen: %3f' %
                (epoch, mean_loss, variance_loss, softmax_loss, gender_loss, loss_val, mae, acc_gen))
                f.write('epoch: %d, test_mae: %3f, test_acc_gen: %3f' % (epoch, mae_test, acc_gen_test))

            writer_train.add_scalar('lossRatio/mean', lR1, epoch)
            writer_train.add_scalar('lossRatio/variance', lR2, epoch)
            writer_train.add_scalar('lossRatio/softmax', lR3, epoch)
            writer_train.add_scalar('lossRatio/gender', lRGender, epoch)

            #writer.add_scalar('mae/val', mae, epoch)
            #writer.add_scalar('mae/test', mae_test, epoch)
            writer_val.add_scalar('mae', mae, epoch)
            writer_test.add_scalar('mae', mae_test, epoch)
            writer_val.add_scalar('accuracy', acc_gen, epoch)
            writer_test.add_scalar('accuracy', acc_gen_test, epoch)
            #writer.add_scalar('total-loss/train', loss_train, epoch)
            #writer.add_scalar('total-loss/val', loss_val, epoch)
            writer_train.add_scalar('total-loss', loss_train, epoch)
            writer_val.add_scalar('total-loss', loss_val, epoch)

            #writer.add_scalar('loss/train-mean', mean_loss_train, epoch)
            #writer.add_scalar('loss/val-mean', mean_loss, epoch)
            writer_train.add_scalar('loss/mean', mean_loss_train, epoch)
            writer_val.add_scalar('loss/mean', mean_loss, epoch)

            #writer.add_scalar('loss/train-var', variance_loss_train, epoch)
            #writer.add_scalar('loss/val-var', variance_loss, epoch)
            writer_train.add_scalar('loss/var', variance_loss_train, epoch)
            writer_val.add_scalar('loss/var', variance_loss, epoch)

            #writer.add_scalar('loss/train-soft', softmax_loss_train, epoch)
            #writer.add_scalar('loss/val-soft', softmax_loss, epoch)
            writer_train.add_scalar('loss/soft', softmax_loss_train, epoch)
            writer_val.add_scalar('loss/soft', softmax_loss, epoch)

            writer_train.add_scalar('loss/gender', gender_loss_train, epoch)
            writer_val.add_scalar('loss/gender', gender_loss, epoch)

            #writer.add_scalars('loss/trainAndVal', {'train':loss_train, 'val':loss_val}, epoch)

            if best_val_mae > mae:
                best_val_mae = mae
                best_mae_epoch = epoch
                torch.save(model.state_dict(), os.path.join(args.result_directory, "model_best_mae"))
            if best_val_loss > loss_val:
                best_val_loss = loss_val
                best_loss_epoch = epoch
                torch.save(model.state_dict(), os.path.join(args.result_directory, "model_best_loss"))
            with open(os.path.join(args.result_directory, 'log'), 'a') as f:
                f.write('best_loss_epoch: %d, best_val_loss: %f, best_mae_epoch: %d, best_val_mae: %f\n'
                        % (best_loss_epoch, best_val_loss, best_mae_epoch, best_val_mae))
            print('best_loss_epoch: %d, best_val_loss: %f, best_mae_epoch: %d, best_val_mae: %f'
                  % (best_loss_epoch, best_val_loss, best_mae_epoch, best_val_mae))
    if args.pred_image and args.pred_model:
        model = ResNet34(END_AGE - START_AGE + 1)
        model.cuda()
        img = cv2.imread(args.pred_image)
        resized_img = cv2.resize(img, (224, 224))
        model.load_state_dict(torch.load(args.pred_model))
        pred = predict(model, resized_img)
        print('Age: ' + str(int(pred)))
        cv2.putText(img, 'Age: ' + str(int(pred)), (int(img.shape[1]*0.1), int(img.shape[0]*0.9)), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
        name, ext = os.path.splitext(args.pred_image)
        cv2.imwrite(name + '_result.jpg', img)

if __name__ == "__main__":
    main()

# * 모든 directory에서 print 교체???
# * result-DMTLgender-resnet34-l2-lr=000640-l1=1000-l2=1000-e000500에서 nan가 발생하는 것은 어떤 이유인가?
#


def cal(n,k):
    re=[]
    if k==1:
        re.append(n)
    else:
        while n>0:
            re.insert(0,n%k)
            temp=0
            while n>=k:
                temp+=1
                n=n-k
            n=temp
    return re

a=input()
del a[0]
del a[-1]
n=0
for i in range(len(a)-1,-1,-1):
    n+=pow(10,i)*int(a[i])
k=1
while True:
    temp=cal(n,k)
    for i in range(0,len(temp)):
        if temp[i]!=1:
            break
    else:
        break
    k+=1
print(k)


#!/usr/bin/env python3

import re
import subprocess
import processes
from loggingtime import logging_time

class ModClass:
    def __init__(self, pid, path):
        self.name = path.split('/')[-1]
        self.att = ""
        self.pids = [pid]
#        self.digsig
        self.accdate = ""
        self.moddate = ""
        self.version = ""
#        self.product = ""
#        self.company = ""
        self.path = path
        self.md5 = ""
        self.sha256 = ""
        self.strpids = ""

    def add_pids(self, pids):
        for pid in pids:
            if pid not in self.pids:
                self.pids.append(pid)

    def make_strpids(self):
        self.strpids = str(self.pids)
        self.strpids = self.strpids.strip()

def get_data(moddict):
    get_data_from_command(moddict)

# @logging_time
def get_data_from_command(moddict):
    argstr = " ".join(moddict.keys())
#    result = subprocess.check_output("./dateandhash.sh " + argstr,
#                                     shell=True).decode("utf-8")
    result = subprocess.check_output("./everyiteration.sh " + argstr,
                                     shell=True).decode("utf-8")
    result = result.strip()
    result = result.split("\n")
    for line in result:
        if line == "":
            continue
        line = line.split(" | ")
        path = line[0]
        moddict[path].accdate = line[1]
        moddict[path].moddate = line[2]
        moddict[path].md5 = line[3]
        moddict[path].sha256 = line[4]
    # self.version

# @logging_time
def modules():
    dirlist = processes.get_processes("/proc/")

    moddict = dict()
    for dirname in dirlist:
        try:
            f = open("/proc/" + dirname + "/maps")
            data = f.readlines()
            for line in data:
                pline = line.replace("\t", " ")
                pline = pline.replace("\n", "")
                pline = re.sub(" +", " ", pline)
                pline = pline.strip()
                pline = pline.split(" ")[-1]
                if pline[0] != '/':
                    continue
                if pline.split(".so")[-1] != "" and ".so." not in pline:
                    continue
                if pline not in moddict:
                    moddict[pline] = ModClass(int(dirname), pline)
                else:
                    moddict[pline].add_pids([int(dirname)])
            f.close()
        except FileNotFoundError:
            continue

    argstr = " ".join(moddict.keys())
    result = subprocess.check_output("./popensh.sh " + argstr,
                                     shell=True).decode("utf-8")
    result = result.strip()
    result = result.split("\n")
    for line in result:
        if line == "":
            break
        line = line.split(" ")
        moddict[line[1]].add_pids(moddict[line[0]].pids)
        del moddict[line[0]]
    get_data(moddict)

    f = open("./res_modules", "w")
    for mod in moddict.values():
        mod.make_strpids()
        printstr = (
            f"{mod.name:<20} {mod.att:<3} {mod.strpids:<50} "
            f"{mod.accdate:<20} {mod.moddate:<20} {mod.version:<5} "
            f"{mod.path:<40} {mod.md5:<50} {mod.sha256:<50}"
        )
#        print(printstr)
        f.write(printstr + "\n")
    f.close()

# placeholder
if __name__ == "__main__":
    modules()


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

import time
from enum import IntEnum

import txaio
from blinker import signal
from dateutil import parser

from . import OKEXWsClientFactory, OKEXWsClientProtocol
from ..quote.master import Side
from ..quote.realtime import Depth, Snapshot, Transaction

class DepthN(IntEnum):
    D5 = 5
    D10 = 10
    D20 = 20
    D200 = 200

class RealtimeService(OKEXWsClientFactory):
    DEPTH_FMT = 'ok_sub_spot_{}_depth'
    DEAL_FMT = 'ok_sub_spot_{}_deals'
    SNAPSHOT_FMT = 'ok_sub_spot_{}_ticker'
    DEPTH_N_FMT = 'ok_sub_spot_{}_depth_{}'

    def sub_snapshot(self, symbols, on_snapshot_handler):
        self._connect_signal(self.SNAPSHOT_FMT, symbols, on_snapshot_handler)

    def unsub_snapshot(self, symbols, on_snapshot_handler):
        self._disconnect_signal(self.SNAPSHOT_FMT, symbols,
                                on_snapshot_handler)

    def sub_depth(self, symbols, on_depth_handler, depth_n=DepthN.D200):
        if depth_n == DepthN.D200:
            self._connect_signal(self.DEPTH_FMT, symbols, on_depth_handler)
        else:
            self._connect_signal(self.DEPTH_N_FMT, symbols, on_depth_handler,
                                 depth_n)

    def unsub_depth(self, symbols, on_depth_handler, depth_n=DepthN.D200):
        if depth_n == DepthN.D200:
            self._disconnect_signal(self.DEPTH_FMT, symbols, on_depth_handler)
        else:
            self._disconnect_signal(self.DEPTH_N_FMT, symbols,
                                    on_depth_handler, depth_n)

    def sub_transaction(self, symbols, on_transaction_handler):
        self._connect_signal(self.DEAL_FMT, symbols, on_transaction_handler)

    def unsub_transaction(self, symbols, on_transaction_handler):
        self._disconnect_signal(self.DEAL_FMT, symbols, on_transaction_handler)

    def _connect_signal(self, channel_format, symbols, handler, suffix=None):
        params = []
        for symbol in symbols:
            channel = self._join_channel(channel_format, symbol, suffix)
            if len(signal(channel).receivers) == 0:
                params.append({'event': 'addChannel', 'channel': channel})
                self.connected_channels.add(channel)
            signal(channel).connect(handler)
        self._send_text(params)
        self.log.info('add channels {}'.format(params))

    def _disconnect_signal(self, channel_format, symbols, handler,
                           suffix=None):
        params = []
        for symbol in symbols:
            channel = self._join_channel(channel_format, symbol, suffix)
            signal(channel).disconnect(handler)
            if len(signal(channel).receivers) == 0:
                params.append({'event': 'removeChannel', 'channel': channel})
                self.connected_channels.remove(channel)
        self._send_text(params)
        self.log.info('remove channels {}'.format(params))

    def _join_channel(self, channel_format, symbol, suffix):
        if suffix:
            return channel_format.format(symbol, suffix)
        else:
            return channel_format.format(symbol)

    def _send_text(self, params):
        if len(params) != 0:
            if self.proto_inst:
                self.proto_inst.send_text(params)

class RealtimeProtocol(OKEXWsClientProtocol):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._channel_handlers = {
            'depth': self._on_depth,
            'deals': self._on_deal,
            'ticker': self._on_snapshot,
            str(DepthN.D5.value): self._on_depth,
            str(DepthN.D10.value): self._on_depth,
            str(DepthN.D20.value): self._on_depth,
            # 'addChannel': self._on_addchannel,
            # 'removeChannel': self._on_rmchannel,
        }

    def _on_open(self):
        super()._on_open()
        params = []
        for channel in self.factory.connected_channels:
            params.append({'event': 'addChannel', 'channel': channel})
        self.send_text(params)

    def _on_depth(self, channel, msg):
        symbol = self._parse_symbol(channel)
        data = msg['data']
        try:
            depth = Depth(
                exchange_ts=data['timestamp'] / 1000.0,
                local_ts=time.time(),
                symbol=symbol,
                depth={
                    Side.ASK: [
                        level_info
                        for level_info in self._level_data_gen(data, 'asks')
                    ],
                    Side.BID: [
                        level_info
                        for level_info in self._level_data_gen(data, 'bids')
                    ],
                })
        except Exception as ex:
            self.log.error('convert depth error {}'.format(ex))
            return
        signal(channel).send(depth)

    def _on_deal(self, channel, msg):
        symbol = self._parse_symbol(channel)
        for record in msg['data']:
            try:
                deal = Transaction(
                    exchange_ts=time.mktime(
                        parser.parse(record[3]).timetuple()),
                    local_ts=time.time(),
                    symbol=symbol,
                    price=float(record[1]),
                    volume=float(record[2]))
            except KeyError as ex:
                self.log.error('convert deal error {}'.format(ex))
                continue
            signal(channel).send(deal)

    def _on_snapshot(self, channel, msg):
        symbol = self._parse_symbol(channel)
        data = msg['data']
        try:
            snapshot = Snapshot(
                exchange_ts=data['timestamp'] / 1000.0,
                local_ts=time.time(),
                symbol=symbol,
                prices={
                    1: float(data['sell']),  # ask 1
                    -1: float(data['buy']),  # bid 1
                },
                sizes={},
                change=float(data['change']),
                volume=None)
        except Exception as ex:
            self.log.error('convert snapshot error {}'.format(ex))
            return
        signal(channel).send(snapshot)

    def _level_data_gen(self, data, ok_side):
        for level_data in data[ok_side]:
            price = float(level_data[0])
            volume = float(level_data[1])
            yield (price, volume)

if __name__ == '__main__':

    def on_msg(msg):
        print(msg)
        # pass

    # from ...util.log import add_stream_handler, add_file_handler
    # add_stream_handler()
    #add_file_handler('okex_trade')
    txaio.start_logging(level='info')

    url = 'wss://real.okex.com:10441/websocket'
    quote_srv = RealtimeService(url)
    quote_srv.protocol = RealtimeProtocol

    from ..onetoken.master import MasterService

    master = MasterService()
    symbols = ['_'.join(symbol.split('.')) for symbol in master.get_available_symbols()]
    # symbols = ['btc_usdt']

    from twisted.internet import reactor, ssl
    txaio.call_later(5, quote_srv.sub_depth, symbols, on_msg, DepthN.D200)
    # txaio.call_later(1, quote_srv.sub_transaction, symbols, on_msg)
    # txaio.call_later(1, quote_srv.sub_snapshot, symbols, on_msg)

    # TODO: use connectws to enable auto ping-pong keepalive
    reactor.connectSSL(quote_srv.host, quote_srv.port, quote_srv,
                       ssl.ClientContextFactory())
    reactor.run()


import os
print()
to_encode = input("What to encode? : ")
print("\n-=-=-=- Encoding -=-=-=-")
output = ""
warn=0
for b in to_encode:
	code = ord(b)
	if (code > 122 or code < 65) and code != 32:
		warn+=1
		print("WARNING: '{}' considered as invalid char".format(chr(code)))
		code = code
	elif code == 90:
		code = 65
	elif code == 122:
		code = 97
	elif code == 32:
		code = 32
	else:
		code+=1
	output+=chr(code)
if warn > 0:
	print("{} warnings detected".format(warn))
else:
	print("NO WARNINGS OR ERRORS DETECTED")
print("-=-=-=-=- Encoded -=-=-=-=-")
print("\nEncoded text: {}".format(output))


from django.conf import settings
from django.db import models
from django.urls import reverse
from ckeditor_uploader.fields import RichTextUploadingField

class Post(models.Model):
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='write_posts',
        related_query_name='write_post',
        verbose_name='작성자'
    )
    title = models.CharField('제목', max_length=50)
    # 기존 코드
    # view_count = models.CharField('내용')
    content = RichTextUploadingField('내용')
    view_count = models.PositiveIntegerField('조회수', default=0)
    like_count = models.PositiveIntegerField('추천수', default=0)
    comment_count = models.PositiveSmallIntegerField('댓글수', default=0)
    like_user = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        through='PostLike'
    )
    created = models.DateTimeField('작성일', auto_now_add=True)
    modified = models.DateTimeField('수정일', auto_now=True)

    class Meta:
        ordering = ['-id']
        verbose_name = '포스트'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title

    @property
    def update_view_count(self):
        self.view_count += 1
        self.save()

    def update_comment_count(self, switch=False):
        if switch:
            self.comment_count += 1
            self.save()
        else:
            self.comment_count -= 1
            if self.comment_count < 0:
                self.comment_count = 0
            self.save()

    def get_absolute_url(self):
        return reverse('posts:post_detail', args=[self.id])

    def like_switch(self, author):
        postlike, postlike_created = self.postlike_set.get_or_create(author=author)
        if postlike_created:
            self.like_count += 1
        else:
            postlike.delete()
            self.like_count -= 1
        self.save()

class PostLike(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name='좋아요 누른 사람')
    post = models.ForeignKey(Post, on_delete=models.CASCADE, verbose_name='포스트')
    created = models.DateTimeField('작성일', auto_now_add=True)

    class Meta:
        verbose_name = '추천'
        verbose_name_plural = verbose_name


import h5py
import json
import logging
import os

from keras import optimizers
from keras.models import load_model

from vectorial.session import Session, SessionCallback

logger = logging.getLogger(__name__)

DATA_DIR = 'models'

class Model(object):
    def __init__(self, name, architecture, data=None):
        self._name = name
        self._architecture = architecture
        self._data = data
        self._loss = architecture.defaults['loss'] if 'loss' in architecture.defaults else None
        self._metrics = architecture.defaults['metrics'] if 'metrics' in architecture.defaults else None
        self._optimizer = architecture.defaults['optimizer'] if 'optimizer' in architecture.defaults else None
        self._session = Session()
        self._callbacks = []

    @property
    def session(self):
        return self._session

    @property
    def optimizer(self):
        return self._optimizer

    @property
    def metrics(self):
        return self._metrics

    @property
    def callbacks(self):
        return self._callbacks

    @optimizer.setter
    def optimizer(self, value):
        self._optimizer = value

    @metrics.setter
    def metrics(self, value):
        self._metrics = value

    @callbacks.setter
    def callbacks(self, value):
        self._callbacks = value

    def train(self, epochs=10, batch_size=64, verbose=1, class_weight=None):
        tg = self._data.train_generator(self._architecture, batch_size)
        vg = self._data.validation_generator(self._architecture, batch_size)

        self._session.clear_callbacks()
        for c in self._callbacks:
            if isinstance(c, SessionCallback):
                self._session.register_callback(c)

        self._architecture.model.compile(loss=self._loss, optimizer=self._optimizer,
                                         metrics=self._metrics)

        self._architecture.model.fit_generator(
            tg, steps_per_epoch=len(tg),
            callbacks=self._callbacks + [self._session],
            epochs=epochs,
            class_weight=class_weight,
            validation_data=vg, validation_steps=len(vg), verbose=verbose)

    def test(self, weights=None, batch_size=64, test_generator=None, test_function=None):
        if test_generator is not None:
            g = test_generator
        else:
            g = self._data.test_generator(self._architecture, batch_size)

        if weights is not None:
            self._architecture.model.load_weights(weights)

        self._architecture.model.compile(loss=self._loss, optimizer=self._optimizer,
                                         metrics=self._metrics)

        if test_function is not None:
            y_pred = self._architecture.model.predict_generator(g, steps=len(g))
            return test_function(g.y, y_pred)
        else:
            return self._architecture.model.evaluate_generator(g, steps=len(g))

    def predict(self, X, weights=None, batch_size=64):
        if weights is not None:
            self._architecture.model.load_weights(weights)

        return self._architecture.model.predict(X, batch_size=batch_size)

    def save(self, name=None):
        if name is None:
            name = self._name

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

        a = os.path.join(DATA_DIR, name + '.h5')
        s = os.path.join(DATA_DIR, name + '.pkl')

        self._architecture._model.save(a)
        self._session.save(s)

    def load(self, name=None, only_weights=True, optimizer_weights=True):
        if name is None:
            name = self._name

        a = os.path.join(DATA_DIR, name + '.h5')
        s = os.path.join(DATA_DIR, name + '.pkl')

        if only_weights:
            self._architecture.model.load_weights(a)
        else:
            self._architecture.model = load_model(a, custom_objects=self._architecture._custom_objects)

        if optimizer_weights:
            f = h5py.File(a, mode='r')
            if 'optimizer_weights' in f:
                training_config = f.attrs.get('training_config')
                training_config = json.loads(training_config.decode('utf-8'))
                optimizer_config = training_config['optimizer_config']
                self._architecture.model.optimizer = optimizers.deserialize(optimizer_config, custom_objects=self._architecture._custom_objects)
                optimizer_weights_group = f['optimizer_weights']
                optimizer_weight_names = [n.decode('utf8') for n in optimizer_weights_group.attrs['weight_names']]
                optimizer_weight_values = [optimizer_weights_group[n] for n in optimizer_weight_names]
                self._architecture.model.optimizer.set_weights(optimizer_weight_values)
            f.close()

class Architecture(object):
    def __init__(self):
        self._model = None
        self._defaults = {}
        self._custom_objects = {}

    @property
    def model(self):
        return self._model

    @property
    def defaults(self):
        return self._defaults

class Data(object):
    def __init__(self, tg, vg, eg):
        self._train_generator = tg
        self._validation_generator = vg
        self._test_generator = eg

    @property
    def validation_generator(self):
        return self._validation_generator

    @property
    def train_generator(self):
        return self._train_generator

    @property
    def test_generator(self):
        return self._test_generator


import numpy as np
import cv2

# Variable Definitions:
font = cv2.FONT_HERSHEY_SIMPLEX
def nothing(self):
	pass

# Initialisation
img = cv2.imread('images/test_1.jpg', 1)
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

cv2.namedWindow('output_edged', cv2.WINDOW_NORMAL)
cv2.namedWindow('output_original', cv2.WINDOW_NORMAL)

cv2.createTrackbar('Pixel Thresholder', 'output_edged', 0, 255, nothing)

sigma = 0.33
v = np.median(img)
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))

# Image Pre-processing:
blurred = cv2.GaussianBlur(img, (5,5), 0)
q
while(1):
	pixel_threshold = cv2.getTrackbarPos('Pixel Thresholder', 'output_edged')
	ret, th1 = cv2.threshold(blurred, pixel_threshold, 255, cv2.THRESH_BINARY_INV)

	edged = cv2.Canny(th1, lower, upper)
	edged = cv2.dilate(edged, None, iterations=1)
	edged = cv2.erode(edged, None, iterations=1)

	# Contour Search
	output, contours, hierarchy = cv2.findContours(
										edged,
										cv2.RETR_EXTERNAL,
										cv2.CHAIN_APPROX_NONE
										)

	#contours = sorted(contours, key = cv2.contourArea, reverse= True)[:5]
	for c in contours:
		perimeter = cv2.arcLength(c, True)
		epsilon = 0.01*perimeter
		approx = cv2.approxPolyDP(c, epsilon, True)

		if len(approx) == 4:
			(x,y,w,h) = cv2.boundingRect(approx)
			aspect_ratio = w/float(h)
			area = cv2.contourArea(c)
			hullArea = cv2.contourArea(cv2.convexHull(c))
			solidity = area/float(hullArea)

			keepSolidity = solidity > 0.9
			keepAspectRatio = aspect_ratio >= 0.8 and aspect_ratio <=1.2
			keepDims = w > 10 and h > 10

			M = cv2.moments(c)
			if M['m00']!=0:
				cX = int(M['m10']/M['m00'])
				cY = int(M['m01']/M['m00'])
			else:
				cX, cY = 0, 0
			speakerPosition = cX, cY

			if keepAspectRatio and keepSolidity and keepDims:
				cv2.drawContours(img, [approx], -1, (0,0,255),2)
				position_text = "Speaker Position: " + str(speakerPosition)
				cv2.putText(img, position_text, (cX, cY-15), font, 0.5,(0,0,255), 2)
				cv2.putText(img, "x", speakerPosition, font, 0.5, (0, 255, 0), 1)

	cv2.resizeWindow('output_edged', 1000, 800)
	cv2.imshow('output_edged', edged)

	cv2.resizeWindow('output_original', 1000, 800)
	cv2.imshow('output_original', img)

	if cv2.waitKey(1) & 0xFF == ord('q'):
		break

cv2.destroyAllWindows()

# Need to create a frame that is very high contrast


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

import os
import re

from pelican.tools.pelican_import import wp2fields, fields2pelican, decode_wp_content
from pelican.tests.support import (unittest, temporary_folder, mute,
                                   skipIfNoExecutable)

CUR_DIR = os.path.dirname(__file__)
WORDPRESS_XML_SAMPLE = os.path.join(CUR_DIR, 'content', 'wordpressexport.xml')
WORDPRESS_ENCODED_CONTENT_SAMPLE = os.path.join(CUR_DIR,
                                                'content',
                                                'wordpress_content_encoded')
WORDPRESS_DECODED_CONTENT_SAMPLE = os.path.join(CUR_DIR,
                                                'content',
                                                'wordpress_content_decoded')

try:
    from bs4 import BeautifulSoup
except ImportError:
    BeautifulSoup = False  # NOQA

@skipIfNoExecutable(['pandoc', '--version'])
@unittest.skipUnless(BeautifulSoup, 'Needs BeautifulSoup module')
class TestWordpressXmlImporter(unittest.TestCase):

    def setUp(self):
        self.posts = list(wp2fields(WORDPRESS_XML_SAMPLE))

    def test_ignore_empty_posts(self):
        self.assertTrue(self.posts)
        for title, content, fname, date, author, categ, tags, format in self.posts:
            self.assertTrue(title.strip())

    def test_can_toggle_raw_html_code_parsing(self):
        def r(f):
            with open(f) as infile:
                return infile.read()
        silent_f2p = mute(True)(fields2pelican)

        with temporary_folder() as temp:

            rst_files = (r(f) for f in silent_f2p(self.posts, 'markdown', temp))
            self.assertTrue(any('<iframe' in rst for rst in rst_files))
            rst_files = (r(f) for f in silent_f2p(self.posts, 'markdown', temp,
                         strip_raw=True))
            self.assertFalse(any('<iframe' in rst for rst in rst_files))
            # no effect in rst
            rst_files = (r(f) for f in silent_f2p(self.posts, 'rst', temp))
            self.assertFalse(any('<iframe' in rst for rst in rst_files))
            rst_files = (r(f) for f in silent_f2p(self.posts, 'rst', temp,
                         strip_raw=True))
            self.assertFalse(any('<iframe' in rst for rst in rst_files))

    def test_decode_html_entities_in_titles(self):
        test_posts = [post for post in self.posts if post[2] == 'html-entity-test']
        self.assertTrue(len(test_posts) == 1)

        post = test_posts[0]
        title = post[0]
        self.assertTrue(title, "A normal post with some <html> entities in the"
                               " title. You can't miss them.")
        self.assertTrue('&' not in title)

    def test_decode_wp_content_returns_empty(self):
        """ Check that given an empty string we return an empty string."""
        self.assertEqual(decode_wp_content(""), "")

    def test_decode_wp_content(self):
        """ Check that we can decode a wordpress content string."""
        with open(WORDPRESS_ENCODED_CONTENT_SAMPLE, 'r') as encoded_file:
            encoded_content = encoded_file.read()
            with open(WORDPRESS_DECODED_CONTENT_SAMPLE, 'r') as decoded_file:
                decoded_content = decoded_file.read()
                self.assertEqual(decode_wp_content(encoded_content, br=False), decoded_content)

    def test_preserve_verbatim_formatting(self):
        def r(f):
            with open(f) as infile:
                return infile.read()
        silent_f2p = mute(True)(fields2pelican)
        test_post = filter(lambda p: p[0].startswith("Code in List"), self.posts)
        with temporary_folder() as temp:
            md = [r(f) for f in silent_f2p(test_post, 'markdown', temp)][0]
            self.assertTrue(re.search(r'\s+a = \[1, 2, 3\]', md))
            self.assertTrue(re.search(r'\s+b = \[4, 5, 6\]', md))

            for_line = re.search(r'\s+for i in zip\(a, b\):', md).group(0)
            print_line = re.search(r'\s+print i', md).group(0)
            self.assertTrue(for_line.rindex('for') < print_line.rindex('print'))

    def test_code_in_list(self):
        def r(f):
            with open(f) as infile:
                return infile.read()
        silent_f2p = mute(True)(fields2pelican)
        test_post = filter(lambda p: p[0].startswith("Code in List"), self.posts)
        with temporary_folder() as temp:
            md = [r(f) for f in silent_f2p(test_post, 'markdown', temp)][0]
            sample_line = re.search(r'-   This is a code sample', md).group(0)
            code_line = re.search(r'\s+a = \[1, 2, 3\]', md).group(0)
            self.assertTrue(sample_line.rindex('This') < code_line.rindex('a'))


import os

import numpy as np
import cv2
import matplotlib.pyplot as plt
from proj5_code.utils import *

from scipy.ndimage.filters import maximum_filter

import tensorflow as tf

def detect_peak(image, filter_size=3, order=0.5):
    local_max = maximum_filter(image, footprint=np.ones((filter_size, filter_size)), mode='constant')
    detected_peaks = np.ma.array(image,mask=~(image == local_max))

    temp = np.ma.array(detected_peaks, mask=~(detected_peaks >= detected_peaks.max() * order))
    peaks_index = np.where((temp.mask != True))
    return peaks_index

def decode(hm, displacements):
    '''
    Decode the heatmap and displacement feilds from the encoder.
    Args:
        hm: heatmap
        displacements: displacement fields

    Returns:
        normalized vertices coordinates in 2D image
    '''
    hm = hm.reshape(hm.shape[2:])     # (40,30)

    peaks=hm.argmax()
    peakX = [peaks%30]
    peakY = [peaks//30]

    peaks=hm.argmax()
    peakX = [peaks%30]
    peakY = [peaks//30]

    scaleX = hm.shape[1]
    scaleY = hm.shape[0]
    objs = []
    for x,y in zip(peakX, peakY):
        conf = hm[y,x]
        print(conf)
        points=[]
        for i in range(8):
            dx = displacements[0, i*2  , y, x]
            dy = displacements[0, i*2+1, y, x]
            points.append((x/scaleX+dx, y/scaleY+dy))
        objs.append(points)
    return objs

def draw_box(image, pts):
    '''
    Drawing bounding box in the image
    Args:
        image: image array
        pts: bounding box vertices

    Returns:

    '''
    scaleX = image.shape[1]
    scaleY = image.shape[0]

    lines = [(0,1), (1,3), (0,2), (3,2), (1,5), (0,4), (2,6), (3,7), (5,7), (6,7), (6,4), (4,5)]
    for line in lines:
        pt0 = pts[line[0]]
        pt1 = pts[line[1]]
        pt0 = (int(pt0[0]*scaleX), int(pt0[1]*scaleY))
        pt1 = (int(pt1[0]*scaleX), int(pt1[1]*scaleY))
        cv2.line(image, pt0, pt1, (255,0,0), thickness=10)

    for i in range(8):
        pt = pts[i]
        pt = (int(pt[0]*scaleX), int(pt[1]*scaleY))
        cv2.circle(image, pt, 8, (0,255,0), -1)
        cv2.putText(image, str(i), pt,  cv2.FONT_HERSHEY_PLAIN, 2, (0,0,0), 2)

def inference(img, model_path):
    """
    Running inference given the image model, and generate heatmap and displacements.
    If you don't know what is heatmap and displacement fields, you should go to read the objectron paper.
    (https://arxiv.org/pdf/2003.03522.pdf);
    Besides, the `objectron.py` in the repo
    Args:
        img: image file
        model_path: .tflite weights file

    Returns: heatmap and displacement files

    """
    # Load TFLite model and allocate tensors.
    interpreter = tf.lite.Interpreter(model_path=model_path)
    interpreter.allocate_tensors()

    # Get input and output tensors.
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()

    # Test model on random input data.
    input_shape = input_details[0]['shape']

    input_data = np.zeros(input_shape)
    input_data[0,:,:,0]=img[0,:,:]
    input_data[0,:,:,1]=img[1,:,:]
    input_data[0,:,:,2]=img[2,:,:]
    input_data = np.array(input_data, dtype=np.float32)
    interpreter.set_tensor(input_details[0]['index'], input_data)

    interpreter.invoke()
    output_data = interpreter.get_tensor(output_details[0]['index'])
    output_data2 = interpreter.get_tensor(output_details[1]['index'])
    # print(output_data)
    output_data_reshape=np.zeros([1,1,40,30])
    output_data_reshape[0,0,:,:]=output_data[0,:,:,0]

    output_data2_reshape=np.zeros([1,16, 40,30])
    for i in range(16):
        output_data2_reshape[0, i,:,:]=output_data2[0,:,:,i]
    return output_data_reshape, output_data2_reshape

def detect_3d_box(img_path):

    '''
        Given an image, this function detects the 3D bounding boxes' 8 vertices of the chair in the image.
        We will only consider one chair in one single image.
        Similar to pose estimation, you're going to use mediapipe to detect the 3D bounding boxes.
        You should try to understand how does the objectron work before trying to finish this function!

        Args:
        -    img_path: the path of the RGB chair image

        Returns:
        -

        boxes: numpy array of 2D points, which represents the 8 vertices of 3D bounding boxes
        annotated_image: the original image with the overlapped bounding boxes

        Useful functions for usage: inference()
    '''

    if os.path.exists('object_detection_3d_chair.tflite'):
        model_path = 'object_detection_3d_chair.tflite'
    elif os.path.exists('../object_detection_3d_chair.tflite'):
        model_path = "../object_detection_3d_chair.tflite"
    elif os.path.exists('../../object_detection_3d_chair.tflite'):
        model_path = "../../object_detection_3d_chair.tflite"

    boxes = None
    hm = None
    displacements = None

    inshapes = [[1, 3, 640, 480]]
    outshapes = [[1, 16, 40, 30], [1, 1, 40, 30]]
    print(inshapes, outshapes)

    if img_path == 'cam':
        cap = cv2.VideoCapture(0)

    while True:
        if img_path == 'cam':
            _, img_orig = cap.read()
        else:
            img_file = img_path
            img_orig = cv2.imread(img_file)

        img = cv2.cvtColor(img_orig, cv2.COLOR_BGR2RGB)
        # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img = cv2.resize(img, (inshapes[0][3], inshapes[0][2]))
        img = img.transpose((2,0,1))
        image = np.array(img, np.float32)/255.0
        ############################################################################
        # TODO: YOUR CODE HERE
        ############################################################################
        hm, displacements = inference (image, model_path)
        ############################################################################
        #                             END OF YOUR CODE
        ############################################################################
        # decode inference result
        boxes = decode(hm, displacements) # 0.7 for original script

        # draw bbox
        for obj in boxes:
            draw_box(img_orig, obj)
        return boxes[0], cv2.cvtColor(img_orig, cv2.COLOR_BGR2RGB)


# Program to make a simple
# login screen
import rospy
from duckietown.dtros import DTROS, NodeType, TopicType
from std_msgs.msg import String

import tkinter as tk
import os

root = tk.Tk()

p1 = tk.PhotoImage(file='/root/.icons/duckietown.png')

# Setting icon of master window
root.iconphoto(False, p1)

# setting the windows size
root.geometry("250x150")
root.title("VLF control tool")

DB_NAME = os.getenv('VEHICLE_NAME')

inter_node = DTROS(
    node_name="InteractionNode",
    node_type=NodeType.DIAGNOSTICS
)

pub = rospy.Publisher(
    f'/{DB_NAME}/vlf_node/action',
    String,
    queue_size=1,
    dt_topic_type=TopicType.GENERIC
)

def submit_stop():
    msg = String()
    msg.data = "stop"
    pub.publish(msg)

def submit_go():
    msg = String()
    msg.data = "go"
    pub.publish(msg)

sub_go_btn = tk.Button(root, text='   Go   ', command=submit_go)
sub_stop_btn = tk.Button(root, text=' Stop ', command=submit_stop)

sub_go_btn.grid(row=0, column=0)
sub_stop_btn.grid(row=1, column=0)

# performing an infinite loop
# for the window to display
root.mainloop()


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

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('interest', '0012_auto_20161220_2040'),
    ]

    operations = [
        migrations.AlterField(
            model_name='interest',
            name='file',
            field=models.FileField(help_text=b"You don't have to upload a CV but it does increase the chances of being invited to apply.", upload_to=b'interest/CV', null=True, verbose_name=b'CV upload', blank=True),
        ),
        migrations.AlterField(
            model_name='interest',
            name='linkedIn',
            field=models.URLField(help_text=b'e.g. http://linkedin.com/joebloggs *field not required', null=True, blank=True),
        ),
    ]


f = open('day6.data', 'r')

message = [{}, {}, {}, {}, {}, {}, {}, {}]

for line in f:
    for i in range(8):
        char = line[i]
        if line[i] in list(message[i]):
            message[i][char] += 1
        else:
            message[i][char] = 1

def getMostCommonLetter(frequency):
    print(frequency)
    maximum = 0
    for char in list(frequency):
        if frequency[char] > maximum:
            output = char
            maximum = frequency[char]

    return output

print(''.join([getMostCommonLetter(x) for x in message]))


# -*- coding: utf-8 -*-
"""
@Time    : 2021/7/16 15:52
@Author  : MaSai
@FileName: ContactAddActivity.py
@SoftWare: PyCharm
"""
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support.wait import WebDriverWait

from Test_appium.test_page.Basepage import BasePage

class ContactAddActivity(BasePage):
# class ContactAddActivity:
#     def __init__(self, driver):
#         self.driver = driver

    def add(self,add_name,gender,phone_number):
        self.find(MobileBy.XPATH, "//*[@class='android.widget.EditText'and @text='必填']").send_keys(
            add_name)

        # curry_text=self.driver.find_element_by_xpath("//*[@text='09988']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']").text
        self.find(MobileBy.XPATH, "//*[@text='性别']/../*[@class='android.widget.RelativeLayout']").click()

        WebDriverWait(self.driver, 10).until(lambda x: self.driver.find_element(MobileBy.XPATH, "//*[@text='女']"))
        if gender == '男':
            self.find(MobileBy.XPATH, "//*[@text='男']").click()
        else:
            self.find(MobileBy.XPATH, "//*[@text='女']").click()

        self.find(MobileBy.XPATH, "//*[@text='手机号']").send_keys(phone_number)

        self.finf_slide("保存").click()
        # print(self.driver.find_element(MobileBy.XPATH, "//*[@class='android.widget.Toast']").text)
        from Test_appium.test_page.MemberInvite import MemberInvite
        return MemberInvite(self.driver)
        # return MemberInvite(BasePage)


"""Files, Directories, and Variables to be used in the tests.

This works only for the running pytest on the test-files!"""

import os

# -------- defining overall path-names etc ----------
current_file_path = os.path.dirname(os.path.realpath(__file__))
_relative_data_dir = "../testdata"
data_dir = os.path.abspath(os.path.join(current_file_path, _relative_data_dir))

raw_data_dir = os.path.join(data_dir, "data")
output_dir = os.path.join(data_dir, "out")
cellpy_data_dir = os.path.join(data_dir, "hdf5")
db_dir = os.path.join(data_dir, "db")
log_dir = os.path.join(data_dir, "log")

# -------- common files -----------------------------

cellpy_file_name = "20160805_test001_45_cc.h5"
cellpy_file_path = os.path.join(cellpy_data_dir, cellpy_file_name)

temporary_cellpy_file_name = "tmpfile.h5"
temporary_cellpy_file_path = os.path.join(cellpy_data_dir, temporary_cellpy_file_name)

db_file_name = "cellpy_db.xlsx"
db_file_path = os.path.join(db_dir, db_file_name)

step_table_file_name = "steps.csv"
step_table_file_path = os.path.join(raw_data_dir, step_table_file_name)

short_step_table_file_name = "steps_short.csv"
short_step_table_file_path = os.path.join(raw_data_dir, short_step_table_file_name)

run_name = "20160805_test001_45_cc"

# -------- arbin specific files ---------------------

res_file_name = "20160805_test001_45_cc_01.res"
res_file_path = os.path.join(raw_data_dir, res_file_name)

res_file_name2 = "20160805_test001_45_cc_02.res"
res_file_path2 = os.path.join(raw_data_dir, res_file_name)

# -------- biologics specific files -----------------
mpr_file_name = "geis.mpr"
mpr_file_path = os.path.join(raw_data_dir, mpr_file_name)

mpr_cellpy_file_name = "geis.h5"
mpr_cellpy_file_path = os.path.join(cellpy_data_dir, mpr_cellpy_file_name)

# -------- some values set used by the old batch ----
example_file_for_batch = "20160805_test001_45_cc_01_cycles.csv"
tot_cycles = 34


#!/usr/bin/python
# -*- coding: UTF-8 -*-
import logging
import os

from basic.ReplaceTools.server.util.ConnectionManager import ConnectionManager
from basic.ReplaceTools.server.util.XmUtil import *
from basic.ReplaceTools.config.start_config import CONFIG

class Processor(object):
    def execute(self, change_entity):
        pass

class DbProcessor(Processor):
    def execute(self, change_entity):
        manager = ConnectionManager(change_entity['db_config'])
        conn = manager.get_connection()
        if conn is not None:
            try:
                cursor = conn.cursor()
                for sql in change_entity['sql']:
                    cursor.execute(sql)
                conn.commit()
            except:
                conn.rollback()
                logging.warn('db Processor execute failure....')
            else:
                logging.info('db Processor execute success....')
            finally:
                conn.close()

class ProProcessor(Processor):
    def execute(self, change_entity):
        targets = [target for target in change_entity['change_config']]
        target_file = os.path.join(CONFIG['root_path'], change_entity['target_file'])
        self.__modify_item(target_file, targets)

    @staticmethod
    def __modify_item(target_file, targets):
        try:
            open_f = open(target_file, "r")
            lines = open_f.readlines()
            for i in range(0, len(lines)):
                line = lines[i].strip(' \t\n')
                if not line or line.startswith("#"):
                    continue
                key = line.split('=')[0].strip(' \t\n')
                for target in targets:
                    if key == target['target_label']:
                        lines[i] = '%s=%s\n' % (key, target['target_value'])
            write_f = open(target_file, "w")
            print('write lines: %s' % lines)
            write_f.writelines(lines)
        except Exception as e:
            logging.exception(('Fail to load properties: %s', e))
            raise e
        else:
            open_f.close()
            write_f.close()

class XmlProcessor(Processor):
    def __init__(self):
        self.change_entity = {}
        self.file_path = ''

    def execute(self, change_entity):
        self.change_entity = change_entity
        self.file_path = os.path.join(CONFIG['root_path'], change_entity['target_file'])
        self.change_value()
        self.add_child()

    def change_value(self):
        """
        该方法判断逻辑：获取‘target_tag’第一级子节点，然后根据唯一标识key，获取到；
        再根据后续层级获得需要修改的标签
        :return:
        """
        try:
            tree = read_xml(self.file_path)
            for change in self.change_entity['change_child']:
                result_nodes = self.__get_target_nodes(tree, change)
                change_node_text(result_nodes, change['target_value'])
            write_xml(tree, self.file_path)
        except IOError as e:
            logging.exception(e)
            return False
        else:
            return True

    def add_child(self):
        tree = read_xml(self.file_path)
        for child in self.change_entity['add_child']:
            result_nodes = self.__get_target_nodes(tree, child)
            node_list = []
            for node_attr in child['new_node']:
                node_list.append(create_node(node_attr['tag'], node_attr['attrs'], node_attr['text_value']))
            for new_node in node_list:
                add_child_node(result_nodes, new_node)
        write_xml(tree, self.file_path)

    @staticmethod
    def __get_target_nodes(tree, node_path):
        tags = node_path['target_tag'].split('/', 1)
        nodes = get_node_by_key(find_nodes(tree, tags[0]), {node_path['key']: node_path['key_value']})
        result_nodes = []
        for node in nodes:
            result_nodes.extend(find_nodes(node, tags[1]))
        return result_nodes


#!/usr/bin/env python
#Youtube Stats/Link Parser

import requests
import json
import re

from Parser import Locker
Lock = Locker(5)

import logging
logger = logging.getLogger("YouTube")

class YouTube(object):
	def Main(self, vidId):
		if not vidId:
			return None
		r = requests.get("http://gdata.youtube.com/feeds/api/videos/{0}?alt=json&v=2".format(vidId))
		try:
			r.raise_for_status()
		except (requests.HTTPError, requests.ConnectionError):
			logger.exception("Failed to poll YouTube")
		r = json.loads(r.text)
		return self.Parse(r['entry'])

	def ConvertTime(self, seconds):
		minutes, seconds = divmod(seconds, 60)
		hours, minutes = divmod(minutes, 60)
		duration = ""
		if hours != 0:
			duration += "{0}:".format(str(hours).zfill(2))
		duration += "{0}:{1}".format(str(minutes).zfill(2), str(seconds).zfill(2))
		return duration

	def Parse(self, reply):
		h = {}
		h['author'] = reply['author'][0]['name']['$t']
		h['title'] = reply['title']['$t']
		h['viewCount'] = int(reply['yt$statistics']['viewCount'])
		h['link'] = "https://youtu.be/"+reply['id']['$t'].split(":")[-1]
		h['duration'] = self.ConvertTime(int(reply['media$group']['yt$duration']['seconds']))

		if reply.get('yt$rating'):
			h['averagerating'] = reply['yt$rating'].get('average', None)
			if h['averagerating'] != None:
				h['averagerating'] = "{:.2}".format(h['averagerating'])
			h['maxrating'] = reply['yt$rating'].get('max', None)
			h['numLikes'] = int(reply['yt$rating'].get('numLikes', None))
			h['numDislikes'] = int(reply['yt$rating'].get('numDislikes', None))

		elif reply.get('gd$rating'):
			h['averagerating'] = reply['gd$rating'].get('average', None)
			if h['averagerating'] != None:
				h['averagerating'] = "{:.2}".format(h['averagerating'])
			h['maxrating'] = reply['gd$rating'].get('max', None)
			h['numLikes'] = int(reply['gd$rating'].get('numLikes', None))
			h['numDislikes'] = int(reply['gd$rating'].get('numDislikes', None))

		else:
			h['averagerating'] = None
			h['maxrating'] = None
			h['numRatings'] = None
			h['numLikes'] = None
			h['numDislikes'] = None
		return h

	def Search(self, terms, results=2):
		link = "https://gdata.youtube.com/feeds/api/videos?q={0}&safeSearch=none&max-results={1}&v=2&alt=json".format(terms, results)
		try:
			r = requests.get(link)
			if r.status_code != 200:
				return None
			r = json.loads(r.text)['feed']['entry']
		except Exception as e:
			logger.exception("Failed to get search info")
			return ['\x02[YouTube]\x02 Failed to get info.']

		results = []
		for vidInfo in r:
			vidInfo = self.Parse(vidInfo)
			# <Title + Uploader> [Length] <Link> [Average/Max Likes/Dislikes] <Views>
			info = "\x02[YouTube]\x02 {0}".format(vidInfo['title'])
			info += " - By: \x02{0}\x02".format(vidInfo['author'])
			info += " - [\x02{0}\x02]".format(vidInfo['duration'])
			if (vidInfo['averagerating'] != None and vidInfo['maxrating'] != None):
				info += " [Rating: \x02{0}\x02/\x02{1}\x02]".format(vidInfo['averagerating'], vidInfo['maxrating'])
			if (vidInfo['numLikes'] != None and vidInfo['numDislikes'] != None):
				info += " - \x02{:,}\x02 Likes".format(vidInfo['numLikes'])
				info += " - \x02{:,}\x02 Dislikes".format(vidInfo['numDislikes'])
			info += " - \x02{:,}\x02 Views".format(vidInfo['viewCount'])
			info += " - {0}".format(vidInfo['link'])
			results.append(info)
		return results

class Main(object):
	def __init__(self, Name, Parser):
		self.__name__ = Name
		self.Parser = Parser
		self.IRC = self.Parser.IRC
		self.YT = YouTube()

	def YouTubeLink(self, data):
		vidIds = list(set(re.findall("v=([\w\d_\-]{11})", ' '.join(data[3:]) )))
		for vidId in vidIds:
			self.YouTubeStats(data, vidId)

	def YouTubeShortLink(self, data):
		vidIds = list(set(re.findall("/([\w\d_\-]{11})", " ".join(data[3:]) )))
		for vidId in vidIds:
			self.YouTubeStats(data, vidId)

	def YouTubeStats(self, data, vidId):
			x = self.YT.Main(vidId)
			if x != None:
				info = "\x02[YouTube]\x02 {0}".format(x['title'])
				info += " - By: \x02{0}\x02".format(x['author'])
				info += " [\x02{0}\x02]".format(x['duration'])
				if (x['averagerating'] != None and x['maxrating'] != None):
					info += " - \x02{0}\x02/\x02{1}\x02".format(x['averagerating'], x['maxrating'])
				if (x['numLikes'] != None and x['numDislikes'] != None):
					info += " - \x02{:,}\x02 Likes".format(x['numLikes'])
					info += " - \x02{:,}\x02 Dislikes".format(x['numDislikes'])
				info += " - \x02{:,}\x02 Views".format(x['viewCount'])
				self.IRC.say(data[2], info)
			else:
				pass

	def YouTubeGetVids(self, data):
		if Lock.Locked:
			self.IRC.notice(data[0].split('!')[0], "Please wait a few seconds before using this command again.")
			return None
		try:
			terms = "+".join(data[4:]).replace("|","%7C")
		except Exception:
			self.IRC.say(data[2], "Supply some searchterms you derp!")
		for vid in self.YT.Search(terms, results=3):
			self.IRC.say(data[2], vid)
		Lock.Lock()

	def Load(self):
		self.Parser.hookCommand("PRIVMSG", self.__name__
			,{"(?:https?:\/\/)?(?:www\.)?youtube\.com\/.*?": self.YouTubeLink
			,"(?:https?:\/\/)?(?:www\.)?youtu.be/([\w\d_\-]{11})": self.YouTubeShortLink
			,"^@yt .*?$": self.YouTubeGetVids}
		)

	def Unload(self):
		pass
	def Reload(self):
		pass


#!/usr/bin/env python3

from flask import Flask, request, render_template
from secrets import compare_digest

app = Flask(__name__, static_folder="static")

challenge_flag = "elite{B1g_Sm0ke's_Ord3r}" # Set your flag here
challenge_answer_encoded = "NDQ1NQ=="

@app.route('/', methods=["GET"])
def index_page():
    return render_template("index.html")

@app.route('/attempt_answer/<answer>', methods=["POST"])
def verify_answer(answer):
    if compare_digest(answer, challenge_answer_encoded):
        return challenge_flag
    else:
        abort(403)

if __name__ == "__main__":
    app.run(debug=False)


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

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """

        if len(nums) == 1:
            return 0

        last = nums[0]
        step = 1
        index = 1
        while last < len(nums) - 1:
            max_distance = 0
            while index <= last:
                if nums[index] + index > max_distance:
                    max_distance = nums[index] + index
                index += 1

            last = max_distance
            step += 1

        return step