clembot/exts/pkmn/pokemon.py
class PokemonXCache:

    _cache = {}
    _pkmn_map = {}
    __shared_state = {}

    def __init__(self):
        self.__dict__ = self.__shared_state

    @classmethod
    def cache_size(cls):
        return cls._cache.__len__()

    @classmethod
    def cache(cls):
        return cls._cache


    @classmethod
    def pokemon(cls, pokemon_id):
        return PokemonX.from_dict(cls._pkmn_map.get(pokemon_id, None))


    @classmethod
    def update_cache(cls, pokemon):

        pkmn_dict = pokemon.to_dict
        for alias in pokemon.alias:
            cls._cache[alias] = pkmn_dict

        cls._pkmn_map[pokemon.pokemon_id] = pkmn_dict



    @classmethod
    def load_cache(cls, list_of_pokemon_records):
        pokemon_form_master = {}
        pokemon_id_map = {}

        for record in list_of_pokemon_records:
            pokemon_id_map[record['pokemon_id']] = record
            for alias in record['pokeform_alias']:
                pokemon_form_master[alias] = record

        cls._cache = pokemon_form_master
        cls._pkmn_map = pokemon_id_map
        SpellHelper.set_dictionary(list(pokemon_form_master.keys()))

    @classmethod
    def to_pokemon(cls, text) -> PokemonX:
        if cls._cache.__len__() < 1:
            raise Exception("Error : Pokemon forms are not loaded.")

        if cls._cache.keys().__contains__(text.upper()):
            my_object = cls._cache.get(text.upper())
            return PokemonX.from_dict(my_object)

        return None

    @classmethod
    async def load_cache_from_dbi(cls, dbi, force_reload = False):

        try:

            if cls._cache.__len__() > 0 and not force_reload:
                return

            result_record = await dbi.table('tbl_pokemon_master').query().select().getjson()

            PokemonCache.load_cache(result_record)

            Logger.info(f'{len(result_record)} Pokemon Form(s) Loaded from tbl_pokemon_master.')
            return result_record
        except Exception as error:
            Logger.error(f"{traceback.format_exc()}")
            raise Exception("Couldn't load pokemon forms from DB due to error " + str(error))

    @classmethod
    async def update_pokemon(cls, local_dbi, pokemon_id, data):

        if local_dbi:
            tbl_pokemon_master = local_dbi.table('tbl_pokemon_master')
            existing_pokemon_record = await tbl_pokemon_master.query().select().where(pokemon_id=pokemon_id).get_first()

            if existing_pokemon_record:
                print(f"updating {pokemon_id} with {data}")
                update_query = tbl_pokemon_master.update(**data).where(pokemon_id=pokemon_id)
                await update_query.commit()
            else:
                insert_query = tbl_pokemon_master.insert(**data)
                await insert_query.commit()

    @classmethod
    async def create_emoji(cls, ctx, local_dbi, pokemon_id):

        pokemon = PokemonCache.pokemon(pokemon_id)

        script_path = os.path.dirname(os.path.realpath(__file__))
        dir_path = os.path.join(script_path)
        folder_path = os.path.join(script_path, "../../../images/pkmn")

        print(folder_path)

        file_path = f"{folder_path}/{pokemon_id.upper()}.png"


        if pokemon and pokemon.emoji:
            return pokemon.emoji


        print(file_path)
        emoji = '<:unknown_encounter:629202330419724288>'


        try:
            with open(file_path, "rb") as image:
                f = image.read()
                image = bytearray(f)

            emoji = await ctx.channel.guild.create_custom_emoji(name=pokemon_id, image=image)

            pokemon.emoji = str(emoji)
            await PokemonCache.update_pokemon(local_dbi, pokemon_id, pokemon.to_dict)
            PokemonCache.update_cache(pokemon)

        except Exception as error:
            Logger.error(f"{traceback.format_exc()}")
            raise Exception(error)



        return emoji
