clembot/core/commands.py
class Cog(Cog):


    pass
clembot/config/constants.py
class MyEmojis:

    DESPAWNED = '💨'
    ON_MY_WAY = '🏎️'
    TRASH = '🗑️'

    REMOTE = f"{parse_emoji(None, config_template.misc_emoji.get('remote_raid'))}"
    INVITE = f"{parse_emoji(None, config_template.misc_emoji.get('add_friend'))}"
    HERE = f"{parse_emoji(None, config_template.misc_emoji.get('here'))}"
    COMING = f"{parse_emoji(None, config_template.misc_emoji.get('coming'))}"
    INTERESTED = f"{parse_emoji(None, config_template.misc_emoji.get('interested'))}"
    INFO = f"{parse_emoji(None, config_template.misc_emoji.get('info'))}"
    ERROR = f"{parse_emoji(None, config_template.misc_emoji.get('error'))}"
    POKE_BATTLER = f"{parse_emoji(None, config_template.misc_emoji.get('pb'))}"
clembot/exts/profile/user_guild_profile.py
class UserGuildProfile:

    TABLE_NAME = 'user_guild_profile'

    dict_fields = ['leaderboard_status']
    list_fields = ['badge_id']

    LEADERBOARD_STATS = ['wilds', 'raids', 'quests', 'eggs', 'nest', 'rocket']

    def __init__(self, bot, db_dict = dict()):
        self.bot = bot
        self.db_dict = {
            'user_id' : None,
            'guild_id' : None,
            'badge_id' :  [],
            'leaderboard_status' : {},
            'status' : None
        }
        self.db_dict.update(Serializer.deserialize(db_dict, dict_fields=UserGuildProfile.dict_fields))


    def __getitem__(self, item):
        return self.db_dict.get(item) or ([] if item in UserGuildProfile.list_fields else None) or ({} if item in UserGuildProfile.dict_fields else None)


    def __setitem__(self, key, value):
        """use [] operator to access members, simpler to create entity objects. Handles array kind of values."""
        if key in UserGuildProfile.list_fields:
            if self.db_dict[key] is None or value is None:
                self.db_dict[key] = []
            if value:
                self.db_dict[key].append(value)
        else:
            self.db_dict[key] = value


    @classmethod
    async def data(cls, bot, user_id, guild_id) -> dict():
        report_user_query = bot.dbi.table('user_metadata').query()
        _data = report_user_query.where(user_id=user_id, guild_id=guild_id)
        db_record = await _data.get()

        if db_record:
            user_metadata = UserGuildProfile.from_db_dict(bot, dict(db_record[0]))
        else:

            user_metadata = UserGuildProfile(bot, user_id, guild_id)
            await user_metadata.insert()

        return user_metadata


    @classmethod
    async def find(cls, bot, user_id, guild_id):
        table = bot.dbi.table(UserGuildProfile.TABLE_NAME)
        query = table.query().select().where(user_id=user_id, guild_id=guild_id)
        user_list = await query.getjson()
        if user_list:
            return cls(bot, user_list[0])
        else:
            await UserGuildProfile.create(bot, user_id, guild_id)
            query = table.query().select().where(user_id=user_id, guild_id=guild_id)
            user_list = await query.getjson()
            if user_list:
                return cls(bot, user_list[0])
        return None


    @classmethod
    async def create(cls, bot, user_id, guild_id):
        user_guild_profile = UserGuildProfile(bot, {'user_id': user_id, 'guild_id': guild_id})
        await user_guild_profile.insert()
        return user_guild_profile


    async def update(self):
        table = self.bot.dbi.table(UserGuildProfile.TABLE_NAME)
        update_dict=Serializer.serialize(self.db_dict)
        update_query = table.update(**update_dict).where(user_id=self['user_id'], guild_id=self['guild_id'])
        await update_query.commit()


    async def insert(self):
        table = self.bot.dbi.table(UserGuildProfile.TABLE_NAME)
        insert_dict=Serializer.serialize(self.db_dict)
        insert_query = table.insert(**insert_dict)
        await insert_query.commit()


    def record_report(self, stat_type, board_type='lifetime', increase_by=1, initialize=False):
        """
            record_report('eggs','lifetime') => increases by 1
            record_report('raids','lifetime', initialize=True) => set to 1
            record_report('wilds','lifetime', increase_by=0, initialize=True) => set to 0
            record_report('quests','lifetime', increase_by=12, initialize=True) => set to 12
        """
        if stat_type in UserGuildProfile.LEADERBOARD_STATS:
            current_stat = 0 if initialize else _.get(self.db_dict,f'leaderboard_status.{board_type}.{stat_type}', 0)
            self.db_dict.setdefault('leaderboard_status',{}).setdefault(board_type, {})[stat_type] = current_stat + increase_by


    def leaderboard_stats_dict(self, board_type):
        return _.get(self.db_dict, f'leaderboard_status.{board_type}')



    def leaderboard_status(self, board_type):
        status_dict = _.get(self.db_dict, f'leaderboard_status.{board_type}')

        wilds, raids, quests, eggs, nest, rocket = ([status_dict.get(stat, 0) for stat in UserGuildProfile.LEADERBOARD_STATS])

        status_text = f"Raids: **{raids}** | Eggs: **{eggs}** | Wilds: **{wilds}** | Research: **{quests}** | Nest: **{nest}** | Grunts: **{rocket}**"

        return status_text

    @property
    def user_id(self):
        return self['user_id']

    @classmethod
    async def find_top10_reporters(cls, bot, guild_id, leaderboard_type, stat_type):

        query = top_10_leaderboard_query
        query_args = [guild_id, f'{leaderboard_type}', f'{leaderboard_type}', None if stat_type == 'total' else stat_type , 10]
        user_rcrd_list = await bot.dbi.execute_query_json(query, *query_args)

        return user_rcrd_list
