예제 #1
0
async def char_command(ctx: tanjun.abc.Context,
                       characters: str,
                       file: bool = False) -> None:
    """Get information about the UTF-8 characters in the executing message.

    Running `char file...` will ensure that the output is always sent as a markdown file.
    """
    if len(characters) > 20:
        file = True

    content: hikari.UndefinedOr[str]
    content = "\n".join(_format_char_line(char, file) for char in characters)
    response_file: hikari.UndefinedOr[hikari.Bytes] = hikari.UNDEFINED

    # highly doubt this'll ever be over 1990 when file is False but better safe than sorry.
    if file or len(content) >= 1990:
        response_file = hikari.Bytes(content.encode(),
                                     "character-info.md",
                                     mimetype="text/markdown; charset=UTF-8")
        content = hikari.UNDEFINED

    else:
        content = content

    await ctx.respond(content=content or "hi there",
                      component=utility.delete_row(ctx))

    if response_file is not hikari.UNDEFINED:
        await ctx.edit_last_response(content=None, attachment=response_file)
예제 #2
0
async def rating(ctx):
    """Plot rating progression"""
    peak = ctx.options.peak
    usernames = ctx.options.usernames

    query = Query()
    if usernames == []:
        usernames = [query.get_handle(ctx.author.id, ctx.get_guild().id)]

    try:
        users = await asyncio.gather(*[query.get_user(username) for username in usernames])
    except ObjectNotFound:
        return await ctx.respond("User not found")

    usernames = [user.username for user in users]
    for i in range(len(users)):
        if users[i] is None:
            return await ctx.respond(f"{usernames[i]} does not exist on DMOJ")
    if len(users) > 10:
        return await ctx.respond("Too many users given, max 10")

    cond = [Contest_DB.rankings.contains(user.username) for user in users]
    q = session.query(Contest_DB).filter(or_(*cond)).filter(Contest_DB.is_rated == 1)
    contests = q.all()

    def get_rating_change(rankings, users):
        ret = {}
        for ranking in rankings:
            for user in users:
                if user.username == ranking["user"] and ranking["new_rating"]:
                    ret[user.username] = ranking["new_rating"]
        return ret

    data = {}
    data["users"] = [user.username for user in users]
    userPrevRating = {}
    for contest in contests:
        changes = get_rating_change(contest.rankings, users)
        data[contest.end_time] = []
        for user in users:
            if user.username in changes and (
                not peak or changes[user.username] >= userPrevRating.get(user.username, -9999)
            ):
                change = changes[user.username]
                userPrevRating[user.username] = change
                data[contest.end_time].append(change)
            else:
                data[contest.end_time].append(None)
    plot_rating(data)

    embed = hikari.Embed(
        title="Rating Progression",
        color=0xFCDB05,
    )
    with open("./graphs/plot.png", "rb") as file:
        embed.set_image(hikari.Bytes(file.read(), "plot.png"))

    return await ctx.respond(embed=embed)
예제 #3
0
def _bytes_from_io(
    stream: io.StringIO,
    name: str,
    mimetype: typing.Optional[str] = "text/x-python;charset=utf-8"
) -> hikari.Bytes:
    index = stream.tell()
    stream.seek(0)
    data = stream.read()
    stream.seek(index)
    return hikari.Bytes(data, name, mimetype=mimetype)
예제 #4
0
 async def factsmeme(self, ctx, *, text=None):
     """Generates a facts meme with given text"""
     if text:
         async with aiohttp.ClientSession() as session:
             data = await fetch(session, f"https://api.alexflipnote.dev/facts?text={text}")
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "facts.png"))
     else:
         await ctx.reply("Please enter text that I can use to create a meme.")