clembot/core/checks.py
class AccessDenied(CommandError):
async def _check_is_owner(ctx):
async def _check_is_trusted(ctx):
async def _check_is_guild_owner(ctx):
async def _check_is_guild_admin(ctx):
async def _check_is_moderator(ctx):
async def check_is_owner(ctx):
async def check_is_trusted(ctx):
async def check_is_guild_owner(ctx):
async def check_is_guild_admin(ctx):
async def check_is_moderator(ctx):
def go_thru_sometimes():
def is_bot_owner():
def is_trusted():
def is_guild_owner():
def is_guild_admin():
def is_guild_mod():
clembot/exts/draft/draft.py
class Draft:

    sample_draft_master = {

        "properties": {
            "code": "",
            "channel_id": -1,
            "guild_id": -1
        },
        "configuration": {
            "admin": [],
            "status": DraftStatus.CREATED,
            "number_of_players": 0,
            "max_number_of_players": 16,
            "draft_team_size": 6,
            "total_drafted_slots": 0,
            "current_drafted_slots": 0,
            "current_player_index": 0,
        },

        "player_list": [
        ],

        "player_draft_order": [
        ],

        "choices": {
            "available": [],
            "drafted": [],
            "excluded": []
        },

        "player_selection": {

        },

        "player_selections": {
            # "drafted": {},
            # "auto_draft_options": {},
            # "enable_auto_draft": False
        },
    }

    def __init__(self, data_dict=None, guild_id=None, channel_id=None):
        if data_dict:
            self.draft_content = json.loads(data_dict['draft_content'])

            new_player_selection = {}
            new_player_selections = {}
            for key, value in self.player_selection.items():
                new_player_selection[int(key)] = value

            for key, value in self.player_selections.items():
                new_player_selections[int(key)] = value

            self.player_selection = new_player_selection
            self.player_selections = new_player_selections

        else:
            self.reset(guild_id, channel_id)

    def __str__(self):
        return self.draft_code
        # return json.dumps(self.draft_content)


    def set_auto_draft(self, player_id, draft: bool):
        self.player_selections.setdefault(player_id, {})['enable_auto_draft'] = draft

    def get_auto_draft(self, player_id):
        return self.player_selections.setdefault(player_id, {}).get('enable_auto_draft', False)


    def get_player_auto_draft_selection(self, player_id):
        return self.player_selections.get(player_id, {}).get('auto_draft_options', [])

    def set_player_auto_draft_selection(self, player_id, list_of_pokemon):
        self.player_selections.setdefault(player_id, {})['auto_draft_options'] = [pokemon for pokemon in list_of_pokemon if pokemon is not None]


    def add_to_player_auto_draft_selection(self, player_id, list_of_pokemon):
        new_list = list(self.get_player_auto_draft_selection(player_id))

        for pokemon in list_of_pokemon:
            if pokemon and pokemon.pokemon_id not in new_list:
                new_list.append(pokemon.pokemon_id)

        self.set_player_auto_draft_selection(player_id, new_list)

        return self.get_player_auto_draft_selection(player_id)

    def remove_from_player_auto_draft_selection(self, player_id, list_of_pokemon):
        new_list = list(self.get_player_auto_draft_selection(player_id))

        for pokemon in list_of_pokemon:
            if pokemon.pokemon_id in self.get_player_auto_draft_selection(player_id):
                new_list.remove(pokemon.pokemon_id)

        self.set_player_auto_draft_selection(player_id, new_list)

        return self.get_player_auto_draft_selection(player_id)

    @property
    def draft_code(self):
        return self.draft_content['properties']['code']

    @property
    def channel_id(self):
        return self.draft_content['properties']['channel_id']

    @property
    def guild_id(self):
        return self.draft_content['properties']['guild_id']

    @property
    def status(self):
        return self.draft_content['configuration']['status']

    @status.setter
    def status(self, draft_status):
        if draft_status == DraftStatus.DRAFT and not self.player_draft_order:
            self.player_draft_order = list(self.player_list)

        self.draft_content['configuration']['status'] = draft_status

    @property
    def number_of_players(self):
        return self.draft_content['configuration']['number_of_players']

    @property
    def max_number_of_players(self):
        return self.draft_content['configuration']['max_number_of_players']


    @property
    def embed_fields(self):

        embed_fields = {
            f"Status": self.status,
        }


        if DraftStatus.value(self.status) == DraftStatus.value(DraftStatus.SIGN_UP):
            players_mention = ""
            for player_id in self.player_list:
                players_mention = f"{players_mention} <@{player_id}>"
            embed_fields[f"Signed up Players ({self.number_of_players}/{self.max_number_of_players})"]=f"{players_mention}"

        elif DraftStatus.value(self.status) >= DraftStatus.value(DraftStatus.DRAFT):
            players_mention = ""
            for player_id in self.player_draft_order:
                players_mention = f"{players_mention} <@{player_id}> {':ballot_box_with_check:' if self.get_auto_draft(player_id) else ''}"

            embed_fields[f"Players (in draft order) [{self.number_of_players}/{self.max_number_of_players}]"] = f"{players_mention}"

        if DraftStatus.value(self.status) >= DraftStatus.value(DraftStatus.DRAFT):
            embed_fields_title = "Teams"

            for part_player_id_list in chunks(list(self.draft_content['player_selection'].keys()), 2):
                player_line = ""

                for player_id in part_player_id_list:

                    player_mention = f"<@{player_id}>"
                    current_player_selection = self.player_selection[player_id]
                    print([get_emoji(pokemon_id) for pokemon_id in current_player_selection])

                    player_selection = f"{(', '.join([get_emoji(pokemon_id) for pokemon_id in current_player_selection]))}"

                    player_line = f"{player_line}\n{player_mention} - {player_selection}"

                embed_fields[f"{embed_fields_title}"] = f"{player_line}"
                embed_fields_title = f"--" if embed_fields_title == "Teams" else f"{embed_fields_title}-"

            pokemon_mention = ""
            for pokemon in self.draft_content['choices']['drafted']:
                pokemon_mention = f"{pokemon_mention}{Pokemon.to_pokemon(pokemon)}, "

        if DraftStatus.value(self.status) == DraftStatus.value(DraftStatus.DRAFT):
            embed_fields[f"Next to pick:"] = f"<@{self.current_player}>"



        return embed_fields

    @property
    def player_draft_order_mentions(self):

        players_mention = ""
        for player_id in self.player_draft_order:
            players_mention = f"{players_mention} <@{player_id}>"
        return f"{players_mention}"

    @property
    def player_list(self):
        return self.draft_content.get('player_list')

    @player_list.setter
    def player_list(self, player_list):
        self.draft_content['player_list'] = player_list

    @property
    def player_draft_order(self):
        return self.draft_content.get('player_draft_order')

    @player_draft_order.setter
    def player_draft_order(self, player_draft_order):
        self.draft_content['player_draft_order'] = player_draft_order


    @property
    def configuration(self):
        return self.draft_content['configuration']

    @property
    def total_drafted_slots(self):
        return self.configuration['total_drafted_slots']

    @total_drafted_slots.setter
    def total_drafted_slots(self, total_drafted_slots):
        self.configuration['total_drafted_slots'] = total_drafted_slots

    @property
    def current_drafted_slots(self):
        return self.configuration['current_drafted_slots']

    @current_drafted_slots.setter
    def current_drafted_slots(self, current_drafted_slots):
        self.configuration['current_drafted_slots'] = current_drafted_slots



    @property
    def admin(self):
        return self.configuration['admin']

    @admin.setter
    def admin(self, admin_list):
        self.configuration['admin'] = admin_list


    @property
    def draft_team_size(self):
        return self.configuration['draft_team_size']

    @property
    def current_player_index(self):
        return self.configuration['current_player_index']

    @current_player_index.setter
    def current_player_index(self, current_player_index):
        self.configuration['current_player_index'] = current_player_index

    @property
    def next_player_index(self):

        size_of_team = self.number_of_players
        players_already_drafted = self.current_drafted_slots
        current_player_index = self.current_player_index

        direction = 0
        next_index = players_already_drafted % size_of_team
        if (players_already_drafted % (size_of_team * 2)) > size_of_team - 1:
            direction = 1
            next_index = size_of_team - next_index - 1

        return next_index

    @property
    def current_player(self):
        return self.player_draft_order[self.current_player_index]


    @property
    def admin_mention(self):
        players_mention = ""
        for player_id in self.admin:
            players_mention = f"{players_mention} <@{player_id}>"
        return players_mention

    def draft_content(self):
        return self.draft_content

    def add_player(self, player: discord.Member):

        if self.status != DraftStatus.SIGN_UP:
            raise Exception("Draft should be in SIGN_UP stage for adding players to draft.")

        if self.is_player_exists(player):
            return False

        self.player_list.append(player.id)
        self.draft_content['configuration']['number_of_players'] = self.number_of_players + 1
        self.total_drafted_slots = 6 * self.number_of_players
        if self.current_player_index == -1:
            self.current_player_index = 0

        return True

    def is_player_exists(self, player: discord.Member):
        return self.draft_content.get('player_list').__contains__(player.id)

    def remove_player(self, player: discord.Member):
        self.draft_content.get('player_list').remove(player.id)

    def reset(self, guild_id, channel_id):
        self.draft_content = self.sample_draft_master
        draft_code = CUIDGenerator.cuid(channel_id)
        self.draft_content["properties"] = {
            "code": draft_code,
            "guild_id": guild_id,
            "channel_id": channel_id,
        }

    def shuffle_player_list(self):
        if self.status != DraftStatus.SIGN_UP:
            raise Exception("Draft should be in SIGN_UP stage for shuffling players.")

        player_draft_order = list(self.player_list)

        print(player_draft_order)
        random.shuffle(player_draft_order)
        print(player_draft_order)

        self.player_draft_order = player_draft_order


    def draft_pokemon(self, player: discord.Member, pokemon: Pokemon):

        if 0 < self.current_drafted_slots >= self.total_drafted_slots:
            raise Exception(f"A team of {self.draft_team_size} has been drafted for everyone.")

        if self.status != DraftStatus.DRAFT:
            raise Exception("Draft should be in DRAFT stage before you can draft pokemon.")

        if player.id not in self.player_list:
            raise Exception(f"{player.mention} is not added to the draft yet!")

        if self.current_player != player.id:
            raise Exception(f"It's not {player.mention}'s turn yet to draft.")

        pokemon_id = pokemon.pokemon_id
        if pokemon_id in self.drafted or pokemon_id in self.excluded:
            raise Exception(f"Pokemon {pokemon} is already drafted (or excluded)!")

        self.player_selection.setdefault(player.id, []).append(pokemon.pokemon_id)
        self.add_as_drafted(pokemon)
        self.current_drafted_slots = self.current_drafted_slots + 1
        if self.complete:
            self.status = DraftStatus.COMPLETE

        self.current_player_index = self.next_player_index


    @property
    def complete(self):
        if self.current_drafted_slots >= self.total_drafted_slots:
            return True
        return False


    @property
    def player_selections(self):
        self.draft_content.setdefault('player_selections',{})
        return self.draft_content['player_selections']

    @player_selections.setter
    def player_selections(self, player_selections_dict):
        self.draft_content['player_selections'] = player_selections_dict

    @property
    def player_selection(self):
        return self.draft_content['player_selection']

    @player_selection.setter
    def player_selection(self, player_selection_dict):
        self.draft_content['player_selection'] = player_selection_dict


    @property
    def choices(self):
        return self.draft_content['choices']

    @property
    def available(self):
        return self.choices['available']

    @property
    def drafted(self):
        return self.choices['drafted']

    @drafted.setter
    def drafted(self, drafted_list):
        self.choices['drafted'] = drafted_list

    @property
    def excluded(self):
        return self.choices['excluded']

    @excluded.setter
    def excluded(self, excluded_list):
        self.choices['excluded'] = excluded_list

    def add_as_excluded(self, excluded_pokemon: Pokemon):
        self.choices.setdefault('excluded', []).append(excluded_pokemon.pokemon_id)

    def add_as_drafted(self, drafted_pokemon: Pokemon):
        self.choices.setdefault('drafted', []).append(drafted_pokemon.pokemon_id)


    def reset_teams(self):
        self.player_selection = {}
        self.current_drafted_slots = 0
        self.current_player_index = self.next_player_index
        self.drafted = []
