import logging
import os
import time
import random
import json
from tqdm import tqdm
import sys
import torch
from itertools import chain
import torch.nn as nn
from torch.nn.utils import clip_grad_norm_
from torch.utils.data import DataLoader
from tensorboardX import SummaryWriter
from torch.optim.lr_scheduler import StepLR, MultiStepLR
import numpy as np
from configs.opts import parser
from model.main_model_2 import AV_VQVAE_Encoder, AT_VQVAE_Encoder, AV_VQVAE_Decoder, AT_VQVAE_Decoder, AVT_VQVAE_Encoder, AVT_VQVAE_Decoder
from model.CLUB import CLUBSample_group
from model.CPC import Cross_CPC, Cross_CPC_AVT
from utils import AverageMeter, Prepare_logger, get_and_save_args
from utils.container import metricsContainer
from utils.Recorder import Recorder
import torch.nn.functional as F
from bert_embedding import BertEmbedding
import pickle
# =================================  seed config ============================
SEED = 43
random.seed(SEED)
np.random.seed(seed=SEED)
torch.manual_seed(seed=SEED)
torch.cuda.manual_seed(seed=SEED)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False

# =============================================================================
def transpose(x):
    return x.transpose(-2, -1)

def normalize(*xs):
    return [None if x is None else F.normalize(x, dim=-1) for x in xs]

def AVPSLoss(av_simm, soft_label):
    """audio-visual pair similarity loss for fully supervised setting,
    please refer to Eq.(8, 9) in our paper.
    """
    # av_simm: [bs, 10]
    relu_av_simm = F.relu(av_simm)
    sum_av_simm = torch.sum(relu_av_simm, dim=-1, keepdim=True)
    avg_av_simm = relu_av_simm / (sum_av_simm + 1e-8)
    loss = nn.MSELoss()(avg_av_simm, soft_label)
    return loss

bert_embedding = BertEmbedding()
with open('../../cnt.pkl', 'rb') as fp:
    id2idx = pickle.load(fp)

def collate_func_AT(samples):
        bsz = len(samples)
        result = bert_embedding([sample['text_fea'] for sample in samples])
        query = []
        query_words = []
        for a, b in result:
            words = []
            words_emb = []
            for word, emb in zip(a, b):
                idx = bert_embedding.vocab.token_to_idx[word]
                if idx in id2idx and idx != 0:
                    words_emb.append(emb)
                    words.append(id2idx[idx])
            query.append(np.asarray(words_emb))
            query_words.append(words)

        query_len = []
        for i, sample in enumerate(query):
            # query_len.append(min(len(sample), 10))#max_num_words:10
            query_len.append(10)#max_num_words:10
        query1 = np.zeros([bsz, max(query_len), 768]).astype(np.float32)
        query_idx = np.zeros([bsz, max(query_len)]).astype(np.float32)
        for i, sample in enumerate(query):
            keep = min(sample.shape[0], query1.shape[1])
            query1[i, :keep] = sample[:keep]
            query_idx[i, :keep] = query_words[i][:keep]
        query_len = np.asarray(query_len)
        query, query_len = torch.from_numpy(query1).float(), torch.from_numpy(query_len).long()
        query_idx = torch.from_numpy(query_idx).long()

        return {
            'query': query,
            'query_idx': query_idx,
            'query_len': query_len,
            'audio_fea': torch.from_numpy(np.asarray([sample['audio_fea'] for sample in samples])).float()
        }

def collate_func_AVT(samples):
        bsz = len(samples)
        result = bert_embedding([sample['text_fea'] for sample in samples])
        query = []
        query_words = []
        for a, b in result:
            words = []
            words_emb = []
            for word, emb in zip(a, b):
                idx = bert_embedding.vocab.token_to_idx[word]
                if idx in id2idx and idx != 0:
                    words_emb.append(emb)
                    words.append(id2idx[idx])
            query.append(np.asarray(words_emb))
            query_words.append(words)

        query_len = []
        for i, sample in enumerate(query):
            # query_len.append(min(len(sample), 10))#max_num_words:10
            query_len.append(10)#max_num_words:10
        query1 = np.zeros([bsz, max(query_len), 768]).astype(np.float32)
        query_idx = np.zeros([bsz, max(query_len)]).astype(np.float32)
        for i, sample in enumerate(query):
            keep = min(sample.shape[0], query1.shape[1])
            """
            There may be cases where the sample length is 0,
            for example if your text happens to not be seen before in this BERT model.
            If that happens, you can
            1) clean the text before it enters BERT,
            2) add an if statement here,
            3) discard idx and directly import all embeddings after.
            """
            query1[i, :keep] = sample[:keep]
            query_idx[i, :keep] = query_words[i][:keep]
        query_len = np.asarray(query_len)
        query, query_len = torch.from_numpy(query1).float(), torch.from_numpy(query_len).long()
        query_idx = torch.from_numpy(query_idx).long()

        return {
            'query': query,
            'audio_fea': torch.from_numpy(np.asarray([sample['audio_fea'] for sample in samples])).float(),
            'video_fea': torch.from_numpy(np.asarray([sample['video_fea'] for sample in samples])).float()
        }