예제 #5
0
 async def floorislava(self, ctx, user=None):
     """Generates a facts meme with given text"""
     if user:
         if user.startswith("<@"):
             user = await self.bot.rest.fetch_user(await mention_converter(user))
         else:
             await ctx.reply("You need to mention the user")
             return
         async with aiohttp.ClientSession() as session:
             data = await fetch(session, f"https://api.alexflipnote.dev/floor?image={user.avatar_url}&text=lava")
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "floorislava.png"))
     else:
         async with aiohttp.ClientSession() as session:
             data = await fetch(session, f"https://api.alexflipnote.dev/floor?image={ctx.message.author.avatar_url}&text=lava")
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "floorislava.png"))
예제 #6
0
    def make_response(self) -> tuple[str, hikari.UndefinedOr[hikari.Bytes]]:
        if self.failed and self.passed:
            page = "Failed bans:\n" + "\n".join(f"* {user_id}: {exc}" for user_id, exc in self.failed.items())
            return (
                f"Successfully banned {len(self.passed)} member(s) but failed to ban {len(self.failed)} member(s)",
                hikari.Bytes(page.encode(), "failed_bans.md", mimetype="text/markdown;charset=UTF-8"),
            )

        elif self.failed:
            page = "Failed bans:\n" + "\n".join(f"* {user_id}: {exc}" for user_id, exc in self.failed.items())
            return (
                f"Failed to ban {len(self.failed)} member(s)",
                hikari.Bytes(page.encode(), "failed_bans.md", mimetype="text/markdown;charset=UTF-8"),
            )

        elif self.passed:
            return f"Successfully banned {len(self.passed)} member(s)", hikari.UNDEFINED

        else:
            return "No members were banned", hikari.UNDEFINED
예제 #7
0
 async def ship(self, ctx, user1: lightbulb.member_converter=None, user2: lightbulb.member_converter=None):
     """Ship two users"""
     if user1 and user2:
         async with aiohttp.ClientSession() as session:
             data = await fetch(
                 session, f"https://api.alexflipnote.dev/ship?user={user1.avatar_url}&user2={user2.avatar_url}"
             )
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "ship.png"))
     else:
         await ctx.reply("Please mention two users to ship")
예제 #8
0
async def solved(ctx):
    """Plot problems solved over time"""
    usernames = ctx.options.usernames

    query = Query()
    if usernames == []:
        usernames = [query.get_handle(ctx.author.id, ctx.get_guild().id)]

    try:
        users = await asyncio.gather(*[query.get_user(username) for username in usernames])
    except ObjectNotFound:
        return await ctx.respond("User not found")

    usernames = [user.username for user in users]
    for i in range(len(users)):
        if users[i] is None:
            return await ctx.respond(f"{usernames[i]} does not exist on DMOJ")
    if len(users) > 10:
        return await ctx.respond("Too many users given, max 10")

    total_data = {}
    for username in usernames:
        q = session.query(Submission_DB).filter(Submission_DB._user == username)
        if q.count() == 0:
            await ctx.respond(f"`{username}` does not have any cached submissions, caching now")
            await query.get_submissions(username)

        q = (
            session.query(func.min(Submission_DB.date))
            .join(Problem_DB, Problem_DB.code == Submission_DB._code)
            .filter(Submission_DB._user == username)
            .filter(Submission_DB.points == Problem_DB.points)
            .group_by(Submission_DB._code)
        )
        dates = list(map(itemgetter(0), q.all()))
        dates.sort()
        data_to_plot = {}
        cnt = 0
        for date in dates:
            cnt += 1
            data_to_plot[date] = cnt
        total_data[username] = data_to_plot

    plot_solved(total_data)

    embed = hikari.Embed(
        title="Problems Solved",
        color=0xFCDB05,
    )
    with open("./graphs/plot.png", "rb") as file:
        embed.set_image(hikari.Bytes(file.read(), "plot.png"))

    return await ctx.respond(embed=embed)
예제 #9
0
 async def supreme(self, ctx, *, text=None):
     """Generate Supreme logo from text"""
     if text:
         async with aiohttp.ClientSession() as session:
             data = await fetch(
                 session,
                 f"https://api.alexflipnote.dev/supreme?text={text[:20]}")
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "supreme.png"))
     else:
         await ctx.reply(
             "Please enter text that I can use to create the logo.")
예제 #10
0
 async def captcha(self, ctx, *, text=None):
     """Generate Google Captcha image from text"""
     if text:
         async with aiohttp.ClientSession() as session:
             data = await fetch(
                 session,
                 f"https://api.alexflipnote.dev/captcha?text={text[:500]}")
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "captcha.png"))
     else:
         await ctx.reply(
             "Please enter text that I can use to create the image.")
