Ejemplo n.º 1
0
class UrlUtil:
    _profile = env.EnvConfig.profile

    project_dir = os.path.abspath(
        __file__)[0:os.path.abspath(__file__).find("\\util")]

    image_dir_self = "reports\\images" + DateUtil.get_date_to_day()
    image_dir = project_dir + "\\" + image_dir_self

    case_dir_self = "cases"
    case_dir = project_dir + "\\" + case_dir_self

    report_dir_self = "reports"
    report_dir = project_dir + "\\" + report_dir_self
    report_file_self = "reports\\report" + DateUtil.get_date_to_day() + ".html"
    report_file = project_dir + "\\" + report_file_self

    log_dir_self = "logs\\" + DateUtil.get_date_to_day()
    log_dir = project_dir + "\\" + log_dir_self

    config_file_self = "config\\application.xml"
    config_file = project_dir + "\\" + config_file_self

    if _profile == "trunk":
        _static_base_url = "http://core-stag-trunk.cbdmnc.com/admin"
    elif _profile == "dev":
        _static_base_url = "http://core-stag-rc.cbdmnc.com:8080/admin/"

    @staticmethod
    def get_login_page_url():
        return UrlUtil._static_base_url + "login.html"

    @staticmethod
    def get_index_page_url():
        return UrlUtil._static_base_url + "index.html"
Ejemplo n.º 2
0
 async def timer(self):
     if self.bot.ws is not None:
         dt_now = DateUtil.get_dt_now(self.bot.tz_str)
         if self.bot.race_time is not None:
             race_begin = self.bot.race_time
             race_end = self.bot.race_time + timedelta(hours=1)
             if dt_now > race_end:
                 await update_race_time(self.bot, None)
             else:
                 str = 'Summer Race'
                 if race_begin <= dt_now <= race_end:
                     str += ' ends '
                     str += DateUtil.fmt_time_short((race_end - dt_now) / timedelta(milliseconds=1))
                 else:
                     str += ' '
                     str += DateUtil.fmt_time_short((race_begin - dt_now) / timedelta(milliseconds=1))
                 str += ' (TalonRO)'
                 game = discord.Game(name=str)
                 await CoroutineUtil.run(self.bot.change_presence(activity=game))
                 return
         evt = get_next_evt(self.bot, timezone(self.bot.tz_str))
         str = ('WoE ' if evt['type'] == 'woe' else '') + evt['name']
         if evt['dt_begin'] <= dt_now <= evt['dt_end']:
             str += ' ends '
             str += DateUtil.fmt_time_short((evt['dt_end'] - dt_now) / timedelta(milliseconds=1))
         else:
             str += ' '
             str += DateUtil.fmt_time_short((evt['dt_begin'] - dt_now) / timedelta(milliseconds=1))
         str += ' (TalonRO)'
         game = discord.Game(name=str)
         await CoroutineUtil.run(self.bot.change_presence(activity=game))
Ejemplo n.º 3
0
def get_evts(bot, timezone, type=None):
    result = []
    for evt in weekly_events:
        if type is not None and evt['type'] != type:
            continue
        evt_begin = evt['begin'].split(':')
        dt_evt_begin = DateUtil.get_dt_now(bot.tz_str).replace(
            hour=int(evt_begin[0]),
            minute=int(evt_begin[1]),
            second=0,
            microsecond=0
        )
        while dt_evt_begin.isoweekday() != int(evt['weekday']):
            dt_evt_begin += timedelta(days=1)
        dt_evt_begin = dt_evt_begin.replace(tzinfo=None)
        dt_evt_begin = timezone.localize(dt_evt_begin, is_dst=False)
        evt_end = evt['end'].split(':')
        dt_evt_end = DateUtil.get_dt_now(bot.tz_str).replace(
            hour=int(evt_end[0]),
            minute=int(evt_end[1]),
            second=0,
            microsecond=0
        )
        while dt_evt_end.isoweekday() != int(evt['weekday']):
            dt_evt_end += timedelta(days=1)
        dt_evt_end = dt_evt_end.replace(tzinfo=None)
        dt_evt_end = timezone.localize(dt_evt_end, is_dst=False)
        evt['dt_begin'] = dt_evt_begin
        evt['dt_end'] = dt_evt_end
        result.append(evt)
    result.sort(key=lambda x: x['dt_begin'])
    return result