def main():
    # utils variable
    global args, logger, writer, dataset_configs
    # statistics variable
    global best_accuracy, best_accuracy_epoch
    best_accuracy, best_accuracy_epoch = 0, 0
    # configs
    dataset_configs = get_and_save_args(parser)
    parser.set_defaults(**dataset_configs)
    args = parser.parse_args()
    # select GPUs
    os.environ['CUDA_DEVICE_ORDER'] = "PCI_BUS_ID"
    # os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu

    '''Create snapshot_pred dir for copying code and saving models '''
    if not os.path.exists(args.snapshot_pref):
        os.makedirs(args.snapshot_pref)

    if os.path.isfile(args.resume):
        args.snapshot_pref = os.path.dirname(args.resume)

    logger = Prepare_logger(args, eval=args.evaluate)

    if not args.evaluate:
        logger.info(f'\nCreating folder: {args.snapshot_pref}')
        logger.info('\nRuntime args\n\n{}\n'.format(json.dumps(vars(args), indent=4)))
    else:
        logger.info(f'\nLog file will be save in a {args.snapshot_pref}/Eval.log.')

    '''dataset selection'''
    if args.dataset_name == 'ave':
        from dataset.AVE_dataset import AVEDataset as AVEDataset
    elif args.dataset_name =='vggsound':
        from dataset.VGGSOUND_dataset import VGGSoundDataset as AVEDataset
    elif args.dataset_name =='vggsound_AT':
        from dataset.VGGSOUND_dataset import VGGSoundDataset_AT as AVEDataset
    elif args.dataset_name =='vggsound_AVT':
        from dataset.VGGSOUND_dataset import VGGSoundDataset_AVT as AVEDataset
    elif args.dataset_name =='vggsound179k' or args.dataset_name =='vggsound81k':
        from dataset.VGGSOUND_dataset179k import VGGSoundDataset as AVEDataset
    else:
        raise NotImplementedError

    '''Dataloader selection'''
    if args.dataset_name == 'ave':
        data_root = 'data'
        train_dataloader = DataLoader(
            AVEDataset(data_root, split='train'),
            batch_size=args.batch_size,
            shuffle=True,
            num_workers=8,
            pin_memory=True
        )
        val_dataloader = DataLoader(
            AVEDataset(data_root, split='val'),
            batch_size=args.batch_size,
            shuffle=False,
            num_workers=8,
            pin_memory=True
        )
        test_dataloader = DataLoader(
            AVEDataset(data_root, split='test'),
            batch_size=args.batch_size,
            shuffle=False,
            num_workers=8,
            pin_memory=True
        )
    elif args.dataset_name == 'vggsound':
        meta_csv_path = 'vggsound-avel40k.csv'
        audio_fea_base_path = 'audio/zip'
        video_fea_base_path = 'video/zip'
        avc_label_base_path = 'label/zip'
        train_dataloader = DataLoader(
            AVEDataset(meta_csv_path, audio_fea_base_path, video_fea_base_path, avc_label_base_path, split='train'),
            batch_size=args.batch_size,
            shuffle=True,
            num_workers=8,
            pin_memory=True
        )
    elif args.dataset_name == 'vggsound_AT':
        meta_csv_path = 'vggsound-avel40k.csv'
        audio_fea_base_path = 'audio/zip'
        train_dataloader = DataLoader(
            AVEDataset(meta_csv_path, audio_fea_base_path, split='train'),
            batch_size=args.batch_size,
            shuffle=True,
            num_workers=8,
            pin_memory=True,
            collate_fn=collate_func_AT
        )
    elif args.dataset_name == 'vggsound_AVT':
        meta_csv_path = 'vggsound-avel40k.csv'
        audio_fea_base_path = 'vggsound40k/feature/audio/zip'
        video_fea_base_path = 'vggsound40k/feature/video/zip'
        train_dataloader = DataLoader(
            AVEDataset(meta_csv_path, audio_fea_base_path, video_fea_base_path, split='train'),
            batch_size=args.batch_size,
            shuffle=True,
            num_workers=8,
            pin_memory=False,
            collate_fn=collate_func_AVT
        )
    elif args.dataset_name == 'vggsound81k':
        meta_csv_path = 'video_name_vggsound81k_checked.csv'
        audio_fea_base_path = 'audio/zip'
        video_fea_base_path = 'video/zip'
        avc_label_base_path = '...'
        train_dataloader = DataLoader(
            AVEDataset(meta_csv_path, audio_fea_base_path, video_fea_base_path, avc_label_base_path, split='train'),
            batch_size=args.batch_size,
            shuffle=True,
            num_workers=8,
            pin_memory=True
        )
    elif args.dataset_name == 'vggsound179k':
        meta_csv_path = 'video_name_vggsound179k_checked.csv'
        audio_fea_base_path = 'audio/zip'
        video_fea_base_path = 'video/zip'
        avc_label_base_path = '...'
        train_dataloader = DataLoader(
            AVEDataset(meta_csv_path, audio_fea_base_path, video_fea_base_path, avc_label_base_path, split='train'),
            batch_size=args.batch_size,
            shuffle=True,
            num_workers=8,
            pin_memory=True
        )
    else:
        raise NotImplementedError

    '''model setting'''
    video_dim = 512
    text_dim = 768
    audio_dim = 128
    text_lstm_dim = 128
    video_output_dim = 2048
    text_output_dim = 256
    audio_output_dim = 256
    n_embeddings = 400
    embedding_dim = 256
    start_epoch = -1
    model_resume = False
    total_step = 0
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    Text_ar_lstm = nn.LSTM(text_dim, text_lstm_dim, num_layers=2, batch_first=True, bidirectional=True)

    if args.dataset_name == 'vggsound_AT':
        Encoder = AT_VQVAE_Encoder(text_lstm_dim*2, audio_dim, text_output_dim, audio_output_dim, n_embeddings, embedding_dim)
    if args.dataset_name == 'vggsound_AVT':
        Encoder = AVT_VQVAE_Encoder(audio_dim, video_dim, text_lstm_dim*2, audio_output_dim, video_output_dim, text_output_dim, n_embeddings, embedding_dim)
    else:
        Encoder = AV_VQVAE_Encoder(video_dim, audio_dim, video_output_dim, audio_output_dim, n_embeddings, embedding_dim)

    if args.dataset_name == 'vggsound_AVT':
        CPC = Cross_CPC_AVT(embedding_dim, hidden_dim=256, context_dim=256, num_layers=2)
    else:
        CPC = Cross_CPC(embedding_dim, hidden_dim=256, context_dim=256, num_layers=2)
    Video_mi_net = CLUBSample_group(x_dim=embedding_dim, y_dim=video_dim, hidden_size=256)
    Text_mi_net = CLUBSample_group(x_dim=embedding_dim, y_dim=text_output_dim, hidden_size=256)
    Audio_mi_net = CLUBSample_group(x_dim=embedding_dim, y_dim=audio_output_dim, hidden_size=256)

    if args.dataset_name == 'vggsound_AT':
        Decoder = AT_VQVAE_Decoder(text_lstm_dim*2, audio_dim, text_output_dim, audio_output_dim)
    if args.dataset_name == 'vggsound_AVT':
        Decoder = AVT_VQVAE_Decoder(audio_dim, video_dim, text_lstm_dim*2, audio_output_dim, video_output_dim, text_output_dim)
    else:
        Decoder = AV_VQVAE_Decoder(video_dim, audio_dim, video_output_dim, audio_output_dim)

    Text_ar_lstm.double()
    Encoder.double()
    CPC.double()
    Video_mi_net.double()
    Text_mi_net.double()
    Audio_mi_net.double()
    Decoder.double()

    '''optimizer setting'''
    Text_ar_lstm.to(device)
    Encoder.to(device)
    CPC.to(device)
    Video_mi_net.to(device)
    Text_mi_net.to(device)
    Audio_mi_net.to(device)
    Decoder.to(device)
    optimizer = torch.optim.Adam(chain(Text_ar_lstm.parameters(), \
                                       Encoder.parameters(), CPC.parameters(), Decoder.parameters()), lr=args.lr)
    optimizer_video_mi_net = torch.optim.Adam(Video_mi_net.parameters(), lr=args.mi_lr)
    optimizer_text_mi_net = torch.optim.Adam(Text_mi_net.parameters(), lr=args.mi_lr)
    optimizer_audio_mi_net = torch.optim.Adam(Audio_mi_net.parameters(), lr=args.mi_lr)
    scheduler = MultiStepLR(optimizer, milestones=[10, 20, 30], gamma=0.5)

    '''loss'''
    criterion = nn.BCEWithLogitsLoss().cuda()
    criterion_event = nn.CrossEntropyLoss().cuda()

    if model_resume is True:
        path_checkpoints = "..."
        checkpoints = torch.load(path_checkpoints)
        Encoder.load_state_dict(checkpoints['Encoder_parameters'])
        CPC.load_state_dict(checkpoints['CPC_parameters'])
        Video_mi_net.load_state_dict(checkpoints['Video_mi_net_parameters'])
        Audio_mi_net.load_state_dict(checkpoints['Audio_mi_net_parameters'])
        Decoder.load_state_dict(checkpoints['Decoder_parameters'])
        optimizer.load_state_dict(checkpoints['optimizer'])
        optimizer_audio_mi_net.load_state_dict(checkpoints['optimizer_audio_mi_net'])
        optimizer_video_mi_net.load_state_dict(checkpoints['optimizer_video_mi_net'])
        start_epoch = checkpoints['epoch']
        total_step = checkpoints['total_step']
        logger.info("Resume from number {}-th model.".format(start_epoch))

    '''Tensorboard and Code backup'''
    writer = SummaryWriter(args.snapshot_pref)
    recorder = Recorder(args.snapshot_pref, ignore_folder="Exps/")
    recorder.writeopt(args)

    '''Training and Evaluation'''

    for epoch in range(start_epoch+1, args.n_epoch):
        loss, total_step = train_epoch(CPC, Encoder,Text_ar_lstm, Audio_mi_net, Video_mi_net,Text_mi_net, Decoder, train_dataloader, criterion, criterion_event,
                                       optimizer, optimizer_audio_mi_net, optimizer_video_mi_net, optimizer_text_mi_net, epoch, total_step, args)

        save_path = os.path.join(args.model_save_path, 'your-model-{}.pt'.format(epoch))
        save_models(CPC, Encoder, Text_ar_lstm, Audio_mi_net, Video_mi_net, Text_mi_net, Decoder, optimizer, optimizer_audio_mi_net, optimizer_video_mi_net, optimizer_text_mi_net, epoch, total_step, save_path)
        logger.info(f"epoch: ******************************************* {epoch}")
        logger.info(f"loss: {loss}")
        scheduler.step()