예제 #11
0
 async def pornhub(self, ctx, text1=None, text2="Hub"):
     """Generates a pornhub logo with given text"""
     if text1:
         async with aiohttp.ClientSession() as session:
             data = await fetch(
                 session,
                 f"https://api.alexflipnote.dev/pornhub?text={text1}&text2={text2}"
             )
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "phub.png"))
     else:
         await ctx.reply(
             "Please enter text that I can use to create the logo.")
예제 #12
0
 async def challenge(self, ctx, *, text=None):
     """Generate Minecraft challenge from text"""
     if text:
         async with aiohttp.ClientSession() as session:
             data = await fetch(
                 session,
                 f"https://api.alexflipnote.dev/challenge?text={text[:50]}&icon={random.randint(1,45)}"
             )
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "challenge.png"))
     else:
         await ctx.reply(
             "Please enter text that I can use to create the image.")
예제 #13
0
 async def salty(self, ctx, *, image_url=None):
     """Generates a salty image from given image"""
     if image_url:
         async with aiohttp.ClientSession() as session:
             data = await fetch(
                 session,
                 f"https://api.alexflipnote.dev/salty?image={image_url}")
         bio = BytesIO(data)
         bio.seek(0)
         await ctx.reply(attachment=hikari.Bytes(bio, "salty.png"))
     else:
         await ctx.reply(
             "Please enter raw image url that I can use to create the image."
         )
예제 #14
0
 async def colorify(self, ctx, image_url=None):
     """Generates colourified image from raw image"""
     if image_url == None:
         await ctx.reply("Please enter image url")
         return
     if not image_url.startswith("http"):
         await ctx.reply("Invalid image url")
     hexcode = "#fa391b"
     async with aiohttp.ClientSession() as session:
         data = await fetch(
             session,
             f"https://api.alexflipnote.dev/colourify?image={image_url}&b={hexcode if hexcode.startswith('#') else '#' + hexcode}"
         )
     bio = BytesIO(data)
     bio.seek(0)
     await ctx.reply(attachment=hikari.Bytes(bio, "colorified.png"))
예제 #15
0
async def on_error(event: lightbulb.CommandErrorEvent) -> None:
    try:
        logger.warning("Error handling: raised %s", event)
        if isinstance(event.exception, lightbulb.NotEnoughArguments):
            return await event.context.respond(
                f"Not enough arguments ({event.exception})")
        if isinstance(event.exception, lightbulb.CommandInvocationError):
            if isinstance(event.exception.original, hikari.ForbiddenError):
                return await event.context.respond(
                    f"I do not have permissions to do this ({event.exception.original.message})"
                )
        if isinstance(event.exception, lightbulb.CommandNotFound):
            return await event.context.respond(
                f"Where command? ({event.exception})")

        if isinstance(event.exception, lightbulb.errors.MissingRequiredRole):
            return await event.context.respond(
                f"Missing required roles ({event.exception})")

        if isinstance(event.exception, lightbulb.errors.NotOwner):
            return await event.context.respond(
                f"You are not the owner of this bot!")

        trace = "".join(
            traceback.format_exception(None, event.exception,
                                       event.exception.__traceback__))
        await event.context.respond(
            """Unhandled exception ({0})
Backtrace:""".format(event.exception),
            attachment=hikari.Bytes(trace, "traceback.txt"),
        )
    except Exception as e:
        logger.critical(
            "Error handling raised error: was handling %s, raised %s", event,
            e)
        await event.context.respond("Crtitical error encountered, check logs")
예제 #16
0
               for n in range(1, 3) if (s := str(n))},
        }
        style = style_map.get(args.style, "2")

        async with self.bot.rest.trigger_typing(ctx.channel_id):
            with BytesIO() as fp:
                await self.spotify_client(
                    fp,
                    data,
                    args.hidden,
                    args.color,
                    style,
                )

                kwargs: typing.Dict[str, typing.Any] = {
                    "attachment": hikari.Bytes(fp, f"{data}-card.png")
                }

                # if random.randint(0, 101) < 25:
                #     kwargs["content"] = (
                #         kwargs.get("content") or ""
                #     ) + "\n\nHave you tried the slash version of this command?"

                await ctx.respond(**kwargs)

    # pylint: disable=no-self-use
    @utils.checks.require_env(*_spotify_vars)
    @core.commands.group()
    @core.cooldown(1, 2, lightbulb.cooldowns.UserBucket)
    async def spotify(self, ctx: Context) -> None:
        """Contains subcommands that utilizes Spotify API."""