clembot/exts/gymmanager/gym.py
class POILocationConverter(commands.Converter):
    """
    !nest chimchar MESC
    !nest pikachu somewhere closer
    !nest aron some park http://google-url.com
    """

    @staticmethod
    async def convert_from_text(ctx, *argument) -> POILocation:

        try:
            if len(argument) == 1:
                city = await ctx.city()
                gym = await GymRepository(ctx.bot.dbi).to_gym_by_code_city(argument[0], city)
                if gym:
                    return POILocation.from_gym(gym)

            text = " ".join(argument)
            maps_link = TextUtil.extract_link_from_text(text)
            if maps_link:
                new_text = text.replace(maps_link, '')
                return POILocation.from_url( new_text if new_text.__len__() > 0 else "Click for directions", maps_link)

            return POILocation.from_location_city(text, "")

        except Exception as error:
            raise BadArgument(error)


    @staticmethod
    async def convert(ctx, argument) -> POILocation:
        try:
            city = await ctx.city()
            if city is None:
                city = await ctx.guild_profile(key='city')
            gym = await GymRepository(ctx.bot.dbi).to_gym_by_code_city(argument, city)

            if gym:
                return POILocation.from_gym(gym)
            else:
                return POILocation.from_location_city(argument, city)
        except Exception as error:
            raise BadArgument(error)

    @staticmethod
    def combine(location_list):

        location_text = []
        for rl in location_list:
            if rl.is_gym:
                return rl
            location_text.append(rl.location)

        return POILocation.from_location_city(" ".join(location_text), location_list[0].city)



    # @staticmethod
    # async def auto_correct(ctx, pokemon_as_text):
    #
    #     not_acceptable_message = f"**{pokemon_as_text}** isn't a Pokemon!"
    #
    #     spellcheck_suggestion = SpellHelper.correction(pokemon_as_text)
    #
    #     if spellcheck_suggestion and spellcheck_suggestion != pokemon_as_text:
    #
    #         not_acceptable_message += f" Did you mean **{spellcheck_suggestion}**?"
    #         replace_pokemon = await Utilities.ask_confirmation(ctx, ctx.message, not_acceptable_message, "Alright!", "That's okay!", "Timed Out!")
    #         if replace_pokemon:
    #             return spellcheck_suggestion
    #
    #     return None
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/core/logs.py
def init_loggers():
clembot/core/utils.py
async def notify_for(bot, guild, role_name):
    role = discord.utils.get(guild.roles, name=role_name.lower())
    if role:
        notify = await bot.data_manager.guild(guild.id).guild_profile('notifications')
        if notify == 'true':
            return role
    return None
