import argparse
import audtorch
import numpy as np
import os
import pandas as pd
import random
import torch
import tqdm
import yaml

from torch.utils.tensorboard import SummaryWriter

from define import (
    EMOTIONS,
    TASK_DICT
)

from datasets import (
    CachedDataset,
    WavDataset
)

from models import (
    Cnn10,
    Cnn14
)
from losses import (
    Uncertainty,
    UncertaintyRevised
)
from utils import (
    disaggregated_evaluation,
    evaluate_multitask,
    transfer_features,
    CCCLoss
)

def fix_index(df, root):
    df.reset_index(inplace=True)
    df['filename'] = df['filename'].apply(lambda x: os.path.join(args.data_root, x))
    df.set_index('filename', inplace=True)
    return df

class Model(torch.nn.Module):
    def __init__(self, cnn, mlp_1, mlp_2, wlen, wshift):
        super().__init__()
        self.cnn = cnn
        self.mlp_1 = mlp_1
        self.mlp_2 = mlp_2
        self.wlen = wlen
        self.wshift = wshift
        self.output_dim = self.mlp_2.fc_lay[-1]

    def forward(self, x):
        # x = x.transpose(1, 2)
        if not self.training:
            x = x.unfold(1, self.wlen, self.wshift).squeeze(0)
        out = self.mlp_2(self.mlp_1(self.cnn(x)))
        if not self.training:
            out = out.mean(0, keepdim=True)
        return out

if __name__ == '__main__':
    parser = argparse.ArgumentParser('EXVO Training')
    parser.add_argument(
        '--data-root',
        help='Path data has been extracted',
        required=True
    )
    parser.add_argument(
        '--results-root',
        help='Path where results are to be stored',
        required=True
    )
    parser.add_argument(
        '--features',
        help='Path to features',
        required=True
    )
    parser.add_argument(
        '--device',
        help='CUDA-enabled device to use for training',
        required=True
    )
    parser.add_argument(
        '--state',
        help='Optional initial state'
    )
    parser.add_argument(
        '--approach',
        default='cnn10',
        choices=[
            'cnn14',
            'cnn10'
        ]
    )
    parser.add_argument(
        '--task',
        default='task1',
        choices=[
            'task1',
            'task3'
        ]
    )
    parser.add_argument(
        '--batch-size',
        type=int,
        default=32,
        help='Batch size'
    )
    parser.add_argument(
        '--epochs',
        type=int,
        default=60
    )
    parser.add_argument(
        '--learning-rate',
        type=float,
        default=0.001
    )
    parser.add_argument(
        '--seed',
        type=int,
        default=0
    )
    parser.add_argument(
        '--optimizer',
        default='SGD',
        choices=[
            'SGD',
            'Adam',
            'AdamW',
            'RMSprop'
        ]
    )
    parser.add_argument(
        '--emo-loss',
        default='CCC',
        choices=[
            'CCC',
            'MSE',
        ]
    )
    parser.add_argument(
        '--meishu-loss',
        default=None,
        choices=[
            'uncertainty',
            'uncertainty-revised'
        ]
    )
    args = parser.parse_args()

    torch.manual_seed(args.seed)
    np.random.seed(args.seed)
    random.seed(args.seed)
    experiment_folder = args.results_root
    os.makedirs(experiment_folder, exist_ok=True)

    df = pd.read_csv(os.path.join(args.data_root, 'data_info.csv'))
    df['file'] = df['File_ID'].apply(lambda x: x.strip('[').strip(']') + '.wav')
    df.set_index('file', inplace=True)
    df_train = df.loc[df['Split'] == 'Train']
    df_dev = df.loc[df['Split'] == 'Val']
    df_test = df.loc[df['Split'] == 'Val']

    if args.task == 'task1':
        target_column = EMOTIONS + ['Age', 'Country']
    else:
        target_column = EMOTIONS

    task_dict = {key: TASK_DICT[key] for key in target_column}
    unit_counter = 0
    for task_index, task in enumerate(target_column):
        task_dict[task]['target'] = task_index
        if task_dict[task]['type'] == 'regression':
            task_dict[task]['unit'] = unit_counter
            unit_counter += 1
        elif task_dict[task]['type'] == 'classification':
            task_dict[task]['unit'] = list(range(unit_counter, unit_counter + len(df_train[task].unique())))
            unit_counter += len(df_train[task].unique())
    output_dim = unit_counter

    if args.emo_loss == 'MSE':
        emo_criterion = torch.nn.MSELoss()
    elif args.emo_loss == 'CCC':
        emo_criterion = CCCLoss()
    if args.task == 'task1':
        if args.meishu_loss is None:
            def criterion(pred, true):
                loss = 0
                for task_index, task in enumerate(target_column):
                    if task_dict[task]['type'] == 'classification':
                        loss += torch.nn.CrossEntropyLoss()(
                            pred[:, task_dict[task]['unit']],
                            true[:, task_dict[task]['target']].long()
                        )
                    else:
                        if task in EMOTIONS:
                            loss += emo_criterion(
                                pred[:, task_dict[task]['unit']],
                                true[:, task_dict[task]['target']].float()
                            )
                        else:
                            loss += torch.nn.MSELoss()(
                                pred[:, task_dict[task]['unit']],
                                true[:, task_dict[task]['target']].float()
                            )
                loss /= len(target_column)
                return loss
        else:
            if args.meishu_loss == 'uncertainty':
                func = Uncertainty()
            elif args.meishu_loss == 'uncertainty-revised':
                func = UncertaintyRevised()
            else:
                raise NotImplementedError(args.meishu_loss)
            def criterion(pred, true):
                output = [
                    pred[:, :10],  # emotion
                    pred[:, 11:],  # country
                    pred[:, 10],  # age
                ]
                emotion = true[:, :10].float()
                age = true[:, 10].float()
                country = true[:, 11].long()
                return func(output, emotion, country, age)
    else:
        criterion = emo_criterion

    features = pd.read_csv(args.features).set_index('file')
    features['features'] = features['features'].apply(lambda x: os.path.join(os.path.dirname(args.features), os.path.basename(x)))

    db_args = {
        'features': features,
        'target_column': target_column
    }
    if args.approach == 'cnn14':
        model = Cnn14(
            output_dim=output_dim
        )
        db_class = CachedDataset
        db_args['transform'] = audtorch.transforms.RandomCrop(250, axis=-2)
        model.to_yaml(os.path.join(experiment_folder, 'model.yaml'))
    elif args.approach == 'cnn10':
        model = Cnn10(
            output_dim=output_dim
        )
        db_class = CachedDataset
        db_args['transform'] = audtorch.transforms.RandomCrop(250, axis=-2)
        model.to_yaml(os.path.join(experiment_folder, 'model.yaml'))

    if args.state is not None:
        initial_state = torch.load(args.state)
        model.load_state_dict(
            initial_state,
            strict=False
        )

    train_dataset = db_class(
        df_train,
        **db_args
    )
    x, y = train_dataset[0]
    print(f'Input shape: {x.shape}')
    print(f'Output shape: {y.shape}')
    # exit()
    db_args.pop('transform')
    if args.approach == 'leafnet':
        db_args['transform'] = lambda x: x.reshape(1, -1)

    dev_dataset = db_class(
        df_dev,
        **db_args
    )

    test_dataset = db_class(
        df_test,
        **db_args
    )
    # create DataLoaders
    train_loader = torch.utils.data.DataLoader(
        train_dataset,
        shuffle=True,
        batch_size=args.batch_size,
        num_workers=4
    )

    dev_loader = torch.utils.data.DataLoader(
        dev_dataset,
        shuffle=False,
        batch_size=1,
        num_workers=4
    )

    test_loader = torch.utils.data.DataLoader(
        test_dataset,
        shuffle=False,
        batch_size=1,
        num_workers=4
    )
    device = args.device
    if not os.path.exists(os.path.join(experiment_folder, 'state.pth.tar')):

        with open(os.path.join(experiment_folder, 'hparams.yaml'), 'w') as fp:
            yaml.dump(vars(args), fp)

        writer = SummaryWriter(log_dir=os.path.join(experiment_folder, 'log'))

        torch.save(
            model.state_dict(),
            os.path.join(
            experiment_folder,
            'initial.pth.tar')
        )

        if args.optimizer == 'SGD':
            optimizer = torch.optim.SGD(
                model.parameters(),
                momentum=0.9,
                lr=args.learning_rate
            )
        elif args.optimizer == 'Adam':
            optimizer = torch.optim.Adam(
                model.parameters(),
                lr=args.learning_rate
            )
        elif args.optimizer == 'AdamW':
            optimizer = torch.optim.AdamW(
                model.parameters(),
                lr=args.learning_rate,
                weight_decay=0.0001
            )
        elif args.optimizer == 'RMSprop':
            optimizer = torch.optim.RMSprop(
                model.parameters(),
                lr=args.learning_rate,
                alpha=.95,
                eps=1e-7
            )
        epochs = args.epochs

        max_metric = -1
        best_epoch = 0
        best_state = None
        best_results = None

        plateau_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
            optimizer,
            mode='max',
            factor=0.9,
            patience=5
        )

        for epoch in range(epochs):
            model.to(device)
            model.train()
            epoch_folder = os.path.join(
                experiment_folder,
                f'Epoch_{epoch+1}'
            )
            os.makedirs(epoch_folder, exist_ok=True)
            for index, (features, targets) in tqdm.tqdm(
                    enumerate(train_loader),
                    desc=f'Epoch {epoch}',
                    total=len(train_loader),
                    disable=True
                ):

                if (features != features).sum():
                    raise ValueError(features)

                output = model(transfer_features(features, device))
                targets = targets.to(device)
                loss = criterion(output, targets)
                if index % 50 == 0:
                    writer.add_scalar(
                        'train/loss',
                        loss,
                        global_step=epoch * len(train_loader) + index
                    )
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
                # break

            # dev set evaluation
            score, results, targets, outputs, predictions = evaluate_multitask(
                model=model,
                device=device,
                loader=dev_loader,
                transfer_func=transfer_features,
                task_dict=task_dict
            )
            results_df = pd.DataFrame(
                index=df_dev.index,
                data=predictions,
                columns=[f'{task}.pred' for task in target_column]
            )
            results_df.reset_index().to_csv(os.path.join(epoch_folder, 'dev.csv'), index=False)
            np.save(os.path.join(epoch_folder, 'outputs.npy'), outputs)
            logging_results = disaggregated_evaluation(
                df=results_df,
                groundtruth=df_dev,
                stratify=['Country_string'],
                task_dict=task_dict
            )
            with open(os.path.join(epoch_folder, 'dev.yaml'), 'w') as fp:
                yaml.dump(logging_results, fp)
            writer.add_scalar(
                'dev/score',
                score,
                (epoch + 1) * len(train_loader)
            )

            for task in logging_results.keys():
                metric = task_dict[task]['score']
                logging_results[task][metric]['all'] = results[task][metric]
                writer.add_scalars(
                    f'dev/{task}/{metric}',
                    logging_results[task][metric],
                    (epoch + 1) * len(train_loader)
                )

            torch.save(model.cpu().state_dict(), os.path.join(
                epoch_folder, 'state.pth.tar'))

            print(f'Dev score at epoch {epoch+1}:{score}')
            # print(f'Dev results at epoch {epoch+1}:\n{yaml.dump(results)}')
            if score > max_metric:
                max_metric = score
                best_epoch = epoch
                best_state = model.cpu().state_dict()
                best_results = results.copy()

            plateau_scheduler.step(score)

        print(
            f'Best dev results found at epoch {best_epoch+1}:\n{yaml.dump(best_results)}')
        best_results['Epoch'] = best_epoch + 1
        with open(os.path.join(experiment_folder, 'dev.yaml'), 'w') as fp:
            yaml.dump(best_results, fp)
        writer.close()
    else:
        best_state = torch.load(os.path.join(
            experiment_folder, 'state.pth.tar'))
        print('Training already run')

    if not os.path.exists(os.path.join(experiment_folder, 'test_holistic.yaml')):
        model.load_state_dict(best_state)
        torch.save(best_state, os.path.join(
            experiment_folder, 'state.pth.tar'))
        score, results, targets, outputs, predictions = evaluate_multitask(
            model=model,
            device=device,
            loader=test_loader,
            transfer_func=transfer_features,
            task_dict=task_dict
        )
        results_df = pd.DataFrame(
            index=df_dev.index,
            data=predictions,
            columns=[f'{task}.pred' for task in target_column]
        )
        print(f'Best test results:\n{yaml.dump(results)}')
        np.save(os.path.join(experiment_folder, 'targets.npy'), targets)
        np.save(os.path.join(experiment_folder, 'outputs.npy'), outputs)
        results_df.reset_index().to_csv(os.path.join(epoch_folder, 'test.csv'), index=False)
        with open(os.path.join(experiment_folder, 'test.yaml'), 'w') as fp:
            yaml.dump(results, fp)
        logging_results = disaggregated_evaluation(
            df=results_df,
            groundtruth=df_test,
            stratify=['Country_string'],
            task_dict=task_dict
        )
        with open(os.path.join(experiment_folder, 'test_holistic.yaml'), 'w') as fp:
            yaml.dump(logging_results, fp)
    else:
        print('Evaluation already run')