clembot/core/bot.py
def group(*args, **kwargs):
    def decorator(func):
        category = kwargs.get("category")
        func.command_category = category
        examples = kwargs.get("examples")
        func.examples = examples
        error_wrapped_func = wrap_error(func)
        result = commands.group(*args, **kwargs)(error_wrapped_func)
        return result
    return decorator
clembot/exts/pkmn/pokemon.py
class OptionalPokemonXConverter(commands.Converter):

    async def convert(self, ctx, argument) -> PokemonX:

        pokemon_form = Pokemon.to_pokemon(argument.upper())
        if pokemon_form:
            return pokemon_form
        else:
            possible_pokemon_form = await PokemonXConverter.auto_correct(ctx, argument.upper())
            if possible_pokemon_form:
                pokemon_form = Pokemon.to_pokemon(possible_pokemon_form)
                return pokemon_form

        return None

    @staticmethod
    def remove_empty_members(list_of_elements):

        new_list = [element for element in list_of_elements if element is not None]
        return new_list
clembot/core/bot.py
def command(*args, **kwargs):
    def decorator(func):
        category = kwargs.get("category")
        examples = kwargs.get("examples")
        func.command_category = category
        func.examples = examples
        error_wrapped_func = wrap_error(func)
        result = commands.command(*args, **kwargs)(error_wrapped_func)
        return result
    return decorator