clembot/exts/wild/wild.py
class Wild:
    by_id = dict()
    by_message = dict()

    def __init__(self, bot, wild_id, guild_id, reporter_id, pkmn: Pokemon, location: POILocation = None, timezone=None,
                 caught_by=None,
                 message_id=None, channel_id=None, reported_time=None, despawn_time=None):
        self.bot = bot
        self.wild_id = wild_id
        self.guild_id = guild_id
        self.reporter_id = reporter_id
        self.location = location
        self.pkmn = pkmn
        self.reported_time = TH.current_epoch(second_precision=True) if reported_time is None else reported_time
        self.despawn_time = self.reported_time + (config_template.development_timer or 30) * 60 if despawn_time is None else despawn_time
        self.message_id = message_id
        self.channel_id = channel_id
        self.caught_by = caught_by or []
        self.timezone = timezone
        self.monitor_task_tuple = None
        self.snowflake = Snowflake()

    def to_db_dict(self):
        state = {
            'wild_id': self.wild_id,
            'guild_id': self.guild_id,
            'reporter_id': self.reporter_id,
            'pokemon_id': self.pkmn.id,
            'location': json.dumps(self.location.to_dict()),
            'reported_time': self.reported_time,
            'despawn_time': self.despawn_time,
            'message_id': self.message_id,
            'channel_id': self.channel_id,
            'timezone': self.timezone
        }
        return state


    @classmethod
    async def from_db_dict(cls, bot, db_dict):

        wild_id, guild_id, reporter_id, pokemon_id, location, reported_time, despawn_time, message_id, channel_id, timezone = [
            db_dict.get(attr, None) for attr in
            ['wild_id', 'guild_id', 'reporter_id', 'pokemon_id', 'location', 'reported_time', 'despawn_time',
             'message_id',
             'channel_id', 'timezone']]

        pkmn = Pokemon.to_pokemon(pokemon_id) if pokemon_id else None
        wild_location = await POILocation.from_dict(bot, json.loads(location))

        wild = cls(bot, wild_id=wild_id, guild_id=guild_id, reporter_id=reporter_id,
                   pkmn=pkmn, location=wild_location, timezone=timezone,
                   message_id=message_id, channel_id=channel_id,
                   reported_time=reported_time, despawn_time=despawn_time)

        Wild.cache(wild)
        return wild


    def create_task_tuple(self, coro):
        task_id = CUIDGenerator.cuid(self.snowflake.next())
        return self.bot.loop.create_task(coro), task_id


    @property
    def monitor_task(self):
        if self.monitor_task_tuple:
            return self.monitor_task_tuple[0]


    @property
    def monitor_task_id(self) -> str:
        if self.monitor_task_tuple:
            return self.monitor_task_tuple[1]


    @monitor_task.setter
    def monitor_task(self, task_tuple: tuple):
        """ reset hatch and expiry tasks"""
        if self.monitor_task_tuple:
            self.monitor_task.cancel()
        self.monitor_task_tuple = task_tuple


    @property
    def reported_at(self):
        """as Readable time"""
        # TODO: add guild timezone
        return TH.as_local_readable_time(self.reported_time, self.timezone)


    def timer_info(self):
        timer_info = f"Reported at: {self.reported_at}" if self.reported_time else ""
        return timer_info


    @classmethod
    def cache(cls, wild):
        cls.by_message[wild.message_id] = wild
        cls.by_id[wild.wild_id] = wild


    @classmethod
    def evict(cls, wild):
        cls.by_message.pop(wild.message_id, None)
        cls.by_id.pop(wild.wild_id, None)


    def set_message(self, message):
        self.message_id = message.id
        self.channel_id = message.channel.id


    @staticmethod
    async def find_all(bot):
        wild_table = bot.dbi.table('wild_report')
        wild_table_query = wild_table.query().select()
        record_list = await wild_table_query.getjson()
        return record_list


    async def insert(self):
        wild_table = self.bot.dbi.table('wild_report')
        wild_table_insert = wild_table.insert(**self.to_db_dict())
        await wild_table_insert.commit()
        Wild.cache(self)


    async def delete(self):
        wild_table = self.bot.dbi.table('wild_report')
        wild_table_delete = wild_table.query().where(wild_id=self.wild_id)
        await wild_table_delete.delete()
        Wild.evict(self)


    def wild_embed(self, ctx):
        return (WildEmbed.from_wild_report(ctx, self)).embed


    def expire_embed(self):
        return (WildEmbed.expire_embed(self)).embed


    async def despawn(self):
        try:
            channel, message = await ChannelMessage.from_id(self.bot, self.channel_id, self.message_id)
            embed = self.expire_embed()
            await message.edit(content="", embed=embed)
            await message.clear_reactions()
        except Exception as error:
            Logger.info(error)

        await self.delete()
        self.monitor_task = None


    async def monitor_status(self):
        Logger.info(f"{self.pkmn.label} at {self.location}")
        sleep_time = self.despawn_time - TH.current_epoch()
        if sleep_time > 0:
            await asyncio.sleep(sleep_time)

        await self.despawn()
clembot/utilities/utils/snowflake.py
CLEM_EPOCH = 1502123160
def to_timestamp(_id):
def create():
    def __init__(self):
    def next(self):
    def dumps(self, number):
    def loads(self, value):
    def cuid(cls, id):