def _export_log(epoch, total_step, batch_idx, lr, loss_meter):
    msg = 'Epoch {}, Batch {}, lr = {:.5f}, '.format(epoch, batch_idx, lr)
    for k, v in loss_meter.items():
        msg += '{} = {:.4f}, '.format(k, v)
    logger.info(msg)
    sys.stdout.flush()
    loss_meter.update({"batch": total_step})

def to_eval(all_models):
    for m in all_models:
        m.eval()

def to_train(all_models):
    for m in all_models:
        m.train()

# If resuming training is not required, downstream tasks only need to save the encoder & epoch & Text_ar_lstm, as these are the only components needed for inference.
def save_models(CPC, Encoder,Text_ar_lstm, Audio_mi_net, Video_mi_net, Text_mi_net, Decoder, optimizer, optimizer_audio_mi_net, optimizer_video_mi_net,optimizer_text_mi_net, epoch_num, total_step, path):
    state_dict = {
        'Encoder_parameters': Encoder.state_dict(),
        'CPC_parameters': CPC.state_dict(),
        'Text_ar_lstm_parameters': Text_ar_lstm.state_dict(),
        'Video_mi_net_parameters': Video_mi_net.state_dict(),
        'Text_mi_net_parameters': Text_mi_net.state_dict(),
        'Audio_mi_net_parameters': Audio_mi_net.state_dict(),
        'Decoder_parameters': Decoder.state_dict(),
        'optimizer': optimizer.state_dict(),
        'optimizer_video_mi_net': optimizer_video_mi_net.state_dict(),
        'optimizer_text_mi_net': optimizer_text_mi_net.state_dict(),
        'optimizer_audio_mi_net': optimizer_audio_mi_net.state_dict(),
        'epoch': epoch_num,
        'total_step': total_step
    }
    torch.save(state_dict, path)
    logging.info('save model to {}'.format(path))

def train_epoch_check(train_dataloader, epoch, total_step, args):
    train_dataloader = tqdm(train_dataloader)
    for n_iter, batch_data in enumerate(train_dataloader):

        '''Feed input to model'''
        visual_feature, audio_feature = batch_data
        visual_feature.cuda()
        audio_feature.cuda()

    return torch.zeros(1)