Ejemplo n.º 4
0
    def get_column_value(self, line):
        """
        根据行数据获取需要插入到数据库的字典
        :param line:
        :return:
        """
        data = self.parser.get_dict(line)
        column_value = {
            'uid': data['uid'],
            'p_type': Product.MINIK.value,
            't_type': Terminal.Mobile.value,
            'a_type': data['action'],
            'action_time': data['action_time'],
            'location': SocketUtil.ip2int(data['ip']),
            'aimei_object': data['aimei_object'],
            'update_time': -1
        }

        month = DateUtil.now('%Y%m')
        column_value['month'] = month
        column_value['update_time'] = DateUtil.now('%Y-%m-%d %H:%M:%S')

        # 流水需要的

        # 总表需要的
        column_value['provinceid'] = -1
        column_value['isp'] = -1
        column_value['count'] = 1
        column_value['time_span'] = DateUtil.timestamp2date(
            data['action_time'], '%d%H')
        return column_value
Ejemplo n.º 5
0
 def insert_total_many(self, column_values):
     month = DateUtil.now('%Y%m')
     prefix = "INSERT INTO t_data_aimei_user_action_mob_%(month)s (p_type, a_type, provinceid, isp, time_span, aimei_object, count, update_time) VALUES "
     prefix = prefix % {'month': month}
     value_fmt = "('%(p_type)s', '%(a_type)s', %(provinceid)s, %(isp)s, %(time_span)s, '%(aimei_object)s', %(count)s, '%(update_time)s') "
     end = "ON DUPLICATE KEY UPDATE count = count + 1, update_time = '%(update_time)s'"
     end = end % {'update_time': DateUtil.now('%Y-%m-%d %H:%M:%S')}
     values = []
     for value in column_values:
         value = value_fmt % value
         values.append(value)
     sql = prefix + ', '.join(values) + end
     self.db.execute(sql)
Ejemplo n.º 6
0
 def insert(self, column_value, data=None):
     """
     插入流水表
     :param column_value:
     """
     # 设置默认值
     month = DateUtil.now('%Y%m')
     column_value['month'] = month
     column_value['update_time'] = DateUtil.now('%Y-%m-%d %H:%M:%S')
     sql = "INSERT INTO t_data_aimei_user_action_%(month)s (uid, p_type, t_type, a_type, action_time, location, aimei_object, update_time) VALUES (%(uid)s, '%(p_type)s', '%(t_type)s', '%(a_type)s', %(action_time)s, %(location)s, '%(aimei_object)s', '%(update_time)s')"
     sql %= column_value  # 格式化
     # self.db.execute(sql)
     return sql, column_value
Ejemplo n.º 7
0
def format_evt(bot, evt, timezone):
    dt_now = DateUtil.get_dt_now(bot.tz_str)
    result = '**'
    result += evt['name']
    result += '** '
    result += evt['dt_begin'].strftime('%H:%M')
    if evt['dt_begin'] <= dt_now <= evt['dt_end']:
        result += ' (ends '
        result += DateUtil.fmt_time((evt['dt_end'] - dt_now) / timedelta(milliseconds=1))
    else:
        result += ' ('
        result += DateUtil.fmt_time((evt['dt_begin'] - dt_now) / timedelta(milliseconds=1))
    result += ')'
    return result
Ejemplo n.º 8
0
 async def woe(self, ctx):
     woe_map = get_woe_map(self.bot, timezone(self.bot.tz_str))
     embed = discord.Embed()
     embed.title = ':european_castle: WoE'
     embed.colour = discord.Colour.gold()
     if woe_map['ongoing'] != '':
         embed.add_field(name='Ongoing :boom:', value=woe_map['ongoing'], inline=False)
     embed.add_field(name='Next :arrow_right:', value=woe_map['next'], inline=False)
     embed.add_field(name='Saturday', value=woe_map['saturday'], inline=False)
     embed.add_field(name='Sunday', value=woe_map['sunday'], inline=False)
     footer = 'Server Time (' + self.bot.tz_str + '): '
     footer += DateUtil.fmt_dt(DateUtil.get_dt_now(self.bot.tz_str))
     embed.set_footer(text=footer)
     await CoroutineUtil.run(ctx.send(embed=embed))