#####################################################################################################################
# Made by:      Aaron                                                                                #
# Desciption:   A python script that uses uiAutomator python wrapper to generate XY coordinates of                  #
#               clickable/scrollable views, which is crucial for simulating and automating basic user actions,      #
#               such as pressing, scrolling, etc. This script only prints coordinates and other useful information  #
#               obtained from uiAutomator's dump().                                                                 #
#               Additional uiAutomator's methods (Eg: d.click(x,y)) can be added at the bottom of the program.      #
#####################################################################################################################

import xml.etree.ElementTree as ET
import networkx as nx
import matplotlib.pyplot as plt
from uiautomator import device as d
import numpy as np
import sys
import random as rd
import time
import hashlib

# To generate hashed states
# Misc
def generateHashedState(state):
    global permissionState
    # Conditions
    clickCondition = "'clickable': 'true'"
    enabledCondition = "'enabled': 'true'"
    longClickCondition = "'long-clickable': 'true'"
    scrollCondition = "'scrollable': 'true'"
    allowPermissionsId = 'com.android.packageinstaller:id/permission_allow_button'
    denyPermissionsId = 'com.android.packageinstaller:id/permission_deny_button'

    # Attributes
    resourceId = ''
    view = ''
    package = ''
    text = ''
    contentDesc = ''
    longClickable = ''
    scroll = ''
    root = ET.fromstring(state)

    for elem in root.iter():
        strAttrib = str(elem.attrib)
        # Find clickable Views
        if clickCondition in strAttrib and enabledCondition in strAttrib:
            # Obtain package names
            start = strAttrib.find("'package': ") + 12
            end = strAttrib.find(",", start) - 1
            temp = strAttrib[start:end]
            package = str(temp)
            # Obtain view names
            start = strAttrib.find("'class': ") + 10
            end = strAttrib.find("'", start)
            temp = strAttrib[start:end]
            view = view+str(temp)
            # Obtain resource-id
            start = strAttrib.find("'resource-id': ") + 16
            end = strAttrib.find("'", start)
            temp = strAttrib[start:end]
            # resource-id is empty
            if temp == '':
                temp = '(No resource.id)'
                resourceId = resourceId + temp
            # Has resource-id
            else:
                resourceId = resourceId + temp
            # Obtain text
            start = strAttrib.find("'text': ") + 9
            end = strAttrib.find("}", start) - 1
            temp = strAttrib[start:end]
            # Text is empty
            if temp == '':
                temp = '(No text)'
                text = text + temp
            else:
                text = text + temp
            # Obtain content-desc
            start = strAttrib.find("'content-desc': ") + 17
            end = strAttrib.find(",", start) - 1
            temp = strAttrib[start:end]
            if temp == '':
                temp = "(no content-desc)"
                contentDesc = contentDesc + temp
            else:
                contentDesc = contentDesc + temp

            # Long clickable
            if longClickCondition in strAttrib:
                longClickable = longClickable + "True"
        # Determine if scrollable
        if scrollCondition in strAttrib and enabledCondition in strAttrib:
            scroll = scroll + 'True'

    # Check if state is a permission state
    if resourceId == str(denyPermissionsId+allowPermissionsId):
        print("Permission state detected.")
        permissionState = True

    # Return Hash
    return hashlib.md5((package+view+resourceId+contentDesc+longClickable+scroll)).digest().encode("base64")

def generateHashedHierachy(state):
    return hashlib.md5(state).digest().encode("base64")

# Use uiAutomator's dump to get screen details
state1 = d.dump(compressed=True).encode('utf-8')
time.sleep(1.5)

# Initialise all required arrays/variables
view = []
resourceId = []
contentDesc = []
clickableXCoor = np.array([])
clickableYCoor = np.array([])
eClickableXCoor = np.array([])
eClickableYCoor = np.array([])
cVisitFreq = []
package = ''
state = ''
longClickable = []
longClickableIndex = []
lcVisitFreq = []
scrollableX = []
scrollableY = []
e_scrollableX = []
e_scrollableY = []
c_scrollableX = []
c_scrollableY = []
scrollableResourceId = []
scrollableView = []
invalidStateList = []
text = []

# Various conditional statements to extract info
condition = "'clickable': 'true'"
condition2 = "'long-clickable': 'true'"
condition3 = "'scrollable': 'true'"
scrollCondition = "'text': 'true'"
enabledCondition = "'enabled': 'true'"
root = ET.fromstring(state1)
longClickIndex = 0

# Iterate through hierarchy (from d.dump) to obtain XY coordinates, etc
for elem in root.iter():
    strAttrib = str(elem.attrib)
    # clickable
    if condition in strAttrib:
        # Obtain XY Coordinates of clickable coordinates (Start)
        start = strAttrib.find("'bounds': '") + 12
        end = strAttrib.find('[', start)
        temp = strAttrib[start:end]
        start = temp.find("[") + 1
        end = temp.find(",", start)
        xCoordinate = int(temp[start:end])
        clickableXCoor = np.append(clickableXCoor, xCoordinate)
        start = temp.find(",") + 1
        end = temp.find("]", start)
        yCoordinate = int(temp[start:end])
        clickableYCoor = np.append(clickableYCoor, yCoordinate)
        # Obtain XY Coordinates of clickable Coordinates (End)
        start = strAttrib.find("[") + len(str(yCoordinate)) + len(str(xCoordinate)) + 3
        end = strAttrib.find(" '", start)
        temp = strAttrib[start:end]
        start = temp.find("[") + 1
        end = temp.find(",", start)
        eClickableXCoor = np.append(eClickableXCoor, int(temp[start:end]))
        start = temp.find(",") + 1
        end = temp.find("]", start)
        eClickableYCoor = np.append(eClickableYCoor, int(temp[start:end]))
        # Obtain package names
        start = strAttrib.find("'package': ") + 12
        end = strAttrib.find("'", start)
        package = strAttrib[start:end]
        # Obtain view names
        start = strAttrib.find("'class': ") + 10
        end = strAttrib.find("'", start)
        temp = strAttrib[start:end]
        temp = str(temp)
        view.append(temp)
        # Obtain resource id
        start = strAttrib.find("'resource-id': ") + 16
        end = strAttrib.find("'", start)
        temp = strAttrib[start:end]
        if temp == '':
            temp = '(No resource.id)'
            resourceId.append(temp)
        else:
            resourceId.append(temp)
        # Obtain text
        start = strAttrib.find("'text': ") + 9
        end = strAttrib.find("}", start) - 1
        temp = strAttrib[start:end]
        # Text is empty
        if temp == '':
            temp = '(No text)'
            text.append(temp)
        else:
            text.append(temp)
        # Obtain content-desc
        start = strAttrib.find("'content-desc': ") + 17
        end = strAttrib.find(",", start) - 1
        temp = strAttrib[start:end]
        if temp == '':
            temp = "(no content-desc)"
            contentDesc.append(temp)
        else:
            contentDesc.append(temp)

        # Update cVisitFreq
        cVisitFreq.append(0)

        # Long clickable
        if condition2 in strAttrib:
            longClickable.append(str(True))
            longClickableIndex.append(longClickIndex)
            lcVisitFreq.append(0)
        else:
            longClickable.append(str(False))

        longClickIndex = longClickIndex + 1

    # scrollable
    if condition3 in strAttrib and enabledCondition in strAttrib:
        # Obtain Start XY Coordinates of scrollable views
        start = strAttrib.find("'bounds': '") + 12
        end = strAttrib.find('[', start)
        temp = strAttrib[start:end]
        start = temp.find("[") + 1
        end = temp.find(",", start)
        xCoordinate = int(temp[start:end])
        scrollableX.append(xCoordinate)
        start = temp.find(",") + 1
        end = temp.find("]", start)
        yCoordinate = int(temp[start:end])
        scrollableY.append(yCoordinate)
        # Obtain End XY Coordinates of scrollable views
        start = strAttrib.find("[") + len(str(yCoordinate)) + len(str(xCoordinate)) + 3
        end = strAttrib.find(" '", start)
        temp = strAttrib[start:end]
        start = temp.find("[") + 1
        end = temp.find(",", start)
        e_scrollableX.append(int(temp[start:end]))
        start = temp.find(",") + 1
        end = temp.find("]", start)
        e_scrollableY.append(int(temp[start:end]))
        # Obtain view names
        start = strAttrib.find("'class': '") + 10
        end = strAttrib.find("'", start)
        temp = strAttrib[start:end]
        temp = str(temp)
        scrollableView.append(temp)
        # Obtain resource id
        start = strAttrib.find("'resource-id': '") + 16
        end = strAttrib.find("'", start)
        temp = strAttrib[start:end]
        if temp == '':
            temp = '(No resource.id)'
            scrollableResourceId.append(temp)
        else:
            scrollableResourceId.append(temp)