def train_epoch(CPC,Encoder,Text_ar_lstm, Audio_mi_net, Video_mi_net, Text_mi_net, Decoder,train_dataloader, criterion, criterion_event, optimizer, optimize_audio_mi_net, optimizer_video_mi_net, optimizer_text_mi_net, epoch, total_step, args):
    batch_time = AverageMeter()
    data_time = AverageMeter()
    losses = AverageMeter()
    train_acc = AverageMeter()
    end_time = time.time()
    models = [CPC,Encoder,Text_ar_lstm, Audio_mi_net, Video_mi_net, Text_mi_net, Decoder]
    to_train(models)
    # Note: here we set the model to a double type precision,
    # since the extracted features are in a double type.
    # This will also lead to the size of the model double increases.

    Encoder.cuda()
    Text_ar_lstm.cuda()
    Text_mi_net.cuda()
    Audio_mi_net.cuda()
    Video_mi_net.cuda()
    Decoder.cuda()
    CPC.cuda()
    optimizer.zero_grad()
    mi_iters = 5

    # train_dataloader = tqdm(train_dataloader)

    for n_iter, batch_data in enumerate(train_dataloader):

        data_time.update(time.time() - end_time)
        '''Feed input to model'''

        # Adjust the input as needed according to the requirements of the model being trained.
        # vggsound_AVT
        query, audio_feature, video_feature = batch_data['query'], batch_data['audio_fea'], batch_data['video_fea']

        # vggsound_AV
        # visual_feature, audio_feature, labels = batch_data    # vggsound40k
        # visual_feature, audio_feature = batch_data            # vggsound179k or vggsound81k
        query = query.double().cuda()
        audio_feature = audio_feature.to(torch.float64)
        batch_dim = query.size()[0]
        hidden_dim = 128
        num_layers = 2
        text_hidden = (torch.zeros(2*num_layers, batch_dim, hidden_dim).double().cuda(),
                  torch.zeros(2*num_layers, batch_dim, hidden_dim).double().cuda())
        text_feature, text_hidden = Text_ar_lstm(query, text_hidden)

        text_feature = text_feature.cuda().to(torch.float64)
        audio_feature = audio_feature.cuda().to(torch.float64)
        video_feature = video_feature.cuda().to(torch.float64)

        for i in range(mi_iters):
            optimizer_video_mi_net, lld_video_loss, optimizer_text_mi_net, lld_text_loss, optimize_audio_mi_net, lld_audio_loss = \
                mi_first_forward(audio_feature, video_feature, text_feature, Encoder, Audio_mi_net, Video_mi_net, Text_mi_net, optimize_audio_mi_net,optimizer_video_mi_net,optimizer_text_mi_net, epoch)

        audio_embedding_loss, video_embedding_loss,text_embedding_loss, mi_audio_loss, mi_video_loss, mi_text_loss, \
        accuracy1, accuracy2, accuracy3, accuracy4, accuracy5, accuracy6, accuracy7, accuracy8, accuracy9,\
        cpc_loss, audio_recon_loss, video_recon_loss, text_recon_loss, \
        audio_class, video_class, text_class, cmcm_loss, equal_num = mi_second_forward(CPC,audio_feature, video_feature, text_feature, Encoder,Audio_mi_net, Video_mi_net, Text_mi_net, Decoder,epoch)

        if n_iter % 20 == 0:
            logger.info("equal_num is {} in {}-th iteration.".format(equal_num, n_iter))

        loss_items = {
            "audio_recon_loss": audio_recon_loss.item(),
            "lld_audio_loss": lld_audio_loss.item(),
            "audio_embed_loss": audio_embedding_loss.item(),
            "audio_mine_loss": mi_audio_loss.item(),
            "text_recon_loss": text_recon_loss.item(),
            "lld_text_loss": lld_text_loss.item(),
            "text_embed_loss": text_embedding_loss.item(),
            "text_mine_loss": mi_text_loss.item(),
            "video_recon_loss": video_recon_loss.item(),
            "lld_video_loss": lld_video_loss.item(),
            "video_embed_loss": video_embedding_loss.item(),
            "video_mine_loss": mi_video_loss.item(),
            "acc_av": accuracy1.item(),
            "acc_at": accuracy2.item(),
            "acc_vt": accuracy3.item(),
            "acc_va": accuracy4.item(),
            "acc_ta": accuracy5.item(),
            "acc_tv": accuracy6.item(),
            "acc_aa": accuracy7.item(),
            "acc_vv": accuracy8.item(),
            "acc_tt": accuracy9.item(),
            "cpc_loss": cpc_loss.item(),
            "cmcm_loss": cmcm_loss.item()
        }

        metricsContainer.update("loss", loss_items)
        loss = audio_recon_loss + video_recon_loss + text_recon_loss + audio_embedding_loss +  video_embedding_loss\
                + text_embedding_loss+ mi_audio_loss + mi_video_loss + mi_text_loss + cpc_loss + cmcm_loss

        if n_iter % 20 == 0:
            _export_log(epoch=epoch, total_step=total_step+n_iter, batch_idx=n_iter, lr=0.0004, loss_meter=metricsContainer.calculate_average("loss"))

        loss.backward()

        '''Clip Gradient'''
        if args.clip_gradient is not None:
            for model in models:
                total_norm = clip_grad_norm_(model.parameters(), args.clip_gradient)

        '''Update parameters'''
        optimizer.step()
        optimizer.zero_grad()

        losses.update(loss.item(), text_feature.size(0) * 10)
        batch_time.update(time.time() - end_time)
        end_time = time.time()

        '''Add loss of a iteration in Tensorboard'''
        writer.add_scalar('Train_data/loss', losses.val, epoch * len(train_dataloader) + n_iter + 1)

        '''Add loss of an epoch in Tensorboard'''
        writer.add_scalar('Train_epoch_data/epoch_loss', losses.avg, epoch)

    return losses.avg, n_iter + total_step

def mi_first_forward(audio_feature, video_feature, text_feature, Encoder, Audio_mi_net, Video_mi_net,Text_mi_net, optimizer_audio_mi_net,optimizer_video_mi_net,optimizer_text_mi_net, epoch):

    optimizer_video_mi_net.zero_grad()
    optimizer_text_mi_net.zero_grad()
    optimizer_audio_mi_net.zero_grad()

    audio_semantic_result, video_semantic_result, text_semantic_result, \
    audio_encoder_result, video_encoder_result, video_club_feature, text_encoder_result, \
    audio_vq, video_vq, text_vq, audio_embedding_loss, video_embedding_loss, text_embedding_loss, cmcm_loss, equal_num\
    = Encoder(audio_feature, video_feature, text_feature, epoch)

    video_club_feature = video_club_feature.detach()
    text_encoder_result = text_encoder_result.detach()
    audio_encoder_result = audio_encoder_result.detach()
    video_vq = video_vq.detach()
    text_vq = text_vq.detach()
    audio_vq = audio_vq.detach()

    # video processing is different from audio and text modalities because video is more complex and feature extraction is more difficult.
    lld_video_loss = -Video_mi_net.loglikeli(video_vq, video_club_feature)
    lld_video_loss.backward()
    optimizer_video_mi_net.step()

    lld_text_loss = -Text_mi_net.loglikeli(text_vq, text_encoder_result)
    lld_text_loss.backward()
    optimizer_text_mi_net.step()

    lld_audio_loss = -Audio_mi_net.loglikeli(audio_vq, audio_encoder_result)
    lld_audio_loss.backward()
    optimizer_audio_mi_net.step()

    return optimizer_audio_mi_net, lld_audio_loss, optimizer_video_mi_net, lld_video_loss, optimizer_text_mi_net, lld_text_loss

def VQ_audio_forward(audio_feature, visual_feature, Encoder, optimizer,epoch):

    audio_vq_forward_loss = Encoder.Audio_vq_forward(audio_feature, visual_feature,epoch)
    audio_vq_forward_loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    return audio_vq_forward_loss, optimizer