Ejemplo n.º 9
0
 async def timer(self):
     if self.bot.ws is not None:
         dt_now = DateUtil.get_dt_now(self.bot.tz_str)
         evt = get_next_evt(self.bot, timezone(self.bot.tz_str))
         str = ('WoE ' if evt['type'] == 'woe' else '') + evt['name']
         if evt['dt_begin'] <= dt_now <= evt['dt_end']:
             str += ' ends '
             str += DateUtil.fmt_time_short((evt['dt_end'] - dt_now) / timedelta(milliseconds=1))
         else:
             str += ' '
             str += DateUtil.fmt_time_short((evt['dt_begin'] - dt_now) / timedelta(milliseconds=1))
         str += ' (TalonRO)'
         game = discord.Game(name=str)
         await CoroutineUtil.run(self.bot.change_presence(activity=game))
Ejemplo n.º 10
0
    def get_column_value(self, line):
        """
        根据行数据获取需要插入到数据库的字典
        :param line:
        :return:
        """
        index = line.find(']')
        line = (line[index + 1:]).strip()
        data = self.parser.split_k_v(line)
        column_value = {
            'uid': data['uid'],
            'p_type': Product.MINIK.value,
            't_type': Terminal.Mobile.value,
            'a_type': -1,
            'action_time': -1,
            'location': -1,
            'aimei_object': '',
            'update_time': -1
        }
        action = data['action']
        if action == 'click_listen_song':
            column_value['a_type'] = Action.REQUEST_SONG.value
            column_value['aimei_object'] = data['songid']
        else:
            column_value['a_type'] = Action.CLICK_BUTTON.value
            aimei_object = ''
            if action == 'click_tab':
                aimei_object = data['tab']
            elif action == 'visit_url':
                aimei_object = data['url']
            elif action == 'click_play_album':
                aimei_object = data['albumid']
            column_value['aimei_object'] = aimei_object
        column_value['action_time'] = DateUtil.date2timestamp(
            data['timestamp'], fmt='%Y-%m-%d_%H:%M:%S')

        month = DateUtil.now('%Y%m')
        column_value['month'] = month
        column_value['update_time'] = DateUtil.now('%Y-%m-%d %H:%M:%S')

        # 流水需要的

        # 总表需要的
        column_value['provinceid'] = -1
        column_value['isp'] = -1
        column_value['count'] = 1
        column_value['time_span'] = self.get_time_span(data['timestamp'])
        return column_value
Ejemplo n.º 11
0
def get_woe_map(bot, timezone):
    dt_now = DateUtil.get_dt_now(bot.tz_str)
    evts = get_evts(bot, timezone, type='woe')
    woe_map = {}
    woe_map['ongoing'] = ''
    woe_map['next'] = ''
    woe_map['saturday'] = ''
    woe_map['sunday'] = ''
    next_evt = evts[0]
    for evt in evts:
        str_woe = '' + format_evt(bot, evt, timezone) + '\n'
        if int(evt['weekday']) == 7:
            woe_map['sunday'] += str_woe
        else:
            woe_map['saturday'] += str_woe
        if evt['dt_begin'] <= dt_now <= evt['dt_end']:
            woe_map['ongoing'] = format_evt(bot, evt, timezone)
        if evt['dt_begin'] <= dt_now:
            continue
        if next_evt['dt_begin'] < dt_now or evt['dt_begin'] < next_evt[
                'dt_begin']:
            next_evt = evt
    if next_evt != None:
        woe_map['next'] = format_evt(bot, next_evt, timezone)
    return woe_map