clembot/exts/pkmn/gm_pokemon.py
class Pokemon:

    _cache = dict()

    def __init__(self, db_dict, pokedex_num, aliases=[], pokemon_form_id=None):
        self.db_dict = db_dict
        self.pokedex_num = pokedex_num
        self.aliases = aliases
        self.pokemon_form_id = pokemon_form_id

    def __getitem__(self, item):
        """use [] operator to access members, simpler to create entity objects"""
        return self.db_dict.get(item)


    def __setitem__(self, key, value):
        """use [] operator to access members, simpler to create entity objects. Handles array kind of values."""
        self.db_dict[key] = value


    def __repr__(self):
        return self.label

    @property
    def id(self):
        return self.aliases[0] if self.aliases else None

    @property
    def label(self):
        return self.id.title()

    # @property
    # def label(self):
    #     if self.pokeform_display_text:
    #         return self.pokeform_display_text.capitalize()
    #     return None


    @property
    def form(self):
        form = _.get(self.db_dict, 'pokemonId')
        if '_ALOLA' in form:
            form = form.replace('_ALOLA','_ALOLA_FORM')
        return form

    @property
    def base_attack(self):
        return _.get(self.db_dict, 'stats.baseAttack')

    @property
    def base_defense(self):
        return _.get(self.db_dict, 'stats.baseDefense')

    @property
    def base_stamina(self):
        return _.get(self.db_dict, 'stats.baseStamina')

    @property
    def fast_moves(self):
        return list(map(lambda move: move.replace("_FAST", ""), _.get(self.db_dict, 'quickMoves')))

    @property
    def fast_moves_labels(self):
        return list(map(lambda move: move.replace("_"," ").title() , self.fast_moves))

    @property
    def charge_moves(self):
        return list(map(lambda move: move, _.get(self.db_dict, 'cinematicMoves')))

    @property
    def charge_moves_labels(self):
        return list(map(lambda move: move.replace("_"," ").title() , self.charge_moves))


    @property
    def type1(self):
        type1 = _.get(self.db_dict, 'type')
        if type1:
            return type1.replace("POKEMON_TYPE_","").upper()
        return None

    @property
    def type2(self):
        type2 = _.get(self.db_dict, 'type2')
        if type2:
            return type2.replace("POKEMON_TYPE_", "").upper()
        return None

    @property
    def types(self):
        if self.type2:
            return [self.type1, self.type2]
        return [self.type1]

    @property
    def type1_icon(self):
        if self.type1:
            key = self.type1.lower()
            return config_template.type_emoji[key]
        return None

    @property
    def type2_icon(self):
        if self.type2:
            key = self.type2.lower()
            return config_template.type_emoji[key]
        return None

    @property
    def shiny(self):
        return False

    def _gender_type(self):
        return 'X'

    @property
    def gender(self):
        return 'MALE'


    @property
    def extended_label(self):
        """returns pokemon(pokedex) type1 type2"""
        extended_label=f"{self.label} ({self.pokedex_num}) {self.type1_icon}"
        if self.type2_icon:
            extended_label=f"{extended_label}{self.type2_icon}"
        return extended_label

    @property
    def preview_url(self):
        url = "https://raw.githubusercontent.com/TrainingB/Clembot/v2-rewrite/images/pkmn/"
        if self.form:
            url += str(self.form)
        if self.shiny:
            url += '_SHINY'
        if self._gender_type() == 'DIMORPH' and self.gender:
            url += f'_{self.gender.upper()}'
        url += '.png'
        # url += '?cache=5'
        return url

    # async def color(self):
    #     url = await self.sprite_url()
    #     color = await formatters.url_color(url)
    #     return color

    @property
    def raid_cp_range(self):
        low_cp = self.calculate_cp(20, 10, 10, 10)
        high_cp = self.calculate_cp(20, 15, 15, 15)
        return [low_cp, high_cp]


    def calculate_cp(self, level, attiv, defiv, staiv):
        if None in [level, attiv, defiv, staiv]:
            return None
        else:
            cpm = CPCalculator().cpM[level]
            att = (self.base_attack + attiv)*cpm
            defense = (self.base_defense + defiv)*cpm
            sta = (self.base_stamina + staiv)*cpm
            cp = math.floor((att*defense**0.5*sta**0.5)/10)
            if cp < 10:
                cp = 10
            return cp

    @classmethod
    def cache(cls, form):
        Pokemon._cache[form.aliases[0]] = form

    @classmethod
    def to_pokemon(cls, search_for):
        if len(cls._cache) < 1:
            raise Exception("Error : Pokemon forms are not loaded yet.")

        if search_for:
            return cls._cache.get(search_for.upper(), None)

        return None

    @classmethod
    async def load(cls, bot):

        if len(Pokemon._cache) == 0:
            table = bot.dbi.table('PB_POKEMON_FORM')
            forms = await table.query().select().getjson()

            for form in forms:
                pForm = Pokemon(json.loads(form.get('data')), form.get('pokedex_id'), form.get('aliases'), form.get('pokemon_form_id'))
                Pokemon.cache(pForm)
        GMPokemonFormSpellHelper.set_dictionary(cls._cache.keys())

    @classmethod
    async def convert(cls, ctx, argument) :

        await cls.load(ctx.bot)

        pokemon_form = cls.to_pokemon(argument.upper())
        if pokemon_form:
            return pokemon_form
        else:
            possible_pokemon_form = await Pokemon.auto_correct(ctx, argument.upper())
            if possible_pokemon_form:
                pokemon_form = cls.to_pokemon(possible_pokemon_form)
                return pokemon_form

        raise BadArgument(f"{argument} could not be resolved to a pokemon.")

    @staticmethod
    async def auto_correct(ctx, pokemon_as_text):

        not_acceptable_message = f"**{pokemon_as_text}** isn't a Pokemon!"

        suggestion = GMPokemonFormSpellHelper.correction(pokemon_as_text)

        if suggestion and suggestion != pokemon_as_text:

            not_acceptable_message += f" Did you mean **{suggestion}**?"
            replace_pokemon = await Utilities.ask_confirmation(ctx, ctx.message, not_acceptable_message, "Alright!", "That's okay!", "Timed Out!")
            if replace_pokemon:
                return suggestion

        return None





    @property
    def weaknesses(self):
        """
        Given a Pokemon name, return a list of its weaknesses as defined in the type chart
        Calculate sum of its weaknesses and resistances.
        -2 == immune , -1 == NVE, 0 == neutral, 1 == SE, 2 == double SE
        """
        type_eff = {}
        for p_type in self.types:
            for atk_type in _TYPE_CHART[p_type]:
                if atk_type not in type_eff:
                    type_eff[atk_type] = 0
                type_eff[atk_type] += _TYPE_CHART[p_type][atk_type]

        # Summarize into a list of weaknesses,
        # sorting double weaknesses to the front and marking them with 'x2'.
        ret = []
        for p_type, effectiveness in sorted(type_eff.items(), key=lambda x: x[1], reverse=True):
            if effectiveness == 1:
                ret.append(p_type.lower())
            elif effectiveness == 2:
                ret.append(p_type.lower() + "x2")

        return ret


    @property
    def weaknesses_icon(self):
        """
        Given a list of weaknesses, return a space-separated string of their type IDs as defined in the type_id_dict
        """
        ret = ""
        for weakness in self.weaknesses:
            # Handle an "x2" postfix defining a double weakness
            x2 = ""
            if weakness[-2:] == "x2":
                weakness = weakness[:-2]
                x2 = "x2"

            # Append to string
            ret += config_template.type_emoji[weakness] + x2 + " "

        return ret