def VQ_video_forward(audio_feature, visual_feature, Encoder, optimizer,epoch):
    optimizer.zero_grad()
    video_vq_forard_loss = Encoder.Video_vq_forward(audio_feature, visual_feature,epoch)
    video_vq_forard_loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    return video_vq_forard_loss, optimizer

def mi_second_forward(CPC, audio_feature, video_feature, text_feature, Encoder, Audio_mi_net, Video_mi_net, Text_mi_net, Decoder,epoch):
    audio_semantic_result, video_semantic_result, text_semantic_result, \
    audio_encoder_result, video_encoder_result, video_club_feature, text_encoder_result, \
    audio_vq, video_vq, text_vq, audio_embedding_loss, video_embedding_loss, text_embedding_loss, cmcm_loss, equal_num \
    = Encoder(audio_feature, video_feature, text_feature, epoch)

    mi_video_loss = Video_mi_net.mi_est(video_vq, video_club_feature)
    mi_text_loss = Text_mi_net.mi_est(text_vq, text_encoder_result)
    mi_audio_loss = Audio_mi_net.mi_est(audio_vq, audio_encoder_result)

    """Cross_CPC"""
    accuracy1, accuracy2, accuracy3, accuracy4, \
    accuracy5, accuracy6, accuracy7, accuracy8, accuracy9, \
    cpc_loss = CPC(audio_semantic_result, video_semantic_result, text_semantic_result)

    audio_recon_loss, video_recon_loss, text_recon_loss, audio_class, video_class, text_class \
        = Decoder(audio_feature, video_feature, text_feature, audio_encoder_result, video_encoder_result, text_encoder_result, audio_vq, video_vq, text_vq)

    return audio_embedding_loss, video_embedding_loss, text_embedding_loss, mi_audio_loss, mi_video_loss, mi_text_loss, \
           accuracy1, accuracy2, accuracy3, accuracy4, accuracy5, accuracy6, accuracy7, accuracy8, accuracy9, cpc_loss,  \
           audio_recon_loss, video_recon_loss, text_recon_loss, audio_class, video_class, text_class, cmcm_loss, equal_num, zero_num, same_layer_fusion_loss, adjacent_layer_separation_loss

def compute_accuracy_supervised(event_scores, labels):
    labels_foreground = labels[:, :, :-1]
    labels_BCE, labels_evn = labels_foreground.max(-1)
    labels_event, _ = labels_evn.max(-1)
    _, event_class = event_scores.max(-1)
    correct = event_class.eq(labels_event)
    correct_num = correct.sum().double()
    acc = correct_num * (100. / correct.numel())
    return acc

def save_checkpoint(state_dict, top1, task, epoch):
    model_name = f'{args.snapshot_pref}/model_epoch_{epoch}_top1_{top1:.3f}_task_{task}_best_model.pth.tar'
    torch.save(state_dict, model_name)

if __name__ == '__main__':
    main()


from pymongo import MongoClient
import ssl
import requests
from bs4 import BeautifulSoup
import re
import requests
import json
import itertools
import os
import sys
import subprocess
from urlextract import URLExtract
import urllib.request
import warnings
warnings.filterwarnings("ignore")

myjsonfile = open('/saltoosiconfig/thisit.json', 'r',encoding="utf8")
jsondata = myjsonfile.read()

obj=json.loads(jsondata)

all_devId = []
devId_json = []
prop = []
mail_list=[]

### DB Connections
client =  MongoClient("mongodb://127.0.0.1:27017/saltoosi",ssl_cert_reqs=ssl.CERT_NONE)
db = client['saltoosi']
Collection = db['xyz']

# The Extractor 9000 for getting any  key from nested json

def json_extract(obj, key):

    arr = []

    def extract(obj, arr, key):

        if isinstance(obj, dict):
            for k, v in obj.items():
                if isinstance(v, (dict, list)):
                    extract(v, arr, key)
                elif k == key:
                    arr.append(v)
        elif isinstance(obj, list):
            for item in obj:
                extract(item, arr, key)
        return arr

    values = extract(obj, arr, key)
    return values

def Merge(dict1, dict2):
    res = {**dict1, **dict2}
    return res

def scrapeLinks():
    # Extracting usefull information like devUrl,ids,imgUrls

    urls = json_extract(obj ,'devUrl')
    ids = json_extract(obj ,'_id')
    imageurls = json_extract(obj ,'imgUrl')

    # Image url for first/main image link of the listing
    baseimage="//d2kcmk0r62r1qk.cloudfront.net/imageSponsors/xlarge/"

    start_urls = "https://www.buzzbuzzhome.com/ca/"
    final_url = ""
    final_list=[]
    for u in urls:
        final_url = start_urls+u
        final_list.append(final_url)
    #Command to print all the urls

        #print(final_url)

    #print("No of urls is :{}".format(len(final_list)))
    Test_list = final_list[:]
    #print(Test_list)
    dict = {}
    mydict=dict.fromkeys(ids,None)
    hes = []
    appenddict = {}
    for j in range(len(Test_list)):
        #To print the image id that we are currently working on
        #print(ids[j])
        url=str(Test_list[j])
        res = requests.get(url)
        #print(source)
        # If else loop  for checking if the image is none so
        if imageurls[j] == 'None':
            pass
        else:
            #print(imageurls[j])
            k =str(imageurls[j])
            specialimage=baseimage +  k

            #print(specialimage)
        try:

            soup = BeautifulSoup(res.text,"lxml")
            key = ids[j]
            dict.setdefault(key,[]).append(specialimage)
            #print("Append Update pt 1")
            appenddict = Merge(appenddict,dict)
            for items in soup.select(".thumb"):
                image = items['style'].split("url(")[1].split(")")[0]
                x = image.replace('/MapImages/ListView/','/xlarge/')
                x = x.replace("'",'')

                result = re.match("/Development/.", x)
                if result:
                    pass
                else:
                    hes.append(x)
                    #print(images)
                    key = ids[j]

                    dict.setdefault(key,[]).append(x)
                    appenddict = Merge(appenddict,dict)
                    #print("Append Update pt 2")

        except Exception as e:
            print(e)

    #print(dict)

    out_file = open("/saltoosiconfig/imagelinks.json", "w")
    json.dump(appenddict, out_file, indent = 6)

    out_file.close()
    #print(appenddict)

    print("We are done ")

    #print(mydict)
    #print(appenddict)
    return(appenddict)

scrapeLinks()