def main():
class Snowflake:
class Base36:
class CUIDGenerator:
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/config/channel_checks.py
async def _is_wild_report_channel(ctx):
async def _is_raid_report_channel(ctx):
async def _is_nest_report_channel(ctx):
def raid_report_enabled():
def wild_report_enabled():
def nest_report_enabled():
clembot/exts/config/guild_metadata.py
class GuildMetadata:


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

    def __eq__(self, other):
        return self.guild.id == other.guild.id

    @property
    def _data(self):
        report_guild_query = self.bot.dbi.table('guild_metadata').query()
        _data = report_guild_query.where(guild_id=self.guild.id)
        return _data


    @classmethod
    async def data(cls, bot, guild_id, config_name):

        report_guild_query = bot.dbi.table('guild_metadata').query()
        _data = report_guild_query.where(guild_id=guild_id, config_name=config_name)
        db_record = await _data.get()

        if db_record:
            guild_metadata = GuildMetadata.deserialize(dict(db_record[0]))
            return guild_metadata

        return {}

    @classmethod
    async def city(cls, bot, guild_id):
        guild_dict = await GuildMetadata.data(bot, guild_id, 'city')
        return guild_dict.get('config_value')

    @classmethod
    async def bingo_card_repo(cls, bot, guild_id):
        guild_dict = await GuildMetadata.data(bot, guild_id, 'bingo-card-repo') or {}
        return guild_dict.get('config_value')

    @staticmethod
    def serialize(data_dict):
        return _.map_values(data_dict, lambda val: json.dumps(val) if isinstance(val, dict) else val)

    @staticmethod
    def deserialize(data_dict):
        return { k :json.loads(v) if k == 'config' and v is not None else v for (k, v) in data_dict.items()}


    @classmethod
    async def update(cls, bot, guild_dict):
        guild_metadata_table = bot.dbi.table('guild_metadata')
        update_dict=GuildMetadata.serialize(guild_dict)
        guild_metadata_table_update = guild_metadata_table.update(**update_dict).where(guild_id=guild_dict.get('guild_id'))
        await guild_metadata_table_update.commit()
        GuildMetadata.cache(guild_dict)

    @classmethod
    async def insert(cls, bot, guild_dict):
        guild_metadata_table = bot.dbi.table('guild_metadata')
        update_dict = GuildMetadata.serialize(guild_dict)
        guild_metadata_table_insert = guild_metadata_table.insert(**update_dict)
        await guild_metadata_table_insert.commit()
        GuildMetadata.cache(guild_dict)

    @staticmethod
    def embed(ctx, guild_dict):
        return (GuildMetadataEmbed.from_guild_metadata(ctx, guild_dict)).embed


Question: import discord
from discord.ext import commands
from discord.ext.commands import BadArgument
from clembot.config.constants import MyEmojis
from clembot.core.bot import group
from clembot.core.commands import Cog
from clembot.core.logs import Logger
from clembot.core.utils import notify_for
from clembot.exts.config import channel_checks
from clembot.exts.config.guild_metadata import GuildMetadata
from clembot.exts.gymmanager.gym import POILocationConverter
from clembot.exts.pkmn.gm_pokemon import Pokemon
from clembot.exts.profile.user_guild_profile import UserGuildProfile
from clembot.exts.wild.wild import Wild
from clembot.utilities.utils import snowflake



class WildCog(commands.Cog):


    wild_SYNTAX_ATTRIBUTE = ['gym', 'others']

    def __init__(self, bot):
        self.bot = bot
        self.bot.loop.create_task(self.load_wild_reports())


    async def load_wild_reports(self):
        await Pokemon.load(self.bot)
        for rcrd in await Wild.find_all(self.bot):
            self.bot.loop.create_task(self.load_wild_report(rcrd))


    async def load_wild_report(self, rcrd):
        Logger.info(f"load_wild_report({rcrd.get('wild_id', None)})")
        wild = await Wild.from_db_dict(self.bot, rcrd)
        wild.monitor_task = wild.create_task_tuple(wild.monitor_status())


    @group(pass_context=True, category='Bot Info', aliases=["wild"])
    @channel_checks.wild_report_enabled()
    async def cmd_wild(self, ctx, pokemon: Pokemon, *loc):
        """Reports a wild spawn
        **Arguments**
        *pokemon* The name of the wild pokemon
        *location* The location of the spawn

        If the location is a gym, directions will be accurate otherwise I will
        just provide a link for **location** + city of the channel.
        """

        timezone = await ctx.timezone()
        wild_id = next(snowflake.create())
        if len(loc) == 0:
            raise BadArgument("Ohh, that's awesome, but where? I can't create a report without location.")
        location = await POILocationConverter.convert(ctx, ' '.join(loc))

        wild = Wild(self.bot, wild_id=wild_id, guild_id=ctx.guild.id, reporter_id=ctx.message.author.id,
                    pkmn=pokemon, location=location, timezone=timezone)

        message_content = None
        role = await notify_for(self.bot, ctx.guild, pokemon.id)
        if role:
            message_content=f"A wild {role.mention} spotted by {ctx.message.author.mention}."

        if message_content:
            wild_report = await ctx.send(content=message_content, embed=wild.wild_embed(ctx))
        else:
            wild_report = await ctx.send(embed=wild.wild_embed(ctx))


Answer:         await wild_report.add_reaction(MyEmojis.DESPAWNED)