# Logic used for scrolling/swiping
if len(scrollableX) >= 1:
    # Obtain center of scrollable views
    for n in range(len(scrollableX)):
        # X-Center coordinates
        temp = int(((e_scrollableX[n] - scrollableX[n]) / 2) + scrollableX[n])
        c_scrollableX.append(temp)
        # Y-Center coordinates
        temp = (((e_scrollableY[n] - scrollableY[n]) / 2) + scrollableY[n])
        c_scrollableY.append(temp)

print("Full Hierarchy")
print(state1)
print("\n")

# Use MD5 hashing to speed up state matching process
print("Hashed Hierarchy")
print(generateHashedHierachy(state1))

# Use MD5 hashing to speed up state matching process
print("Hashed State")
print(generateHashedState(state1))

# Clickable Views
print("Clickable views")
print(view)
print("\n")
print("Clickable package")
print(package)
print("\n")
print("Clickable resource-id")
print(resourceId)
print("\n")
print("Clickable text")
print(text)
print("\n")
print("Clickable Content-Desc")
print(contentDesc)
print("\n")
print("Clickable XY coordinates (Top-left bounds)")
print(clickableXCoor)
print(clickableYCoor)
print("\n")
print("Clickable XY coordinates (bottom-right bounds)")
print(eClickableXCoor)
print(eClickableYCoor)
print("\n")
print("Clickable # of visits")
print(cVisitFreq)
print("\n")

# Long-clickable views
print("Long Clickable indexes")
# Refers XY coordinates of clickable views that are also long-clickable
print(longClickable)
# Refers to index of clickable XY coordinates that are also long-clickable
print(longClickableIndex)
print("\n")
print("Long-clickable # of visits")
print(lcVisitFreq)
print("\n")

print("Scrollable views Details")
# XY Coordinates of scrollable views (Top-left)
print(scrollableX)
print(scrollableY)
# XY Coordinates of scrollable views (Bottom-right)
print(e_scrollableX)
print(e_scrollableY)
# Xy Coordinates of scrollable views (Centre)
print(c_scrollableX)
print(c_scrollableY)
print("\n")
print("Scrollable view's name")
print(scrollableView)
print("\n")
print("Scrollable view's resource id")
print(scrollableResourceId)
print("\n")

# Tally of clickable, scrollable views (Limited to uiAutomator dump)
print("Tally:")
print("Number of clickable views:" + str(len(clickableXCoor)))
print("Number of scrollable views:" + str(len(scrollableX)))
count = 0
for i in longClickable:
    if i is str(True):
        count = count+1
print("Number of long-clickable views:" + str(count))

# Add your operations here:
d.click(clickableXCoor[4], clickableYCoor[4])


import math

from line import Line
from vector import Vector
class Plane(object):
    """
       This class gives simple functionalities related to a Plane in 3d
       params:
           normal_vector: of type vector
           constant_term: Constant term in the vector equation the Plane.
           basepoint: generated according to the normal_vector and constant_term

       Example of Plane equation:
       Ax + By + Cz = k
       (A, B, C).(x, y) = k
       (A, B, C) => Normal Vector
       k => Constant Term

       Example initialization:
       p = Plane(Vector([2, 3, 4]), 5)
       This will generate a plane of the form, 2x + 3y +4z = 5
       """

    NO_NONZERO_ELTS_FOUND_MSG = 'No nonzero elements found'

    def __init__(self, normal_vector=None, constant_term=None):
        # super(Plane, self).__init__(normal_vector, constant_term)
        self.dimension = 3
        if not normal_vector:
            normal_vector = Vector([0] * self.dimension)
        self.normal_vector = normal_vector

        if not constant_term:
            constant_term = 0
        self.constant_term = constant_term

        self.set_basepoint()

    def set_basepoint(self):
        try:
            n = self.normal_vector
            c = self.constant_term
            basepoint_coords = ['0']*self.dimension

            initial_index = Line.first_nonzero_index(n)
            initial_coefficient = n[initial_index]

            basepoint_coords[initial_index] = c/initial_coefficient
            self.basepoint = Vector(basepoint_coords)

        except Exception as e:
            if str(e) == Line.NO_NONZERO_ELTS_FOUND_MSG:
                self.basepoint = None
            else:
                raise e

    def is_parallel_to(self,oll):
        n1 = self.normal_vector
        n2 = oll.normal_vector
        return n1.is_parallel_to(n2)

if __name__ == '__main__':
    p1 = Plane(Vector([-0.412, 3.806, 0.728]), -3.46)
    p2 = Plane(Vector([1.03, -9.515, -1.82]), 8.65)
    print("Plane \n", p1, "\nand \n", p2)
    print("Parallel: ", p1.is_parallel_to(p2))
    print("Equal: ", p1 == p2)
    print('-' * 80)

    p1 = Plane(Vector([2.611, 5.528, 0.283]), 4.6)
    p2 = Plane(Vector([7.715, 8.306, 5.342]), 3.76)
    print("Plane \n", p1, "\nand \n", p2)
    print("Parallel: ", p1.is_parallel_to(p2))
    print("Equal: ", p1 == p2)
    print('-' * 80)

    p1 = Plane(Vector([-7.926, 8.625, -7.212]), -7.952)
    p2 = Plane(Vector([-2.642, 2.875, -2.404]), -2.443)
    print("Plane \n", p1, "\nand \n", p2)
    print("Parallel: ", p1.is_parallel_to(p2))
    print("Equal: ", p1 == p2)
    print('-' * 80)


import os
import torch
import torch.nn as nn
from pathlib import Path
from models.transx import TransE, TransH, TransR, TransD
from models.prtransx import PrTransE, PrTransH
from models.darling import DARLING

# import constants
from constants import *

# define models
models = {
    TRANSE: TransE,
    TRANSH: TransH,
    TRANSR: TransR,
    TRANSD: TransD,
    PRTRANSE: PrTransE,
    PRTRANSH: PrTransH,
    DARLIN: DARLING
}

# meter class for storing results
class AverageMeter(object):
    """Computes and stores the average and current value"""
    def __init__(self):
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val / n
        self.sum += val
        self.count += n
        self.avg = self.sum / self.count

class NegativeSampling:
    def __init__(self, num_entities):
        self.num_entities = num_entities
        self.demographic_aware = args.demographic_aware
        self.prob_embedding = args.prob_embedding

    def __call__(self, pos):
        if args.demographic_aware or args.prob_embedding:
            return {
                **self.uniform(pos),
                **{
                    DEMOGRAPHIC: pos[DEMOGRAPHIC],
                    PROBABILITY: torch.FloatTensor([args.negative_prob] * pos[TRIPLE].shape[0]).to(DEVICE)
                }
            }
        else:
            return self.uniform(pos)

    def uniform(self, pos):
        pos_heads, pos_relations, pos_tails = pos[TRIPLE][:, 0], pos[TRIPLE][:, 1], pos[TRIPLE][:, 2]

        replace = torch.randint(high=2, size=pos_heads.size()).to(DEVICE) # 1 for head, 0 for tail

        random_entities = torch.randint(high=self.num_entities, size=pos_heads.size()).to(DEVICE)

        neg_heads = torch.where(replace == 1, random_entities, pos_heads)
        neg_tails = torch.where(replace == 0, random_entities, pos_tails)

        return {
            TRIPLE: torch.stack((neg_heads, pos_relations, neg_tails), dim=1).to(DEVICE)
        }

class RankEvaluator:
    def __init__(self, vocabs):
        self.vocabs = vocabs
        self.task_ids = {
            TREATMENT_RECOMMENDATION: [v for k, v in self.vocabs[ENTITY].items() if k.startswith('p_')],
            MEDICINE_RECOMMENDATION: [v for k, v in self.vocabs[ENTITY].items() if not k.startswith('p_') and not k.startswith('d_')]
        }

    def _hits_at_k(self, predicted, actual, k=10):
        return torch.sum(torch.eq(predicted.topk(k=k, largest=False)[1], actual.unsqueeze(1))).item() / actual.size(0)

    def _mean_rank(self, predicted, actual):
        return torch.sum(torch.eq(predicted.argsort(), actual.unsqueeze(1)).nonzero()[:, 1].float().add(1.0)) / actual.size(0)

    def _mean_reciprocal_rank(self, predicted, actual):
        return torch.sum((1.0 / torch.eq(predicted.argsort(), actual.unsqueeze(1)).nonzero()[:, 1].float().add(1.0))).item() / actual.size(0)

    def _filter_entities(self, predicted, actual, task):
        filter_predicted, filter_actual = [], []
        entity_vocab_list = list(self.vocabs[ENTITY].keys())
        for p, a in zip(predicted.tolist(), actual.tolist()):
            if task == TREATMENT_RECOMMENDATION and not entity_vocab_list[a].startswith('p_'):
                continue
            if task == MEDICINE_RECOMMENDATION and (entity_vocab_list[a].startswith('p_') or entity_vocab_list[a].startswith('d_')):
                continue
            fp = [pv for i, pv in enumerate(p) if i in self.task_ids[task]]

            assert len(fp) == len(self.task_ids[task])

            filter_predicted.append(torch.FloatTensor(fp))
            filter_actual.append(fp.index(p[a]))

        return torch.stack(filter_predicted).to(DEVICE), torch.LongTensor(filter_actual).to(DEVICE)

    def _filter_medicines(self, predicted, actual):
        return None

    def _rank(self, predicted, actual, task):
        if task in [TREATMENT_RECOMMENDATION, MEDICINE_RECOMMENDATION]:
            predicted, actual = self._filter_entities(predicted, actual, task)
        assert predicted.size(0) == actual.size(0)

        self.metrics[HITS_AT_1].update(self._hits_at_k(predicted, actual, 1))
        self.metrics[HITS_AT_3].update(self._hits_at_k(predicted, actual, 3))
        self.metrics[HITS_AT_10].update(self._hits_at_k(predicted, actual, 10))
        self.metrics[MR].update(self._mean_rank(predicted, actual))
        self.metrics[MRR].update(self._mean_reciprocal_rank(predicted, actual))

    def _results(self):
        return {
            HITS_AT_1: self.metrics[HITS_AT_1].avg,
            HITS_AT_3: self.metrics[HITS_AT_3].avg,
            HITS_AT_10: self.metrics[HITS_AT_10].avg,
            MR: self.metrics[MR].avg,
            MRR: self.metrics[MRR].avg
        }

    def _reset(self):
        self.metrics = {
            HITS_AT_1: AverageMeter(),
            HITS_AT_3: AverageMeter(),
            HITS_AT_10: AverageMeter(),
            MR: AverageMeter(),
            MRR: AverageMeter()
        }

    def evaluate(self, data_loader, model, task=args.task):
        # reset metrics
        self._reset()

        # switch to evaluate mode
        model.eval()

        entity_ids = torch.arange(end=len(self.vocabs[ENTITY])).to(DEVICE)
        with torch.no_grad():
            for _, data in enumerate(data_loader):
                val_triples = data[TRIPLE]

                # get batch size
                batch_size = val_triples.shape[0]

                all_entities = entity_ids.repeat(batch_size, 1)

                heads, relations, tails = val_triples[:, 0], val_triples[:, 1], val_triples[:, 2]

                # exapnd for all entities
                expanded_heads = heads.reshape(-1, 1).repeat(1, all_entities.size()[1])
                expanded_relations = relations.reshape(-1, 1).repeat(1, all_entities.size()[1])

                expanded_triples = torch.stack((expanded_heads, expanded_relations, all_entities), dim=2).reshape(-1, val_triples.shape[1])

                if args.demographic_aware:
                    expanded_demographics = data[DEMOGRAPHIC].reshape(-1, 1).repeat(1, all_entities.size()[1]).reshape(-1, 1).squeeze()

                if args.prob_embedding:
                    expanded_probabilities = data[PROBABILITY].reshape(-1, 1).repeat(1, all_entities.size()[1]).reshape(-1, 1).squeeze()

                # chunk data and predict results
                predicted_tails = []
                for i in range(0, len(expanded_triples), batch_size**2):
                    model_data = {TRIPLE: expanded_triples[i:i + batch_size**2]}

                    if args.demographic_aware:
                        model_data.update({DEMOGRAPHIC: expanded_demographics[i:i + batch_size**2]})

                    if args.prob_embedding:
                        model_data.update({PROBABILITY: expanded_probabilities[i:i + batch_size**2]})

                    predicted_tails.append(model.predict(model_data))

                predicted_tails = torch.cat(predicted_tails, dim=0).reshape(batch_size, -1)

                # rank results
                self._rank(predicted_tails, tails, task)

        return self._results()