Ejemplo n.º 12
0
def get_gmc_map(bot, timezone):
    dt_now = DateUtil.get_dt_now(bot.tz_str)
    weekday_today = dt_now.isoweekday()
    weekday_tomorrow = 1 if weekday_today == 7 else (weekday_today + 1)
    evts = get_evts(bot, timezone, type='gmc')
    gmc_map = {}
    gmc_map['ongoing'] = ''
    gmc_map['next'] = ''
    gmc_map['today'] = ''
    gmc_map['tomorrow'] = ''
    next_evt = evts[0]
    for evt in evts:
        str_woe = '' + format_evt(bot, evt, timezone) + '\n'
        if int(evt['weekday']) == weekday_today:
            gmc_map['today'] += str_woe
        elif int(evt['weekday']) == weekday_tomorrow:
            gmc_map['tomorrow'] += str_woe
        if evt['dt_begin'] <= dt_now <= evt['dt_end']:
            gmc_map['ongoing'] = format_evt(bot, evt, timezone)
        if evt['dt_begin'] <= dt_now:
            continue
        if next_evt['dt_begin'] < dt_now or evt['dt_begin'] < next_evt['dt_begin']:
            next_evt = evt
    if next_evt != None:
        gmc_map['next'] = format_evt(bot, next_evt, timezone)
    return gmc_map
Ejemplo n.º 13
0
 async def gmc(self, ctx):
     gmc_map = get_gmc_map(self.bot, timezone(self.bot.tz_str))
     embed = discord.Embed()
     embed.title = ':dragon_face: GMC'
     embed.colour = discord.Colour.gold()
     if gmc_map['ongoing'] != '':
         embed.add_field(name='Ongoing :boom:', value=gmc_map['ongoing'], inline=False)
     embed.add_field(name='Next :arrow_right:', value=gmc_map['next'], inline=False)
     if gmc_map['today'] != '':
         embed.add_field(name='Today', value=gmc_map['today'], inline=False)
     if gmc_map['tomorrow'] != '':
         embed.add_field(name='Tomorrow', value=gmc_map['tomorrow'], inline=False)
     footer = 'Server Time (' + self.bot.tz_str + '): ' 
     footer += DateUtil.fmt_dt(DateUtil.get_dt_now(self.bot.tz_str))
     embed.set_footer(text=footer)
     await CoroutineUtil.run(ctx.send(embed=embed))
Ejemplo n.º 14
0
 def insert_or_update_total(self, column_value, data=None):
     """
     插入或更新流水总表
     :param column_value:
     """
     # 设置默认值
     month = DateUtil.now('%Y%m')
     column_value['month'] = month
     column_value['provinceid'] = -1
     column_value['isp'] = -1
     column_value['count'] = 1
     column_value['time_span'] = self.get_time_span(data['timestamp'])
     column_value['update_time'] = DateUtil.now('%Y-%m-%d %H:%M:%S')
     sql = "INSERT INTO t_data_aimei_user_action_mob_%(month)s (p_type, a_type, provinceid, isp, time_span, aimei_object, count, update_time) VALUES ('%(p_type)s', '%(a_type)s', %(provinceid)s, %(isp)s, %(time_span)s, '%(aimei_object)s', %(count)s, '%(update_time)s') ON DUPLICATE KEY UPDATE count = count + 1, update_time = '%(update_time)s'"
     sql %= column_value  # 格式化
     # self.db.execute(sql)
     return sql, column_value
Ejemplo n.º 15
0
    def remove_expired(cls, chow_list):
        # remove chows that are expired
        currTime = datetime.datetime.now().isoformat()

        # ensure date format is correct on meet time
        return [
            chow for chow in chow_list
            if not ('meetTime' in chow and dateutil.iso_date_valid(
                chow['meetTime']) and chow['meetTime'] < currTime)
        ]
Ejemplo n.º 16
0
    def write_to_html(self, message, level):
        self._create_log()

        f = open(self.log_file, "r", encoding="utf-8")
        content = f.read()
        f.close()

        position = content.find("</table>")
        if level == "Info" or level == "Debug":
            new_row = "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>".format(
                DateUtil.get_date_to_second(), self.log_name, message, level)
        else:
            new_row = "<tr bgcolor='#FF0000'><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>".format(
                DateUtil.get_date_to_second(), self.log_name, message, level)

        f = open(self.log_file, "w", encoding="utf-8")
        content = content[0:position] + new_row + content[position:]
        f.write(content)
        f.close()
