import torch
import os
import argparse
import random
import numpy as np
from datetime import datetime
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as ddp
import logging
import sys
import time

from utils.data.data_dir import default_dir
from utils.data.augment import hard_trans
from utils.data.dataset import MyDataset
from torch.utils.data import DataLoader
from utils.log import logger_init
from utils.seed_init import rand_seed

from ea_nas.res_supernet import resnet_nas, choose_rand
import utils.models as models
import utils.optimizers as optimizers

def run(args, encoder, fc, criterion, optimizer, scheduler, trainloader, validloader, logger):
    # train
    for i_epoch in range(args.max_epoch):
        encoder.train()
        fc.train()
        trainloader.sampler.set_epoch(i_epoch)
        correct = torch.tensor(0.0).cuda()
        total = torch.tensor(0.0).cuda()
        start_time = time.time()

        for i_iter, data in enumerate(trainloader):
            img, label = data[:2]
            img, label = img.cuda(), label.cuda()

            choose = epoch_choose(i_epoch)

            optimizer.zero_grad()
            f = encoder(img, choose)
            s = fc(f)
            loss = criterion(s, label)
            loss.backward()
            optimizer.step()

            # acc
            _, predicted = torch.max(s.data, 1)
            correct += predicted.eq(label.data).sum()
            total += label.size(0)

            # print info
            log_fre = len(trainloader) if args.log_fre == -1 else args.log_fre
            if (i_iter + 1) % log_fre == 0:
                correct_tmp = correct.clone()
                total_tmp = total.clone()
                dist.reduce(correct_tmp, dst=0, op=dist.ReduceOp.SUM)
                dist.reduce(total_tmp, dst=0, op=dist.ReduceOp.SUM)
                if args.local_rank == 0:
                    eta = (time.time() - start_time) / 60.
                    logger.info("Training: Epoch[{:0>3}/{:0>3}] "
                                "Iter[{:0>3}/{:0>3}] "
                                "lr: {:.5f} "
                                "Loss: {:.4f} "
                                "Acc:{:.2%} "
                                "Run-T:{:.2f}m".format(
                        i_epoch + 1, args.max_epoch,
                        i_iter + 1, len(trainloader),
                        optimizer.state_dict()['param_groups'][0]['lr'],
                        loss.cpu().item() / dist.get_world_size(),
                        correct.cpu().item() / total.cpu().item(),
                        eta))

        scheduler.step()
        if args.local_rank == 0:
            torch.save(encoder.state_dict(), '%s/encoder.pth' % args.log_dir)
            torch.save(fc.state_dict(), '%s/fc.pth' % args.log_dir)

        # valid
        if i_epoch % 10 == 0:
            choose_valid = epoch_choose(0)
            valid(args, encoder, fc, validloader, logger, choose_valid)