from collections import deque

n = int(input())
arr = deque(i for i in range(1,n+1))

while len(arr) > 1 :
    arr.popleft()
    data = arr.popleft()
    arr.append(data)

print(*arr)


import pygame
import time

width = 1200
height = 750
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# FPS
fpsclock = pygame.time.Clock()
FPS = 30
pygame.init()

# Cấu hình màn hình
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Tree")
# Khởi tạo font
font = pygame.font.Font(None, 36)

class Button:
    def __init__(self, link, size, index):
        self.surface = pygame.image.load(link).convert_alpha()
        self.w, self.h = size
        self.x, self.y = index
        self.delta = 0
        self.surface = pygame.transform.scale(self.surface, size)

    def draw(self):
        surface_tempt = pygame.transform.scale(
            self.surface, (self.w - self.delta, self.h - self.delta))
        if (self.delta > 0 and self.delta < 10):
            # print(str(self.w - self.delta) + " " + str(self.h - self.delta) + "\n")
            self.delta += 3
        else:
            self.delta = 0
        screen.blit(surface_tempt, (self.x - (self.w - self.delta) /
                    2, self.y - (self.h - self.delta)/2))

    def click(self, x, y):
        if (x > self.x - self.w/2 and x < self.x + self.w/2
           and y > self.y - self.h/6 and y < self.y + self.h/6):
            self.delta = 1
            return True
        return False

class Text:
    def __init__(self, link, link2, size, index, name):
        self.surface = pygame.image.load(link).convert_alpha()
        self.w, self.h = size
        self.x, self.y = index
        self.surface = pygame.transform.scale(self.surface, (self.w, self.h/6))
        self.name = name + ": "
        if name == "Value":
            self.num = "0"
        else:
            self.num = ""
        self.mouse = 0
        self.mouse_surface = pygame.image.load(link2).convert_alpha()
        self.mouse_surface = pygame.transform.scale(
            self.mouse_surface, (2, self.h/6))

    def draw(self):
        screen.blit(self.surface, (self.x, self.y))
        if (self.mouse != 0):
            self.mouse += 1
            if (self.mouse % 7 == 0):
                screen.blit(self.mouse_surface, (self.x - 3 +
                            len(self.name)*14 + len(self.num)*14, self.y))
                self.mouse = 1
        if (self.num == ""):
            if self.name == "Value: ":
                self.num = "0"
            else:
                self.num = ""
        if self.name == "Value: ":
            text_surface = font.render(self.name + str(self.num), True, BLACK)
        else:
            text_surface = font.render(self.name + self.num, True, BLACK)
        screen.blit(text_surface, (self.x, self.y))

    def click(self, x, y):
        if (x > self.x and x < self.x + self.w
           and y > self.y and y < self.y + 20):
            return True
        return False

    def push(self, event):
        # if(self.num == 0):
        #     return
        if self.name == "Value: ":
            if event in [pygame.K_0, pygame.K_1, pygame.K_2, pygame.K_3,
                         pygame.K_4, pygame.K_5, pygame.K_6, pygame.K_7,
                         pygame.K_8, pygame.K_9]:
                if (self.mouse != 0):
                    if self.num == "0":
                        self.num = str(event - 48)
                    else:
                        self.num += str(event - 48)
        elif event >= 97 and event <= 122:
            if (self.mouse != 0):
                self.num += chr(event - 32)

        elif event == pygame.K_BACKSPACE:
            if self.num != "" and self.num != "0":
                self.num = self.num[:len(self.num) - 1]

class ButtonNode:
    def __init__(self, link, link2, size, index, value, name):
        self.surface1 = pygame.image.load(link).convert_alpha()
        self.surface2 = pygame.image.load(link2).convert_alpha()
        self.w, self.h = size
        self.x, self.y = index
        self.check = 0
        self.value = value
        self.name = name
        self.click = False
        self.surface1 = pygame.transform.scale(self.surface1, size)
        self.surface2 = pygame.transform.scale(self.surface2, size)

    def draw(self, x, y):
        if (self.click == True):
            self.x, self.y = x, y
        if self.check == 0:
            screen.blit(self.surface1, (self.x -
                        (self.w)/2, self.y - (self.h)/2))
        else:
            screen.blit(self.surface2, (self.x -
                        (self.w)/2, self.y - (self.h)/2))
        text_surface = font.render(str(self.value), True, BLACK)
        screen.blit(text_surface, (self.x - (self.w)/2 -
                    len(str(self.value))*7 + 27, self.y - (self.h)/2 + 20))
        text_surface = font.render(self.name, True, BLACK)
        screen.blit(text_surface, (self.x - (self.w)/2 -
                    len(self.name)*10 + 25, self.y - (self.h)/2))

    def check_click(self, x, y):
        if (self.x - (self.w)/2 < x and self.x + (self.w)/2 > x
                and y > self.y - (self.h)/2 and y < self.y + (self.h)/2):
            self.x, self.y = x, y
            self.click = True
            return True
        return False

def mui_ten(A, B, value):
    pygame.draw.line(screen, BLACK, (A), (B))
    pygame.draw.circle(screen, (255, 0, 220), (B), 5)
    text_surface = font.render(str(value), True, BLACK)
    x, y = (A[0] + B[0])/2, (A[1] + B[1])/2
    screen.blit(text_surface, ((x + B[0])/2 -
                len(str(value))*7 + 27, (y + B[1])/2))

class Matrix:
    def __init__(self):
        self.matrix = []
        self.arr = []

    def draw(self, x, y, index):
        for i, j, t in self.matrix:
            mui_ten((self.arr[i].x, self.arr[i].y),
                    (self.arr[j].x, self.arr[j].y), t)

        j = 0
        for i in self.arr:
            if j == index:
                i.check = 1
            else:
                i.check = 0
            j += 1
            i.draw(x, y)

    def conect(self, A, B, value):
        if ([A, B, value] not in self.matrix):
            self.matrix.append([A, B, value])

    def push(self, value, name):
        if name not in self.arr:
            self.arr.append(ButtonNode('./btn1.png', './btn2.png',
                            (50, 50), (800, 200), value, name))

    def delete(self, A, B):
        for i in range(len(self.matrix)):
            if self.matrix[i][0] == A and self.matrix[i][1] == B:
                del self.matrix[i]

    def check_click(self, x, y):
        for i in range(1, len(self.arr) + 1):
            if (self.arr[-i].check_click(x, y)):
                break

class Node:
    def __init__(self, value) -> None:
        self.value = value
        self.left = None
        self.right = None

def matrix_to_adj_list(matrix):
    num_vertices = len(matrix)
    adj_list = {}
    for i in range(num_vertices):
        adj_list[i] = []
        for j in range(num_vertices):
            if matrix[i][j] != 0:
                adj_list[i].append(j)
    return adj_list

def reconstruct_path(came_from, current):
    path = [current]
    while current in came_from:
        current = came_from[current]
        path.append(current)
    path.reverse()
    return path

def h_score_average(current, goal, graph):
    total_weight = 0
    num_neighbors = 0
    for neighbor, weight in enumerate(graph[goal]):
        if weight > 0:
            num_neighbors += 1
            total_weight += abs(graph[current]
                                [neighbor] - graph[goal][neighbor])
    return total_weight / num_neighbors if num_neighbors > 0 else 0

def Search(matrix, start, goal):
    n = len(matrix.arr)  # Độ dài cạnh của ma trận
    A = [[0 for j in range(n)] for i in range(n)]
    for i in range(len(matrix.matrix)):
        A[matrix.matrix[i][0]][matrix.matrix[i][1]] = matrix.matrix[i][2]
    print(A)

    open_set = set([start])
    closed_set = set()
    g_score = [float('inf')] * len(matrix.arr)
    g_score[start] = 0
    f_score = [float('inf')] * len(matrix.arr)
    ds_ke = matrix_to_adj_list(A)
    f_score[start] = h_score_average(start, goal, ds_ke)
    came_from = {}
    while open_set:
        # Lấy đỉnh trong danh sách mở có giá trị f-score nhỏ nhất
        current = min(open_set, key=lambda x: f_score[x])
        if current == goal:
            # Đã tìm thấy đường đi từ đỉnh xuất phát đến đỉnh đích
            return reconstruct_path(came_from, current)
        open_set.remove(current)  # Loại bỏ đỉnh hiện tại khỏi danh sách mở
        closed_set.add(current)  # Thêm đỉnh hiện tại vào danh sách đóng
        #
        for neighbor in ds_ke[current]:
            # Tính toán giá trị g-score mới cho đỉnh kề
            tentative_g_score = g_score[current] + A[current][neighbor]

            # Nếu đỉnh kề chưa được xét, thêm nó vào danh sách mở và cập nhật các thông tin về đỉnh kề
            if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
                open_set.add(neighbor)
                came_from[neighbor] = current
                g_score[neighbor] = tentative_g_score
                f_score[neighbor] = g_score[neighbor] + \
                    h_score_average(neighbor, goal, ds_ke)
    return None