def push():
    with open('/saltoosiconfig/imagelinks.json') as f:
        file_data = json.load(f)

    if Collection.count() == 0:
        if isinstance(file_data, list):
            Collection.inset_one(file_data)
        else:
            Collection.insert_one(file_data)
    else:
        Collection.delete_many({})
        Collection.insert_one(file_data)
push()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# */AIPND-revision/intropyproject-classify-pet-images/get_pet_labels.py
#
# PROGRAMMER: Ed Bennett
# DATE CREATED: 06/22/23
# REVISED DATE:
# PURPOSE: Create the function get_pet_labels that creates the pet labels from
#          the image's filename. This function inputs:
#           - The Image Folder as image_dir within get_pet_labels function and
#             as in_arg.dir for the function call within the main function.
#          This function creates and returns the results dictionary as results_dic
#          within get_pet_labels function and as results within main.
#          The results_dic dictionary has a 'key' that's the image filename and
#          a 'value' that's a list. This list will contain the following item
#          at index 0 : pet image label (string).
##
# Imports python modules
from os import listdir

def get_pet_labels(image_dir:str):
    """
    Creates a dictionary of pet labels (results_dic) based upon the filenames
    of the image files. These pet image labels are used to check the accuracy
    of the labels that are returned by the classifier function, since the
    filenames of the images contain the true identity of the pet in the image.
    (ex. filename = 'Boston_terrier_02259.jpg' Pet label = 'boston terrier')
    Parameters:
    image_dir - The (full) path to the folder of images that are to be
                classified by the classifier function (string)
    Returns:
    results_dic - Dictionary with 'key' as image filename and 'value' as a
    List. The list contains for following item:
        index 0 = pet image label (string)
    """
    images_name_list = [img for img in listdir(image_dir) if not img.startswith('.')] # ignore hidden files
    images_name_labels = {}

    for image_name in images_name_list:
        # format image label
        label = " ".join(sub_name.strip() for sub_name in image_name.lower().split('_') if sub_name.isalpha())
        images_name_labels[image_name] = [label]

    return images_name_labels


from enum import Enum
from typing import List, Optional
import pandas as pd
from dataclasses import dataclass
from abc import ABC, abstractmethod
from settings_and_params import extract_prediction_window_size, extract_run_id

class DataFrameMergerType(Enum):
  INTERSECTION  = "intersection"
  UNION         = "union"

class DataFrameMergerUtils:
  @staticmethod
  def get_long_minus_short_col_name(model_id: str) -> str:
    return f"long_minus_short_{model_id}"

  @staticmethod
  def get_long_slope_col_name(model_id: str) -> str:
    return f"long_slope_{model_id}"

  @staticmethod
  def get_short_slope_col_name(model_id: str) -> str:
    return f"short_slope_{model_id}"

@dataclass
class DataFrameInfo:
  name                  : str
  df                    : pd.DataFrame
  prediction_window_size: int

class BaseDataFrameMerger(ABC):
  def process(self, csv_list: List[str]) -> Optional[pd.DataFrame]:
    df_info = self._read_all_dataframe_csv_files(csv_list)

    if self._validate_dataframes(df_info):
      merged_df = self._create_merge_dataframe(df_info)
      self._calculate_values(merged_df)

      return merged_df
    else:
      print("The CSV files have mismatching prediction window sizes")
      return None

  @abstractmethod
  def get_method_as_string(self) -> str:
    pass

  def _read_dataframe_csv(self, file_path: str) -> DataFrameInfo:
    file_name               = file_path.split('/')[-1].split('.')[0]
    prediction_window_size  = extract_prediction_window_size(file_name)
    run_id                  = extract_run_id(file_name)
    df                      = pd.read_csv(file_path)

    columns_to_keep = ['close_time', 'BTCUSDT_Open', 'BTCUSDT_High', 'BTCUSDT_Low', 'BTCUSDT_Close', 'long_minus_short', 'long_slope', 'short_slope']
    df = df[columns_to_keep]

    column_name_change = {
        'BTCUSDT_Open'      : "open"
      , 'BTCUSDT_High'      : "high"
      , 'BTCUSDT_Low'       : "low"
      , 'BTCUSDT_Close'     : "close"
      , 'long_minus_short'  : DataFrameMergerUtils.get_long_minus_short_col_name(run_id)
      , 'long_slope'        : DataFrameMergerUtils.get_long_slope_col_name(run_id)
      , 'short_slope'       : DataFrameMergerUtils.get_short_slope_col_name(run_id)
    }
    df.rename(columns=column_name_change, inplace=True)

    df.index = pd.to_datetime(df["close_time"], utc=True)
    df.drop(columns=["close_time"], inplace=True)

    return DataFrameInfo(file_name, df, prediction_window_size)

  def _read_all_dataframe_csv_files(self, csv_list: List[str]) -> List[DataFrameInfo]:
    return [self._read_dataframe_csv(csv_file) for csv_file in csv_list]

  def _validate_dataframes(self, df_list: List[DataFrameInfo]):
    first_entry = df_list[0]

    return all(entry.prediction_window_size == first_entry.prediction_window_size
               for entry in df_list)

  def _create_merge_dataframe(self, df_list: List[DataFrameInfo]) -> pd.DataFrame:
    merged_df = df_list[0].df

    if len(df_list) > 1:
      columns_to_drop = ['open', 'high', 'low', 'close']

      for df_info in df_list[1:]:
        df_info.df.drop(columns=columns_to_drop, inplace=True)
        merged_df = merged_df.merge(df_info.df, on="close_time", how=self._get_merge_strategy())

    return merged_df

  def _calculate_avg_value(self, df: pd.DataFrame, col_prefix: str):
    col_names     = [col for col in df.columns if col.startswith(col_prefix)]
    new_col_name  = f"{col_prefix}_avg"
    df[new_col_name] = df[col_names].apply(lambda row: row.mean(), axis=1)

  def _calculate_values(self, df: pd.DataFrame):
    self._calculate_avg_value(df, "long_slope")
    self._calculate_avg_value(df, "short_slope")
    self._calculate_avg_value(df, "long_minus_short")

  @abstractmethod
  def _get_merge_strategy(self) -> str:
    pass

class IntersectionDataFrameMerger(BaseDataFrameMerger):
  def get_method_as_string(self) -> str:
    return DataFrameMergerType.INTERSECTION.value

  def _get_merge_strategy(self) -> str:
    return "inner"

class UnionDataFrameMerger(BaseDataFrameMerger):
  def get_method_as_string(self) -> str:
    return DataFrameMergerType.UNION.value

  def _get_merge_strategy(self) -> str:
    return "outer"