def epoch_choose(i_epoch, s_epoch=60, times=1):
    epoches = [1 * times, 1 * times, 1 * times, 1 * times, 1 * times,
               4 * times, 4 * times, 4 * times, 4 * times, 4 * times,
               2 * times,
               1 * times, 1 * times]
    epoches = np.array(epoches)
    epoches = np.cumsum(epoches)
    if i_epoch < s_epoch:
        stages = (tuple(range(6, 5, -1)),
                  tuple(range(8, 7, -1)),
                  tuple(range(12, 11, -1)),
                  tuple(range(6, 5, -1)))
        channel_scales = (1.5,)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[0]:
        stages = (tuple(range(6, 5, -1)),
                  tuple(range(8, 7, -1)),
                  tuple(range(12, 11, -1)),
                  tuple(range(6, 5, -1)))
        channel_scales = (1.5, 1.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[1]:
        stages = (tuple(range(6, 5, -1)),
                  tuple(range(8, 7, -1)),
                  tuple(range(12, 11, -1)),
                  tuple(range(6, 5, -1)))
        channel_scales = (1.5, 1.25, 1.0)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[2]:
        stages = (tuple(range(6, 5, -1)),
                  tuple(range(8, 7, -1)),
                  tuple(range(12, 11, -1)),
                  tuple(range(6, 5, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[3]:
        stages = (tuple(range(6, 5, -1)),
                  tuple(range(8, 7, -1)),
                  tuple(range(12, 11, -1)),
                  tuple(range(6, 5, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[4]:
        stages = (tuple(range(6, 5, -1)),
                  tuple(range(8, 7, -1)),
                  tuple(range(12, 11, -1)),
                  tuple(range(6, 5, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[5]:
        stages = (tuple(range(6, 4, -1)),
                  tuple(range(8, 6, -1)),
                  tuple(range(12, 10, -1)),
                  tuple(range(6, 4, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[6]:
        stages = (tuple(range(6, 3, -1)),
                  tuple(range(8, 5, -1)),
                  tuple(range(12, 9, -1)),
                  tuple(range(6, 3, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[7]:
        stages = (tuple(range(6, 2, -1)),
                  tuple(range(8, 4, -1)),
                  tuple(range(12, 8, -1)),
                  tuple(range(6, 2, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[8]:
        stages = (tuple(range(6, 1, -1)),
                  tuple(range(8, 3, -1)),
                  tuple(range(12, 7, -1)),
                  tuple(range(6, 1, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[9]:
        stages = (tuple(range(6, 0, -1)),
                  tuple(range(8, 2, -1)),
                  tuple(range(12, 6, -1)),
                  tuple(range(6, 0, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[10]:
        stages = (tuple(range(6, 0, -1)),
                  tuple(range(8, 1, -1)),
                  tuple(range(12, 5, -1)),
                  tuple(range(6, 0, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[11]:
        stages = (tuple(range(6, 0, -1)),
                  tuple(range(8, 1, -1)),
                  tuple(range(12, 4, -1)),
                  tuple(range(6, 0, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    elif i_epoch < s_epoch + epoches[12]:
        stages = (tuple(range(6, 0, -1)),
                  tuple(range(8, 1, -1)),
                  tuple(range(12, 3, -1)),
                  tuple(range(6, 0, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    else:
        stages = (tuple(range(6, 0, -1)),
                  tuple(range(8, 1, -1)),
                  tuple(range(12, 2, -1)),
                  tuple(range(6, 0, -1)))
        channel_scales = (1.5, 1.25, 1.0, 0.75, 0.5, 0.25)
        kernels = [(1, 3), (1, 5), (1, 7)]
    choose = choose_rand(stages, channel_scales, kernels)
    return choose

def valid(args, encoder, fc, validloader, logger, choose_valid):
    with torch.no_grad():
        encoder.eval()
        fc.eval()
        correct = torch.tensor([0.0]).cuda()
        total = torch.tensor([0.0]).cuda()
        for data in validloader:
            img, label = data[:2]
            img, label = img.cuda(), label.cuda()

            feature = encoder(img, choose_valid)
            s = fc(feature)

            # acc
            _, predicted = torch.max(s.data, 1)
            correct += predicted.eq(label.data).sum()
            total += label.size(0)
        dist.reduce(correct, dst=0, op=dist.ReduceOp.SUM)
        dist.reduce(total, dst=0, op=dist.ReduceOp.SUM)
        if args.local_rank == 0:
            logger.info('valid-acc:{:.2%}'.format(correct.cpu().item() / total.cpu().item()))
            logger.info('--------------------------')

def main(args):
    # dist init
    torch.cuda.set_device(args.local_rank)
    torch.distributed.init_process_group(backend='nccl', init_method='env://')

    # dataloader
    train_dir, valid_dir = default_dir[args.dataset]
    train_trans, valid_trans = hard_trans(args.img_size)

    trainset = MyDataset(train_dir, transform=train_trans)
    train_sampler = torch.utils.data.distributed.DistributedSampler(trainset)
    trainloader = DataLoader(trainset, batch_size=args.bs, shuffle=False,
                             num_workers=8, pin_memory=True, sampler=train_sampler)

    validset = MyDataset(valid_dir, transform=valid_trans)
    valid_sampler = torch.utils.data.distributed.DistributedSampler(validset)
    validloader = DataLoader(validset, batch_size=args.bs, shuffle=False,
                             num_workers=8, pin_memory=True, sampler=valid_sampler)

    # model
    supernet_choose = choose_rand(([6], [8], [12], [6]), (1.5,), [(1, 7)])
    supernet = resnet_nas(supernet_choose)
    fc = models.__dict__['cos'](trainloader.dataset.n_classes, supernet.emb_size, 100.0)
    criterion = models.__dict__['cross_entropy'](1.0)
    supernet = supernet.cuda()
    fc = fc.cuda()
    criterion = criterion.cuda()

    # optimizer
    optimizer = optimizers.__dict__['sgd']((supernet, fc), args.optim_lr)
    scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, args.optim_step, gamma=0.1)

    # ddp
    supernet = torch.nn.SyncBatchNorm.convert_sync_batchnorm(supernet)
    supernet = ddp(supernet, device_ids=[args.local_rank], find_unused_parameters=True)
    fc = ddp(fc, device_ids=[args.local_rank], find_unused_parameters=True)

    # log
    if args.local_rank == 0:
        time_str = datetime.strftime(datetime.now(), '%y-%m-%d-%H-%M-%S')
        args.log_dir = os.path.join('logs', args.dataset + '_' + time_str)
        if not os.path.exists(args.log_dir):
            os.makedirs(args.log_dir)
        logger = logger_init(args.log_dir)
    else:
        logger = None
    if args.local_rank == 0:
        logger.info(args)
        logger.info('n_classes:%d' % trainloader.dataset.n_classes)

    # train and valid
    run(args, supernet, fc, criterion, optimizer, scheduler, trainloader, validloader, logger)
    if args.local_rank == 0:
        logger.info(args.log_dir)

if __name__ == "__main__":
    # -------------------   参数读取   ------------------------------
    parser = argparse.ArgumentParser("finetuning with Pytorch")
    # data
    parser.add_argument('--dataset', type=str, default='image3403',
                        help='The dataset_name')
    parser.add_argument('--img_size', type=int, default=224,
                        help='Input image size.')
    parser.add_argument('--bs', type=int, default=64,
                        help='The batch-size of single-gpu training and validating.')

    # optimizer
    parser.add_argument('--optim', type=str, default='sgd',
                        help='optimizer type.')
    parser.add_argument('--optim_lr', type=float, default=2e-1,
                        help='The init learning rate.')
    parser.add_argument('--optim_step', type=list, default=[100, 160, 200],
                        help='optim step.')
    parser.add_argument('--max_epoch', type=int, default=250,
                        help='max epoch.')

    # GPU
    parser.add_argument("--local_rank", default=0, type=int,
                        help='master rank')

    # info
    parser.add_argument('--log_fre', type=int, default=50,
                        help='log show fre.')

    args = parser.parse_args()
    rand_seed(0)
    main(args)


from random import randint
from time import sleep

def sorteia(lista):
    for i in range(0, 5):
        n = randint(1, 10)
        lista.append(n)
        sleep(0.3)
    print(f"Sorteando 5 valores da lista: {lista} ", end="", flush=True)
    print("PRONTO!")

def somaPar(lista):
    somaPares = 0
    for p in lista:
        if p % 2 == 0:
            somaPares += p
    print(f"Somando os valores pares de: {lista}, temos {somaPares}")

numeros = list()
sorteia(numeros)
somaPar(numeros)


from ..schemas import AudioWordsSchema, AudioImageSchema
from . import audio, MethodView, abort, basepath
from ..models import Word, User
from .. import db
from sqlalchemy.exc import IntegrityError
from flask_jwt_extended import jwt_required, get_jwt_identity
from flask import current_app
import base64, os
from werkzeug.utils import secure_filename

def convert_base64(num):

    # 选择要转换的图片
    selected_image = "record_imgs/" + str(num) + ".png"

    # 打开文件并将其转换为Base64编码
    with open(selected_image, "rb") as image_file:
        encoded_string = base64.b64encode(image_file.read()).decode("utf-8")

    # 将Base64编码添加到data URI字符串中
    data_uri = f"data:image/png;base64,{encoded_string}"

    # 打印Base64编码的data URI字符串
    return data_uri

@audio.route("/word")
class Words(MethodView):
    @audio.arguments(AudioWordsSchema)
    @jwt_required(fresh=True)
    def post(self, word_data):
        user = User.query.filter_by(id=get_jwt_identity()).first()
        if user.role_id != 1:
            return {"status": 403, "message": "权限不足"}, 403
        current_app.logger.info(word_data)

        word = Word(
            stem=word_data["stem"], meaning=word_data["meaning"]
        )

        if "lang" in word_data:
            word.lang = word_data["lang"]
        if "translation" in word_data:
            word.translation = word_data["translation"]
        if "prompt" in word_data:
            word.prompt = word_data["prompt"]

        try:
            db.session.add(word)
            db.session.commit()

        except IntegrityError as e:
            # 数据库出错回滚
            db.session.rollback()
            current_app.logger.error(e)
            abort(422, message="已存在该词汇")

        except Exception as e:
            # 数据库出错回滚
            db.session.rollback()
            current_app.logger.error(e)
            abort(404, message="数据库查询异常")

        return {"status": 201, "message": "录入成功"}, 201

@audio.route("/word/<word_id>/image")
class UploadImage(MethodView):
    @audio.arguments(AudioImageSchema)
    @jwt_required(fresh=True)
    def post(self, image_data, word_id):
        user = User.query.filter_by(id=get_jwt_identity()).first()
        if user.role_id != 1:
            return {"status": 403, "message": "权限不足"}, 403
        try:
            word = Word.query.filter_by(id=word_id).first()
        except Exception as e:
            return {"status": 404, "message": "未找到该词汇"}, 404
        try:
            imageData = base64.b64decode(image_data["image_file"])
            upload_path = os.path.join(
                basepath,
                "record_imgs",
                secure_filename(str(word.id) + ".png"),
            )
            with open(upload_path, "wb") as out_image:
                out_image.write(imageData)
            word.image_path = upload_path
        except Exception as e:
            current_app.logger.error(e)
            return {"status": 400, "message": "未成功上传图片文件"}, 400
        try:
            db.session.add(word)
            db.session.commit()  # SQLAlchemy用
        except Exception as e:
            # 数据库出错回滚
            db.session.rollback()
            current_app.logger.error(e)
            os.remove(upload_path)
            return {"status": 404, "message": "数据库查询异常"}, 404

        return {"status": 201,"message": "ok"}

@audio.route("/word/<word_id>")
class WordById(MethodView):
    def get(self, word_id):
        word = Word.query.filter_by(id=word_id).first()
        return {
            "id": word.id,
            "stem": word.stem,
            "stemtranslation": word.translation,
            # "img": convert_base64(word.id),
            "desc": word.meaning,
            "prompt": word.prompt,
        }


import sys
import numpy as np
import json

import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def existsOR( data, keys ):
  ret = False
  for k in keys:
    ret = ret or (k in data)
  return ret

def existsAND( data, keys ):
  ret = True
  for k in keys:
    ret = ret and (k in data)
  return ret

def sub( series, i ):
  return [ v[i] for v in series.values[:-1] ]

kIsCartesian = False
lbl_xyz = ['x','y','z']
lbl_quat = ['qx','qy','qz', 'qw']
ln_color = ['r', 'g', 'b', 'k']

plt.ion()

argc = len( sys.argv )
if argc < 2:
  raise RuntimeError( "Expects an argument: path to json file to plot.")

fp = sys.argv[1]
print( "Will plot {}".format( fp ) )

f = open( fp )
f_str = f.read()
f_str = f_str.replace( "nan", "\"NaN\"" )
json_data = json.loads( f_str )

data = pd.DataFrame.from_dict( json_data['data'] )

kIsCartesian = False
if 'type' in json_data:
  kIsCartesian = ( json_data['type'].lower().startswith('cart') )
if 'x' in data and 'dx' in data:
  kIsCartesian = False
  if len( data['x'].values[0] ) == 7 and len( data['dx'].values[0] ) == 6:
    kIsCartesian = True

print( "{}".format( "CARTESIAN" if kIsCartesian else "VECTOR" ) )

t = data['time'].values[:-1]

if existsOR( data, ['s', 'ds', 'dds'] ):
  f, axarr = plt.subplots(3)
  if 's' in data:
    axarr[0].plot( t, data['s'].values[:-1] )
    axarr[0].set_title( "s" )
  if 'ds' in data:
    axarr[1].plot( t, data['ds'].values[:-1] )
    axarr[1].set_title( "ds" )
  if 'dds' in data:
    axarr[2].plot( t, data['dds'].values[:-1] )
    axarr[2].set_title( "dds" )

if existsOR( data, ['seg_idx',] ):
  f, axarr = plt.subplots(1)
  axarr.plot( t, data['seg_idx'].values[:-1] )
  axarr.set_title( "segment index" )

if kIsCartesian:
  suffixes = []
  if existsOR( data, ['x', 'dx', 'ddx'] ):
    suffixes.append( ('','-') )
  if existsOR( data, ['x_target', 'dx_target', 'ddx_target'] ):
    suffixes.append( ('_target',':') )
  ft, axarrt = plt.subplots(1,2)
  f, axarr = plt.subplots(2,2)
  for (suffix, ln) in suffixes:
    ax_i = 0
    ax_j = 0
    for i in range( 3 ):
      axarrt[ax_i+0].plot(t, sub( data['x'+suffix], i ), ln+ln_color[i], label="dof={}".format( lbl_xyz[i]+suffix ) )
    axarrt[ax_i+0].set_title( "position" )
    axarrt[ax_i+0].legend()
    for i in range( 4 ):
      axarrt[ax_i+1].plot(t, sub( data['x'+suffix], 3+i ), ln+ln_color[i], label="dof={}".format( lbl_quat[i]+suffix ) )
    axarrt[ax_i+1].set_title( "orientation" )
    axarrt[ax_i+1].legend()
    for (vec, name) in [( data['dx'+suffix], 'velocity' ), ( data['ddx'+suffix], 'acceleration' ) ]:
      for i in range( 3 ):
        axarr[ax_i+0, ax_j].plot(t, sub( vec, i ), ln+ln_color[i], label="dof={}".format( lbl_xyz[i]+suffix ) )
      axarr[ax_i+0, ax_j].set_title( "linear " + name )
      axarr[ax_i+0, ax_j].legend()
      for i in range( 3 ):
        axarr[ax_i+1, ax_j].plot(t, sub( vec, 3+i ), ln+ln_color[i], label="dof={}".format( lbl_xyz[i]+suffix ) )
      axarr[ax_i+1, ax_j].set_title( "angular " + name )
      axarr[ax_i+1, ax_j].legend()
      ax_j += 1

    # 3D plot
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.plot( sub( data['x'], 0 ), sub( data['x'], 1 ), sub( data['x'], 2 ) )
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title('3D position')

else: # NOT cartesian
  suffixes = []
  if existsOR( data, ['x', 'dx', 'ddx'] ):
    suffixes.append( ('','-') )
  if existsOR( data, ['x_target', 'dx_target', 'ddx_target'] ):
    suffixes.append( ('_target',':') )
  f, axarr = plt.subplots(1,3)
  for (suffix, ln) in suffixes:
    ax_j = 0
    for (vec, name) in [( data['x'+suffix], 'position' ), ( data['dx'+suffix], 'velocity' ), ( data['ddx'+suffix], 'acceleration' ) ]:
      for i in range( len(vec.values[0]) ):
        axarr[ax_j].plot(t, sub( vec, i ), label="dof={}".format( lbl_xyz[i] ) )
      axarr[ax_j].set_title( name )
      axarr[ax_j].legend()
      ax_j += 1

plt.show()

try:
  input("Enter to quit.")
except:
  pass


#declare dictionary with known values
name_age = {
'Carly':16,
'Mom':55,
'Dad':60,
'Max':9,
'Uncle Bernard':62,
'Aunt Linda':58,
'Lauren':31,
'Christina':29,
}
#assign variable to value related to the key 'Max'
word = name_age['Max']
#declare an empty dictionary
users={}
#add key and value to dictionary
users['Carly']=16

print(name_age)


import base64
from datetime import datetime
from typing import Optional

import discord
from discord.ext import commands

from configuration import Config

config = Config()

class Encuesta(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    # FIXME: Here the problem is that with app_commands  I couldn't
    # figure out the option of having "*option" (former implementation),
    # but for slash commands. Tried to look for "multiple optional commands"
    # but I couldn't find anything.
    @commands.hybrid_command(name="encuesta", help="Comando de encuesta", pass_context=True)
    async def encuesta(
        self,
        ctx,
        pregunta: str,
        option_0: Optional[str] = "",
        option_1: Optional[str] = "",
        option_2: Optional[str] = "",
        option_3: Optional[str] = "",
        option_4: Optional[str] = "",
        option_5: Optional[str] = "",
        option_6: Optional[str] = "",
        option_7: Optional[str] = "",
        option_8: Optional[str] = "",
        option_9: Optional[str] = "",
    ):
        def get_number_emoji(n):
            if 0 <= n < 10:
                return f"{n}\N{COMBINING ENCLOSING KEYCAP}"
            else:
                return n

        if not pregunta:
            e = self.get_help_error()
            await ctx.send(embed=e)
            return

        options = [
            option_0,
            option_1,
            option_2,
            option_3,
            option_4,
            option_5,
            option_6,
            option_7,
            option_8,
            option_9,
        ]

        # Log
        with open(str(config.log_file), "a") as f:
            # date;command;message_id;channel;author;message
            message = " ".join(options).encode("utf-8")
            message_enc = base64.b64encode(message)
            line = (
                f'"{datetime.now()}";'
                f'"encuesta";'
                f'"{ctx.message.id}";'
                f'"{ctx.channel.name}";'
                f'"{ctx.message.author.id}";'
                f'"{ctx.message.author}";'
                f'"{message_enc}"\n'
            )
            f.write(line)

        head = f"**Encuesta \N{BAR CHART}**\n" f"Pregunta: **{pregunta}**\n\n"
        foot = (
            "\n\n¡Participa utilizando las reacciones al mensaje \N{HAPPY PERSON RAISING ONE HAND}!"
        )

        # Errors
        n = sum(1 for o in options if o)

        # Only one arg, assumes a Yes/No question
        if n == 0:
            si_emoji = "\N{WHITE HEAVY CHECK MARK}"
            no_emoji = "\N{CROSS MARK}"

            msg = await ctx.send(f"{head}{si_emoji} Sí\n{no_emoji} No{foot}")

            await msg.add_reaction(si_emoji)
            await msg.add_reaction(no_emoji)

        # Error, because one question, with one option makes no sense.
        elif n == 1:
            await ctx.send("\N{NO ENTRY} No es posible tener solo una opción por pregunta.")
            return
        else:
            # Collapse options
            options = [o for o in options if o]

            body = "\n".join(f"{get_number_emoji(i)} {options[i]}" for i in range(n))
            msg = await ctx.send(f"{head}{body}{foot}")

            for i in range(1, n):
                await msg.add_reaction(get_number_emoji(i - 1))

        try:
            await discord.Message.delete(ctx.message)
        except discord.NotFound:
            print("Using slash command, no need to remove original message")

    def get_help_error(self):
        embed = discord.Embed(
            title="\N{NO ENTRY} No se encontró ningún argumento.\n\n",
            description="**¿Cómo realizar encuestas?**",
            colour=0x2B597B,
        )
        embed.add_field(
            name="Para preguntas de Sí y No",
            value='`%encuesta "pregunta"`',
            inline=False,
        )
        embed.add_field(
            name="Para preguntas de varias opciones",
            value='`%encuesta "pregunta" "opción 1" "opción 2" ...`',
            inline=False,
        )
        return embed


from queue import Queue
from utility import print_matrixi

def breadth_first_tree_search(has_edge: list[list[int]], first_node_index: int):
    queue: Queue = Queue()
    has_visited: list[bool] = len(has_edge) * [False]

    queue.put(first_node_index)

    while queue.qsize() > 0:
        next_node_index: int = queue.get()
        if has_visited[next_node_index]:
            continue
        print(next_node_index)
        has_visited[next_node_index] = True

        for neighbor_index in range(0, len(has_edge[next_node_index])):
            if next_node_index == neighbor_index:
                continue
            if has_visited[neighbor_index]:
                continue
            if has_edge[next_node_index][neighbor_index] == 1:
                queue.put(neighbor_index)

def main():
    edges: dict[int, list[int]] = { 0: [1, 2, 3],
                                    1: [2, 5],
                                    2: [3, 4, 5, 6],
                                    3: [4, 6],
                                    4: [6, 7]}
    num_nodes: int = 8
    has_edge: list[list[int]] = [[0 for j in range(0, num_nodes)] for i in range(0, num_nodes)]
    for node_index in range(0, num_nodes - 1):
        for neighbor_index in range(node_index + 1, num_nodes):
            if node_index in edges:
                if neighbor_index in edges[node_index]:
                    has_edge[node_index][neighbor_index] = 1
                    has_edge[neighbor_index][node_index] = 1
    print_matrixi(matrix=has_edge)
    breadth_first_tree_search(has_edge=has_edge, first_node_index=0)

if __name__ == "__main__":
    main()


from create_statement_creator.athena_schema import create_athena_schema_from_avro
from util.avsc_file_parser import parse_literal_schema_from_file

def create_athena_table_statement_from_avsc(database: str,
                                            table_name: str,
                                            path_to_avsc: str,
                                            partition_statement: str,
                                            s3_location: str) -> str:

    avro_schema_literal = parse_literal_schema_from_file(path_to_avsc)
    athena_schema = create_athena_schema_from_avro(avro_schema_literal)

    return f'''
    CREATE EXTERNAL TABLE IF NOT EXISTS
    `{database}`.`{table_name}`
    ({athena_schema})
    {partition_statement}
    ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
    WITH SERDEPROPERTIES ('avro.schema.literal'='{avro_schema_literal}')
    STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
    OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
    LOCATION '{s3_location}'
    '''


import binascii
import enum
import json
import mobiclip
import MySQLdb
import nlzss
import os
import sqlite3
import struct
import sys
import textwrap
from ninfile import NinchDllist
from ninfile2 import GameTDB
from ninfile3 import *

with open("./config.json", "rb") as f:
    config = json.load(f)

def u8(data):
    if not 0 <= data <= 255:
        print("u8 out of range: %s" % data, "INFO")
        data = 0
    return struct.pack(">B", data)

def u16(data):
    if not 0 <= data <= 65535:
        print("u16 out of range: %s" % data, "INFO")
        data = 0
    return struct.pack(">H", data)

def u32(data):
    if not 0 <= data <= 4294967295:
        print("u32 out of range: %s" % data, "INFO")
        data = 0
    return struct.pack(">I", data)

def enc(text, length):
    name_fixes = {
        "Take-Two Interactive / GameTek / Rockstar Games / Global Star Software": "Take-Two Interactive",
        "Sierra Entertainment / Vivendi Games / Universal Interactive Studios": "Sierra Entertainment",
        "Marvelous Entertainment / Victor Entertainment / Pack-In-Video / Rising Star Games": "Marvelous Entertainment",
        "Take-Two Interactive / Global Star Software / Gotham Games / Gathering of Developers": "Take-Two Interactive",
    }

    if text in name_fixes:
        text = name_fixes[text]

    if len(text) > length:
        print(len(text))
        print("Error: Text too long.")
        print(text)
        # sys.exit(1)
    return text.encode("utf-16be").ljust(length, b"\0")[:length]

def enc_utf_8(text, length):
    if len(text) > length:
        print("Error: Text too long.")
        sys.exit(1)
    return text.encode("utf-8").ljust(length, b"\0")[:length]

class MakeDList:
    def __init__(self, databases):
        self.header = {}
        self.databases = databases
        self.make_header()
        self.write_ratings_table()
        self.write_title_types()
        self.write_company_table()
        self.write_title_table()
        self.write_new_title_table()
        self.write_videos()
        self.write_new_video_table()
        self.write_demos()
        self.write_recommendations()
        self.write_recent_recommendation_table()
        self.write_pop_videos()
        self.write_rating_images()
        self.write_detailed_ratings_table()
        self.write_file()

    def offset_count(self):
        """
        This function returns the offset of where the selected table is
        """
        return sum(len(values) for values in list(self.header.values()) if values)

    def make_header(self):
        """Creates the header for the DlList"""
        self.header["unknown"] = u16(0)
        self.header["version"] = u8(6)
        self.header["unknownRegion"] = u8(2)
        self.header["filesize"] = u32(0)
        self.header["crc32"] = u32(0)
        self.header["dllistid"] = u32(0x14454D5B)
        self.header["thumbnailId"] = u32(1)
        self.header["countryCode"] = u32(49)
        self.header["languageCode"] = u32(1)
        self.header["unknown2_0"] = u8(1)
        self.header["unknown2_1"] = u8(0x50)
        self.header["unknown2_2"] = u8(0x3C)
        self.header["unknown2_3"] = u8(0xEF)
        self.header["unknown2_4"] = u8(0)
        self.header["unknown2_5"] = u8(0)
        self.header["unknown2_6"] = u8(0)
        self.header["unknown2_7"] = u8(0)
        self.header["unknown2_8"] = u8(0)
        self.header["ratingsEntryNumber"] = u32(0)
        self.header["ratingsTableOffset"] = u32(0)
        self.header["titleTypesEntryNumber"] = u32(0)
        self.header["titleTypesTableOffset"] = u32(0)
        self.header["companyEntryNumber"] = u32(0)
        self.header["companyTableOffset"] = u32(0)
        self.header["titleEntryNumber"] = u32(0)
        self.header["titleTableOffset"] = u32(0)
        self.header["newTitleEntryNumber"] = u32(0)
        self.header["newTitleTableOffset"] = u32(0)
        self.header["videos1EntryNumber"] = u32(0)
        self.header["videos1TableOffset"] = u32(0)
        self.header["newVideoEntryNumber"] = u32(0)
        self.header["newVideoTableOffset"] = u32(0)
        self.header["demosEntryNumber"] = u32(0)
        self.header["demosTableOffset"] = u32(0)
        self.header["unknown5"] = u32(0)
        self.header["unknown6"] = u32(0)
        self.header["recommendationsEntryNumber"] = u32(0)
        self.header["recommendationsTableOffset"] = u32(0)
        for i in range(4):
            self.header["unknown7_%s" % i] = u32(0)
        self.header["recentRecommendationsEntryNumber"] = u32(0)
        self.header["recentRecommendationsTableOffset"] = u32(0)
        for i in range(2):
            self.header["unknown8_%s" % i] = u32(0)
        self.header["popularVideosEntryNumber"] = u32(0)
        self.header["popularVideosTableOffset"] = u32(0)
        self.header["detailedRatingsEntryNumber"] = u32(0)
        self.header["detailedRatingsTableOffset"] = u32(0)
        self.header["lastUpdate"] = enc("RiiConnect24 Edition 2.0", 62)
        self.header["unknown9_0"] = u8(0)
        self.header["unknown9_1"] = u8(0x2E)
        self.header["unknown9_2"] = u8(1)
        for i in range(5):
            self.header["dlUrlIds_%s" % i] = enc_utf_8(
                "THqOxqSaiDd5bjhSQS6hk6nkYJVdioanD5Lc8mOHkobUkblWf8KxczDUZwY84FIV", 256
            )
        self.header["unknown10"] = u32(285278430)

    def write_ratings_table(self):
        """Writes the ESRB rating scales from EC (Early Childhood) to M (Mature)"""
        self.header["ratingsTableOffset"] = u32(self.offset_count())
        ratings_entry_number = 0
        for rating in nin_ratings_table:
            # This is the ESRB value.
            rating_group = 2

            self.header[f"rating_ratingID{ratings_entry_number}"] = u8(
                nin_ratings_table[rating]["rating_id"]
            )
            self.header[f"rating_ratingGroup{ratings_entry_number}"] = u8(rating_group)
            self.header[f"rating_age{ratings_entry_number}"] = u8(
                nin_ratings_table[rating]["age"]
            )
            self.header[f"rating_unknown{ratings_entry_number}"] = u8(222)
            self.header[f"rating_jpegOffset{ratings_entry_number}"] = u32(
                nin_ratings_table[rating]["jpeg_offset"]
            )
            self.header[f"rating_jpegSize{ratings_entry_number}"] = u32(
                nin_ratings_table[rating]["jpeg_size"]
            )
            self.header[f"rating_title{ratings_entry_number}"] = enc(
                nin_ratings_table[rating]["title"], 22
            )

            ratings_entry_number += 1

        self.header["ratingsEntryNumber"] = u32(ratings_entry_number)

    def write_detailed_ratings_table(self):
        """Writes the detailed ratings for titles.
        Examples are "Alcohol Reference" and "Blood and Gore"
        """
        self.header["detailedRatingsTableOffset"] = u32(self.offset_count())
        detail_entry_number = 0
        for detail in nin_detailed_ratings_table:
            self.header["detailedRatingGroup_%s" % detail_entry_number] = u8(
                nin_detailed_ratings_table[detail]["rating_group"]
            )
            self.header["detailedRatingID_%s" % detail_entry_number] = u8(
                nin_detailed_ratings_table[detail]["rating_id"]
            )
            self.header["detailedTitle_%s" % detail_entry_number] = enc(
                nin_detailed_ratings_table[detail]["title"], 204
            )
            detail_entry_number += 1

        self.header["detailedRatingsEntryNumber"] = u32(detail_entry_number)

    def write_title_types(self):
        """Writes the types of titles that the Nintendo Channel supports
        They are Wii Channels, Virtual Console, Disc Games, WiiWare, 3DS and DS/DSi games.
        """
        self.header["titleTypesTableOffset"] = u32(self.offset_count())
        title_types_entry_number = 0
        for title_type in nin_title_types_table:
            self.header["typeID_%s" % title_types_entry_number] = u8(
                nin_title_types_table[title_type]["type_id"]
            )
            self.header["consoleModel_%s" % title_types_entry_number] = enc_utf_8(
                nin_title_types_table[title_type]["console_model"], 3
            )
            self.header["title_%s" % title_types_entry_number] = enc(
                nin_title_types_table[title_type]["title"], 102
            )
            self.header["groupID_%s" % title_types_entry_number] = u8(
                nin_title_types_table[title_type]["group_id"]
            )
            self.header["unknown_title_type_%s" % title_types_entry_number] = u8(
                nin_title_types_table[title_type]["unknown"]
            )
            title_types_entry_number += 1

        self.header["titleTypesEntryNumber"] = u32(title_types_entry_number)

    def write_rating_images(self):
        """Writes the ESRB rating images to the file. It also updates the JPEG Offset and Size which is handy"""
        rating_names = [
            "EC.jpg",
            "E.jpg",
            "E10.jpg",
            "T.jpg",
            "M.jpg",
            "visitesrb.jpg",
            "visitesrb.jpg",
            "maycontain.jpg",
        ]
        for i, rating in enumerate(nin_ratings_table):
            deadbeef = {0: 0xDE, 1: 0xAD, 2: 0xBE, 3: 0xEF}
            # Write the image to our file then update the rating table's offset to the image
            if i == 8:
                return
            with open(f"./ratings/ESRB/{rating_names[i]}", "rb") as image:
                self.header[f"jpegOffset{i}"] = u32(self.offset_count())
                self.header[f"ratingJPEGData{i}"] = image.read()
                counter = 0
                while self.offset_count() % 32 != 0:
                    self.header[f"deadbeef_{i}_{counter}"] = u8(deadbeef[counter % 4])
                    counter += 1
                # Seek to end of file to set filesize
                image.seek(0, os.SEEK_END)
                self.header[f"jpegSize{i}"] = u32(image.tell())
                image.close()

    def write_company_table(self):
        """Writes the companies that made games on the Wii."""
        self.header["companyTableOffset"] = u32(self.offset_count())
        entry_number = 0
        for s in self.databases["Wii"][1].findall("companies"):
            for w in s.findall("company"):
                id = w.get("code").encode()
                id = int(id.hex(), base=16)
                self.header["company_id_%s" % w] = u32(id)
                self.header["devTitle_%s" % w] = enc(w.get("name"), 62)
                self.header["pubTitle_%s" % w] = enc(w.get("name"), 62)
                entry_number += 1
        self.header["companyEntryNumber"] = u32(entry_number)

    def write_title_table(self):
        self.header["titleTableOffset"] = u32(self.offset_count())
        entry_number = 0
        game_type = {
            "3DS": {
                None: 0x12,
                "3DS": 0x12,
                "3DSWare": 0x13,
                "New3DS": 0x18,
                "New3DSWare": 0x19,
                "VC-NES": 0x1A,
                "VC-GB": 0x14,
                "VC-GBC": 0x1C,
                "VC-GBA": 0x1D,
                "VC-GG": 0x1E,
            },
            "NDS": {
                None: 0x0A,
                "DS": 0x0A,
                "DSi": 0x10,
                "DSiWare": 0x11,
            },
            "Switch": {
                None: 0x17,
                "Switch": 0x17,
                "eShop": 0x27,
            },
            "Wii": {
                None: 0x01,
                "Wii": 0x01,
                "Channel": 0x02,
                "WiiWare": 0x0B,
                "VC-NES": 0x03,
                "VC-SNES": 0x04,
                "VC-N64": 0x05,
                "VC-SMS": 0x0C,
                "VC-MD": 0x07,
                "VC-PCE": 0x06,
                "VC-NEOGEO": 0x08,
                "VC-Arcade": 0x0E,
                "VC-C64": 0x0D,
                "VC-MSX": 0x28,
            },
            "WiiU": {
                None: 0x15,
                "WiiU": 0x15,
                "eShop": 0x16,
                "VC-NES": 0x1F,
                "VC-SNES": 0x20,
                "VC-N64": 0x21,
                "VC-GBA": 0x22,
                "VC-DS": 0x23,
                "VC-PCE": 0x24,
                "VC-MSX": 0x25,
                "Channel": 0x26,
            },
        }  # The XML returns None for disc games when we query the type.

        platforms = ["Wii", "NDS", "3DS", "WiiU"]

        titles = {}

        # import leaderboards from RiiTag
        if config["production"]:
            con = MySQLdb.connect(
                "localhost", config["dbuser"], config["dbpass"], "rc24_RiiTag", charset="utf8mb4"
            )

            cur = con.cursor()

            titles_ranking = []

            cur.execute("SELECT game_id FROM game ORDER BY playcount DESC")

            for row in cur.fetchall():
                titles_ranking.append(row)

        titles_keys = {}

        for platform in platforms:
            for title in self.databases[platform][1].findall("game"):
                if title.find("locale", {"lang": "EN"}) is not None:
                    titles[
                        title.find("locale", {"lang": "EN"}).find("title").text
                        + " - "
                        + title.find("id").text
                        + " - "
                        + platform
                    ] = title

        j = 0
        conflict_number = 0
        for key, s in sorted(titles.items()):
            if (
                s.find("region").text == "NTSC-U"
                or s.find("region").text == "USA"
                or s.find("region").text == "ALL"
            ):
                if (
                    s.find("type").text != "CUSTOM"
                    and s.find("type").text != "GameCube"
                ):
                    title = "lmfao null"
                    if s.find("locale", {"lang": "EN"}) is not None:
                        title = (
                            s.find("locale", {"lang": "EN"})
                            .find("title")
                            .text.replace(" - ", ": ")
                            .replace("Ō", "O")
                            .replace("&", "&")
                        )

                    title_platform = key.split(" - ")[-1]

                    titles_key = (
                        " - ".join(key.split(" - ")[:-2]) + " - " + title_platform
                    )

                    if titles_key in titles_keys.keys():
                        """if titles_keys[titles_key][0] == "ALL" and s.find("region").text == "USA" or len(titles_keys[titles_key][2]) == 4 and len(key.split(" - ")[-2]) == 6:
                            for header_key in self.header.keys():
                                if "title_" in header_key and str(titles_keys[titles_key][1]) in header_key:
                                    conflict_number += 1
                                    del header_key
                        else:
                             continue"""

                        continue

                    titles_keys[titles_key] = [
                        s.find("region").text,
                        entry_number,
                        key.split(" - ")[-2],
                    ]

                    if title_platform == "Switch" and s.find("type").text == "eShop":
                        continue

                    # Create custom ID
                    text_id = s.find("id").text[:4]
                    id = int(text_id.encode().hex(), base=16)

                    # for NDS, 3DS, WiiU, and Switch, we xor the id to avoid conflicts. (for example, Mario Kart 7 for 3DS and Mario Kart 8 for Wii U both have the ID "AMKE")
                    if title_platform == "NDS":
                        id ^= 0x22222222

                    elif title_platform == "3DS":
                        id ^= 0x33333333

                    elif title_platform == "WiiU":
                        id ^= 0x44444444

                    elif title_platform == "Switch":
                        id ^= 0x55555555

                    self.header[f"title_id_{entry_number}"] = u32(id)
                    self.header[f"title_titleId_{entry_number}"] = enc_utf_8(
                        s.find("id").text[:4], 4
                    )

                    try:
                        if s.find("type").text in game_type[title_platform]:
                            self.header[f"title_titleType_{entry_number}"] = u8(
                                game_type[title_platform][s.find("type").text]
                            )
                        else:
                            print(title_platform, s.find("type").text)
                            continue
                            # self.header[f"title_titleType_{entry_number}"] = u8(0)
                    except:
                        print(title_platform, s.find("type").text)
                        continue

                    # Parse the genre's. The XML is a giant mess for this, this will be a giant dictionary.
                    genre_dict = {
                        "arcade": 15,
                        "party": 13,
                        "puzzle": 5,
                        "action": 1,
                        "2D platformer": 1,
                        "3D platformer": 1,
                        "shooter": 12,
                        "first-person shooter": 12,
                        "third-person shooter": 12,
                        "rail shooter": 12,
                        "run and gun": 12,
                        "shoot 'em up": 12,
                        "stealth action": 1,
                        "survival horror": 1,
                        "sports": 4,
                        "adventure": 2,
                        "hidden object": 13,
                        "interactive fiction": 2,
                        "interactive movie": 2,
                        "point-and-click": 13,
                        "music": 10,
                        "rhythm": 10,
                        "dance": 10,
                        "karaoke": 10,
                        "racing": 7,
                        "fighting": 14,
                        "simulation": 9,
                        "role-playing": 6,
                        "strategy": 8,
                        "traditional": 11,
                        "health": 3,
                        "others": 13,
                    }

                    # We will have a static variable to store our genre. This is because I didn't include
                    # many subgenres in the dict since they share the same ID as their parent genre.
                    _genre = 13
                    genre_text = s.find("genre")

                    # Check for None
                    if genre_text is None:
                        self.header[f"title_genre_{entry_number}_0"] = u8(13)
                        self.header[f"title_genre_{entry_number}_1"] = u8(13)
                        self.header[f"title_genre_{entry_number}_2"] = u8(13)
                    else:
                        # This is a mess. Some titles don't have genres, some have only 1 or 2 genres, so
                        # workarounds were made
                        genre_list = genre_text.text.split(",")

                        for i in range(3):
                            try:
                                if genre_list[i] in genre_dict:
                                    _genre = genre_dict[genre_list[i]]
                                    self.header[f"title_genre_{entry_number}_{i}"] = u8(
                                        _genre
                                    )
                                else:
                                    self.header[f"title_genre_{entry_number}_{i}"] = u8(
                                        _genre
                                    )
                            except IndexError:
                                self.header[f"title_genre_{entry_number}_{i}"] = u8(
                                    _genre
                                )

                    # We will default to Nintendo because why not
                    self.header[f"title_companyOffset_{entry_number}"] = self.header[
                        "companyTableOffset"
                    ]
                    company_start = struct.unpack(
                        ">I", self.header["companyTableOffset"]
                    )[0]

                    for c in self.databases["Wii"][1].findall("companies"):
                        for i, company in enumerate(c.findall("company")):
                            # Firstly, we will try to find the company by the company code.
                            # This method will only work for disc games. As such, methods below exist
                            if s.find("id").text[4:] != "":
                                if s.find("id").text[4:] == company.get("code"):
                                    self.header[
                                        f"title_companyOffset_{entry_number}"
                                    ] = u32(company_start + (128 * i))
                                    break

                            # If None we will default to Nintendo as well
                            if s.find("publisher").text is None:
                                self.header[
                                    f"title_companyOffset_{entry_number}"
                                ] = self.header["companyTableOffset"]
                                break
                            if company.get("name") in s.find("publisher").text:
                                self.header[
                                    f"title_companyOffset_{entry_number}"
                                ] = u32(company_start + (128 * i))
                                break

                    if s.find("date").get("year") == "":
                        release_year = 0xFFFF
                    else:
                        release_year = s.find("date").get("year")

                    if s.find("date").get("month") == "":
                        release_month = 0xFF
                    else:
                        release_month = s.find("date").get("month")

                    if s.find("date").get("day") == "":
                        release_day = 0xFF
                    else:
                        release_day = s.find("date").get("day")

                    self.header[f"title_releaseYear_{entry_number}"] = u16(
                        int(release_year)
                    )
                    self.header[f"title_releaseMonth_{entry_number}"] = u8(
                        int(release_month) - 1
                    )  # the month starts at 0, not 1
                    self.header[f"title_releaseDay_{entry_number}"] = u8(
                        int(release_day)
                    )

                    if title_platform == "Switch":
                        try:
                            rating = s.find("rating_ESRB").get("value")
                        except AttributeError:
                            rating = ""

                        rating_group = "ESRB"

                    else:
                        try:
                            rating = s.find("rating").get("value")
                            rating_group = s.find("rating").get("type")
                        except AttributeError:
                            rating = ""
                            rating_group = "ESRB"

                    if rating == "E10+" or rating == "E10 ":
                        # GameTDB has E10 as E10+. As I cannot use that as an enum key, here we are
                        rating = "E10"
                    elif rating == "AO":
                        # The Wii has Adults Only?????
                        rating = "M"
                    elif rating == "3":
                        # I don't know why PEGI ratings are getting mixed in
                        rating = "E"
                    elif rating == "" or rating == "Ratin":
                        # Default to E
                        rating = "E"

                    self.header[f"title_ratingId_{entry_number}"] = u8(
                        self.RatingSystem[rating].value
                    )

                    # Unknown Value
                    self.header[f"title_unknown1_{entry_number}"] = u16(2080)

                    # Up ahead is some extremely lazy code. This should work, but some flags will be incorrect such as
                    # Hardcore and casual
                    self.header[f"title_hardcore_{entry_number}"] = u32(536872960)
                    self.header[f"title_friends_{entry_number}"] = u32(2863311530)
                    self.header[f"title_unknown2_{entry_number}"] = u32(2863311530)
                    self.header[f"title_unknown3_{entry_number}"] = u16(43690)
                    # Unknown4 will be a combo of what in the kaitai is unknown16 and unknown17 and other flags
                    self.header[f"title_unknown4_{entry_number}"] = u16(170)
                    self.header[
                        f"title_unknown5_{entry_number}"
                    ] = 168  # contains unknown17 through multiplayer
                    self.header[f"title_unknown6_{entry_number}"] = u32(50331648)
                    self.header[f"title_unknown7_{entry_number}"] = u32(0)
                    self.header[f"title_medal_{entry_number}"] = u8(0)
                    self.header[f"title_unknown9_{entry_number}"] = u8(222)

                    for feature in s.find("wi-fi").findall("feature"):
                        if "online" not in feature.text:
                            self.header[
                                f"title_unknown5_{entry_number}"
                            ] |= 4  # online flag set to no

                    try:
                        if int(s.find("input").get("players")) < 2:
                            self.header[
                                f"title_unknown5_{entry_number}"
                            ] |= 1  # multiplayer flag set to no
                    except TypeError:
                        pass

                    self.header[f"title_unknown5_{entry_number}"] = u8(
                        self.header[f"title_unknown5_{entry_number}"]
                    )

                    if len(title) > 30:
                        fixed_title = textwrap.wrap(title, width=30)[0]
                        fixed_subtitle = textwrap.wrap(title, width=30)[1]

                    elif ": " in title:
                        fixed_title = title.split(": ")[0] + ": "
                        fixed_subtitle = title.split(": ")[1]

                    elif " - " in title:
                        fixed_title = title.split(" - ")[0] + ": "
                        fixed_subtitle = title.split(" - ")[1]

                    else:
                        fixed_title = title
                        fixed_subtitle = ""

                    if config["production"]:
                        if s.find("id").text in titles_ranking:
                            if titles_ranking.index(s.find("id").text) <= 15:
                                self.header[f"title_medal_{entry_number}"] = u8(
                                    4
                                )  # platinum
                            elif titles_ranking.index(s.find("id").text) <= 30:
                                self.header[f"title_medal_{entry_number}"] = u8(
                                    3
                                )  # gold
                            elif titles_ranking.index(s.find("id").text) <= 50:
                                self.header[f"title_medal_{entry_number}"] = u8(
                                    2
                                )  # silver
                            elif titles_ranking.index(s.find("id").text) <= 100:
                                self.header[f"title_medal_{entry_number}"] = u8(
                                    1
                                )  # bronze

                    self.header[f"title_title_{entry_number}"] = enc(fixed_title, 62)
                    self.header[f"title_subtitle_{entry_number}"] = enc(
                        fixed_subtitle, 62
                    )

                    # print(title)

                    self.header[f"title_shortTitle_{entry_number}"] = enc("", 62)
                    entry_number += 1

                    if config["make_info"]:
                        if not os.path.exists(
                            config["file_path"] + "/soft/US/en/" + str(id) + ".info"
                        ):
                            print(
                                "Making info file for {} {}...".format(
                                    title_platform, text_id
                                )
                            )

                            os.system(
                                "python3.10 info.py {} {}".format(
                                    title_platform, text_id
                                )
                            )

            j += 1

        entry_number -= conflict_number

        self.header["titleEntryNumber"] = u32(entry_number)

    def write_new_title_table(self):
        """Writes the offset where the title is in the title table."""
        self.header["newTitleTableOffset"] = u32(self.offset_count())
        entry_number = 0
        for new_title in nin_new_title_table:
            self.header[f"newTitle_offset_{entry_number}"] = self.header[
                "titleTableOffset"
            ]
            entry_number += 1
        self.header["newTitleEntryNumber"] = u32(entry_number)

    def write_videos(self):
        """Writes the videos"""
        self.header["videos1TableOffset"] = u32(self.offset_count())
        entry_number = 0
        for video in nin_videos_1_table:
            self.header["video_id_%s" % entry_number] = u32(
                nin_videos_1_table[video]["id"]
            )
            print(str(nin_videos_1_table[video]["id"]))
            try:
                with open("/var/www/rc24/wapp.wii.com/nintendo/entus/public_html/6/movie/US/en/" + str(nin_videos_1_table[video]["id"]) + "-h.mo", "rb") as f:
                    f.seek(12)
                    fps = struct.unpack("<I", f.read(4))[0]
                    chunk_count = struct.unpack("<I", f.read(4))[0]
                    f.close()
                self.header["video_timeLength_%s" % entry_number] = u16(int(
                    chunk_count / (fps / 256)
                ))
            except FileNotFoundError:
                print(str(nin_popular_videos_table[pop]["id"]) + "-h.mo not found")
                self.header["video_timeLength_%s" % entry_number] = u16(int(
                    0
                ))
            self.header["video_titleID_%s" % entry_number] = u32(
                nin_videos_1_table[video]["title_id"]
            )
            self.header["video_videoType_%s" % entry_number] = u8(
                nin_videos_1_table[video]["video_type"]
            )
            for i in range(14):
                self.header["bruh_unknown_%s_%s" % (i, entry_number)] = u8(0)
            self.header["video_unknown2_%s" % entry_number] = u8(
                nin_videos_1_table[video]["unknown_2"]
            )
            self.header["video_ratingID_%s" % entry_number] = u8(
                nin_videos_1_table[video]["rating_id"]
            )
            self.header["video_unknown3_%s" % entry_number] = u8(
                nin_videos_1_table[video]["unknown_3"]
            )
            self.header["video_newTag_%s" % entry_number] = u8(
                nin_videos_1_table[video]["new_tag"]
            )
            self.header["videoIndex_%s" % entry_number] = u8(
                nin_videos_1_table[video]["video_index"]
            )
            self.header["unknown4_1_%s" % entry_number] = u8(61 + entry_number)
            self.header["unknown4_2_%s" % entry_number] = u8(222)
            self.header["video_title_%s" % entry_number] = enc(
                nin_videos_1_table[video]["title"], 246
            )
            entry_number += 1

        self.header["videos1EntryNumber"] = u32(entry_number)

    def write_new_video_table(self):
        """Writes the new videos"""
        self.header["newVideoTableOffset"] = u32(self.offset_count())
        entry_number = 0
        for new_video in nin_new_video_table:
            entry_number += 1
            self.header["new_videoID_%s" % entry_number] = u32(
                nin_new_video_table[new_video]["id"]
            )
            try:
                with open("/var/www/rc24/wapp.wii.com/nintendo/entus/public_html/6/movie/US/en/" + str(nin_new_video_table[new_video]["id"]) + "-h.mo", "rb") as f:
                    f.seek(12)
                    fps = struct.unpack("<I", f.read(4))[0]
                    chunk_count = struct.unpack("<I", f.read(4))[0]
                    f.close()
                print(chunk_count / (fps / 256))
                try:
                    self.header["new_video_timeLength_%s" % entry_number] = u16(int(
                        chunk_count / (fps / 256)
                    ))
                except:
                    self.header["new_video_timeLength_%s" % entry_number] = u16(int(
                        0
                    ))
            except FileNotFoundError:
                print(str(nin_new_video_table[new_video]["id"]) + "-h.mo not found")
                self.header["new_video_timeLength_%s" % entry_number] = u16(int(
                    0
                ))
            self.header["new_video_titleID_%s" % entry_number] = u32(
                nin_new_video_table[new_video]["title_id"]
            )
            for i, data in enumerate(nin_new_video_table[new_video]["unknown_2"]):
                if i == 0:
                    self.header["new_video_unknown2_%s_%s" % (i, entry_number)] = u8(8)
                elif i == 1:
                    self.header["new_video_unknown2_%s_%s" % (i, entry_number)] = u8(1)
                else:
                    self.header["new_video_unknown2_%s_%s" % (i, entry_number)] = u8(
                        data
                    )
            self.header["new_video_title_%s" % entry_number] = enc(
                nin_new_video_table[new_video]["title"], 204
            )

        self.header["newVideoEntryNumber"] = u32(entry_number)

    def write_demos(self):
        """Writes the demos"""
        self.header["demosTableOffset"] = u32(self.offset_count())
        entry_number = 0
        for demo in nin_demos_table:
            self.header["demo_id_%s" % entry_number] = u32(nin_demos_table[demo]["id"])
            self.header["demo_title_%s" % entry_number] = enc(
                nin_demos_table[demo]["title"], 62
            )
            self.header["demo_subtitle_%s" % entry_number] = enc(
                nin_demos_table[demo]["subtitle"], 62
            )
            self.header["demo_titleID_%s" % entry_number] = u32(
                nin_demos_table[demo]["titleid"]
            )
            self.header["demo_company_offset_%s" % entry_number] = u32(
                nin_demos_table[demo]["company_offset"]
            )
            self.header["demo_removal_year_%s" % entry_number] = u16(65535)
            self.header["demo_removal_month_%s" % entry_number] = u8(255)
            self.header["demo_removal_day_%s" % entry_number] = u8(255)
            self.header["demo_unknown_%s" % entry_number] = u32(0)
            self.header["demo_rating_id_%s" % entry_number] = u8(
                nin_demos_table[demo]["rating_id"]
            )
            self.header["demo_new_tag_%s" % entry_number] = u8(
                nin_demos_table[demo]["new_tag"]
            )
            self.header["demo_new_tag_index_%s" % entry_number] = u8(
                nin_demos_table[demo]["new_tag_index"]
            )
            for i in range(205):
                self.header["demo_unknown2_%s_%s" % (entry_number, i)] = u8(0)
            entry_number += 1

        self.header["demosEntryNumber"] = u32(entry_number)

    def write_recommendations(self):
        """Writes the recommended games"""
        self.header["recommendationsTableOffset"] = u32(self.offset_count())
        entry_number = 0
        for recommend in nin_recommendations_table:
            self.header[
                "recommend_recommendation_title_offset_%s" % entry_number
            ] = self.header["titleTableOffset"]
            entry_number += 1
        self.header["recommendationsEntryNumber"] = u32(entry_number)

    def write_recent_recommendation_table(self):
        self.header["recentRecommendationsTableOffset"] = u32(self.offset_count())
        entry_number = 0
        for idk in nin_recent_recommendations_table:
            self.header[
                "recent_recommendation_title_offset_%s" % entry_number
            ] = self.header["titleTableOffset"]
            self.header["recent_recommendation_unknown_%s" % entry_number] = u16(
                nin_recent_recommendations_table[idk]["unknown"]
            )
            entry_number += 1

        self.header["recentRecommendationsEntryNumber"] = u32(entry_number)

    def write_pop_videos(self):
        self.header["popularVideosTableOffset"] = u32(self.offset_count())
        entry_number = 0
        for pop in nin_popular_videos_table:
            self.header["pop_video_id_%s" % entry_number] = u32(
                nin_popular_videos_table[pop]["id"]
            )
            try:
                with open("/var/www/rc24/wapp.wii.com/nintendo/entus/public_html/6/movie/US/en/" + str(nin_popular_videos_table[pop]["id"]) + "-h.mo", "rb") as f:
                    f.seek(12)
                    fps = struct.unpack("<I", f.read(4))[0]
                    chunk_count = struct.unpack("<I", f.read(4))[0]
                    f.close()
                self.header["pop_video_time_%s" % entry_number] = u16(int(
                    chunk_count / (fps / 256)
                ))
            except FileNotFoundError:
                print(str(nin_popular_videos_table[pop]["id"]) + "-h.mo not found")
                self.header["pop_video_time_%s" % entry_number] = u16(int(
                    0
                ))
            self.header["pop_video_title_id_%s" % entry_number] = u32(0)
            self.header["pop_video_bar_color_%s" % entry_number] = u8(0)
            for i in range(15):
                self.header["pop_video_unknown_%s_%s" % (i, entry_number)] = u8(0)
            self.header["pop_video_ratingID_%s" % entry_number] = u8(
                nin_popular_videos_table[pop]["rating_id"]
            )
            self.header["pop_video_unknown3_%s" % entry_number] = u8(1)
            self.header["pop_video_videoRank_%s" % entry_number] = u8(1)
            self.header["pop_video_unknown4_%s" % entry_number] = u8(222)
            self.header["pop_video_title_%s" % entry_number] = enc(
                nin_popular_videos_table[pop]["title"], 204
            )
            entry_number += 1
        self.header["popularVideosEntryNumber"] = u32(entry_number)

    class RatingSystem(enum.Enum):
        EC = 8
        E = 9
        E10 = 10
        T = 11
        M = 12

    def write_file(self):
        # Now that all the file contents are written, calculate filesize
        self.header["filesize"] = u32(self.offset_count())

        filename = "testing.bin"

        if os.path.exists(filename + "-1"):
            os.remove(filename + "-1")

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

        self.writef = open(filename + "-1", "ab")

        for values in self.header.values():
            self.writef.write(values)

        self.writef.close()

        self.readf = open(filename + "-1", "rb")

        read = self.readf.read()

        self.writef2 = open(filename, "wb")

        self.writef2.write(read)
        self.writef2.seek(8)
        self.writef2.write(
            binascii.unhexlify(format(binascii.crc32(read) & 0xFFFFFFFF, "08x"))
        )

        os.remove(filename + "-1")

        self.writef2.close()

        nlzss.encode_file(filename, filename.replace(".bin", ".LZ"))

MakeDList(GameTDB(True).parse())

# Get genres
# genre_type = {"action": 1, "adventure": 2, "sports": 4, "puzzle": 5,
# "strategy RPG": 6, "tactical RPG": 6, "action RPG": 6, "MMORPG": 6, "roguelike": 6}
# for s in self.databases["Wii"][1].findall("genres"):
# for k in s.findall("maingenre"):
# print(k.get("name"))


from typing import NamedTuple

import flax
import jax
import jax.numpy as jnp
import jax.tree_util as jtu
from flax.core.frozen_dict import FrozenDict

import energy
import models

class MetaModule:
    def __init__(self):
        pass

    def __call__(self, meta_state, x, method=None):
        pass

    def reset_hparams(self, rng, sample_input):
        pass

    def reset_params(self, rng, hparams, sample_input):
        pass

class ComplexSynapseMetaParams(NamedTuple):
    omega: FrozenDict
    log_lambda: FrozenDict

class ComplexSynapseParams(NamedTuple):
    base_learner: FrozenDict

class ComplexSynapse(MetaModule):
    def __init__(self, loss_fn_inner, loss_fn_outer, base_learner, l2_reg=None, variant="imaml"):
        self.loss_fn_inner = loss_fn_inner
        self.loss_fn_outer = loss_fn_outer

        self.base_learner = base_learner
        self.l2_reg = l2_reg
        self.variant = variant

        if variant == "complex_synapse":
            assert l2_reg is not None
            self.loss_fn_inner = energy.add(self.loss_fn_inner, energy.complex_synapse(l2_reg))

        elif variant == "imaml":
            assert l2_reg is not None
            self.loss_fn_inner = energy.add(self.loss_fn_inner, energy.imaml(l2_reg))

        elif variant == "init":
            self.loss_fn_inner = self.loss_fn_inner

        elif variant == "l2_reg":
            self.loss_fn_inner = energy.add(self.loss_fn_inner, energy.l2_learned())

        else:
            raise ValueError("Variant \"{}\" not defined.".format(variant))

    def __call__(self, params, hparams, x, method=None):
        return self.base_learner.apply({"params": params.base_learner}, x, method=method)

    def reset_hparams(self, rng, sample_input):
        hparams_omega = self.base_learner.init(rng, sample_input)["params"]

        if self.variant in ["complex_synapse", "l2_reg"]:
            hparams_log_lambda = jtu.tree_map(
                lambda x: jnp.log(self.l2_reg) * jnp.ones_like(x), hparams_omega
            )
        else:
            hparams_log_lambda = FrozenDict()

        return ComplexSynapseMetaParams(hparams_omega, hparams_log_lambda)

    def reset_params(self, rng, hparams, sample_input):
        return ComplexSynapseParams(hparams.omega)

class GainModMetaParams(NamedTuple):
    body: FrozenDict
    head_init: FrozenDict
    bias_init: FrozenDict
    gain_init: FrozenDict

class GainModParams(NamedTuple):
    head: FrozenDict
    bias: FrozenDict
    gain: FrozenDict

class GainMod(MetaModule):
    def __init__(self, loss_fn_inner, loss_fn_outer, hidden_dims, output_dim):
        self.loss_fn_inner = loss_fn_inner
        self.loss_fn_outer = loss_fn_outer

        self.hidden_dims = hidden_dims
        self.output_dim = output_dim

        self.body = models.FeedforwardNetwork(hidden_dims)
        self.head = flax.linen.Dense(output_dim)

    def __call__(self, params, hparams, x):

        features = self.body.apply(
            {"params": hparams.body}, x, params.bias, params.gain,
            method=self.body.forward_modulated
        )

        return self.head.apply({"params": params.head}, features)

    def reset_hparams(self, rng, sample_input):
        rng_body, rng_head = jax.random.split(rng, 2)

        hparams_body = self.body.init(rng_body, sample_input)["params"]
        hparams_head = self.head.init(
            rng_head, jnp.empty((sample_input.shape[0], self.hidden_dims[0]))
        )["params"]

        hparams_bias = FrozenDict({
            l: jnp.zeros(h_dim) for l, h_dim in enumerate(self.hidden_dims)
        })
        hparams_gain = FrozenDict({
            l: jnp.ones(h_dim) for l, h_dim in enumerate(self.hidden_dims)
        })

        return GainModMetaParams(hparams_body, hparams_head, hparams_bias, hparams_gain)

    def reset_params(self, rng, hparams, sample_input):
        params_head = hparams.head_init

        return GainModParams(params_head, hparams.bias_init, hparams.gain_init)

class AlmostNoInnerLoopMetaParams(NamedTuple):
    body: FrozenDict
    head_init: FrozenDict

class AlmostNoInnerLoopParams(NamedTuple):
    head: FrozenDict

class AlmostNoInnerLoop(MetaModule):
    def __init__(self, loss_fn_inner, loss_fn_outer, hidden_dims, output_dim):
        self.loss_fn_inner = loss_fn_inner
        self.loss_fn_outer = loss_fn_outer

        self.hidden_dims = hidden_dims
        self.output_dim = output_dim

        self.body = models.FeedforwardNetwork(hidden_dims)
        self.head = flax.linen.Dense(output_dim)

    def __call__(self, params, hparams, x):

        features = self.body.apply({"params": hparams.body}, x)

        return self.head.apply({"params": params.head}, features)

    def reset_hparams(self, rng, sample_input):
        hparams_body = self.body.init(rng, sample_input)["params"]
        hparams_head = self.head.init(rng, jnp.empty((1, self.hidden_dims[0])))["params"]

        return AlmostNoInnerLoopMetaParams(hparams_body, hparams_head)

    def reset_params(self, rng, hparams, sample_input):
        params_head = hparams.head_init

        return AlmostNoInnerLoopParams(params_head)


# -*- coding: utf-8 -*-

import boto3
import json
import os
import subprocess
import sys
import urllib.parse

from base64 import b64decode
from boto3.dynamodb.conditions import Key, Attr
from datetime import datetime
from datetime import timedelta

ENCRYPTED = os.environ['ENCRYPTED_GOOGLE_API_KEY']
os.environ['GOOGLE_API_KEY'] = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED))['Plaintext'].decode(
    'utf-8')
ENCRYPTED = os.environ['ENCRYPTED_GOOGLE_APP_ID']
os.environ['GOOGLE_APP_ID'] = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED))['Plaintext'].decode(
    'utf-8')

def _(cmd):
    return subprocess.check_output(cmd.split())

def lambda_handler(event, context):
    start = datetime.now()

    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(os.environ['TABLE_NAME'])
    title = event['queryStringParameters']['title']

    histories = table.query(
        KeyConditionExpression=Key('title').eq(title),
        ScanIndexForward=False
    )

    if histories['Count'] == 0 or \
            ('cache' in event['queryStringParameters'] and
             event['queryStringParameters']['cache'] == 'no'):
        os.environ['REQUEST_URI'] = 'info_json.sh?title=' \
                                    + urllib.parse.quote_plus(title, safe='+',
                                                              encoding='utf-8')
        json_string = ""
        try:
            json_string = _('bash info_json.sh')
            result = json.loads(json_string)
        except Exception as e:
            print("exception:", e)
            print("string:", json_string)
            raise
    elif histories['Count'] > 0 and 'result' in histories['Items'][0]:
        result = json.loads(histories['Items'][0]['result'])
    else:
        result = {}

    completed = datetime.now()
    timestamp = start.strftime('%Y/%m/%d %H:%M:%S') + '.%03d' % (start.microsecond // 1000)
    history = {
        'title': title,
        'timestamp': timestamp,
        'completed': completed.strftime('%Y/%m/%d %H:%M:%S') + '.%03d' % (completed.microsecond // 1000),
        'event': json.dumps(event),
        'result': json.dumps(result),
        'is_error': 'error' in result,
        'ttl': int((completed + timedelta(days=31)).timestamp())
    }
    table.put_item(Item=history)

    return {
        'isBase64Encoded': False,
        'statusCode': 200 if ('error' not in result) else 403,
        'headers': {'Access-Control-Allow-Origin': '*'},
        'body': json.dumps(result)
    }


import cobble.command
import cobble.validations
import discord
import databaseManager as dbm
from customcommands.customvalidations import *

import neatTables

class ILBoardCommand(cobble.command.Command):
    def __init__(self, bot: cobble.bot.Bot):
        """
        Parameters:
            bot - The bot object the command will belong to
        """
        super().__init__(bot, "IL Leaderboard", "ilboard", "Show the leaderboard for a given IL", cobble.permissions.EVERYONE)
        self.addArgument(cobble.command.Argument("map", "The IL map", IsMap()))
        self.addArgument(cobble.command.Argument("category", "The IL category", IsILCategory()))
        self.addArgument(cobble.command.Argument("start", "Where to start from", cobble.validations.IsInteger(), True))

    async def execute(self, messageObject: discord.message, argumentValues: dict, attachedFiles: dict) -> str:
        """
        Generate a leaderboard for the given category
        Parameters:
            argumentValues - a dictionary containing values for every argument provided, keyed to the argument name
        """
        if "start" in argumentValues.keys():
            start = int(argumentValues["start"])-1
        else:
            start = 0

        if argumentValues["map"] in dbm.levelNames.values():
            argumentValues["map"] = dbm.getMapFromLevelName(argumentValues["map"])

        lbData = dbm.generateILBoard(argumentValues["map"], argumentValues["category"])[start:start+20]
        tableData = [["Place", "Runner", "Time"]]
        for entry in lbData:
            place = durations.formatLeaderBoardPosition(dbm.fetchILPlace(entry[0], argumentValues["category"]))
            runner = entry[1]
            time = entry[2]
            tableData.append([place, runner, time])

        table = "```"+neatTables.generateTable(tableData, padding=2)+"```"

        return table


from PySide2.QtCore import Qt, QPointF, QMimeData, QAbstractListModel, QModelIndex
from PySide2.QtWidgets import QListView
from sortedcontainers import SortedDict

from nfb_studio.serial import mime, hooks

class Toolbox(QAbstractListModel):
    """A list of scheme nodes that can be dragged to the scheme.
    """

    DragMimeType = "application/x-toolbox-drag"
    """Toolbox assumes that all its items have the same MIME type."""

    def __init__(self, parent=None):
        super().__init__(parent)

        self._items = SortedDict()

    def getView(self):
        """Get a new QListView suitable for displaying the toolbox."""
        v = QListView()
        v.setModel(self)

        v.setSelectionMode(v.SingleSelection)
        v.setDragEnabled(True)
        v.setDragDropMode(v.DragOnly)

        return v

    def rowCount(self, parent=QModelIndex()):
        return len(self._items)

    def data(self, index: QModelIndex, role=Qt.DisplayRole):
        i = index.row()

        if role == Qt.DisplayRole:
            return self._items.peekitem(i)[0]
        return None

    def headerData(self, section, orientation: Qt.Orientation, role=Qt.DisplayRole):
        if role == Qt.DisplayRole:
            if orientation == Qt.Vertical:
                return section
            return "Node toolbox"
        return None

    def addItem(self, name, item):
        i = self._items.bisect_right(name)

        self.beginInsertRows(QModelIndex(), i, i)
        self._items[name] = item
        self.endInsertRows()

    def removeItem(self, name):
        """Remove an item with a specified name from a toolbox.
        If an item with such a name does not exist, does nothing.
        """
        if name not in self._items:
            return None

        i = self._items.index(name)

        self.beginRemoveRows(QModelIndex(), i, i)
        item = self._items.pop(name)
        self.endRemoveRows()

        return item

    def flags(self, index: QModelIndex):
        default_flags = super().flags(index)

        if index.isValid():
            return default_flags | Qt.ItemIsDragEnabled
        return default_flags

    def mimeTypes(self):
        return [self.DragMimeType]

    def mimeData(self, indexes):
        assert len(indexes) == 1
        i = indexes[0].row()

        package = QMimeData()
        mime.dump(self._items.peekitem(i)[1], package, self.DragMimeType, hooks=hooks.qt)

        return package

    def schemeDropEvent(self, scheme, event):
        """Event to be executed when an item from this toolbox gets dropped into a scheme.
        This function can be added as a custom drop event for this toolbox's MIME type, which is usually done by the
        SchemeEditor.
        """
        package = event.mimeData()
        node = mime.load(package, self.DragMimeType, hooks=hooks.qt)

        pos = event.scenePos() - QPointF(
            node.boundingRect().size().width()/2,
            node.boundingRect().size().height()/2
        )
        node.setPos(pos)
        scheme.addItem(node)

    # Serialization ====================================================================================================
    def serialize(self) -> dict:
        return self._items

    @classmethod
    def deserialize(cls, data: dict):
        obj = cls()
        obj._items = data

        return obj


# ----------------------------------------------------------------------
# Name:        Find the Town Judge
# Author(s):   Trinity Nguyen
# ----------------------------------------------------------------------

"""
   In a town, there are N people labelled from 1 to N.
   There is a rumor that one of these people is secretly the town judge.

    If the town judge exists, then:

    The town judge trusts nobody.
        1. Everybody (except for the town judge) trusts the town judge.
        2. There is exactly one person that satisfies properties 1 and 2.
        3. You are given trust, an array of pairs trust[i] = [a, b]
        representing that the person labelled a trusts the person labelled b.

    If the town judge exists and can be identified, return the label of the town judge.
    Otherwise, return -1.

    Example 1:
    Input: N = 2, trust = [[1,2]]
    Output: 2

    Example 2:
    Input: N = 3, trust = [[1,3],[2,3]]
    Output: 3

    Example 3:
    Input: N = 3, trust = [[1,3],[2,3],[3,1]]
    Output: -1

    Example 4:
    Input: N = 3, trust = [[1,2],[2,3]]
    Output: -1

    Example 5:
    Input: N = 4, trust = [[1,3],[1,4],[2,3],[2,4],[4,3]]
    Output: 3

    Note:
    1 <= N <= 1000
    trust.length <= 10000
    trust[i] are all different
    trust[i][0] != trust[i][1]
    1 <= trust[i][0], trust[i][1] <= N

"""

class Solution:
    def findJudge(self, N: int, trust: List[List[int]]) -> int:
        if len(trust) < N - 1:
            return -1

        trusted_by = [0] * (N + 1)  # trusted by others
        trusters = [0] * (N + 1)   # trust others

        for a, b in trust:
            trusters[a] += 1
            trusted_by[b] += 1

        for i in range(1, N+1):
            if(trusted_by[i] == N-1 and trusters[i] == 0):
                return i

        return -1

    def findJudge2(self, N: int, trust: List[List[int]]) -> int:
        trusters = {x[0] for x in trust}
        trusted_by = 0
        candidate = -1
        for i in range(1, N+1):
            if i not in trusters:
                candidate = i

        for a, b in trust:
            if b == candidate:
                trusted_by += 1

        if trusted_by != N - 1:
            candidate = -1

        return candidate


with open("puzzle input 3") as file:
    data = [x for x in file.readlines()]

# Variablen und Listen
trees = 1
tree = 0
position = 0
pattern = [1, 3, 5, 7, 9]
right = 1
second = False

for p in pattern:
    if p != 9:
        right = p
        for x in data:
            if x[position % 31] == "#":
                tree += 1
            position += right
    else:
        for x in data:
            second = not second
            if second:
                if x[position % 31] == "#":
                    tree += 1
                position += right
    position = 0
    print("Bäume: ", tree)
    trees *= tree
    tree = 0
    right = 1
print("Bäume Produkt: ", trees)