clembot/exts/draft/draft.py
class DraftStatus:

    status_by_rank = ['CREATED', 'SIGN_UP', 'DRAFT', 'COMPLETE']

    CREATED, SIGN_UP, DRAFT, COMPLETE = status_by_rank

    @classmethod
    def value(cls, status):
        return cls.status_by_rank.index(status)
clembot/utilities/utils/utilities.py
class Utilities:

    numbers = {"0": ":zero:", "1": ":one:", "2": ":two:", "3": ":three:", "4": ":four:", "5": ":five:", "6": ":six:", "7": ":seven:", "8": ":eight:", "9": ":nine:"}

    @staticmethod
    def trim_to(text, length, delimiter=","):
        if len(text) == 0:
            return "None"
        if text and delimiter:
            return text[:text.rfind(delimiter, 0, length)] + " ** and more.**" if len(text) > length else text
        return text

    @staticmethod
    def emojify_numbers(number):
        number_emoji = ""

        reverse = "".join(reversed(str(number)))

        for digit in reverse[::-1]:

            emoji = Utilities.numbers.get(digit)
            if not emoji:
                emoji = ":regional_indicator_" + digit.lower() + ":"

            number_emoji = number_emoji + emoji

        return number_emoji

    @staticmethod
    def _normalize(emoji):
        initial_emoji = emoji
        if isinstance(emoji, discord.Reaction):
            emoji = emoji.emoji

        if isinstance(emoji, discord.Emoji):
            emoji = ':%s:%s' % (emoji.name, emoji.id)

        elif isinstance(emoji, discord.PartialEmoji):
            emoji = emoji._as_reaction()
        elif isinstance(emoji, str):
            pass

        if emoji.count(':') == 1 and not emoji.startswith(':'):
            emoji = f":{emoji}"

        if emoji.__contains__(">") and emoji.__contains__("<"):
            emoji = emoji.replace('<','').replace('>','')
        return emoji


    @staticmethod
    def _demojify(emoji):
        # convert emoji to id
        if isinstance(emoji, discord.Reaction):
            emoji = emoji.emoji.id

        if isinstance(emoji, discord.Emoji):
            emoji = emoji.id
        elif isinstance(emoji, discord.PartialEmoji):
            emoji = emoji.id if emoji.id else emoji.name
        elif isinstance(emoji, str):
            pass

        return emoji

    @staticmethod
    def _emojify(emoji):
        if emoji.__contains__(">") and emoji.__contains__("<"):
            emoji = emoji.replace('<', '').replace('>', '')
        return emoji

    @staticmethod
    def _uuid(cls, id):
        try:
            return '%x' % (hash(id) % 10 ** 8)
        except Exception as error:
            Logger.error(error)
            return id

    @staticmethod
    async def _send_error_message(channel, description, user=None):

        color = discord.Colour.red()
        user_mention = ""
        if user:
            user_mention = f"Beep Beep! **{user.display_name}** "
        error_embed = discord.Embed(description=f"{user_mention}{description}", colour=color)
        return await channel.send(embed=error_embed)

    @staticmethod
    async def message(destination, description, user=None):

        color = discord.Colour.green()
        user_mention = ""
        if user:
            user_mention = f"Beep Beep! **{user.display_name}** "
        error_embed = discord.Embed(description=f"{user_mention}{description}", colour=color)
        return await destination.send(embed=error_embed)

    @staticmethod
    async def message_as_text(channel, description):
        return await channel.send(description)

    @staticmethod
    async def error(channel, description, user=None):

        color = discord.Colour.red()
        user_mention = ""
        if user:
            user_mention = f"Beep Beep! **{user.display_name}** "
        error_message = f"{user_mention}{description}"
        error_embed = discord.Embed(description=f"{error_message}", colour=color)
        Logger.error(error_message)
        return await channel.send(embed=error_embed)

    @staticmethod
    async def _send_message(channel, description, title=None, footer=None, user=None):
        try:

            error_message = "The output contains more than 2000 characters."

            user_mention = ""
            if user:
                user_mention = f"Beep Beep! **{user.display_name}** "

            if len(description) >= 2000:
                discord.Embed(description="{0}".format(error_message))

            color = discord.Colour.green()
            message_embed = discord.Embed(description=f"{user_mention}{description}", colour=color, title=title)
            if footer:
                message_embed.set_footer(text=footer)
            return await channel.send(embed=message_embed)
        except Exception as error:
            Logger.error(error)

    @staticmethod
    async def _send_embed(channel, description=None, title=None, additional_fields={}, footer=None):

        embed = discord.Embed(description=description, colour=discord.Colour.gold(), title=title)

        for label, value in additional_fields.items():
            if value:
                embed.add_field(name="**{0}**".format(label), value=value, inline=False)

        if footer:
            embed.set_footer(text=footer)

        try:
            return await channel.send(embed=embed)
        except Exception as error:
            return await channel.send(error)

    @command(name="export")
    async def _export(self, ctx):

        return await self._send_message(ctx.channel, "Beep Beep! **{}**, This feature is under-development!".format(ctx.message.author.display_name))

        Logger.error("_export() called!")

        raid_dict = ctx.bot.guild_dict[ctx.guild.id]['raidchannel_dict'][ctx.channel.id]

        channel_mentions = ctx.message.raw_channel_mentions

        if len(channel_mentions) < 1:
            await self._send_error_message(ctx.channel, "Beep Beep! **{}**, Please provide the channel reference to export the details!".format(ctx.message.author.display_name))

    @command(name="clean_content")
    async def _clean_content(self, message):

        message_content = {}
        content_without_mentions = message.content

        for mention in message.mentions:
            mention_text = mention.mention.replace("!", "")
            content_without_mentions = content_without_mentions.replace("<@!", "<@").replace(mention_text, '')

        # remove extra spaces
        message_content['content_without_mentions'] = re.sub(' +', ' ', content_without_mentions)

        return message_content

    @staticmethod
    def get_help_embed(description, usage, available_value_title, available_values, mode="message"):

        if mode == "message":
            color = discord.Colour.green()
        else:
            color = discord.Colour.red()

        help_embed = discord.Embed( description="**{0}**".format(description), colour=color)

        help_embed.add_field(name="**Usage :**", value = "**{0}**".format(usage))
        help_embed.add_field(name="**{0} :**".format(available_value_title), value=_("**{0}**".format(", ".join(available_values))), inline=False)

        return help_embed

    @staticmethod
    async def _send_error_message_and_cleanup(channel, message, user):
        log_message = await Embeds.error(channel, message, user=user)
        await asyncio.sleep(8)
        await log_message.delete()


    @staticmethod
    async def get_image_embed(channel, image_url):
        embed = discord.Embed(colour=channel.guild.me.colour)
        embed.set_thumbnail(url=image_url)
        return await channel.send(embed=embed)

    @staticmethod
    async def ask(message, destination, user_list=None, *, react_list=['✅', '❎']):
        if user_list and type(user_list) != __builtins__.list:
            user_list = [user_list]


        def check(reaction, user):
            if user_list and type(user_list) is __builtins__.list:
                return (user.id in user_list) and (reaction.message.id == message.id) and (reaction.emoji in react_list)
            elif not user_list:
                return (user.id != message.guild.me.id) and (reaction.message.id == message.id) and (reaction.emoji in react_list)


        for r in react_list:
            await asyncio.sleep(0.25)
            await message.add_reaction(r)
        try:
            reaction, user = await Clembot.wait_for('reaction_add', check=check, timeout=60)
            return reaction, user
        except asyncio.TimeoutError:
            await message.clear_reactions()
            return


    @staticmethod
    @wrap_error
    async def ask_confirmation(ctx, message, rusure_message, yes_message, no_message, timed_out_message):
        author = message.author
        channel = message.channel

        reaction_list = ['✅', '❎']
        # reaction_list = ['❔', '✅', '❎']

        rusure = await ctx.channel.send(f"Beep Beep! {rusure_message}")
        await rusure.add_reaction( "✅")  # checkmark
        await rusure.add_reaction( "❎")  # cross

        def check(react, user):
            if user.id != author.id:
                return False
            return True

        # res = await Clembot.wait_for_reaction(reaction_list, message=rusure, check=check, timeout=60)
        try:
            reaction, user = await ctx.bot.wait_for('reaction_add', check=check, timeout=10)
        except asyncio.TimeoutError:
            await rusure.delete()
            confirmation = await channel.send(f"Beep Beep! {timed_out_message}")
            await asyncio.sleep(1)
            await confirmation.delete()
            return False

        if reaction.emoji == "❎":
            await rusure.delete()
            confirmation = await channel.send(f"Beep Beep! {no_message}")
            await asyncio.sleep(1)
            await confirmation.delete()
            return False
        elif reaction.emoji == "✅":
            await rusure.delete()
            confirmation = await channel.send(f"Beep Beep! {yes_message}")
            await asyncio.sleep(1)
            await confirmation.delete()
            return True


    @staticmethod
    @wrap_error
    async def ask_via_reactions(ctx, message, question_message, accepted_message, rejected_message, timed_out_message, reaction_dict, error_response):
        author = message.author
        channel = message.channel

        rusure = await ctx.channel.send(f"{question_message}")

        for r in reaction_dict.keys():
            await rusure.add_reaction(r)

        def check(react, user):
            if user.id != author.id:
                return False
            return True

        try:
            reaction, user = await ctx.bot.wait_for('reaction_add', check=check, timeout=10)
        except asyncio.TimeoutError:
            await rusure.delete()
            confirmation = await channel.send(f"{timed_out_message}")
            await asyncio.sleep(1)
            await confirmation.delete()
            return error_response

        if reaction.emoji not in reaction_dict.keys():
            await rusure.delete()
            confirmation = await channel.send(f"{rejected_message}")
            await asyncio.sleep(1)
            await confirmation.delete()
            return error_response

        elif reaction.emoji in reaction_dict.keys():
            await rusure.delete()
            confirmation = await channel.send(f"{accepted_message}")
            await asyncio.sleep(1)
            await confirmation.delete()
            return reaction_dict.get(reaction.emoji, error_response)


    @staticmethod
    async def send_to_hastebin(destination, whatever):
        whatever = whatever.encode('ascii', errors='replace').decode('utf-8')
        print(whatever)