Ejemplo n.º 17
0
 def insert_many(self, column_values):
     month = DateUtil.now('%Y%m')
     prefix = "INSERT INTO t_data_aimei_user_action_%(month)s (uid, p_type, t_type, a_type, action_time, location, aimei_object, update_time) VALUES "
     prefix = prefix % {'month': month}
     value_fmt = "(%(uid)s, '%(p_type)s', '%(t_type)s', '%(a_type)s', %(action_time)s, %(location)s, '%(aimei_object)s', '%(update_time)s')"
     values = []
     for value in column_values:
         value = value_fmt % value
         values.append(value)
     sql = prefix + ', '.join(values)
     self.db.execute(sql)
Ejemplo n.º 18
0
def get_next_evt(bot, timezone):
    dt_now = DateUtil.get_dt_now(bot.tz_str)
    evts = get_evts(bot, timezone)
    next_evt = None
    for evt in evts:
        if evt['dt_end'] < dt_now:
            continue
        if next_evt is None:
            next_evt = evt
        if evt['dt_begin'] <= dt_now <= evt['dt_end']: #ongoing
            return next_evt
            break
        if evt['dt_begin'] < next_evt['dt_begin']: #next
            next_evt = evt
    return next_evt
Ejemplo n.º 19
0
    def process(self, lines):
        # 格式:[I 160815 00:00:00 record_handler:181] timestamp=2016-08-15_00:00:00&action=click_listen_song&songid=2306797&uid=1277909
        column_values = []
        total_column_values = []
        for line in lines:
            index = line.find(']')
            line = (line[index + 1:]).strip()
            data = self.parser.split_k_v(line)
            column_value = {
                'uid': data['uid'],
                'p_type': Product.MINIK.value,
                't_type': Terminal.Mobile.value,
                'a_type': -1,
                'action_time': -1,
                'location': -1,
                'aimei_object': '',
                'update_time': -1
            }
            action = data['action']
            if action == 'click_listen_song':
                column_value['a_type'] = Action.REQUEST_SONG.value
                column_value['aimei_object'] = data['songid']
            else:
                column_value['a_type'] = Action.CLICK_BUTTON.value
                aimei_object = ''
                if action == 'click_tab':
                    aimei_object = data['tab']
                elif action == 'visit_url':
                    aimei_object = data['url']
                elif action == 'click_play_album':
                    aimei_object = data['albumid']
                column_value['aimei_object'] = aimei_object
            column_value['action_time'] = DateUtil.date2timestamp(
                data['timestamp'], fmt='%Y-%m-%d_%H:%M:%S')

            # user_action = UserAction.gen_model(column_value)
            # user_action.session.add(user_action)
            # user_action.session.commit()
            sql, column_value = self.insert(column_value)
            column_values.append(column_value)
            sql, total_column_value = self.insert_or_update_total(
                column_value, data)
            total_column_values.append(total_column_value)

        self.insert_many(column_values)
        self.insert_total_many(total_column_values)
Ejemplo n.º 20
0
    def test_case1(self):
        self.util_load(__file__)
        self.case_info.start_time = DateUtil.get_date_to_second()
        if self.flag > 1:
            self.setUp()
        try:
            self.step = "match username info"
            self.logger.info(self.step)
            self.assertEqual(self.get_text(self.index_page.username_info),
                             self.username_value, "username not match")
            self.case_info.result = "Pass"

        except TimeoutException:
            self.timeout_method()

        except Exception as err:
            self.exception_method(err)

        finally:
            self.finally_method()