bg_surface = pygame.image.load('./bg.png').convert()
bg_surface = pygame.transform.scale(bg_surface, (width, height))
btnInsert = Button('./btnInsert.png', (200, 150), (200, 200))
btnSearch = Button('./btnSearch.png', (200, 150), (200, 310))
btnConnect = Button('./btnConnect.png', (200, 150), (200, 400))
btnDelete = Button('./btnDelete.png', (200, 150), (200, 550))
textInsert1 = Text('./text.png', './mouse.png', (150, 150), (120, 240), "Name")
textInsert2 = Text('./text.png', './mouse.png',
                   (150, 150), (120, 270), "Value")
textSearch = Text('./text.png', './mouse.png', (150, 150), (120, 340), "Name")
textConnect1 = Text('./text.png', './mouse.png',
                    (150, 150), (120, 420), "Name 1")
textConnect2 = Text('./text.png', './mouse.png',
                    (150, 150), (120, 450), "Name 2")
textConnect3 = Text('./text.png', './mouse.png',
                    (150, 150), (120, 480), "Value")
textDelete1 = Text('./text.png', './mouse.png',
                   (150, 150), (120, 580), "Name 1")
textDelete2 = Text('./text.png', './mouse.png',
                   (150, 150), (120, 610), "Name 2")
# root = Tree()
matrix = Matrix()
matrix.push(10, "A")
matrix.push(15, "B")
matrix.push(20, "C")
matrix.push(25, "D")
matrix.push(25, "E")
matrix.conect(0, 2, 7)
matrix.conect(0, 1, 15)
matrix.conect(0, 4, 15)
matrix.conect(1, 3, 2)
node_surface = ButtonNode('./btn1.png', './btn2.png',
                          (50, 50), (800, 200), 100, "A")
search = -1
texts = [Text('./text.png', './mouse.png', (150, 150), (120, 240), "Name"),
         Text('./text.png', './mouse.png', (150, 150), (120, 270), "Value"),
         Text('./text.png', './mouse.png', (150, 150), (120, 340), "Name"),
         Text('./text.png', './mouse.png', (150, 150), (120, 420), "Name 1"),
         Text('./text.png', './mouse.png', (150, 150), (120, 450), "Name 2"),
         Text('./text.png', './mouse.png', (150, 150), (120, 480), "Value"),
         Text('./text.png', './mouse.png', (150, 150), (120, 580), "Name 1"),
         Text('./text.png', './mouse.png', (150, 150), (120, 610), "Name 2")]
a = []
while True:
    screen.blit(bg_surface, (0, 0))
    btnInsert.draw()
    btnSearch.draw()
    btnConnect.draw()
    btnDelete.draw()
    for text in texts:
        text.draw()

    mouse_x, mouse_y = pygame.mouse.get_pos()
    if len(a) == 0 or search == -1:
        index = -1
    else:
        index = a[search]
        search += 1
        if (search >= len(a)):
            search = -1
    matrix.draw(mouse_x, mouse_y, index)
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()
        elif event.type == pygame.MOUSEBUTTONDOWN:  # nếu click chuột

            pygame.draw.circle(screen, (255, 220, 220), (mouse_x, mouse_y), 15)
            print('Clicked at:', mouse_x, mouse_y)

            matrix.check_click(mouse_x, mouse_y)
            for text in texts:
                text.mouse = 0

            for text in texts:
                if text.click(mouse_x, mouse_y) == True:
                    text.mouse = 1
                    break

            if btnInsert.click(mouse_x, mouse_y) == True:
                if (texts[0].num != ""):
                    matrix.push(int(texts[1].num), texts[0].num)
                    texts[1].num = "0"
                    texts[0].num = ""
                break
            if btnSearch.click(mouse_x, mouse_y) == True:
                if texts[2].num != "":
                    d = -1
                    for i in range(len(matrix.arr)):
                        if texts[2].num == matrix.arr[i].name:
                            d = i
                    if d != -1:
                        a = Search(matrix, 0, d)
                        search = 0
                texts[2].num = ""

                break
            if btnConnect.click(mouse_x, mouse_y) == True:
                if (texts[5].num != 0 and texts[3].num != "" and texts[4].num != ""):
                    d1 = -1
                    d2 = -1
                    for i in range(len(matrix.arr)):
                        if texts[3].num == matrix.arr[i].name:
                            d1 = i
                        if texts[4].num == matrix.arr[i].name:
                            d2 = i
                    if d1 != -1 and d2 != -1:
                        matrix.conect(d1, d2, int(texts[5].num))
                    texts[5].num = "0"
                    texts[3].num = ""
                    texts[4].num = ""
                break
            if btnDelete.click(mouse_x, mouse_y) == True:
                if (texts[6].num != "" and texts[7].num != ""):
                    d1 = -1
                    d2 = -1
                    for i in range(len(matrix.arr)):
                        if texts[6].num == matrix.arr[i].name:
                            d1 = i
                        if texts[7].num == matrix.arr[i].name:
                            d2 = i
                    if d1 != -1 and d2 != -1:
                        matrix.delete(d1, d2)
                texts[6].num = ""
                texts[7].num = ""
                break

        elif event.type == pygame.MOUSEBUTTONUP:
            # node_surface.click = False
            for i in matrix.arr:
                i.click = False
        elif event.type == pygame.KEYDOWN:
            for text in texts:
                if text.mouse != 0:
                    text.push(event.key)
    # node_surface.draw(mouse_x, mouse_y)
    pygame.display.update()
    fpsclock.tick(FPS)


from django import forms
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.serializers.json import DjangoJSONEncoder
from django.forms.widgets import Media
from django.templatetags.static import static
from django.utils.encoding import force_str
from django.utils.functional import Promise
from django.utils.translation import get_language
from js_asset import JS

from .configs import DEFAULT_CONFIG

class LazyEncoder(DjangoJSONEncoder):
    def default(self, obj):
        if isinstance(obj, Promise):
            return force_str(obj)
        return super().default(obj)

json_encode = LazyEncoder().encode

class CKEditorWidget(forms.Textarea):
    """
    Widget providing CKEditor for Rich Text Editing.
    Supports direct image uploads and embed.
    """

    def __init__(
        self,
        config_name="default",
        extra_plugins=None,
        external_plugin_resources=None,
        template_name="ckeditor/widget.html",
        *args,
        **kwargs
    ):
        self.template_name = template_name
        super().__init__(*args, **kwargs)

        self.config_name = config_name
        # Setup config from defaults.
        self.config = DEFAULT_CONFIG.copy()

        # Try to get valid config from settings.
        configs = getattr(settings, "CKEDITOR_CONFIGS", None)
        if configs:
            if isinstance(configs, dict):
                # Make sure the config_name exists.
                if self.config_name in configs:
                    config = configs[self.config_name]
                    # Make sure the configuration is a dictionary.
                    if not isinstance(config, dict):
                        raise ImproperlyConfigured(
                            'CKEDITOR_CONFIGS["%s"] \
                                setting must be a dictionary type.'
                            % self.config_name
                        )
                    # Override defaults with settings config.
                    self.config.update(config)
                else:
                    raise ImproperlyConfigured(
                        "No configuration named '%s' \
                            found in your CKEDITOR_CONFIGS setting."
                        % self.config_name
                    )
            else:
                raise ImproperlyConfigured(
                    "CKEDITOR_CONFIGS setting must be a\
                        dictionary type."
                )

        extra_plugins = extra_plugins or self.config.pop("extra_plugins", None) or []

        if extra_plugins:
            self.config["extraPlugins"] = ",".join(extra_plugins)

        self.external_plugin_resources = (
            external_plugin_resources
            or self.config.pop("external_plugin_resources", None)
            or []
        )

    @property
    def media(self):
        return Media(
            css={"all": ["ckeditor/ckeditor.css"]},
            js=(
                JS(
                    "ckeditor/ckeditor-init.js",
                    {
                        "id": "ckeditor-init-script",
                        "data-ckeditor-basepath": getattr(
                            settings,
                            "CKEDITOR_BASEPATH",
                            None,
                        )
                        or static("ckeditor/ckeditor/"),
                    },
                ),
                "ckeditor/ckeditor/ckeditor.js",
            )
        )

    def get_context(self, name, value, attrs):
        context = super().get_context(name, value, attrs)

        self._set_config()
        context["widget"]["config"] = json_encode(self.config)

        external_plugin_resources = [
            [force_str(a), force_str(b), force_str(c)]
            for a, b, c in self.external_plugin_resources
        ]
        context["widget"]["external_plugin_resources"] = json_encode(
            external_plugin_resources
        )
        return context

    def _set_config(self):
        lang = get_language().lower()
        if lang == "zh-hans":
            lang = "zh-cn"
        elif lang == "zh-hant":
            lang = "zh"
        self.config["language"] = lang


import os
from argparse import ArgumentParser, RawTextHelpFormatter
from astropy.table import Table

###################################################################

parser = ArgumentParser(description="Create new moment maps for (cleaned!) line cubes for a given taskid, beam, cubes",
                        formatter_class=RawTextHelpFormatter)

parser.add_argument('-t', '--taskid', default='190915041',
                    help='Specify the input taskid (default: %(default)s).')

parser.add_argument('-c', '--cubes', default='1,2,3',
                    help='Specify the cubes on which to do source finding (default: %(default)s).')

parser.add_argument('-s', '--sources', default='all',
                    help='Specify sources to flag if necessary.  Can specify range or list. (default: %(default)s).')

parser.add_argument('-p', '--prefix', default=None,
                    help='Add a prefix to the file name (making new ones?). (default: %(default)s).')

parser.add_argument('-w', '--smooth', action='store_true',
                    help='If option is included apply edits to the smoothed SIP images.')

###################################################################

# Parse the arguments above
args = parser.parse_args()

# Range of cubes/sources to work on:
taskid = args.taskid
cubes = [int(c) for c in args.cubes.split(',')]
if args.prefix:
    prefix = args.prefix + '_'
else:
    prefix = ''