__author__ = 'Thomas Rueckstiess, ruecksti@in.tum.de'

from .episodic import EpisodicExperiment
from scipy import arange

class QueuedExperiment(EpisodicExperiment):
    """ This experiment type runs n episodes at the beginning, followed by a learning step.
        From then on it removes the oldest episode, learns a new one, and executes another
        training step with the n current episodes. This way, learning happens after each
        episode, and each episode is considered n times for learning until discarded. """

    def run(self, queuelength, learningcycles=-1):
        # fill the queue with given number of episodes
        self._fillQueue(queuelength)

        # start the queue loop
        if learningcycles == -1:
            while True:
                # indefinite learning
                self._stepQueueLoop()
        else:
            for _ in arange(learningcycles):
                # learn the given number of times
                self._stepQueueLoop()

    def _fillQueue(self, queuelength):
        # reset agent (empty queue)
        self.agent.reset()
        # fill queue with first n episodes
        self.doEpisodes(queuelength)

    def _stepQueueLoop(self):
        # let agent learn with full queue
        self.agent.learn()
        # remove oldest episode
        self.agent.history.removeSequence(0)
        # execute one new episode
        self.doEpisodes(1)


import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector
from cvzone.PlotModule import LivePlot

cap = cv2.VideoCapture(0)
detector = FaceMeshDetector(maxFaces=1)  # only one face
id_list = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]
plotY = LivePlot(640, 360, [0, 40], invert=True)
ratiolist = []
blinkCounter = 0
counter = 0

while True:
    if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # to let the camera on always

    success, img = cap.read()
    img, faces = detector.findFaceMesh(img, draw=False)

    if faces:
        face = faces[0]
        for id in id_list:
            cv2.circle(img, face[id], 5, (255, 0, 255), thickness=cv2.FILLED)
        LeftUp = face[159]
        LeftDown = face[23]
        LeftLeft = face[130]
        LeftRight = face[243]

        lengthVert, _ = detector.findDistance(LeftUp, LeftDown)  # to get the number not the list  (the distance)
        lengthHor, _ = detector.findDistance(LeftLeft, LeftRight)

        cv2.line(img, LeftUp, LeftDown, (0, 200, 0), 3)  # to draw the distance between the leftup and the left down
        cv2.line(img, LeftLeft, LeftRight, (0, 200, 0),
                 3)  # to draw the distance between the left left  and the left right

        # print(int((lengthVert / lengthHor)*100))
        ratio = (lengthVert / lengthHor) * 100
        ratiolist.append(ratio)
        if len(ratiolist) > 3:
            ratiolist.pop(0)
        ratioAvg = sum(ratiolist) / len(ratiolist)

        # to calculate the number of blinks
        if ratioAvg < 26 and counter == 0:
            blinkCounter += 1
            counter = 1

        if counter != 0:
            counter += 1
            if counter > 10:
                counter = 0

        cvzone.putTextRect(img, f'blink count :{blinkCounter}', (50, 100))

        ImagePlot = plotY.update(ratioAvg)
        img = cv2.resize(img, (640, 360))

        imgStack = cvzone.stackImages([img, ImagePlot], 1, 1)  # plot them together

    else :
        img = cv2.resize(img, (640, 360))
        imgStack = cvzone.stackImages([img, img], 1, 1)

    # img = cv2.resize(img, (640, 360))

    cv2.imshow('imgStack', imgStack)

    key = cv2.waitKey(1)
    if key == 27:
        break