clembot/exts/draft/draft.py
class DraftInterface:

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

    async def load_draft_from_db(self):

        draft_master_query = self.dbi.table("draft_master").query().select('draft_content')

        record_list = await draft_master_query.getjson()

        return record_list




    async def find_draft(self, guild_id, channel_id):

        try:

            draft_master_query = self.dbi.table("draft_master").query().select('draft_content').where(guild_id=guild_id, channel_id=channel_id)

            existing_draft_master = await draft_master_query.getjson()

            if existing_draft_master:
                return Draft(existing_draft_master[0])

        except Exception as error:
            raise Exception("No draft found.")


    async def find_draft_code(self, draft_code=None):

        try:
            draft_master_query = self.dbi.table("draft_master").query().select('draft_content').where(draft_code=draft_code)

            existing_draft_master = await draft_master_query.getjson()

            return existing_draft_master


        except Exception as error:
            Logger.error(f"{traceback.format_exc()}")


    async def update_draft(self, draft: Draft):

        try:

            tbl_draft_master = self.dbi.table('draft_master')

            existing_draft_master_record = await tbl_draft_master.query().select().where(
                draft_code=draft.draft_code).get_first()

            if existing_draft_master_record:
                update_query = tbl_draft_master.update(draft_content=json.dumps(draft.draft_content)).where(
                    draft_id=existing_draft_master_record["draft_id"])
                await update_query.commit()

        except Exception as error:
            Logger.error(f"{traceback.format_exc()}")


    async def save_draft(self, draft: Draft):

        try:
            draft_master_record = dict(
                guild_id=draft.guild_id,
                channel_id=draft.channel_id,
                draft_code=draft.draft_code,
                draft_content=json.dumps(draft.draft_content)
            )
            tbl_draft_master = self.dbi.table('draft_master')

            existing_draft_master_record = await tbl_draft_master.query().select().where(guild_id=draft.guild_id,
                                                                                         channel_id=draft.channel_id).get_first()

            if existing_draft_master_record:
                update_query = tbl_draft_master.update(draft_content=json.dumps(draft.draft_content)).where(
                    draft_id=existing_draft_master_record["draft_id"])
                await update_query.commit()
            else:
                insert_query = tbl_draft_master.insert(**draft_master_record)
                await insert_query.commit()

            print(f"{draft} is saved successfully!")
        except Exception as error:
            Logger.error(f"{traceback.format_exc()}")