mos_loc = 'mos_' + taskid + '/'
for c in cubes:
    filename = taskid + '_HIcube' + str(c) + '_clean_image'
    if args.smooth:
        filename = taskid + '_HIcube' + str(c) + '_clean_smooth_image'
    catalog = Table.read(mos_loc + filename + '_cat.xml')

    if args.sources == 'all':
        sources = [str(s + 1) for s in range(len(catalog))]
    elif '-' in args.sources:
        src_range = args.sources.split('-')
        sources = [str(s + int(src_range[0])) for s in range(int(src_range[1]) - int(src_range[0]) + 1)]
    else:
        sources = [str(s) for s in args.sources.split(',')]

    for s in sources:
        cat = catalog[catalog['id'] == int(s)]
        if len(cat) > 0:
            infile = f"{mos_loc}{filename}_figures/{filename}_{s}_combo.png"
            outfile = f"{mos_loc}{filename}_figures/{prefix}AHC{cat['name'][0].split(' ')[1]}_{taskid}_{s}_combo.png"
            os.system(f"mv {infile} {outfile}")


import logging
import json
import operator

from configparser import ConfigParser
from pathlib import Path

from .execute_pointer_sources import call_malloc
from .exploration_techniques import FreeExecution, HeartBeat

from ..analyses.arguments_analyses import filter_unused_args
from ..utils import *

from angrcli.interaction.explore import ExploreInteractive
import angrcli.plugins.ContextView
import angrcli.plugins.watches

l = logging.getLogger("execute_free     ")
l.setLevel(logging.INFO)

config = ConfigParser()
config.read((Path(__file__).parent.parent / "./heapster.ini").resolve())

def dse_it(state, hooks):

    sm = state.project.factory.simgr(state)

    dfs = angr.exploration_techniques.DFS()
    ed = ExplosionDetector(threshold=int(config["fix_hml"]["dse_max_states"]))
    free_exec = FreeExecution(current_hooks=hooks)

    sm.use_technique(dfs)
    sm.use_technique(ed)
    sm.use_technique(free_exec)
    sm.use_technique(HeartBeat())

    def timeout():
        l.debug("Timeout during DSE has been reached.")
        ed.timed_out.set()
    timer = Timer(int(config["fix_hml"]["dse_timeout"]), timeout)

    l.info("[+]   Starting timer [{} seconds]".format(config["fix_hml"]["dse_timeout"]))
    timer.start()
    start_time = time.time()
    sm.run() # Run it!
    timer.cancel()
    end_time = time.time()

    # Calculate delta of latest function if didn't end properly.
    if free_exec.current_function in free_exec.executed_funcs.keys():
        free_exec.executed_funcs[free_exec.current_function] += (end_time - start_time)

    # Stop exploration has been forced from timeout, something went wrong.
    if ed.timed_out_bool:
        l.info("[!]   Exploration timeout is expired!")
        # If we timeout we try to skip the function in which we spent the most time.
        func_to_skip = max(free_exec.executed_funcs.items(), key=operator.itemgetter(1))[0]
        l.info("[+]   Spent {} in func {}. Hooking it next time.".format(free_exec.executed_funcs[func_to_skip], hex(func_to_skip)))
        if func_to_skip == state.project.kb.functions[state.addr].addr:
            l.fatal("[!] We should skip the entire free. This can't be done, something is wrong. Aborting.")
            assert(False)
        return False, func_to_skip

    return True, free_exec.last_state

def call_free(base_state, hb_state, chunk_to_free):
    l.debug("Deallocating chunk {}".format(hex(chunk_to_free)))
    project = base_state.project

    free_addr = int(hb_state["final_allocator"]["free"], 16)
    free = project.kb.functions[free_addr]

    free_prototype = json.loads(hb_state["free_prototype"])
    free_param = []
    free_prototype_args = []
    free_cc_args = free.calling_convention.args

    for f_arg_key, f_arg_val in free_prototype.items():
        if f_arg_key == 'ret':
            continue
        else:
            free_prototype_args.append(f_arg_val)

    cs = project.factory.call_state(free.addr,  base_state=base_state, ret_addr=0xdeadbeef)
    cs.regs.sp = project.arch.initial_sp

    # Just to make sure
    setattr(cs.regs, "lr", 0xdeadbeef)
    cs.callstack.ret_addr = 0xdeadbeef
    cs.callstack_return_address = 0xdeadbeef

    # Setup parameter for free.
    for f_arg, f_cc_reg in zip(free_prototype_args, free_cc_args):
        if f_arg != "ptr_to_free":
            arg_val = hb_state["free_unknown_arguments_vals"][f_cc_reg.reg_name][0]
        else:
            arg_val = cs.solver.BVV(chunk_to_free, project.arch.bits)
        setattr(cs.regs, f_cc_reg.reg_name, arg_val)

    # Emulate until we can hit the end of the function.
    success = False
    hooks = set()
    attempt = 0
    while success == False:
        l.info("[+]  Attempt {}. Executing free with {} hooks.".format(attempt + 1, len(hooks)))
        for j,h in enumerate(hooks):
            l.info("[+]   Hook-{}: {}".format(j, hex(h)))
        success, result = dse_it(cs, hooks)
        if success == False:
            l.debug("[+]   Skipping function {} next time".format(hex(result)))
            # result is the function we need to skip next time.
            hooks.add(result)
        else:
            if result != None and result.solver.eval(result.regs.pc) == 0xdeadbeef:
                l.info("[+]  ✓ Successfully executed free.")
            else:
                l.debug("[!] ✗ Free could not reach end of execution.")
                l.debug("[!] This can be a fatal error or simply due to hooks inserted in the algorithm.")
                l.debug("Current hooks {}".format(hooks))

            # result is the final state at this point.
            return result, hooks
        attempt += 1


import copy

import numpy as np
import torch
import torch.nn as nn
from deepmodel import threelayer
from experience_replay import ReplayMemory
import sys

class DQNAgent:

    def __init__(self, state_size = 8, action_size = 4, batch_size = 32, buffer_size = 100000, epsilon_decay = 0.999, gamma = 0.99, hidden_size1 = 32, hidden_size2 = 32, learning_rate = 0.0001, regularization = 0.000001, momentum = 0.99, qnet_update_freq = 5):

        self.state_size = state_size
        self.action_size = action_size
        self.device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
        print("Currently using:", self.device)
        self.hidden_size1 = hidden_size1
        self.hidden_size2 = hidden_size2
        self.qnet = threelayer.ThreeLayerNet(self.state_size, self.hidden_size1, self.hidden_size2, self.action_size).to(self.device)
        print("DQN architecture layers", self.state_size, "->", self.hidden_size1,"->", self.hidden_size2,"->", self.action_size)
        # 6 states -> 4 actions
        self.fixed_qnet = copy.deepcopy(self.qnet)
        self.batch_size = batch_size
        self.qnet_update_freq = qnet_update_freq
        self.fixed_qnet_update_freq = 1 * self.qnet_update_freq
        self.learning_rate = learning_rate
        self.reg = regularization
        self.momentum = momentum
        self.buffer_size = buffer_size

        self.loss_fn = nn.MSELoss()
        # self.optimizer = torch.optim.SGD(self.qnet.parameters(), lr = self.learning_rate,) #momentum = self.momentum, weight_decay = self.reg)
        # self.optimizer = torch.optim.Adam(self.qnet.parameters())

        self.optimizer = torch.optim.Adam(self.qnet.parameters(),
                                          lr = self.learning_rate, weight_decay = self.reg,
                                          betas = [0.9,0.999],
                                          eps = 1e-04, amsgrad= True)
        self.replay_memory = ReplayMemory(self.buffer_size)
        self.num_steps = 0
        self.gamma = gamma

        self.epsilon = 1
        self.epsilon_decay = epsilon_decay

    def learn(self, sars):

        self.replay_memory.add(sars)
        if self.num_steps >= self.batch_size:

            s_sample, a_sample, r_sample, s_prime_sample, d_sample = self.replay_memory.sample(self.batch_size)
            if torch.cuda.is_available():
                s_sample = s_sample.cuda()
                s_prime_sample = s_prime_sample.cuda()
            Q_s_prime_a_prime = self.fixed_qnet(s_prime_sample)

            max_Q_s_prime_a_prime = Q_s_prime_a_prime.max(1)[0].unsqueeze(1)

            targets = r_sample + self.gamma*max_Q_s_prime_a_prime*(1-d_sample)

            Q_s_a = self.qnet(s_sample)
            q_values = Q_s_a[np.arange(self.batch_size), a_sample].unsqueeze(1)
            # q_values = torch.gather(Q_s_a, 1, a_sample)
            self.optimizer.zero_grad()
            loss = self.loss_fn(q_values, targets)
            loss.backward()
            self.optimizer.step()

        if self.num_steps % self.qnet_update_freq == 0:
            self.update_fixed_network()
            # self.fixed_qnet = copy.deepcopy(self.qnet)

        self.num_steps += 1

    # def pick_action(self, state):

        # state = torch.from_numpy(state).float().unsqueeze(0).to(self.device)
        #
        # q_values = self.qnet(state)
        # # print(q_values)
        # # print(q_values.shape)
        # # sys.exit()
        #
        # # compute the probs of each action (1, num_actions)
        # probs = nn.Softmax(dim=1)(q_values.data/0.01)
        # probs = probs.cpu().detach().numpy()
        # probs = np.array(probs)
        # probs /= probs.sum()
        #
        # # select action
        # action = np.random.choice(self.action_size, 1, p=probs.squeeze())
        # action = int(action)
        # # print(action)
        # # print(action.shape)
        # return action

    def pick_action(self, state):

        # action = np.random.randint(self.action_size)
        # print(self.epsilon)
        if np.random.random() < self.epsilon:
            action = np.random.randint(self.action_size)
        else:
            state = torch.from_numpy(state).float().unsqueeze(0).to(self.device)
            # self.qnet.eval()
            # with torch.no_grad():
            q_values = self.qnet(state)
            # self.qnet.train()
            action = np.argmax(q_values.cpu().data.numpy())
            # print(action)

        return action

    # def softmax(self, action_values, tau=0.01):
    #     """
    #     Args:
    #         action_values: A torch tensor (2d) of size (batch_size, num_actions).
    #         tau: Tempearture parameter.
    #
    #     Returns:
    #         probs: A torch tensor of size (batch_size, num_actions). The value represents the probability of select
    #         that action.
    #     """
    #
    #     max_action_value = torch.max(action_values, axis=1, keepdim=True)[0] / tau
    #     action_values = action_values / tau
    #
    #     preference = action_values - max_action_value
    #
    #     exp_action = torch.exp(preference)
    #     sum_exp_action = torch.sum(exp_action, axis=1).view(-1, 1)
    #
    #     probs = exp_action / sum_exp_action
    #
    #     return probs

    def update_fixed_network(self):

        # self.fixed_qnet = copy.deepcopy(self.qnet)
        TAU = 0.01
        for source_parameters, target_parameters in zip(self.qnet.parameters(), self.fixed_qnet.parameters()):
            target_parameters.data.copy_(TAU * source_parameters.data + (1.0 - TAU) * target_parameters.data)


import base64

from googletrans import Translator, constants

#constants.LANGUAGES[detection.lang]
from DjangoReader.services.helper import fromBase64