예제 #17
0
async def eval_command(
    ctx: tanjun.abc.MessageContext,
    component: alluka.Injected[tanjun.abc.Component],
    component_client: alluka.Injected[yuyo.ComponentClient],
    file_output: bool = False,
    # ephemeral_response: bool = False,
    suppress_response: bool = False,
) -> None:
    """Dynamically evaluate a script in the bot's environment.

    This can only be used by the bot's owner.

    Arguments:
        * code: Greedy multi-line string argument of the code to execute. This should be in a code block.
        * suppress_response (-s, --suppress): Whether to suppress this command's confirmation response.
            This defaults to false and will be set to true if no value is provided.
    """
    assert ctx.message.content is not None  # This shouldn't ever be the case in a command client.
    code = re.findall(r"```(?:[\w]*\n?)([\s\S(^\\`{3})]*?)\n*```",
                      ctx.message.content)
    if not code:
        raise tanjun.CommandError("Expected a python code block.")

    if suppress_response:
        await eval_python_code_no_capture(ctx, component, "<string>", code[0])
        return

    stdout, stderr, exec_time, failed = await eval_python_code(
        ctx, component, code[0])

    if file_output:
        await ctx.respond(
            attachments=[
                hikari.Bytes(stdout,
                             "stdout.py",
                             mimetype="text/x-python;charset=utf-8"),
                hikari.Bytes(stderr,
                             "stderr.py",
                             mimetype="text/x-python;charset=utf-8"),
            ],
            component=utility.delete_row(ctx),
        )
        return

    colour = utility.FAILED_COLOUR if failed else utility.PASS_COLOUR
    string_paginator = yuyo.sync_paginate_string(_yields_results(
        stdout, stderr),
                                                 wrapper="```python\n{}\n```",
                                                 char_limit=2034)
    embed_generator = ((
        hikari.UNDEFINED,
        hikari.Embed(colour=colour,
                     description=text,
                     title=f"Eval page {page}").set_footer(
                         text=f"Time taken: {exec_time} ms"),
    ) for text, page in string_paginator)
    paginator = yuyo.ComponentPaginator(
        embed_generator,
        authors=[ctx.author.id],
        triggers=(
            yuyo.pagination.LEFT_DOUBLE_TRIANGLE,
            yuyo.pagination.LEFT_TRIANGLE,
            yuyo.pagination.STOP_SQUARE,
            yuyo.pagination.RIGHT_TRIANGLE,
            yuyo.pagination.RIGHT_DOUBLE_TRIANGLE,
        ),
        timeout=datetime.timedelta(
            days=99999),  # TODO: switch to passing None here
    )
    first_response = await paginator.get_next_entry()
    executor = utility.paginator_with_to_file(
        ctx,
        paginator,
        make_files=lambda: [
            _bytes_from_io(stdout, "stdout.py"),
            _bytes_from_io(stderr, "stderr.py")
        ])

    assert first_response is not None
    content, embed = first_response
    message = await ctx.respond(content=content,
                                embed=embed,
                                components=executor.builders,
                                ensure_result=True)
    component_client.set_executor(message, executor)
예제 #18
0
            yuyo.pagination.STOP_SQUARE,
            yuyo.pagination.RIGHT_TRIANGLE,
            yuyo.pagination.RIGHT_DOUBLE_TRIANGLE,
        ),
        timeout=datetime.timedelta(
            days=500),  # TODO: switch to passing None here once its supported
    )
    first_response = await paginator.get_next_entry()
    assert first_response
    content, embed = first_response

    executor = utility.paginator_with_to_file(
        ctx,
        paginator,
        make_files=lambda:
        [hikari.Bytes(data["lyrics"], f"{title} lyrics.txt")])
    message = await ctx.respond(content=content,
                                embed=embed,
                                components=executor.builders,
                                ensure_result=True)
    component_client.set_executor(message, executor)


_T = typing.TypeVar("_T")


def _assert_in_choices(
        choices: typing.Collection[_T]) -> typing.Callable[[_T], _T]:
    def verify(value: _T) -> _T:
        if value in choices:
            return value