clembot/core/commands.py
class Cog(Cog):


    pass
clembot/core/logs.py
def init_loggers():


Question: import json
import traceback
import discord
from discord.ext import commands
from discord.ext.commands import UserConverter
from clembot.core import checks
from clembot.core.bot import group, command
from clembot.core.commands import Cog
from clembot.core.logs import Logger
from clembot.exts.draft.draft import DraftStatus, Draft, DraftInterface
from clembot.exts.pkmn.gm_pokemon import Pokemon
from clembot.exts.pkmn.pokemon import OptionalPokemonXConverter, PokemonXCache
from clembot.utilities.utils.utilities import Utilities
    @checks.is_guild_owner()
    async def _draft_check(self, ctx, text):

        try:

            pokemon = await Pokemon.convert(text, ctx, text)

            if pokemon:
                await Utilities.message(ctx.channel, f"{pokemon} details {pokemon.to_dict}")

        except Exception as error:
            await Utilities.error(ctx.channel, error)



    @_draft.command(aliases=["create", "new"], pass_context=True)
    @checks.is_guild_owner()
    async def _draft_create(self, ctx, draft_channel: discord.TextChannel = None):

        if draft_channel is None:
            draft_channel = ctx.channel

        draft = await self.draft_interface.find_draft(guild_id=ctx.guild.id, channel_id=draft_channel.id)
        if draft:
            return await Utilities.message(ctx.message.channel, f"A draft already exists for {draft_channel.mention} with code **{draft.draft_code}**")


        draft = Draft(guild_id=ctx.guild.id, channel_id=draft_channel.id)
        await self.draft_interface.save_draft(draft)

        return await Utilities.message(ctx.message.channel, f"A new draft can be managed in {draft_channel.mention} with code **{draft.draft_code}**")


    @_draft.command(aliases=["info"], pass_context=True)
    async def _draft_info(self, ctx):
        try:
            draft = await self.fetch_draft_for_channel(ctx.guild.id, ctx.channel.id)
            if draft:
                print(draft.draft_content)
                return await Utilities._send_embed(ctx.channel, "", f"**Draft [{draft.draft_code}] - {draft.status} **", draft.embed_fields, footer=f"Managed by : {draft.draft_code} | check mark - Auto draft enabled!")
            else:
                return await Utilities.error(ctx.message.channel, f"No draft found for **{ctx.channel.mention}**")
        except Exception as error:
            Logger.error(f"{traceback.format_exc()}")
            return await Utilities.error(ctx.message.channel, f"{error}")


    @_draft.command(aliases=["reset"], pass_context=True)
    @checks.is_guild_owner()
    async def _draft_reset(self, ctx, mode=None):
        draft = await self.fetch_draft_for_channel(ctx.guild.id, ctx.channel.id)

        if mode == 'team':
            draft.reset_teams()
        else:
            draft.reset(ctx.guild.id, ctx.channel.id)

        await self.draft_interface.save_draft(draft)

        await Utilities.message(ctx.channel, f"Draft **{draft}** has been reset.")


    @_draft.command(aliases=["shuffle"], pass_context=True)
    @checks.is_guild_owner()
    async def _draft_shuffle(self, ctx):
        draft = await self.fetch_draft_for_channel(ctx.guild.id, ctx.channel.id)

        draft.shuffle_player_list()

        await self.draft_interface.save_draft(draft)

        await Utilities.message(ctx.channel, f"Current draft order is : {draft.player_draft_order_mentions}")

    @_draft.command(aliases=["add-player", "ap"], pass_context=True)
    @checks.is_guild_owner()
    async def _draft_add_player(self, ctx, *player_list: discord.Member):

        draft = await self.fetch_draft_for_channel(ctx.guild.id, ctx.channel.id)
        if DraftStatus.value(draft.status) >= DraftStatus.value(DraftStatus.DRAFT):
            return await Utilities.error(ctx.channel, f"Draft {draft} is in {draft.status} status. New players can not be added to the draft anymore.")


        for player in player_list:
            if draft.is_player_exists(player):
                await Utilities.error(ctx.channel, f"{player.mention} is already on the player list.")
                continue
            if draft.add_player(player):
                await Utilities.message(ctx.channel, f"**[{draft.number_of_players}/{draft.max_number_of_players}]** {player.mention} has been added to the draft.")
                await self.draft_interface.save_draft(draft)

        print(draft)


    @_draft.command(aliases=["join"], pass_context=True)
    async def _draft_join(self, ctx):

        draft = await self.fetch_draft_for_channel(ctx.guild.id, ctx.channel.id)
        if DraftStatus.value(draft.status) >= DraftStatus.value(DraftStatus.DRAFT):
            return await Utilities.error(ctx.channel, f"Draft {draft} is in {draft.status} status. New players can not be added to the draft anymore.")

        player = ctx.message.author
        if draft.is_player_exists(player):
            await Utilities.error(ctx.channel, f"{player.mention} you are already on the player list.")

        if draft.add_player(player):
            await Utilities.message(ctx.channel, f"**[{draft.number_of_players}/{draft.max_number_of_players}]** {player.mention} has been added to the draft.")
            await self.draft_interface.save_draft(draft)

        print(draft)







    @command(aliases=["dump-form"], pass_context=True)
    @commands.has_permissions(manage_guild=True)
    async def _dump_pokeform(self, ctx):


Answer:         await Utilities.send_to_hastebin(ctx.channel, json.dumps(PokemonXCache.cache()))