translator = Translator()

def translate(text, origin_language_name, translating_language_name):
    text = fromBase64(text)
    name = None
    name2 = None
    for key, value in constants.LANGUAGES.items():
        if (value == origin_language_name):
            name = key
        if (value == translating_language_name):
            name2 = key
            #sample_string = "GeeksForGeeks is the best"
            #sample_string_bytes = sample_string.encode("ascii")

            #base64_bytes = base64.b64encode(sample_string_bytes)
            #base64_string = base64_bytes.decode("ascii")
            a = translator.translate(text=text, src=name, dest=name2).text
    return base64.b64encode(translator.translate(text=text, src=name, dest=name2).text.encode()).decode()


from telegram import *
from telegram.ext import *
from telegram.constants import ParseMode
from dotenv import load_dotenv
from random import randint
from PIL import Image, ImageDraw
from io import BytesIO
from Authenticator import Authenticator
import traceback
import html
import Utils
import os
import json
import asyncio

class CollageCreator:
    def createCollage(self, imagesBytesList: list[bytes]) -> BytesIO:
        new = Image.new("RGBA", (100,100))
        memory = BytesIO()

        for i in range(len(imagesBytesList)):
            imageBytes = imagesBytesList[i]
            image = Image.open(BytesIO(imageBytes))
            image = image.resize((50, 50))
            draw = ImageDraw.Draw(image)
            draw.text((0, 0), str(i + 1), (87, 0, 3))

            height = 0
            width = 0
            if i == 1:
                width = 50
            elif i == 2:
                height = 50
            elif i == 3:
                height = 50
                width = 50

            new.paste(image, (width,height))

        memory.name = "image.png"
        new.save(
            memory,
            "PNG",
            optimize = True,
            quality = 10
        )
        memory.seek(0)
        return memory