예제 #19
0
async def type(ctx):
    """Graph problems solved by popular problem types"""
    # TODO: This is aids, pls fix

    usernames = ctx.options.usernames
    graph_type = ctx.options.graph_type
    as_percent = ctx.options.as_percent

    query = Query()
    if usernames == []:
        usernames = [query.get_handle(ctx.author.id, ctx.get_guild().id)]

    try:
        users = await asyncio.gather(*[query.get_user(username) for username in usernames])
    except ObjectNotFound:
        return await ctx.respond("User not found")

    for i in range(len(users)):
        if users[i] is None:
            return await ctx.respond(f"{usernames[i]} does not exist on DMOJ")

    if len(users) > 6:
        return await ctx.respond("Too many users given, max 6")

    usernames = [data.username for data in users]

    important_types = [
        ["Data Structures"],
        ["Dynamic Programming"],
        ["Graph Theory"],
        ["String Algorithms"],
        ["Advanced Math", "Geometry", "Intermediate Math", "Simple Math"],
        ["Ad Hoc"],
        ["Greedy Algorithms"],
    ]
    labels = [
        "Data Structures",
        "Dynamic Programming",
        "Graph Theory",
        "String Algorithms",
        "Math",
        "Ad Hoc",
        "Greedy Algorithms",
    ]

    data = {}
    data["group"] = []
    for label in labels:
        data[label] = []
    for username in usernames:
        data["group"].append(username)

    def calculate_partial_points(points: int):
        p = 0
        for i in range(min(100, len(points))):
            p += (0.95**i) * points[i]
        return p

    max_percentage = 0

    for username in usernames:
        q = session.query(Submission_DB).filter(Submission_DB._user == username)
        if q.count() == 0:
            await ctx.respond(f"`{username}` does not have any cached submissions, caching now")
            await query.get_submissions(username)

    for i, types in enumerate(important_types):
        total_problems = await query.get_problems(_type=types, cached=True)
        total_points = list(map(attrgetter("points"), total_problems))
        total_points.sort(reverse=True)
        total_points = calculate_partial_points(total_points)

        for username in usernames:
            points = query.get_attempted_problems(username, types)

            points.sort(reverse=True)

            points = calculate_partial_points(points)
            if as_percent:
                percentage = 100 * points / total_points
            else:
                percentage = points
            max_percentage = max(max_percentage, percentage)
            data[labels[i]].append(percentage)

    logger.debug("plot type data: %s", data)

    if graph_type == "radar":
        plot_type_radar(data, as_percent, max_percentage)
    elif graph_type == "bar":
        plot_type_bar(data, as_percent)

    embed = hikari.Embed(
        title="Problem types solved",
        color=0xFCDB05,
    )
    with open("./graphs/plot.png", "rb") as file:
        embed.set_image(hikari.Bytes(file.read(), "plot.png"))

    return await ctx.respond(embed=embed)
예제 #20
0
async def points(ctx):
    """Plot point progression"""
    usernames = ctx.options.usernames

    query = Query()
    if usernames == []:
        usernames = [query.get_handle(ctx.author.id, ctx.get_guild().id)]

    try:
        users = await asyncio.gather(*[query.get_user(username) for username in usernames])
    except ObjectNotFound:
        return await ctx.respond("User not found")

    usernames = [user.username for user in users]
    for i in range(len(users)):
        if users[i] is None:
            return await ctx.respond(f"{usernames[i]} does not exist on DMOJ")
    if len(users) > 10:
        return await ctx.respond("Too many users given, max 10")

    total_data = {}
    for username in usernames:
        q = (
            session.query(Submission_DB)
            .options(orm.joinedload("problem"))
            .join(User_DB, User_DB.username == Submission_DB._user, aliased=True)
            .filter(User_DB.username == username)
            .order_by(Submission_DB.date)
        )

        submissions = q.all()
        if len(submissions) == 0:
            await ctx.respond(f"`{username}` does not have any cached submissions, caching now")
            await query.get_submissions(username)
            submissions = q.all()
        problems_ACed = dict()
        code_to_points = dict()

        points_arr = []
        data_to_plot = {}
        # O(N^2logN) :blobcreep:
        for submission in submissions:
            code = submission.problem[0].code
            points = submission.points
            result = submission.result

            if points is not None:
                if result == "AC":
                    problems_ACed[code] = 1
                if code not in code_to_points:
                    # log N search, N insert
                    code_to_points[code] = points
                    bisect.insort(points_arr, points)
                elif points > code_to_points[code]:
                    # N remove, log N search, N insert
                    points_arr.remove(code_to_points[code])
                    code_to_points[code] = points
                    bisect.insort(points_arr, points)
                cur_points = calculate_points(points_arr[::-1], len(problems_ACed))
                data_to_plot[submission.date] = cur_points
        total_data[username] = data_to_plot

    plot_points(total_data)

    embed = hikari.Embed(
        title="Problems Progression",
        color=0xFCDB05,
    )
    with open("./graphs/plot.png", "rb") as file:
        embed.set_image(hikari.Bytes(file.read(), "plot.png"))

    return await ctx.respond(embed=embed)