"""Create users table

Revision ID: 3bde29f4c8db
Revises:
Create Date: 2021-01-21 12:12:21.616250

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = '3bde29f4c8db'
down_revision = None
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('users',
    sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
    sa.Column('password', sa.String(), nullable=False),
    sa.Column('email', sa.String(length=80), nullable=False),
    sa.Column('username', sa.String(length=40), nullable=False),
    sa.PrimaryKeyConstraint('id')
    )
    op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True)
    op.create_index(op.f('ix_users_id'), 'users', ['id'], unique=False)
    op.create_index(op.f('ix_users_username'), 'users', ['username'], unique=True)
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_index(op.f('ix_users_username'), table_name='users')
    op.drop_index(op.f('ix_users_id'), table_name='users')
    op.drop_index(op.f('ix_users_email'), table_name='users')
    op.drop_table('users')
    # ### end Alembic commands ###


def gcdOfStrings(str1: str, str2: str) -> str:
    l = [""]

    if (len(str1) < len(str2)):
        for j in range(0, len(str1) + 1):
            req = str1[0:j]
            copy2 = str2.replace(req, '')
            copy1 = str1.replace(req, '')
            if len(copy1) == 0 and len(copy2) == 0:
                l.append(req)
    else:
        for j in range(0, len(str2) + 1):
            req = str2[0:j]
            copy2 = str2.replace(req, '')
            copy1 = str1.replace(req, '')
            if len(copy1) == 0 and len(copy2) == 0:
                l.append(req)
    return l[-1]

i0=input()
i1=input()
print(gcdOfStrings(i0,i1))

Goldman Sachs Problems/Greatest Common Divisor.py


N, M = map(int, input().split())

pocket = {}
pocketmon = {}

for i in range(1, N+1):
    monster = input()
    pocket[i] = monster
    pocketmon[monster] = i

for _ in range(M):
    question = input()
    if question.isalpha():
        print(pocketmon[question])
    else:
        print(pocket[int(question)])


# baek1399 단어 수학
arr =dict()
for i in range(65,91):
    arr[chr(i)]=0
for i in range(int(input())):
    ss=input().rstrip()
    k=len(ss)-1
    for j in ss:
        arr[j] += (10**k)
        k-=1
arr =sorted(arr.items(),key =lambda x: x[1],reverse=True)

ans =0
value=9
for c,cnt in arr:
    if cnt==0:
        break
    ans +=value*cnt
    value-=1

print(ans)


from modules.loaders.lefigaro_loader import LeFigaroLoader
from modules.parentspider import NewspaperSpider
from modules.items import NewspaperItem
from modules.database import Database

class LeFigaroSpider(NewspaperSpider):
    """
        This class inherits from NeswpaperSpider and personalize the extraction of
        information for articles from Le Figaro.
    """
    name = "lefigaro"

    def parse(self, response):
        """
            This method take a response in parameter and call the different
            processes involve in the scrapping task and then save the
            informations in a JSON file.
        """
        loader = LeFigaroLoader(item=NewspaperItem(), selector=response)
        loader.add_value("newspaper", "Le Figaro")
        loader.add_xpath("description", "//p[@itemprop='about']//text()")
        if response.xpath("//time//text()").extract_first(default='') != '':
            loader.add_xpath("date", "//time//text()")
        loader.add_xpath("author", "//a[@itemprop='name']//text()")
        loader.add_xpath("body", "//div[@itemprop='articleBody']/*[not(script)][not(img)][not(video)]//text()")
        item = self.load_item(loader, response)
        self.save('Le Figaro', item)


# COMP1021 Lab 2 Python Sketchbook
# Name: HASAN, Md Mubin
# Student ID: 20901262
# Email: mmhasanaa@connect.ust.hk

import turtle       # Import the turtle module for the program

turtle.width(4)
turtle.speed(10)

##### Initialize the colour
fillcolor = "black"
turtle.pencolor("black")
turtle.fillcolor(fillcolor)

print("Welcome to the Python Sketchbook!")

##### While loop to repeat the main menu

# Initialize the option to empty in order to enter the while loop
option = ""

while option != "q": # While the option is not "q"
    print()
    print("Please choose one of the following options:")
    print()
    print("m - Move the turtle")
    print("t - Rotate the turtle")
    print("l - Draw a line")
    print("r - Draw a rectangle")
    print("c - Draw a circle")
    print("p - Change the pen colour of the turtle")
    print("f - Change the fill colour of the turtle")
    print("g - Draw a generated flower")
    print("e - Draw a generated explosion")
    print("a - Draw the author's information")
    print("q - Quit the program")
    print()

    option = input("Please enter your option: ")

    ##### Handle the move option
    if option == "m":
        print()

        # Ask the user for the x and y value
        x = input("Please enter the x value: ")
        x = int(x)
        y = input("Please enter the y value: ")
        y = int(y)

        # Move the turtle without drawing anything
        turtle.up()
        turtle.goto(x, y)
        turtle.down()

    ##### Handle the rotate option
    if option == "t":
        print()

        #
        # Please put your code here
        angle = int(input("Please enter the angle of rotation: "))
        turtle.left(angle)
        #

    ##### Handle the line option
    if option == "l":
        print()

        # Ask the user for the x and y value
        x = input("Please enter the x value: ")
        x = int(x)
        y = input("Please enter the y value: ")
        y = int(y)

        # Move the turtle and draw a line
        turtle.goto(x, y)

    ##### Handle the rectangle option
    if option == "r":
        print()

        #
        # Please put your code here
        width = input("Please enter the width of the rectangle: ")
        width = int(width)
        height = input("Please enter the height of the rectangle: ")
        height = int(height)
        turtle.begin_fill()
        turtle.forward(width)
        turtle.left(90)
        turtle.forward(height)
        turtle.left(90)
        turtle.forward(width)
        turtle.left(90)
        turtle.forward(height)
        turtle.left(90)
        turtle.end_fill()
        #

    ##### Handle the circle option
    if option == "c":
        print()

        #
        # Please put your code here
        radius = input("Please enter the radius of the circle: ")
        radius = int(radius)
        turtle.begin_fill()
        turtle.circle(radius)
        turtle.end_fill()
        #

    ##### Handle the pen colour option
    if option == "p":
        print()

        #
        # Please put your code here
        pen_color = input("Please enter a colour name for the pen colour: ")
        turtle.pencolor(pen_color)
        #

    ##### Handle the fill colour option
    if option == "f":
        print()

        #
        # Please put your code here
        fillcolor = input("Please enter a colour name for the fill colour: ")
        turtle.fillcolor(fillcolor)
        #
    ##### Handle the generate flower option
    if option == "g":
        print()

        #
        # Please put your code here
        petal = int(input("Please enter the size of the flower petal: "))
        for _ in range(12):
            for __ in range(3):
                turtle.forward(petal)
                turtle.left(120)
            turtle.left(30)
        #
    ##### Handle the generated explosion
    if option == "e":
        print()

        #
        # Please put your code here
        size = int(input("Please enter the size of the explosion (>=160): "))
        oldpencolor = turtle.pencolor()
        oldfillcolor = turtle.fillcolor()

        for thiscolor in ["sienna", "brown",  \
                  "red", "dark orange", "orange","gold2", "gold", "yellow"]:
            turtle.color(thiscolor)
            turtle.dot(size)
            size = size - 10

        turtle.pencolor(oldpencolor)
        turtle.fillcolor(oldfillcolor)
        #
    ##### Handle the author's information
    if option == "a":
        print()

        #
        # Please put your code here
        turtle.up()
        turtle.backward(200)
        turtle.down()
        turtle.left(90)
        turtle.forward(80)
        turtle.right(130)
        turtle.forward(30)
        turtle.left(80)
        turtle.forward(30)
        turtle.right(130)
        turtle.forward(80)
        turtle.left(90)

        turtle.up()
        turtle.forward(10)
        turtle.down()

        turtle.left(90)
        turtle.forward(80)
        turtle.backward(80)
        turtle.right(90)
        turtle.forward(40)
        turtle.left(90)
        turtle.forward(80)
        turtle.backward(80)
        turtle.right(90)

        turtle.up()
        turtle.forward(10)
        turtle.down()

        turtle.circle(20, 180)
        turtle.right(180)
        turtle.circle(20, 180)
        turtle.left(90)
        turtle.forward(80)
        turtle.left(90)

        turtle.up()
        turtle.forward(30)
        turtle.down()

        turtle.left(90)
        turtle.forward(80)
        turtle.backward(80)
        turtle.right(90)
        turtle.up()
        turtle.forward(10)
        turtle.down()
        turtle.left(90)
        turtle.forward(80)
        turtle.right(120)
        turtle.forward(160)
        turtle.left(120)
        turtle.forward(80)

        turtle.up()
        turtle.right(90)
        turtle.goto(0,0)
        turtle.down()
turtle.done()


# RG
# 5a.10

def sum_of_arrays(_arr, _arr2):
    n1 = 0
    n2 = 0
    _arr3 = []
    for i in range(len(_arr)):
        n1 += _arr[i]*pow(10, (len(_arr)-i-1))
    for j in range(len(_arr2)):
        n2 += _arr2[j]*pow(10, (len(_arr2)-j-1))
    n3 = n1 + n2
    while n3 != 0:
        _arr3.insert(0, n3 % 10)
        n3 //= 10
    return _arr3

print(sum_of_arrays([1, 0, 2, 9], [3, 4, 5, 6, 7]))