class TelegramVerifier:
    isUserCorrect: bool = False
    auth: Authenticator = None
    messageStack: list[Message] = []
    itemKeys = []

    class CannotVerify(Exception): pass

    def __init__(self) -> None:
        load_dotenv()

        self.chatId = os.getenv("chat_id")
        self.token = os.getenv("bot_token")

    def run(self):
        loop = asyncio.get_event_loop()

        if loop.is_closed():
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)

        self.application = Application.builder().token(token = self.token).build()
        self.application.add_handler(CommandHandler("start", self.start))
        self.application.add_handler(CallbackQueryHandler(self.onItemClick))
        self.application.add_error_handler(self.errorHandler)

        loop.run_until_complete(self.verify())
        print("> Please answer immediately!")
        self.application.run_polling()
        print("> Stopping telegram bot...")

    async def verify(self) -> bool:
        retries = 3
        objectToFind: str = None

        while retries > 0:
            try:
                if retries < 3:
                    print(f"> Retrying [{retries}]")

                self.isUserCorrect = False
                if objectToFind == None:
                    humanizedHeaders = {
                        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
                        "Host": self.auth.webHost,
                        "Referer": self.auth.ENDPOINTS["travel"],
                        "Connection": "keep-alive",
                        "Sec-Fetch-Dest": "document",
                        "Sec-Fetch-Mode": "navigate",
                        "Sec-Fetch-Site": "same-origin",
                        "Sec-Fetch-User": "?1",
                        "Upgrade-Insecure-Requests": "1",
                        "x-requested-with": self.auth.packageName,
                        "User-Agent": self.auth.userAgent["webView"]
                    }

                    response = self.auth.get(
                        url = self.auth.ENDPOINTS["verifyPage"],
                        headers = humanizedHeaders
                    )

                    objectToFind = Utils.getStringInBetween(
                        string = response.text,
                        delimiter1 = '
',
                        delimiter2 = '
'
                    )

                self.itemKeys = self.getItemKeys(response.text)
                self.itemKeys.pop(0)

                print("> Obtaining images...")
                itemImages = self.getItemImages()

                print("> Collaging images...")
                collageCreator = CollageCreator()
                collagedImages = collageCreator.createCollage(itemImages)

                buttons = [
                    [InlineKeyboardButton("1", callback_data="0")],
                    [InlineKeyboardButton("2", callback_data="1")],
                    [InlineKeyboardButton("3", callback_data="2")],
                    [InlineKeyboardButton("4", callback_data="3")]
                ]

                print("> Sending the images...")
                message = await self.application.updater.bot.sendPhoto(
                    chat_id = self.chatId,
                    photo = collagedImages,
                    caption = f"🔍 Find: {objectToFind.strip()}",
                    reply_markup = InlineKeyboardMarkup(buttons)
                )
                self.messageStack.append(message)
            except:
                retries -= 1
                raise Exception()
            else:
                return

        raise self.CannotVerify("Please verify it manually, ASAP!")

    async def errorHandler(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Log the error and send a telegram message to notify the developer."""
        # Log the error before we do anything else, so we can see it even if something breaks.
        self.logger.error(msg="Exception while handling an update:", exc_info=context.error)

        # traceback.format_exception returns the usual python message about an exception, but as a
        # list of strings rather than a single string, so we have to join them together.
        tb_list = traceback.format_exception(None, context.error, context.error.__traceback__)
        tb_string = "".join(tb_list)

        # Build the message with some markup and additional information about what happened.
        # You might need to add some logic to deal with messages longer than the 4096 character limit.
        update_str = update.to_dict() if isinstance(update, Update) else str(update)
        message = (
            f"An exception was raised while handling an update\n"
            f"
update = {html.escape(json.dumps(update_str, indent=2, ensure_ascii=False))}"
            "
\n\n"
            f"
context.chat_data = {html.escape(str(context.chat_data))}
\n\n"
            f"
context.user_data = {html.escape(str(context.user_data))}
\n\n"
            f"
{html.escape(tb_string)}
"
        )

        # Finally, send the message
        await context.bot.send_message(
            chat_id=self.chatId, text=message, parse_mode=ParseMode.HTML
        )

    def getItemKeys(self, verificationDetails: str) -> list[str]:
        return Utils.getMultipleStringsInBetween(
            string = verificationDetails,
            delimiter1 = "chooseItem('",
            delimiter2 = "'"
        )

    def getItemImages(self) -> list[bytes]:
        contents = []
        humanizedHeaders = {
            "Accept": "image/avif,image/webp,*/*",
            "Host": self.auth.webHost,
            "Referer": self.auth.ENDPOINTS["verifyPage"],
            "Connection": "keep-alive",
            "Sec-Fetch-Dest": "image",
            "Sec-Fetch-Mode": "no-cors",
            "Sec-Fetch-Site": "same-origin",
            "x-requested-with": self.auth.packageName,
            "User-Agent": self.auth.userAgent["webView"]
        }

        for i in range(0, 4):
            item = self.auth.get(
                url = self.auth.ENDPOINTS["verifyImages"] + str(i),
                headers = humanizedHeaders
            ).content

            contents.append(item)

        return contents

    async def onItemClick(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        query = update.callback_query
        await query.answer()

        try:
            latestVerificationMessage = self.messageStack[0]
            expiredMessage = "⚠ Error: verification message expired!"
            if query.message.id != latestVerificationMessage.id:
                await query.edit_message_caption(
                    caption = expiredMessage,
                    reply_markup = None
                )
                return
        finally:
            pass

        item = int(query.data)
        self.isUserCorrect = self.getVerificationResults(itemPosition = item)

        status = "incorrect ❗"
        if self.isUserCorrect:
            print("> Verification successful!")
            status = "correct ✅"
        else:
            print("> Verification failed!")

        try:
            statusMessage = f"{query.message.caption}\n🔒 Verification [{item + 1}] is {status}"
            await query.edit_message_caption(
                caption = statusMessage,
                reply_markup = None
            )
            self.messageStack.pop()
        finally:
            asyncio.get_event_loop().stop()
            return

    async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """A ping function to send a dummy message"""
        await update.message.reply_text("Hi! I'm a bot!")

    def getVerificationResults(self, itemPosition: int) -> bool:
        x, y = self.humanizeMouseClick()

        humanizedData = {
            "data": self.itemKeys[itemPosition],
            "x": x,
            "y": y
        }

        humanizedHeaders = {
            "Accept": "*/*",
            "Host": self.auth.webHost,
            "Origin": self.auth.WEB_ENDPOINT,
            "Referer": self.auth.ENDPOINTS["verifyPage"],
            "x-requested-with": self.auth.packageName,
            "Connection": "keep-alive",
            "User-Agent": self.auth.userAgent["webView"]
        }

        result = self.auth.post(
            url = self.auth.ENDPOINTS["verifyXHR"],
            data = humanizedData,
            headers = humanizedHeaders
        )

        try:
            parsedResult = json.loads(result.text)
            isSuccess = parsedResult["type"] == "success"
            if isSuccess:
                return True
            else:
                return False
        except:
            raise self.CannotVerify("Please verify it manually, ASAP!")

    def humanizeMouseClick(self):
        xPosition = randint(291, 410)
        yPosition = randint(381, 398)

        return (xPosition, yPosition)


import discord
from discord.ext import commands
from cogs.utils import checks
from __main__ import settings

class Verify:
    """Custom Verify tool."""

    def __init__(self, bot):
        self.bot = bot

    @commands.command(no_pm=True, pass_context=True)
    async def verifyme(self, ctx, rolename: str="Verified", user: discord.Member=None):
        """Adds the specified role to the user"""
        author = ctx.message.author
        channel = ctx.message.channel
        server = ctx.message.server
        role = discord.utils.find(lambda r: r.name.lower() == rolename.lower(),
                                  ctx.message.server.roles)
        if user is None:
            user = author

        if role is None:
            await self.bot.say('Something went wrong.  The "Verified" role cannot be found.')
            return

        if not channel.permissions_for(server.me).manage_roles:
            await self.bot.say('I don\'t have manage_roles permissions.')
            return

        await self.bot.add_roles(user, role)
        await self.bot.say('Added role {} to {}'.format(role.name, user.name))

def setup(bot):
    bot.add_cog(Verify(bot))


import logging
import os
import shutil

import pytest

import salt.config
import salt.loader
import salt.modules.cmdmod as cmdmod
import salt.modules.config as configmod
import salt.modules.file as filemod
import salt.utils.data
import salt.utils.files
import salt.utils.platform
import salt.utils.stringutils
from tests.support.mock import MagicMock, call, patch

log = logging.getLogger(__name__)

@pytest.fixture
def configure_loader_modules():
    return {
        filemod: {
            "__salt__": {
                "config.manage_mode": configmod.manage_mode,
                "cmd.run": cmdmod.run,
                "cmd.run_all": cmdmod.run_all,
            },
            "__opts__": {
                "test": False,
                "file_roots": {"base": "tmp"},
                "pillar_roots": {"base": "tmp"},
                "cachedir": "tmp",
                "grains": {},
            },
            "__grains__": {"kernel": "Linux"},
        }
    }

@pytest.fixture
def tmp_sub_dir(tmp_path):
    directory = tmp_path / "file-basics-test-dir"
    directory.mkdir()

    yield directory

    shutil.rmtree(str(directory))

@pytest.fixture
def tfile(tmp_sub_dir):
    filename = str(tmp_sub_dir / "file-basics-test-file")

    with salt.utils.files.fopen(filename, "w+") as fp:
        fp.write("Hi hello! I am a file.")

    yield filename

    os.remove(filename)

@pytest.fixture
def myfile(tmp_sub_dir):
    filename = str(tmp_sub_dir / "myfile")

    with salt.utils.files.fopen(filename, "w+") as fp:
        fp.write(salt.utils.stringutils.to_str("Hello\n"))

    yield filename

    os.remove(filename)

@pytest.fixture
def a_link(tmp_sub_dir):
    path = tmp_sub_dir / "a_link"
    linkname = str(path)

    yield linkname

    if path.exists():
        os.remove(linkname)

@pytest.fixture
def a_hardlink(tmp_sub_dir):
    path = tmp_sub_dir / "a_hardlink"
    linkname = str(path)

    yield linkname

    if path.exists():
        os.remove(linkname)

@pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows")
def test_symlink_already_in_desired_state(tfile, a_link):
    os.symlink(tfile, a_link)
    result = filemod.symlink(tfile, a_link)
    assert result

@pytest.mark.skip_on_windows(reason="os.link is not available on Windows")
def test_hardlink_sanity(tfile, a_hardlink):
    target = a_hardlink
    result = filemod.link(tfile, target)
    assert result

@pytest.mark.skip_on_windows(reason="os.link is not available on Windows")
def test_hardlink_numlinks(tfile, a_hardlink):
    target = a_hardlink
    result = filemod.link(tfile, target)
    name_i = os.stat(tfile).st_nlink
    assert name_i > 1

@pytest.mark.skip_on_windows(reason="os.link is not available on Windows")
def test_hardlink_working(tfile, a_hardlink):
    target = a_hardlink
    result = filemod.link(tfile, target)
    name_i = os.stat(tfile).st_ino
    target_i = os.stat(target).st_ino
    assert name_i == target_i

def test_source_list_for_list_returns_file_from_dict_via_http():
    with patch("salt.modules.file.os.remove") as remove:
        remove.return_value = None
        with patch.dict(
            filemod.__salt__,
            {
                "cp.list_master": MagicMock(return_value=[]),
                "cp.list_master_dirs": MagicMock(return_value=[]),
                "cp.cache_file": MagicMock(return_value="/tmp/http.conf"),
            },
        ):
            with patch("salt.utils.http.query") as http_query:
                http_query.return_value = {}
                ret = filemod.source_list(
                    [{"http://t.est.com/http/httpd.conf": "filehash"}], "", "base"
                )
                assert list(ret) == ["http://t.est.com/http/httpd.conf", "filehash"]

def test_source_list_use_requests():
    with patch("salt.modules.file.os.remove") as remove:
        remove.return_value = None
        with patch.dict(
            filemod.__salt__,
            {
                "cp.list_master": MagicMock(return_value=[]),
                "cp.list_master_dirs": MagicMock(return_value=[]),
                "cp.cache_file": MagicMock(return_value="/tmp/http.conf"),
            },
        ):
            expected_call = call(
                "http://t.est.com/http/file1",
                decode_body=False,
                method="HEAD",
            )
            with patch(
                "salt.utils.http.query", MagicMock(return_value={})
            ) as http_query:
                ret = filemod.source_list(
                    [{"http://t.est.com/http/file1": "filehash"}], "", "base"
                )
                assert list(ret) == ["http://t.est.com/http/file1", "filehash"]
                assert expected_call in http_query.mock_calls

def test_source_list_for_list_returns_existing_file():
    with patch.dict(
        filemod.__salt__,
        {
            "cp.list_master": MagicMock(return_value=["http/httpd.conf.fallback"]),
            "cp.list_master_dirs": MagicMock(return_value=[]),
        },
    ):
        ret = filemod.source_list(
            ["salt://http/httpd.conf", "salt://http/httpd.conf.fallback"],
            "filehash",
            "base",
        )
        assert list(ret) == ["salt://http/httpd.conf.fallback", "filehash"]

def test_source_list_for_list_returns_file_from_other_env():
    def list_master(env):
        dct = {"base": [], "dev": ["http/httpd.conf"]}
        return dct[env]

    with patch.dict(
        filemod.__salt__,
        {
            "cp.list_master": MagicMock(side_effect=list_master),
            "cp.list_master_dirs": MagicMock(return_value=[]),
        },
    ):
        ret = filemod.source_list(
            [
                "salt://http/httpd.conf?saltenv=dev",
                "salt://http/httpd.conf.fallback",
            ],
            "filehash",
            "base",
        )
        assert list(ret) == ["salt://http/httpd.conf?saltenv=dev", "filehash"]

def test_source_list_for_list_returns_file_from_dict():
    with patch.dict(
        filemod.__salt__,
        {
            "cp.list_master": MagicMock(return_value=["http/httpd.conf"]),
            "cp.list_master_dirs": MagicMock(return_value=[]),
        },
    ):
        ret = filemod.source_list([{"salt://http/httpd.conf": ""}], "filehash", "base")
        assert list(ret) == ["salt://http/httpd.conf", "filehash"]

def test_source_list_for_list_returns_existing_local_file_slash(myfile):
    with patch.dict(
        filemod.__salt__,
        {
            "cp.list_master": MagicMock(return_value=[]),
            "cp.list_master_dirs": MagicMock(return_value=[]),
        },
    ):
        ret = filemod.source_list([myfile + "-foo", myfile], "filehash", "base")
        assert list(ret) == [myfile, "filehash"]

def test_source_list_for_list_returns_existing_local_file_proto(myfile):
    with patch.dict(
        filemod.__salt__,
        {
            "cp.list_master": MagicMock(return_value=[]),
            "cp.list_master_dirs": MagicMock(return_value=[]),
        },
    ):
        ret = filemod.source_list(
            ["file://" + myfile + "-foo", "file://" + myfile],
            "filehash",
            "base",
        )
        assert list(ret) == ["file://" + myfile, "filehash"]

def test_source_list_for_list_returns_local_file_slash_from_dict(myfile):
    with patch.dict(
        filemod.__salt__,
        {
            "cp.list_master": MagicMock(return_value=[]),
            "cp.list_master_dirs": MagicMock(return_value=[]),
        },
    ):
        ret = filemod.source_list([{myfile: ""}], "filehash", "base")
        assert list(ret) == [myfile, "filehash"]

def test_source_list_for_list_returns_local_file_proto_from_dict(myfile):
    with patch.dict(
        filemod.__salt__,
        {
            "cp.list_master": MagicMock(return_value=[]),
            "cp.list_master_dirs": MagicMock(return_value=[]),
        },
    ):
        ret = filemod.source_list([{"file://" + myfile: ""}], "filehash", "base")
        assert list(ret) == ["file://" + myfile, "filehash"]

def test_symlink_lexists_called_follow_symlinks_false():
    tfile = "/tmp/file-basics-test-file"
    a_link = "/tmp/a_link"

    exists = MagicMock(return_value=False)
    lexists = MagicMock(return_value=False)

    with patch("os.path.exists", exists), patch("os.path.lexists", lexists), patch(
        "os.symlink", MagicMock(return_value=True)
    ):
        filemod.symlink(tfile, a_link)
        lexists.assert_not_called()
        exists.assert_called()

        lexists.reset_mock()
        exists.reset_mock()

        filemod.symlink(tfile, a_link, follow_symlinks=False)
        lexists.assert_called()
        exists.assert_not_called()


import torch
from dataset import ShapeNetDataset
from model import ClassificationNN, SegmentationNN, FeatureTransform, train
from torch.utils.data import random_split

import subprocess
import os
import argparse

def parse():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model_type', type=str, default = 'cls', help = 'cls or seg')
    parser.add_argument('--dataset_root', type=str, default = './datasets/ModelNet10', help='dataset root dir')
    parser.add_argument('--epochs', type=int, default = 20, help='epochs')
    parser.add_argument('--batch_size', type=int, default = 32, help='batch size')
    parser.add_argument('--lr', type=float, default = 0.0001,  help='learning rate')
    parser.add_argument('--train_split', type=float, default = 0.7,  help='train/test split')
    parser.add_argument('--point_num', type=int, default = 1000, help = 'point num of point cloud')
    parser.add_argument('--cls_num', type=int, default = 10, help = 'class num')

    return parser.parse_args()

def load_data(path):
    if os.path.exists(path):
        pass
    else:
        if not os.path.exists("./datasets/"): os.makedirs("./datasets/")
        if path=='./datasets/ModelNet10':
            if not os.path.exists('./ModelNet10.zip'):
                print('downloading')
                process = subprocess.Popen(["wget", "http://3dvision.princeton.edu/projects/2014/3DShapeNets/ModelNet10.zip"])
                process.wait()
            subprocess.Popen(["unzip", "ModelNet10.zip", "-d", "./datasets/"])
        if path=='./datasets/ModelNet40':
            if not os.path.exists('./ModelNet40.zip'):
                process = subprocess.Popen(["wget", "http://modelnet.cs.princeton.edu/ModelNet40.zip"])
            process.wait()
            subprocess.Popen(["unzip", "-o", "ModelNet40.zip", "-d", "./datasets/"])

def prepare_dataset(opt):
    trainset = ShapeNetDataset(opt.dataset_root, train=True, n=opt.point_num)
    dataset_length = len(trainset)
    train_len = int(dataset_length * opt.train_split)
    test_len = dataset_length - train_len
    trainset, testset = random_split(trainset, [train_len, test_len])
    testset.train = False
    return trainset, testset

def train_pointNet_cls():
    opt = parse()
    load_data(opt.dataset_root)
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    trainset, valset = prepare_dataset(opt)
    classification_model = ClassificationNN(opt.cls_num).to(device)

    optimizer = torch.optim.Adam(classification_model.parameters(), lr=opt.lr)
    train(classification_model, trainset, valset, optimizer, epochs=opt.epochs, batch_size=opt.batch_size, device=device)

# def train_pointNet_seg():
#     opt = parse()
#     load_data(opt)
#     device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
#     trainset, valset = prepare_dataset(opt)
#     segmentation_model = SegmentationNN(opt.cls_num).to(device)

#     optimizer = torch.optim.Adam(segmentation_model.parameters(), lr=opt.lr)
#     train(segmentation_model, trainset, valset, optimizer, epochs=opt.epochs, batch_size=opt.batch_size, device=device)

# def train_pointNet():
#     if
if __name__=='__main__':
    train_pointNet_cls()