예제 #21
0
async def _docs_command(
    ctx: tanjun.abc.Context,
    component_client: yuyo.ComponentClient,
    index: DocIndex,
    base_url: str,
    docs_url: str,
    name: str,
    path: str | None,
    public: bool,
    desc_splitter: str = "\n",
    **kwargs: typing.Any,
) -> None:
    if not path:
        await ctx.respond(base_url, component=utility.delete_row(ctx))
        return

    if kwargs["list"]:
        iterator = utility.embed_iterator(
            utility.chunk((f"[{m.fullname}]({index.make_link(docs_url, m)})" for m in index.search(path)), 10),
            lambda entries: "\n".join(entries),
            title=f"{name} Documentation",
            url=docs_url,
        )
        paginator = yuyo.ComponentPaginator(
            iterator,
            authors=(ctx.author,) if not public else (),
            triggers=(
                yuyo.pagination.LEFT_DOUBLE_TRIANGLE,
                yuyo.pagination.LEFT_TRIANGLE,
                yuyo.pagination.STOP_SQUARE,
                yuyo.pagination.RIGHT_TRIANGLE,
                yuyo.pagination.RIGHT_DOUBLE_TRIANGLE,
            ),
            timeout=datetime.timedelta(days=99999),  # TODO: switch to passing None here
        )
        executor = utility.paginator_with_to_file(
            ctx,
            paginator,
            make_files=lambda: [hikari.Bytes("\n".join(m.fullname for m in index.search(str(path))), "results.txt")],
        )
        components = executor.builders

    else:
        iterator = (
            (
                hikari.UNDEFINED,
                hikari.Embed(
                    description=_form_description(metadata, desc_splitter=desc_splitter),
                    color=utility.embed_colour(),
                    title=metadata.fullname,
                    url=index.make_link(docs_url, metadata),
                ),
            )
            for metadata in index.search(path)
        )
        executor = paginator = yuyo.ComponentPaginator(
            iterator,
            authors=(ctx.author,) if not public else (),
            triggers=(
                yuyo.pagination.LEFT_DOUBLE_TRIANGLE,
                yuyo.pagination.LEFT_TRIANGLE,
                yuyo.pagination.STOP_SQUARE,
                yuyo.pagination.RIGHT_TRIANGLE,
                yuyo.pagination.RIGHT_DOUBLE_TRIANGLE,
            ),
        )
        components = executor.builder()

    if first_response := await paginator.get_next_entry():
        content, embed = first_response
        message = await ctx.respond(content=content, components=components, embed=embed, ensure_result=True)
        component_client.set_executor(message, executor)
        return
예제 #22
0
            authors=(ctx.author, ) if not public else (),
            triggers=(
                yuyo.pagination.LEFT_DOUBLE_TRIANGLE,
                yuyo.pagination.LEFT_TRIANGLE,
                yuyo.pagination.STOP_SQUARE,
                yuyo.pagination.RIGHT_TRIANGLE,
                yuyo.pagination.RIGHT_DOUBLE_TRIANGLE,
            ),
            timeout=datetime.timedelta(
                days=99999),  # TODO: switch to passing None here
        )

        executor = utility.paginator_with_to_file(
            ctx,
            paginator,
            make_files=lambda: [hikari.Bytes("\n".join(uses), "results.txt")])

        first_response = await paginator.get_next_entry()
        assert first_response
        content, embed = first_response
        message = await ctx.respond(content=content,
                                    components=executor.builders,
                                    embed=embed,
                                    ensure_result=True)
        component_client.set_executor(message, executor)


@dataclasses.dataclass(frozen=True, slots=True)
class _IndexAutocomplete:
    index: ReferenceIndex