Ejemplo n.º 21
0
    def send_mail():
        EmailUtil.mail.attach(MIMEText(
            '通过报告路径直接访问:  xxxx\\TestReport\\Automation\\report\\report' + DateUtil.get_date_to_day() + '.html',
            'plain', 'utf-8'))

        # 构造附件
        att = MIMEBase('application', 'octet-stream')
        fp = open(UrlUtil.report_file, 'r', encoding="utf-8")
        att.set_payload(fp.read())
        fp.close()
        encoders.encode_base64(att)
        att.add_header('Content-Disposition', 'attachment;filename="{0}"'.format(UrlUtil.report_file_self))
        EmailUtil.mail.attach(att)

        server = smtplib.SMTP(host=EmailUtil.host)
        server.connect(EmailUtil.host, 25)
        server.ehlo()
        server.starttls()
        server.login(EmailUtil.username, EmailUtil.password)
        server.sendmail(EmailUtil.mail['From'], EmailUtil.mail['To'], EmailUtil.mail.as_string())
        server.quit()
        server.close()
Ejemplo n.º 22
0
 def finally_method(self):
     self.case_info.end_time = DateUtil.get_date_to_second()
     time.sleep(2)
     self.driver.quit()
Ejemplo n.º 23
0
 def get_table_name(cls, column_value):
     return 't_data_aimei_user_action_%s' % DateUtil.now('%Y%m')
Ejemplo n.º 24
0
async def update_channel_message(bot, channel_state):
    mobile = bot.guild_state_map.get(channel_state['id_guild'])['mobile']
    type = channel_state['type']
    embed = discord.Embed()
    embed.colour = discord.Colour.gold()
    embed.title = (':crown: ' if type == TrackType.MVP else
                   ':pick: ') + entry_desc(type) + 'S'
    names = []
    maps = []
    remaining_times = []
    id_mob_first_entry = None
    cmp = 'r2' if type == TrackType.MVP else 'r1'
    for entry_state in channel_state['entry_state_list']:
        if entry_state[cmp] > -bot.config['table_entry_expiration_mins']:
            remaining_time = fmt_r1_r2(int(entry_state['r1']))
            if type == TrackType.MVP:
                if id_mob_first_entry is None:
                    id_mob_first_entry = entry_state['entry']['id_mob']
                remaining_time += ' to ' + fmt_r1_r2(int(entry_state['r2']))
            remaining_time += ' mins'
            if mobile:
                name = entry_state['entry']['name']
                if type == TrackType.MVP:
                    name += ' (' + entry_state['entry']['map'] + ')'
                name += ' | ' + remaining_time
                names.append(name)
            else:
                names.append(entry_state['entry']['name'])
                if type == TrackType.MVP:
                    maps.append(entry_state['entry']['map'])
                remaining_times.append(remaining_time)
    if len(names) == 0:
        embed.add_field(name=':x:',
                        value='No ' + entry_desc(type) + ' has been tracked.',
                        inline=False)
    else:
        max_length = 20
        if len(names) > max_length + 1:
            diff = len(names) - max_length
            for i in range(0, diff):
                names.pop()
                if type == TrackType.MVP:
                    maps.pop()
                remaining_times.pop()
            names.append('and ' + str(diff) + ' more...')
        if type == TrackType.MVP:
            embed.set_thumbnail(url="https://file5s.ratemyserver.net/mobs/" +
                                str(id_mob_first_entry) + ".gif")
        if mobile:
            embed.add_field(name='Name', value=fmt_column(names), inline=False)
        else:
            embed.add_field(name='Name', value=fmt_column(names), inline=True)
            if type == TrackType.MVP:
                embed.add_field(name='Map',
                                value=fmt_column(maps),
                                inline=True)
            embed.add_field(name='Remaining Time',
                            value=fmt_column(remaining_times),
                            inline=True)
    if len(channel_state['entry_log_list']) > 0:
        result = ''
        for entry_log in channel_state['entry_log_list']:
            if result != '':
                result += '\n'
            milliseconds = (entry_log['entry_time'] -
                            datetime.now()) / timedelta(milliseconds=1)
            result += '**[' + DateUtil.fmt_time_short(milliseconds) + ']**'
            result += ' ' + entry_log['entry']['name']
            if type == TrackType.MVP:
                result += ' (' + entry_log['entry']['map'] + ')'
            result += ' by <@' + str(entry_log['id_user']) + '>'
        embed.add_field(name='Track Log', value=result, inline=False)
    guild = next((x for x in bot.guilds if x.id == channel_state['id_guild']),
                 None)
    if guild is None:
        return
    channel = next(
        (x for x in guild.channels if x.id == channel_state['id_channel']),
        None)
    if validate_channel(bot, channel) is not None:
        return
    message = None
    if channel_state['id_message'] is not None:
        message = await CoroutineUtil.run_with_retries(
            channel.fetch_message(channel_state['id_message']))
    if message is None:
        message = await CoroutineUtil.run(channel.send(embed=embed))
        if message is not None:
            channel_state['id_message'] = message.id
    else:
        await CoroutineUtil.run(message.edit(embed=embed, content=''))
        await CoroutineUtil.run(message.clear_reactions())
Ejemplo n.º 25
0
 async def track(self, ctx, *args):
     validate_msg = validate_channel(self.bot, ctx.message.channel)
     if validate_msg is not None:
         await CoroutineUtil.run(ctx.send(validate_msg))
         return
     guild_state = self.bot.guild_state_map[ctx.guild.id]
     channel_state = guild_state['channel_state_map'].get(
         ctx.message.channel.id)
     if channel_state is None:
         await CoroutineUtil.run(
             ctx.send('This command can only be used in a track channel.'))
         return
     mins_ago = 0
     if len(args) == 0:
         return
     query_last_idx = len(args) - 1
     if args[query_last_idx].isnumeric():
         mins_ago = int(args[query_last_idx])
         query_last_idx -= 1
     elif len(args[query_last_idx]) == 5 and args[query_last_idx][2] == ':':
         hrs_mins = args[query_last_idx].split(':')
         if len(hrs_mins) == 2 and hrs_mins[0].isnumeric(
         ) and hrs_mins[1].isnumeric():
             hh = int(hrs_mins[0])
             mm = int(hrs_mins[1])
             track_time = DateUtil.get_dt_now(self.bot.tz_str)
             if hh > track_time.hour or (hh == track_time.hour
                                         and mm > track_time.minute):
                 track_time -= timedelta(days=1)
             track_time = track_time.replace(hour=hh, minute=mm)
             td = DateUtil.get_dt_now(self.bot.tz_str) - track_time
             mins_ago = td / timedelta(minutes=1)
             query_last_idx -= 1
     if mins_ago < 0:
         mins_ago = 0
     query = args[0]
     for i in range(1, query_last_idx + 1):
         query += ' ' + args[i]
     type = channel_state['type']
     results = find_entry(self.bot, query, type)
     if len(results) == 0:
         await CoroutineUtil.run(
             ctx.send(entry_desc(type) + ' "' + query + '" not found.'))
     elif len(results) == 1:
         bot_reply_msg = await update_track_time(self.bot, channel_state,
                                                 results[0], mins_ago,
                                                 ctx.message.author.id)
         await CoroutineUtil.run(ctx.send(bot_reply_msg))
     else:
         bot_reply_msg = 'More than one ' + entry_desc(type)
         bot_reply_msg += ' starting with "' + query + '" has been found.\n'
         bot_reply_msg += '\n'
         bot_reply_msg += 'Type or react with the number of the ' + entry_desc(
             type)
         bot_reply_msg += ' that you want to track:\n'
         bot_reply_msg += '```'
         for i in range(0, min(len(results), 5)):
             bot_reply_msg += str(i + 1) + '. ' + results[i]['name']
             if type == TrackType.MVP:
                 bot_reply_msg += ' (' + results[i]['map'] + ')'
             bot_reply_msg += '\n'
         bot_reply_msg += '```'
         bot_msg = await CoroutineUtil.run(ctx.send(bot_reply_msg))
         user_entry_state = guild_state['user_state_map'].get(
             ctx.message.author.id)
         if user_entry_state is not None and user_entry_state[
                 'bot_msg'] is not None:
             await CoroutineUtil.run(user_entry_state['bot_msg'].delete())
         guild_state['user_state_map'][ctx.message.author.id] = {
             'command': 'TRACK',
             'bot_msg': bot_msg,
             'results': results,
             'mins_ago': mins_ago
         }
         for i in range(0, min(len(results), 5)):
             await CoroutineUtil.run(
                 bot_msg.add_reaction(number_emoji_list[i]))