From 177cac5985ab0c5105710516d566f846051eabb8 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Fri, 18 Mar 2022 11:29:10 -0300
Subject: [PATCH 01/31] Created helper classes to aid Pages methods'
 customization; Removed `boolean cache` from lazyPaginate methods, replaced
 with `List<Page> pageCache` to allow cache modification on the go.

---
 .../com/github/ygimenez/method/Pages.java     | 157 +++++++++++++++---
 .../ygimenez/model/helper/BaseHelper.java     |  81 +++++++++
 .../model/helper/ButtonizeHelper.java         |  36 ++++
 .../model/helper/CategorizeHelper.java        |  23 +++
 .../model/helper/LazyPaginateHelper.java      |  36 ++++
 .../ygimenez/model/helper/PaginateHelper.java |  43 +++++
 6 files changed, 352 insertions(+), 24 deletions(-)
 create mode 100644 src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
 create mode 100644 src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
 create mode 100644 src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
 create mode 100644 src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
 create mode 100644 src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java

diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index bf6f264..fb1a4cf 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -6,6 +6,10 @@
 import com.github.ygimenez.exception.NullPageException;
 import com.github.ygimenez.listener.MessageHandler;
 import com.github.ygimenez.model.*;
+import com.github.ygimenez.model.helper.ButtonizeHelper;
+import com.github.ygimenez.model.helper.CategorizeHelper;
+import com.github.ygimenez.model.helper.LazyPaginateHelper;
+import com.github.ygimenez.model.helper.PaginateHelper;
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.JDA;
 import net.dv8tion.jda.api.entities.*;
@@ -113,6 +117,32 @@ public static MessageHandler getHandler() {
 		return handler;
 	}
 
+	/**
+	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
+	 * which will navigate through a given {@link List} of pages. This versions uses a helper class
+	 * to aid customization and allow reusage of configurations.
+	 *
+	 * @param helper    A {@link PaginateHelper} holding desired pagination settings.
+	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
+	 *                                         or cannot be accessed when triggering a
+	 *                                         {@link GenericMessageReactionEvent}.
+	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
+	 *                                         due to lack of bot permission.
+	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
+	 */
+	public static void paginate(@Nonnull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+		paginate(
+				helper.getMessage(),
+				helper.getContent(),
+				helper.isUsingButtons(),
+				helper.getTime(),
+				helper.getUnit(),
+				helper.getSkipAmount(),
+				helper.isFastForward(),
+				helper.getCanInteract()
+		);
+	}
+
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will navigate through a given {@link List} of pages.
@@ -620,6 +650,32 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 		});
 	}
 
+	/**
+	 * Adds menu-like buttons to the specified {@link Message}/{@link MessageEmbed}
+	 * which will browse through a given {@link Map} of pages. You may only specify
+	 * one {@link Page} per button, adding another button with an existing unicode
+	 * will overwrite the current button's {@link Page}. This versions uses a helper class
+	 * to aid customization and allow reusage of configurations.
+	 *
+	 * @param helper    A {@link CategorizeHelper} holding desired categorization settings.
+	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
+	 *                                         or cannot be accessed when triggering a
+	 *                                         {@link GenericMessageReactionEvent}.
+	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
+	 *                                         due to lack of bot permission.
+	 * @throws InvalidStateException           Thrown if the library wasn't activated.
+	 */
+	public static void categorize(@Nonnull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+		categorize(
+				helper.getMessage(),
+				helper.getContent(),
+				helper.isUsingButtons(),
+				helper.getTime(),
+				helper.getUnit(),
+				helper.getCanInteract()
+		);
+	}
+
 	/**
 	 * Adds menu-like buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will browse through a given {@link Map} of pages. You may only specify
@@ -836,6 +892,34 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 		});
 	}
 
+	/**
+	 * Adds buttons to the specified {@link Message}/{@link MessageEmbed}, with each
+	 * executing a specific task on click. You may only specify one {@link Runnable}
+	 * per button, adding another button with an existing unicode will overwrite the
+	 * current button's {@link Runnable}. This versions uses a helper class
+	 * to aid customization and allow reusage of configurations.
+	 *
+	 * @param helper    A {@link ButtonizeHelper} holding desired buttonization settings.
+	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
+	 *                                         or cannot be accessed when triggering a
+	 *                                         {@link GenericMessageReactionEvent}.
+	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
+	 *                                         due to lack of bot permission.
+	 * @throws InvalidStateException           Thrown if the library wasn't activated.
+	 */
+	public static void buttonize(@Nonnull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+		buttonize(
+				helper.getMessage(),
+				helper.getContent(),
+				helper.isUsingButtons(),
+				helper.isCancellable(),
+				helper.getTime(),
+				helper.getUnit(),
+				helper.getCanInteract(),
+				helper.getOnCancel()
+		);
+	}
+
 	/**
 	 * Adds buttons to the specified {@link Message}/{@link MessageEmbed}, with each
 	 * executing a specific task on click. You may only specify one {@link Runnable}
@@ -1129,7 +1213,33 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
-	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
+	 * This versions uses a helper class to aid customization and allow reusage of configurations.
+	 *
+	 * @param helper    A {@link LazyPaginateHelper} holding desired lazy pagination settings.
+	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
+	 *                                         or cannot be accessed when triggering a
+	 *                                         {@link GenericMessageReactionEvent}.
+	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
+	 *                                         due to lack of bot permission.
+	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
+	 */
+	public static void lazyPaginate(@Nonnull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+		lazyPaginate(
+				helper.getMessage(),
+				helper.getContent(),
+				helper.getPageLoader(),
+				helper.isUsingButtons(),
+				helper.getTime(),
+				helper.getUnit(),
+				helper.getCanInteract()
+		);
+	}
+
+	/**
+	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
+	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 *
 	 * @param msg        The {@link Message} sent which will be paginated.
 	 * @param pageLoader {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
@@ -1144,7 +1254,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
 	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageLoader, useButtons, false, 0, null, null);
+		lazyPaginate(msg, null, pageLoader, useButtons, 0, null, null);
 	}
 
 	/**
@@ -1171,13 +1281,13 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
 	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageLoader, useButtons, false, time, unit, null);
+		lazyPaginate(msg, null, pageLoader, useButtons, time, unit, null);
 	}
 
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
-	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 *
 	 * @param msg         The {@link Message} sent which will be paginated.
 	 * @param pageLoader  {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
@@ -1194,13 +1304,13 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
 	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageLoader, useButtons, false, 0, null, canInteract);
+		lazyPaginate(msg, null, pageLoader, useButtons, 0, null, canInteract);
 	}
 
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
-	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 * You can specify how long the listener will stay active before shutting down itself after a
 	 * no-activity interval.
 	 *
@@ -1223,20 +1333,20 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
 	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageLoader, useButtons, false, time, unit, canInteract);
+		lazyPaginate(msg, null, pageLoader, useButtons, time, unit, canInteract);
 	}
 
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
-	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 *
 	 * @param msg        The {@link Message} sent which will be paginated.
+	 * @param pageCache	 The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
 	 * @param pageLoader {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
 	 *                   returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                   {@link Message} was not sent by the bot.
-	 * @param cache      Enables {@link Page} caching, saving previously visited pages.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1244,23 +1354,23 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, boolean cache) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageLoader, useButtons, cache, 0, null, null);
+	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+		lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, null);
 	}
 
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
-	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 * You can specify how long the listener will stay active before shutting down itself after a
 	 * no-activity interval.
 	 *
 	 * @param msg        The {@link Message} sent which will be paginated.
+	 * @param pageCache	 The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
 	 * @param pageLoader {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
 	 *                   returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                   {@link Message} was not sent by the bot.
-	 * @param cache      Enables {@link Page} caching, saving previously visited pages.
 	 * @param time       The time before the listener automatically stop listening
 	 *                   for further events (recommended: 60).
 	 * @param unit       The time's {@link TimeUnit} (recommended:
@@ -1272,21 +1382,21 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, boolean cache, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageLoader, useButtons, cache, time, unit, null);
+	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+		lazyPaginate(msg, pageCache, pageLoader, useButtons, time, unit, null);
 	}
 
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
-	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 *
 	 * @param msg         The {@link Message} sent which will be paginated.
+	 * @param pageCache	 The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
 	 * @param pageLoader  {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
 	 *                    returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons  Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                    {@link Message} was not sent by the bot.
-	 * @param cache       Enables {@link Page} caching, saving previously visited pages.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
@@ -1296,23 +1406,23 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, boolean cache, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageLoader, useButtons, cache, 0, null, canInteract);
+	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, canInteract);
 	}
 
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
-	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 * You can specify how long the listener will stay active before shutting down itself after a
 	 * no-activity interval.
 	 *
 	 * @param msg         The {@link Message} sent which will be paginated.
+	 * @param pageCache	 The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
 	 * @param pageLoader  {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
 	 *                    returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons  Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                    {@link Message} was not sent by the bot.
-	 * @param cache       Enables {@link Page} caching, saving previously visited pages.
 	 * @param time        The time before the listener automatically stop listening
 	 *                    for further events (recommended: 60).
 	 * @param unit        The time's {@link TimeUnit} (recommended:
@@ -1326,17 +1436,16 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, boolean cache, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
+		boolean cache = pageCache != null;
 
 		if (!msg.getAuthor().equals(paginator.getHandler()))
 
 			clearButtons(msg);
 		clearReactions(msg);
 
-		List<Page> pageCache = cache ? new ArrayList<>() : null;
-
 		Page pg = pageLoader.apply(0);
 		if (pg == null) {
 			throw new InvalidStateException();
diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
new file mode 100644
index 0000000..e781583
--- /dev/null
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -0,0 +1,81 @@
+package com.github.ygimenez.model.helper;
+
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.User;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
+abstract class BaseHelper<Sub extends BaseHelper<Sub, T>, T> {
+	private final Class<Sub> subClass;
+
+	private final Message message;
+	private final T content;
+	private final boolean useButtons;
+
+	private boolean cancellable = true;
+	private int time = 0;
+	private TimeUnit unit = null;
+	private Predicate<User> canInteract = null;
+
+	public BaseHelper(Class<Sub> subClass, Message message, T buttons, boolean useButtons) {
+		this.subClass = subClass;
+		this.message = message;
+		this.content = buttons;
+		this.useButtons = useButtons;
+	}
+
+	public Message getMessage() {
+		return message;
+	}
+
+	public T getContent() {
+		return content;
+	}
+
+	public boolean isUsingButtons() {
+		return useButtons;
+	}
+
+	public boolean isCancellable() {
+		return cancellable;
+	}
+
+	public int getTime() {
+		return time;
+	}
+
+	public TimeUnit getUnit() {
+		return unit;
+	}
+
+	public Predicate<User> getCanInteract() {
+		return canInteract;
+	}
+
+	protected Sub setCancellable(boolean cancellable) {
+		this.cancellable = cancellable;
+		return subClass.cast(this);
+	}
+
+	protected Sub setTime(int time) {
+		this.time = time;
+		return subClass.cast(this);
+	}
+
+	protected Sub setUnit(TimeUnit unit) {
+		this.unit = unit;
+		return subClass.cast(this);
+	}
+
+	protected Sub setTimeUnit(int time, TimeUnit unit) {
+		this.time = time;
+		this.unit = unit;
+		return subClass.cast(this);
+	}
+
+	protected Sub setCanInteract(Predicate<User> canInteract) {
+		this.canInteract = canInteract;
+		return subClass.cast(this);
+	}
+}
diff --git a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
new file mode 100644
index 0000000..6e9884d
--- /dev/null
+++ b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
@@ -0,0 +1,36 @@
+package com.github.ygimenez.model.helper;
+
+import com.github.ygimenez.model.ButtonWrapper;
+import com.github.ygimenez.model.ThrowingConsumer;
+import net.dv8tion.jda.api.entities.Emoji;
+import net.dv8tion.jda.api.entities.Message;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+
+public class ButtonizeHelper extends BaseHelper<ButtonizeHelper, Map<Emoji, ThrowingConsumer<ButtonWrapper>>> {
+	private Consumer<Message> onCancel = null;
+
+	public ButtonizeHelper(Message message, boolean useButtons) {
+		super(ButtonizeHelper.class, message, new LinkedHashMap<>(), useButtons);
+	}
+
+	public ButtonizeHelper(Message message, Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons) {
+		super(ButtonizeHelper.class, message, buttons, useButtons);
+	}
+
+	public ButtonizeHelper addCategory(Emoji emoji, ThrowingConsumer<ButtonWrapper> action) {
+		getContent().put(emoji, action);
+		return this;
+	}
+
+	public Consumer<Message> getOnCancel() {
+		return onCancel;
+	}
+
+	public ButtonizeHelper setOnCancel(Consumer<Message> onCancel) {
+		this.onCancel = onCancel;
+		return this;
+	}
+}
diff --git a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
new file mode 100644
index 0000000..f1d0157
--- /dev/null
+++ b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
@@ -0,0 +1,23 @@
+package com.github.ygimenez.model.helper;
+
+import com.github.ygimenez.model.Page;
+import net.dv8tion.jda.api.entities.Emoji;
+import net.dv8tion.jda.api.entities.Message;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class CategorizeHelper extends BaseHelper<CategorizeHelper, Map<Emoji, Page>> {
+	public CategorizeHelper(Message message, boolean useButtons) {
+		super(CategorizeHelper.class, message, new LinkedHashMap<>(), useButtons);
+	}
+
+	public CategorizeHelper(Message message, Map<Emoji, Page> categories, boolean useButtons) {
+		super(CategorizeHelper.class, message, categories, useButtons);
+	}
+
+	public CategorizeHelper addCategory(Emoji emoji, Page page) {
+		getContent().put(emoji, page);
+		return this;
+	}
+}
diff --git a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
new file mode 100644
index 0000000..4efd320
--- /dev/null
+++ b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
@@ -0,0 +1,36 @@
+package com.github.ygimenez.model.helper;
+
+import com.github.ygimenez.model.Page;
+import com.github.ygimenez.model.ThrowingFunction;
+import net.dv8tion.jda.api.entities.Message;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LazyPaginateHelper extends PaginateHelper {
+	private final ThrowingFunction<Integer, Page> pageLoader;
+
+	public LazyPaginateHelper(Message message, ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) {
+		super(message, new ArrayList<>(), useButtons);
+		this.pageLoader = pageLoader;
+	}
+
+	public LazyPaginateHelper(Message message, ThrowingFunction<Integer, Page> pageLoader, List<Page> initialPages, boolean useButtons) {
+		super(message, initialPages, useButtons);
+		this.pageLoader = pageLoader;
+	}
+
+	public LazyPaginateHelper addPage(Page page) {
+		getContent().add(page);
+		return this;
+	}
+
+	public ThrowingFunction<Integer, Page> getPageLoader() {
+		return pageLoader;
+	}
+
+	public LazyPaginateHelper load(int page) {
+		getContent().set(page, pageLoader.apply(page));
+		return this;
+	}
+}
diff --git a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
new file mode 100644
index 0000000..16394e3
--- /dev/null
+++ b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
@@ -0,0 +1,43 @@
+package com.github.ygimenez.model.helper;
+
+import com.github.ygimenez.model.Page;
+import net.dv8tion.jda.api.entities.Message;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PaginateHelper extends BaseHelper<PaginateHelper, List<Page>> {
+	private int skipAmount = 0;
+	private boolean fastForward = false;
+
+	public PaginateHelper(Message message, boolean useButtons) {
+		super(PaginateHelper.class, message, new ArrayList<>(), useButtons);
+	}
+
+	public PaginateHelper(Message message, List<Page> pages, boolean useButtons) {
+		super(PaginateHelper.class, message, pages, useButtons);
+	}
+
+	public PaginateHelper addPage(Page page) {
+		getContent().add(page);
+		return this;
+	}
+
+	public int getSkipAmount() {
+		return skipAmount;
+	}
+
+	public PaginateHelper setSkipAmount(int skipAmount) {
+		this.skipAmount = skipAmount;
+		return this;
+	}
+
+	public boolean isFastForward() {
+		return fastForward;
+	}
+
+	public PaginateHelper setFastForward(boolean fastForward) {
+		this.fastForward = fastForward;
+		return this;
+	}
+}

From c1f25705ee93259927832bbd2c92c8c1b252e267 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Fri, 18 Mar 2022 11:33:20 -0300
Subject: [PATCH 02/31] Changed BaseHelper methods visibility to public.

---
 .../com/github/ygimenez/model/helper/BaseHelper.java   | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
index e781583..b0b45c0 100644
--- a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -53,28 +53,28 @@ public Predicate<User> getCanInteract() {
 		return canInteract;
 	}
 
-	protected Sub setCancellable(boolean cancellable) {
+	public Sub setCancellable(boolean cancellable) {
 		this.cancellable = cancellable;
 		return subClass.cast(this);
 	}
 
-	protected Sub setTime(int time) {
+	public Sub setTime(int time) {
 		this.time = time;
 		return subClass.cast(this);
 	}
 
-	protected Sub setUnit(TimeUnit unit) {
+	public Sub setUnit(TimeUnit unit) {
 		this.unit = unit;
 		return subClass.cast(this);
 	}
 
-	protected Sub setTimeUnit(int time, TimeUnit unit) {
+	public Sub setTimeUnit(int time, TimeUnit unit) {
 		this.time = time;
 		this.unit = unit;
 		return subClass.cast(this);
 	}
 
-	protected Sub setCanInteract(Predicate<User> canInteract) {
+	public Sub setCanInteract(Predicate<User> canInteract) {
 		this.canInteract = canInteract;
 		return subClass.cast(this);
 	}

From 5243a77d574af271f58ea6569a503b47c2afaf9b Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Fri, 18 Mar 2022 11:33:42 -0300
Subject: [PATCH 03/31] Changed BaseHelper methods visibility to public.

---
 src/main/java/com/github/ygimenez/model/helper/BaseHelper.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
index b0b45c0..dbe9e5a 100644
--- a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -18,7 +18,7 @@ abstract class BaseHelper<Sub extends BaseHelper<Sub, T>, T> {
 	private TimeUnit unit = null;
 	private Predicate<User> canInteract = null;
 
-	public BaseHelper(Class<Sub> subClass, Message message, T buttons, boolean useButtons) {
+	protected BaseHelper(Class<Sub> subClass, Message message, T buttons, boolean useButtons) {
 		this.subClass = subClass;
 		this.message = message;
 		this.content = buttons;

From 58d189691f3fae4848e3e12560dfd29e876be9bb Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Fri, 18 Mar 2022 11:45:52 -0300
Subject: [PATCH 04/31] Fixed dumb icon not aligning properly on README.md.

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 1c55926..2c2f13b 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@
 [ ![license-shield][] ][license]
 [ ![issue-shield][] ][issue]
 
-<img style="float: right" src="https://raw.githubusercontent.com/ygimenez/Pagination-Utils/master/icon.png" height=225 width=225 alt="Pagination Utils logo">
+<img align="right" src="https://raw.githubusercontent.com/ygimenez/Pagination-Utils/master/icon.png" height=225 width=225 alt="Pagination Utils logo">
 
 # Pagination Utils - JDA Pagination made easier!
 

From a6c324d14eb347fe82ebe2facd1ac1d1a1ecdf9b Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Fri, 18 Mar 2022 11:47:28 -0300
Subject: [PATCH 05/31] Fixed dumb icon not aligning properly on README.md

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 2c2f13b..d1ff85c 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@
 
 # Pagination Utils - JDA Pagination made easier!
 
-With this library you will be using pages and categories in your bot commands in no time!
+With this library you will be using pages, categories and buttons in your bot in no time!
 
 ## What is a page/category/button?
 

From d80945d02e41c8d903b015f5c909e743fbd96068 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Fri, 18 Mar 2022 11:47:28 -0300
Subject: [PATCH 06/31] Fixed dumb icon not aligning properly on README.md

---
 README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 2c2f13b..3f3c25f 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@
 
 # Pagination Utils - JDA Pagination made easier!
 
-With this library you will be using pages and categories in your bot commands in no time!
+With this library you will be using pages, categories and buttons in your bot in no time!
 
 ## What is a page/category/button?
 
@@ -38,7 +38,7 @@ With this library you will be using pages and categories in your bot commands in
 ![Buttonization Example](https://i.imgur.com/4PBVoTn.gif)
 
 Have you been using a bot and came across one of those three GIFs and thought: "That must've been hard to make." or "I'd
-like one of those in my bot!". Fear no more, KuuHaKu to the rescue!
+like one of those in my bot!"? Fear no more, KuuHaKu to the rescue!
 
 ## How do I paginate?
 

From fa9b81c0ef923392f51aaac9eb9e802cbe56b1a9 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Fri, 18 Mar 2022 11:51:59 -0300
Subject: [PATCH 07/31] Fixed dumb icon not aligning properly on README.md

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 3f3c25f..9bc0045 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ With this library you will be using pages, categories and buttons in your bot in
 ![Buttonization Example](https://i.imgur.com/4PBVoTn.gif)
 
 Have you been using a bot and came across one of those three GIFs and thought: "That must've been hard to make." or "I'd
-like one of those in my bot!"? Fear no more, KuuHaKu to the rescue!
+like one of those in my bot!"? Fear no more, Pagination Utils to the rescue!
 
 ## How do I paginate?
 

From fd049c3555b08b95d6428882909248d18913dd1d Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 21 Mar 2022 11:40:10 -0300
Subject: [PATCH 08/31] Helpers can now be applied to a `MessageAction` to load
 buttons (INTERACTION ONLY); `clearReactions` and `clearButtons` are no-op if
 the message doesn't contain reactions/buttons; Pagination Button style is now
 controlled by the first Page only.

---
 .../ygimenez/exception/NullPageException.java |   5 +-
 .../com/github/ygimenez/method/Pages.java     | 511 +++++++-----------
 .../ygimenez/model/helper/BaseHelper.java     |  13 +-
 .../model/helper/ButtonizeHelper.java         |  71 ++-
 .../model/helper/CategorizeHelper.java        |  70 ++-
 .../model/helper/LazyPaginateHelper.java      |  75 ++-
 .../ygimenez/model/helper/PaginateHelper.java |  81 ++-
 .../java/com/github/ygimenez/type/Emote.java  |   7 +
 8 files changed, 489 insertions(+), 344 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/exception/NullPageException.java b/src/main/java/com/github/ygimenez/exception/NullPageException.java
index 51b5109..92a8fe9 100644
--- a/src/main/java/com/github/ygimenez/exception/NullPageException.java
+++ b/src/main/java/com/github/ygimenez/exception/NullPageException.java
@@ -1,18 +1,19 @@
 package com.github.ygimenez.exception;
 
+import com.github.ygimenez.model.Page;
 import net.dv8tion.jda.api.entities.Message;
 
 import java.util.List;
 
 /**
- * Exception thrown when trying to paginate an empty {@link List}.
+ * Exception thrown when trying to paginate an empty {@link List} or action returned a null {@link Page}.
  */
 public class NullPageException extends RuntimeException {
 	/**
 	 * Default constructor.
 	 */
 	public NullPageException() {
-		super("The informed collection does not contain any Page");
+		super("The informed collection does not contain any Page or Page is null");
 	}
 
 	/**
diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index fb1a4cf..8bd42ef 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -117,32 +117,6 @@ public static MessageHandler getHandler() {
 		return handler;
 	}
 
-	/**
-	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
-	 * which will navigate through a given {@link List} of pages. This versions uses a helper class
-	 * to aid customization and allow reusage of configurations.
-	 *
-	 * @param helper    A {@link PaginateHelper} holding desired pagination settings.
-	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
-	 *                                         or cannot be accessed when triggering a
-	 *                                         {@link GenericMessageReactionEvent}.
-	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
-	 *                                         due to lack of bot permission.
-	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
-	 */
-	public static void paginate(@Nonnull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(
-				helper.getMessage(),
-				helper.getContent(),
-				helper.isUsingButtons(),
-				helper.getTime(),
-				helper.getUnit(),
-				helper.getSkipAmount(),
-				helper.isFastForward(),
-				helper.getCanInteract()
-		);
-	}
-
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will navigate through a given {@link List} of pages.
@@ -525,16 +499,40 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
 	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		if (!isActivated() || pages.isEmpty()) throw new InvalidStateException();
-		boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
-
-		List<Page> pgs = Collections.unmodifiableList(pages);
-		clearButtons(msg);
-		clearReactions(msg);
+		paginate(msg, new PaginateHelper(pages, useButtons)
+				.setTimeUnit(time, unit)
+				.setSkipAmount(skipAmount)
+				.setFastForward(fastForward)
+				.setCanInteract(canInteract)
+		);
+	}
 
-		Page pg = pgs.get(0);
-		if (useBtns) addButtons((InteractPage) pg, msg, skipAmount > 1, fastForward);
-		else addReactions(msg, skipAmount > 1, fastForward);
+	/**
+	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
+	 * which will navigate through a given {@link List} of pages. This versions uses a helper class
+	 * to aid customization and allow reusage of configurations.
+	 *
+	 * @param msg    The {@link Message} sent which will be paginated.
+	 * @param helper A {@link PaginateHelper} holding desired pagination settings.
+	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
+	 *                                         or cannot be accessed when triggering a
+	 *                                         {@link GenericMessageReactionEvent}.
+	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
+	 *                                         due to lack of bot permission.
+	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
+	 */
+	public static void paginate(@Nonnull Message msg, @Nonnull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+		if (!isActivated() || helper.getContent().isEmpty()) throw new InvalidStateException();
+		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
+		List<Page> pgs = Collections.unmodifiableList(helper.getContent());
+
+		if (useBtns && helper.shouldUpdate(msg)) {
+			helper.apply(msg.editMessageComponents()).submit();
+		} else if (!useBtns) {
+			clearButtons(msg);
+			clearReactions(msg);
+			addReactions(msg, helper.getSkipAmount() > 1, helper.isFastForward());
+		}
 
 		handler.addEvent(msg, new ThrowingBiConsumer<>() {
 			private final int maxP = pgs.size() - 1;
@@ -551,15 +549,15 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 			private final Function<Button, Button> UPPER_BOUNDARY_CHECK = b -> b.withDisabled(p == maxP);
 
 			{
-				if (time > 0 && unit != null)
-					timeout = executor.schedule(() -> finalizeEvent(msg, success), time, unit);
+				if (helper.getTime() > 0 && helper.getUnit() != null)
+					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
 			}
 
 			@Override
 			public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
-				if (canInteract == null || canInteract.test(u)) {
+				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
 					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
 						return;
 
@@ -592,13 +590,13 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 							break;
 						case SKIP_BACKWARD:
 							if (p > 0) {
-								p -= (p - skipAmount < 0 ? p : skipAmount);
+								p -= (p - helper.getSkipAmount() < 0 ? p : helper.getSkipAmount());
 								update = true;
 							}
 							break;
 						case SKIP_FORWARD:
 							if (p < maxP) {
-								p += (p + skipAmount > maxP ? maxP - p : skipAmount);
+								p += (p + helper.getSkipAmount() > maxP ? maxP - p : helper.getSkipAmount());
 								update = true;
 							}
 							break;
@@ -622,7 +620,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 					if (update) {
 						pg = pgs.get(p);
 						updatePage(m, pg);
-						updateButtons(m, pg, useBtns, skipAmount > 1, fastForward);
+						updateButtons(m, helper);
 
 						if (pg instanceof InteractPage) {
 							modifyButtons(m, Map.of(
@@ -639,8 +637,8 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 
 					if (timeout != null)
 						timeout.cancel(true);
-					if (time > 0 && unit != null)
-						timeout = executor.schedule(() -> finalizeEvent(m, success), time, unit);
+					if (helper.getTime() > 0 && helper.getUnit() != null)
+						timeout = executor.schedule(() -> finalizeEvent(m, success), helper.getTime(), helper.getUnit());
 
 					if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
 						subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
@@ -650,32 +648,6 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 		});
 	}
 
-	/**
-	 * Adds menu-like buttons to the specified {@link Message}/{@link MessageEmbed}
-	 * which will browse through a given {@link Map} of pages. You may only specify
-	 * one {@link Page} per button, adding another button with an existing unicode
-	 * will overwrite the current button's {@link Page}. This versions uses a helper class
-	 * to aid customization and allow reusage of configurations.
-	 *
-	 * @param helper    A {@link CategorizeHelper} holding desired categorization settings.
-	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
-	 *                                         or cannot be accessed when triggering a
-	 *                                         {@link GenericMessageReactionEvent}.
-	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
-	 *                                         due to lack of bot permission.
-	 * @throws InvalidStateException           Thrown if the library wasn't activated.
-	 */
-	public static void categorize(@Nonnull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
-		categorize(
-				helper.getMessage(),
-				helper.getContent(),
-				helper.isUsingButtons(),
-				helper.getTime(),
-				helper.getUnit(),
-				helper.getCanInteract()
-		);
-	}
-
 	/**
 	 * Adds menu-like buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will browse through a given {@link Map} of pages. You may only specify
@@ -781,41 +753,40 @@ public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> ca
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
 	public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		categorize(msg, new CategorizeHelper(categories, useButtons)
+				.setTimeUnit(time, unit)
+				.setCanInteract(canInteract)
+		);
+	}
+
+	/**
+	 * Adds menu-like buttons to the specified {@link Message}/{@link MessageEmbed}
+	 * which will browse through a given {@link Map} of pages. You may only specify
+	 * one {@link Page} per button, adding another button with an existing unicode
+	 * will overwrite the current button's {@link Page}. This versions uses a helper class
+	 * to aid customization and allow reusage of configurations.
+	 *
+	 * @param msg    The {@link Message} sent which will be categorized.
+	 * @param helper A {@link CategorizeHelper} holding desired categorization settings.
+	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
+	 *                                         or cannot be accessed when triggering a
+	 *                                         {@link GenericMessageReactionEvent}.
+	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
+	 *                                         due to lack of bot permission.
+	 * @throws InvalidStateException           Thrown if the library wasn't activated.
+	 */
+	public static void categorize(@Nonnull Message msg, @Nonnull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
-		boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
+		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
-		Map<Emoji, Page> cats = Collections.unmodifiableMap(categories);
-		clearButtons(msg);
-		clearReactions(msg);
+		Map<Emoji, Page> cats = Collections.unmodifiableMap(helper.getContent());
 
 		if (useBtns) {
-			List<ActionRow> rows = new ArrayList<>();
-
-			List<Component> row = new ArrayList<>();
-			for (Emoji k : cats.keySet()) {
-				if (row.size() == 5) {
-					rows.add(ActionRow.of(row));
-					row = new ArrayList<>();
-				}
-
-				row.add(Button.secondary(Emote.getId(k), k));
-			}
-
-			Button button = Button.danger(CANCEL.name(), paginator.getEmote(CANCEL));
-			if (rows.size() == 5 && row.size() == 5) {
-				row.set(4, button);
-			} else if (row.size() == 5) {
-				rows.add(ActionRow.of(row));
-				row = new ArrayList<>();
-
-				row.add(button);
-			} else {
-				row.add(button);
-			}
-
-			rows.add(ActionRow.of(row));
-			msg.editMessageComponents(rows).submit();
+			helper.apply(msg.editMessageComponents()).submit();
 		} else {
+			clearButtons(msg);
+			clearReactions(msg);
+
 			for (Emoji k : cats.keySet()) {
 				msg.addReaction(k.getAsMention().replaceAll("[<>]", "")).submit();
 			}
@@ -834,15 +805,15 @@ public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> ca
 			};
 
 			{
-				if (time > 0 && unit != null)
-					timeout = executor.schedule(() -> finalizeEvent(msg, success), time, unit);
+				if (helper.getTime() > 0 && helper.getUnit() != null)
+					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
 			}
 
 			@Override
 			public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
-				if (canInteract == null || canInteract.test(u)) {
+				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
 					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
 						return;
 
@@ -881,8 +852,8 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 
 					if (timeout != null)
 						timeout.cancel(true);
-					if (time > 0 && unit != null)
-						timeout = executor.schedule(() -> finalizeEvent(m, success), time, unit);
+					if (helper.getTime() > 0 && helper.getUnit() != null)
+						timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
 
 					if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
 						subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
@@ -892,34 +863,6 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 		});
 	}
 
-	/**
-	 * Adds buttons to the specified {@link Message}/{@link MessageEmbed}, with each
-	 * executing a specific task on click. You may only specify one {@link Runnable}
-	 * per button, adding another button with an existing unicode will overwrite the
-	 * current button's {@link Runnable}. This versions uses a helper class
-	 * to aid customization and allow reusage of configurations.
-	 *
-	 * @param helper    A {@link ButtonizeHelper} holding desired buttonization settings.
-	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
-	 *                                         or cannot be accessed when triggering a
-	 *                                         {@link GenericMessageReactionEvent}.
-	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
-	 *                                         due to lack of bot permission.
-	 * @throws InvalidStateException           Thrown if the library wasn't activated.
-	 */
-	public static void buttonize(@Nonnull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
-		buttonize(
-				helper.getMessage(),
-				helper.getContent(),
-				helper.isUsingButtons(),
-				helper.isCancellable(),
-				helper.getTime(),
-				helper.getUnit(),
-				helper.getCanInteract(),
-				helper.getOnCancel()
-		);
-	}
-
 	/**
 	 * Adds buttons to the specified {@link Message}/{@link MessageEmbed}, with each
 	 * executing a specific task on click. You may only specify one {@link Runnable}
@@ -1072,22 +1015,22 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 	 * current button's {@link Runnable}. You can specify the time in which the
 	 * listener will automatically stop itself after a no-activity interval.
 	 *
-	 * @param msg              The {@link Message} sent which will be buttoned.
-	 * @param buttons          The buttons to be shown. The buttons are defined by a
-	 *                         Map containing emoji unicodes or emote ids as keys and
-	 *                         {@link ThrowingTriConsumer}&lt;{@link Member}, {@link Message}, {@link InteractionHook}&gt;
-	 *                         containing desired behavior as value.
-	 * @param useButtons       Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
-	 *                         {@link Message} was not sent by the bot.
-	 * @param showCancelButton Should the {@link Emote#CANCEL} button be created automatically?
-	 * @param time             The time before the listener automatically stop
-	 *                         listening for further events (recommended: 60).
-	 * @param unit             The time's {@link TimeUnit} (recommended:
-	 *                         {@link TimeUnit#SECONDS}).
-	 * @param canInteract      {@link Predicate} to determine whether the
-	 *                         {@link User} that pressed the button can interact
-	 *                         with it or not.
-	 * @param onCancel         Action to be run after the listener is removed.
+	 * @param msg         The {@link Message} sent which will be buttoned.
+	 * @param buttons     The buttons to be shown. The buttons are defined by a
+	 *                    Map containing emoji unicodes or emote ids as keys and
+	 *                    {@link ThrowingTriConsumer}&lt;{@link Member}, {@link Message}, {@link InteractionHook}&gt;
+	 *                    containing desired behavior as value.
+	 * @param useButtons  Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
+	 *                    {@link Message} was not sent by the bot.
+	 * @param cancellable Should the {@link Emote#CANCEL} button be created automatically?
+	 * @param time        The time before the listener automatically stop
+	 *                    listening for further events (recommended: 60).
+	 * @param unit        The time's {@link TimeUnit} (recommended:
+	 *                    {@link TimeUnit#SECONDS}).
+	 * @param canInteract {@link Predicate} to determine whether the
+	 *                    {@link User} that pressed the button can interact
+	 *                    with it or not.
+	 * @param onCancel    Action to be run after the listener is removed.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1095,51 +1038,50 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
+	public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean cancellable, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
+		buttonize(msg, new ButtonizeHelper(buttons, useButtons)
+				.setCancellable(cancellable)
+				.setTimeUnit(time, unit)
+				.setCanInteract(canInteract)
+				.setOnCancel(onCancel)
+		);
+	}
+
+	/**
+	 * Adds buttons to the specified {@link Message}/{@link MessageEmbed}, with each
+	 * executing a specific task on click. You may only specify one {@link Runnable}
+	 * per button, adding another button with an existing unicode will overwrite the
+	 * current button's {@link Runnable}. This versions uses a helper class
+	 * to aid customization and allow reusage of configurations.
+	 *
+	 * @param msg    The {@link Message} sent which will be buttoned.
+	 * @param helper A {@link ButtonizeHelper} holding desired buttonization settings.
+	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
+	 *                                         or cannot be accessed when triggering a
+	 *                                         {@link GenericMessageReactionEvent}.
+	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
+	 *                                         due to lack of bot permission.
+	 * @throws InvalidStateException           Thrown if the library wasn't activated.
+	 */
+	public static void buttonize(@Nonnull Message msg, @Nonnull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
-		boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
+		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
-		Map<Emoji, ThrowingConsumer<ButtonWrapper>> btns = Collections.unmodifiableMap(buttons);
-		clearButtons(msg);
-		clearReactions(msg);
+		Map<Emoji, ThrowingConsumer<ButtonWrapper>> btns = Collections.unmodifiableMap(helper.getContent());
 
 		if (useBtns) {
-			List<ActionRow> rows = new ArrayList<>();
-
-			List<Component> row = new ArrayList<>();
-			for (Emoji k : btns.keySet()) {
-				if (row.size() == 5) {
-					rows.add(ActionRow.of(row));
-					row = new ArrayList<>();
-				}
-
-				row.add(Button.secondary(Emote.getId(k), k));
-			}
-
-			if (!btns.containsKey(paginator.getEmote(CANCEL)) && showCancelButton) {
-				Button button = Button.danger(CANCEL.name(), paginator.getEmote(CANCEL));
-
-				if (rows.size() == 5 && row.size() == 5) {
-					row.set(4, button);
-				} else if (row.size() == 5) {
-					rows.add(ActionRow.of(row));
-					row = new ArrayList<>();
-
-					row.add(button);
-				} else {
-					row.add(button);
-				}
-			}
-
-			rows.add(ActionRow.of(row));
-			msg.editMessageComponents(rows).submit();
+			helper.apply(msg.editMessageComponents()).submit();
 		} else {
+			clearButtons(msg);
+			clearReactions(msg);
+
 			for (Emoji k : btns.keySet()) {
 				msg.addReaction(k.getAsMention().replaceAll("[<>]", "")).submit();
 			}
 
-			if (!btns.containsKey(paginator.getEmote(CANCEL)) && showCancelButton)
+			if (!btns.containsKey(paginator.getEmote(CANCEL)) && helper.isCancellable()) {
 				msg.addReaction(paginator.getStringEmote(CANCEL)).submit();
+			}
 		}
 
 		handler.addEvent(msg, new ThrowingBiConsumer<>() {
@@ -1148,20 +1090,20 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 				if (timeout != null)
 					timeout.cancel(true);
 				handler.removeEvent(msg);
-				if (onCancel != null) onCancel.accept(msg);
+				if (helper.getOnCancel() != null) helper.getOnCancel().accept(msg);
 				if (paginator.isDeleteOnCancel()) msg.delete().submit();
 			};
 
 			{
-				if (time > 0 && unit != null)
-					timeout = executor.schedule(() -> finalizeEvent(msg, success), time, unit);
+				if (helper.getTime() > 0 && helper.getUnit() != null)
+					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
 			}
 
 			@Override
 			public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
-				if (canInteract == null || canInteract.test(u)) {
+				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
 					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
 						return;
 
@@ -1180,7 +1122,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 						}
 					}
 
-					if ((!btns.containsKey(paginator.getEmote(CANCEL)) && showCancelButton) && emt == CANCEL) {
+					if ((!btns.containsKey(paginator.getEmote(CANCEL)) && helper.isCancellable()) && emt == CANCEL) {
 						finalizeEvent(m, success);
 						return;
 					}
@@ -1199,8 +1141,8 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 
 					if (timeout != null)
 						timeout.cancel(true);
-					if (time > 0 && unit != null)
-						timeout = executor.schedule(() -> finalizeEvent(m, success), time, unit);
+					if (helper.getTime() > 0 && helper.getUnit() != null)
+						timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
 
 					if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
 						subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
@@ -1210,32 +1152,6 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 		});
 	}
 
-	/**
-	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
-	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
-	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
-	 * This versions uses a helper class to aid customization and allow reusage of configurations.
-	 *
-	 * @param helper    A {@link LazyPaginateHelper} holding desired lazy pagination settings.
-	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
-	 *                                         or cannot be accessed when triggering a
-	 *                                         {@link GenericMessageReactionEvent}.
-	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
-	 *                                         due to lack of bot permission.
-	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
-	 */
-	public static void lazyPaginate(@Nonnull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(
-				helper.getMessage(),
-				helper.getContent(),
-				helper.getPageLoader(),
-				helper.isUsingButtons(),
-				helper.getTime(),
-				helper.getUnit(),
-				helper.getCanInteract()
-		);
-	}
-
 	/**
 	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
 	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
@@ -1342,7 +1258,7 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 *
 	 * @param msg        The {@link Message} sent which will be paginated.
-	 * @param pageCache	 The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
+	 * @param pageCache  The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
 	 * @param pageLoader {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
 	 *                   returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
@@ -1366,7 +1282,7 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 	 * no-activity interval.
 	 *
 	 * @param msg        The {@link Message} sent which will be paginated.
-	 * @param pageCache	 The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
+	 * @param pageCache  The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
 	 * @param pageLoader {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
 	 *                   returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
@@ -1392,7 +1308,7 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
 	 *
 	 * @param msg         The {@link Message} sent which will be paginated.
-	 * @param pageCache	 The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
+	 * @param pageCache   The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
 	 * @param pageLoader  {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
 	 *                    returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons  Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
@@ -1418,7 +1334,7 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 	 * no-activity interval.
 	 *
 	 * @param msg         The {@link Message} sent which will be paginated.
-	 * @param pageCache	 The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
+	 * @param pageCache   The {@link List} that'll hold previously visited pages (can be pre-filled or edited anytime).
 	 * @param pageLoader  {@link ThrowingFunction}&lt;{@link Integer}, {@link Page}&gt; to generate the next page. If this
 	 *                    returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons  Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
@@ -1437,25 +1353,40 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
 	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		if (!isActivated()) throw new InvalidStateException();
-		boolean useBtns = useButtons && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
-		boolean cache = pageCache != null;
+		lazyPaginate(msg, new LazyPaginateHelper(pageLoader, pageCache, useButtons)
+				.setTimeUnit(time, unit)
+				.setCanInteract(canInteract)
+		);
+	}
 
-		if (!msg.getAuthor().equals(paginator.getHandler()))
+	/**
+	 * Adds navigation buttons to the specified {@link Message}/{@link MessageEmbed}
+	 * which will lazily load content by using supplied {@link ThrowingFunction}. For this reason,
+	 * this pagination type cannot have skip nor fast-forward buttons given the unknown page limit.
+	 * This versions uses a helper class to aid customization and allow reusage of configurations.
+	 *
+	 * @param msg    The {@link Message} sent which will be paginated.
+	 * @param helper A {@link LazyPaginateHelper} holding desired lazy pagination settings.
+	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
+	 *                                         or cannot be accessed when triggering a
+	 *                                         {@link GenericMessageReactionEvent}.
+	 * @throws InsufficientPermissionException Thrown if this library cannot remove reactions
+	 *                                         due to lack of bot permission.
+	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
+	 */
+	public static void lazyPaginate(@Nonnull Message msg, @Nonnull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+		if (!isActivated()) throw new InvalidStateException();
+		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
+		boolean cache = helper.getContent() != null;
 
+		if (useBtns && helper.shouldUpdate(msg)) {
+			helper.apply(msg.editMessageComponents()).submit();
+		} else if (!useBtns) {
 			clearButtons(msg);
-		clearReactions(msg);
-
-		Page pg = pageLoader.apply(0);
-		if (pg == null) {
-			throw new InvalidStateException();
+			clearReactions(msg);
+			addReactions(msg, false, false);
 		}
 
-		if (cache) pageCache.add(pg);
-
-		if (useBtns) addButtons((InteractPage) pg, msg, false, false);
-		else addReactions(msg, false, false);
-
 		handler.addEvent(msg, new ThrowingBiConsumer<>() {
 			private int p = 0;
 			private ScheduledFuture<?> timeout;
@@ -1467,15 +1398,15 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 			};
 
 			{
-				if (time > 0 && unit != null)
-					timeout = executor.schedule(() -> finalizeEvent(msg, success), time, unit);
+				if (helper.getTime() > 0 && helper.getUnit() != null)
+					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
 			}
 
 			@Override
 			public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
-				if (canInteract == null || canInteract.test(u)) {
+				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
 					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
 						return;
 
@@ -1496,18 +1427,25 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 						case PREVIOUS:
 							if (p > 0) {
 								p--;
-								pg = cache ? pageCache.get(p) : pageLoader.apply(p);
+								pg = cache ? helper.getContent().get(p) : helper.getPageLoader().apply(p);
 
 								updatePage(m, pg);
-								updateButtons(m, pg, useBtns, false, false);
+								updateButtons(m, helper);
 							}
 							break;
 						case NEXT:
 							p++;
-							if (cache && pageCache.size() > p) {
-								pg = pageCache.get(p);
+							if (cache && helper.getContent().size() > p) {
+								pg = helper.getContent().get(p);
+								if (pg == null) {
+									pg = helper.getPageLoader().apply(p);
+									if (pg == null) {
+										p--;
+										return;
+									}
+								}
 							} else {
-								pg = pageLoader.apply(p);
+								pg = helper.getPageLoader().apply(p);
 								if (pg == null) {
 									p--;
 									return;
@@ -1515,9 +1453,9 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 							}
 
 							updatePage(m, pg);
-							updateButtons(m, pg, useBtns, false, false);
+							updateButtons(m, helper);
 
-							if (cache) pageCache.add(pg);
+							if (cache) helper.getContent().add(pg);
 							break;
 						case CANCEL:
 							finalizeEvent(m, success);
@@ -1526,8 +1464,8 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 
 					if (timeout != null)
 						timeout.cancel(true);
-					if (time > 0 && unit != null)
-						timeout = executor.schedule(() -> finalizeEvent(m, success), time, unit);
+					if (helper.getTime() > 0 && helper.getUnit() != null)
+						timeout = executor.schedule(() -> finalizeEvent(m, success), helper.getTime(), helper.getUnit());
 
 					if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
 						subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
@@ -1554,11 +1492,19 @@ private static void updatePage(@Nonnull Message msg, Page p) {
 		}
 	}
 
-	private static void updateButtons(Message msg, Page pg, boolean useButtons, boolean withSkip, boolean withGoto) {
-		if (useButtons) {
-			addButtons((InteractPage) pg, msg, withSkip, withGoto);
+	private static void updateButtons(Message msg, PaginateHelper helper) {
+		if (helper.isUsingButtons()) {
+			helper.apply(msg.editMessageComponents()).submit();
 		} else {
-			addReactions(msg, withSkip, withGoto);
+			addReactions(msg, helper.getSkipAmount() > 1, helper.isFastForward());
+		}
+	}
+
+	private static void updateButtons(Message msg, LazyPaginateHelper helper) {
+		if (helper.isUsingButtons()) {
+			helper.apply(msg.editMessageComponents()).submit();
+		} else {
+			addReactions(msg, false, false);
 		}
 	}
 
@@ -1619,6 +1565,8 @@ private static Emoji toEmoji(MessageReaction.ReactionEmote reaction) {
 	 * @param msg The {@link Message} to have reactions/buttons removed from.
 	 */
 	public static void clearReactions(Message msg) {
+		if (msg.getReactions().isEmpty()) return;
+
 		try {
 			if (msg.getChannel().getType().isGuild())
 				msg.clearReactions().submit();
@@ -1638,6 +1586,8 @@ else for (MessageReaction r : msg.getReactions()) {
 	 * @param msg The {@link Message} to have reactions/buttons removed from.
 	 */
 	public static void clearButtons(Message msg) {
+		if (msg.getButtons().isEmpty()) return;
+
 		try {
 			subGet(msg.editMessageComponents());
 		} catch (InsufficientPermissionException | IllegalStateException e) {
@@ -1703,65 +1653,4 @@ public static void addReactions(Message msg, boolean withSkip, boolean withGoto)
 
 		RestAction.allOf(acts).submit();
 	}
-
-	/**
-	 * Utility method to add navigation buttons.
-	 *
-	 * @param page     The {@link InteractPage} containing button styles and captions.
-	 * @param msg      The {@link Message} to have reactions removed from.
-	 * @param withSkip Whether to include {@link Emote#SKIP_BACKWARD} and {@link Emote#SKIP_FORWARD} buttons.
-	 * @param withGoto Whether to include {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons.
-	 */
-	public static void addButtons(InteractPage page, Message msg, boolean withSkip, boolean withGoto) {
-		clearReactions(msg);
-
-		List<ActionRow> rows = new ArrayList<>();
-
-		List<Component> row;
-		if (withSkip && withGoto) {
-			row = List.of(
-					page.makeButton(NONE),
-					page.makeButton(PREVIOUS),
-					page.makeButton(CANCEL),
-					page.makeButton(NEXT),
-					page.makeButton(NONE)
-			);
-		} else if (withSkip) {
-			row = List.of(
-					page.makeButton(SKIP_BACKWARD),
-					page.makeButton(PREVIOUS),
-					page.makeButton(CANCEL),
-					page.makeButton(NEXT),
-					page.makeButton(SKIP_FORWARD)
-			);
-		} else if (withGoto) {
-			row = List.of(
-					page.makeButton(GOTO_FIRST),
-					page.makeButton(PREVIOUS),
-					page.makeButton(CANCEL),
-					page.makeButton(NEXT),
-					page.makeButton(GOTO_LAST)
-			);
-		} else {
-			row = List.of(
-					page.makeButton(PREVIOUS),
-					page.makeButton(CANCEL),
-					page.makeButton(NEXT)
-			);
-		}
-		rows.add(ActionRow.of(row));
-
-		if (withSkip && withGoto) {
-			row = List.of(
-					page.makeButton(GOTO_FIRST),
-					page.makeButton(SKIP_BACKWARD),
-					page.makeButton(NONE),
-					page.makeButton(SKIP_FORWARD),
-					page.makeButton(GOTO_LAST)
-			);
-			rows.add(ActionRow.of(row));
-		}
-
-		subGet(msg.editMessageComponents(rows));
-	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
index dbe9e5a..48ea6d5 100644
--- a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -2,6 +2,7 @@
 
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.requests.restaction.MessageAction;
 
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
@@ -9,7 +10,6 @@
 abstract class BaseHelper<Sub extends BaseHelper<Sub, T>, T> {
 	private final Class<Sub> subClass;
 
-	private final Message message;
 	private final T content;
 	private final boolean useButtons;
 
@@ -18,17 +18,12 @@ abstract class BaseHelper<Sub extends BaseHelper<Sub, T>, T> {
 	private TimeUnit unit = null;
 	private Predicate<User> canInteract = null;
 
-	protected BaseHelper(Class<Sub> subClass, Message message, T buttons, boolean useButtons) {
+	protected BaseHelper(Class<Sub> subClass, T buttons, boolean useButtons) {
 		this.subClass = subClass;
-		this.message = message;
 		this.content = buttons;
 		this.useButtons = useButtons;
 	}
 
-	public Message getMessage() {
-		return message;
-	}
-
 	public T getContent() {
 		return content;
 	}
@@ -78,4 +73,8 @@ public Sub setCanInteract(Predicate<User> canInteract) {
 		this.canInteract = canInteract;
 		return subClass.cast(this);
 	}
+
+	public abstract MessageAction apply(MessageAction action);
+
+	public abstract boolean shouldUpdate(Message msg);
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
index 6e9884d..931d382 100644
--- a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
@@ -1,23 +1,32 @@
 package com.github.ygimenez.model.helper;
 
+import com.github.ygimenez.method.Pages;
 import com.github.ygimenez.model.ButtonWrapper;
 import com.github.ygimenez.model.ThrowingConsumer;
+import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Emoji;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.interactions.components.ActionRow;
+import net.dv8tion.jda.api.interactions.components.Button;
+import net.dv8tion.jda.api.interactions.components.Component;
+import net.dv8tion.jda.api.requests.restaction.MessageAction;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import static com.github.ygimenez.type.Emote.CANCEL;
 
 public class ButtonizeHelper extends BaseHelper<ButtonizeHelper, Map<Emoji, ThrowingConsumer<ButtonWrapper>>> {
 	private Consumer<Message> onCancel = null;
 
-	public ButtonizeHelper(Message message, boolean useButtons) {
-		super(ButtonizeHelper.class, message, new LinkedHashMap<>(), useButtons);
+	public ButtonizeHelper(boolean useButtons) {
+		super(ButtonizeHelper.class, new LinkedHashMap<>(), useButtons);
 	}
 
-	public ButtonizeHelper(Message message, Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons) {
-		super(ButtonizeHelper.class, message, buttons, useButtons);
+	public ButtonizeHelper(Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons) {
+		super(ButtonizeHelper.class, buttons, useButtons);
 	}
 
 	public ButtonizeHelper addCategory(Emoji emoji, ThrowingConsumer<ButtonWrapper> action) {
@@ -33,4 +42,54 @@ public ButtonizeHelper setOnCancel(Consumer<Message> onCancel) {
 		this.onCancel = onCancel;
 		return this;
 	}
+
+	@Override
+	public MessageAction apply(MessageAction action) {
+		if (!isUsingButtons()) return action;
+
+		List<ActionRow> rows = new ArrayList<>();
+
+		List<Component> row = new ArrayList<>();
+		for (Emoji k : getContent().keySet()) {
+			if (row.size() == 5) {
+				rows.add(ActionRow.of(row));
+				row = new ArrayList<>();
+			}
+
+			row.add(Button.secondary(Emote.getId(k), k));
+		}
+
+		if (!getContent().containsKey(Pages.getPaginator().getEmote(CANCEL)) && isCancellable()) {
+			Button button = Button.danger(CANCEL.name(), Pages.getPaginator().getEmote(CANCEL));
+
+			if (rows.size() == 5 && row.size() == 5) {
+				row.set(4, button);
+			} else if (row.size() == 5) {
+				rows.add(ActionRow.of(row));
+				row = new ArrayList<>();
+
+				row.add(button);
+			} else {
+				row.add(button);
+			}
+		}
+
+		rows.add(ActionRow.of(row));
+
+		return action.setActionRows(rows);
+	}
+
+	@Override
+	public boolean shouldUpdate(Message msg) {
+		if (!isUsingButtons()) return false;
+
+		Predicate<Set<Emoji>> checks = e -> !isCancellable() || e.contains(Pages.getPaginator().getEmote(CANCEL));
+		Set<Emoji> emojis = msg.getButtons().stream()
+				.map(Button::getEmoji)
+				.collect(Collectors.toSet());
+
+		checks = checks.and(e -> e.containsAll(getContent().keySet()));
+
+		return checks.test(emojis);
+	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
index f1d0157..3057d96 100644
--- a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
@@ -1,23 +1,81 @@
 package com.github.ygimenez.model.helper;
 
+import com.github.ygimenez.method.Pages;
 import com.github.ygimenez.model.Page;
+import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Emoji;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.interactions.components.ActionRow;
+import net.dv8tion.jda.api.interactions.components.Button;
+import net.dv8tion.jda.api.interactions.components.Component;
+import net.dv8tion.jda.api.requests.restaction.MessageAction;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import static com.github.ygimenez.type.Emote.*;
 
 public class CategorizeHelper extends BaseHelper<CategorizeHelper, Map<Emoji, Page>> {
-	public CategorizeHelper(Message message, boolean useButtons) {
-		super(CategorizeHelper.class, message, new LinkedHashMap<>(), useButtons);
+	public CategorizeHelper(boolean useButtons) {
+		super(CategorizeHelper.class, new LinkedHashMap<>(), useButtons);
 	}
 
-	public CategorizeHelper(Message message, Map<Emoji, Page> categories, boolean useButtons) {
-		super(CategorizeHelper.class, message, categories, useButtons);
+	public CategorizeHelper(Map<Emoji, Page> categories, boolean useButtons) {
+		super(CategorizeHelper.class, categories, useButtons);
 	}
 
 	public CategorizeHelper addCategory(Emoji emoji, Page page) {
 		getContent().put(emoji, page);
 		return this;
 	}
+
+	@Override
+	public MessageAction apply(MessageAction action) {
+		if (!isUsingButtons()) return action;
+
+		List<ActionRow> rows = new ArrayList<>();
+
+		List<Component> row = new ArrayList<>();
+		for (Emoji k : getContent().keySet()) {
+			if (row.size() == 5) {
+				rows.add(ActionRow.of(row));
+				row = new ArrayList<>();
+			}
+
+			row.add(Button.secondary(Emote.getId(k), k));
+		}
+
+		if (isCancellable()) {
+			Button button = Button.danger(CANCEL.name(), Pages.getPaginator().getEmote(CANCEL));
+			if (rows.size() == 5 && row.size() == 5) {
+				row.set(4, button);
+			} else if (row.size() == 5) {
+				rows.add(ActionRow.of(row));
+				row = new ArrayList<>();
+
+				row.add(button);
+			} else {
+				row.add(button);
+			}
+		}
+
+		rows.add(ActionRow.of(row));
+
+		return action.setActionRows(rows);
+	}
+
+	@Override
+	public boolean shouldUpdate(Message msg) {
+		if (!isUsingButtons()) return false;
+
+		Predicate<Set<Emoji>> checks = e -> !isCancellable() || e.contains(Pages.getPaginator().getEmote(CANCEL));
+		Set<Emoji> emojis = msg.getButtons().stream()
+				.map(Button::getEmoji)
+				.collect(Collectors.toSet());
+
+		checks = checks.and(e -> e.containsAll(getContent().keySet()));
+
+		return checks.test(emojis);
+	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
index 4efd320..848b529 100644
--- a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
@@ -1,26 +1,46 @@
 package com.github.ygimenez.model.helper;
 
+import com.github.ygimenez.exception.InvalidStateException;
+import com.github.ygimenez.exception.NullPageException;
+import com.github.ygimenez.model.InteractPage;
 import com.github.ygimenez.model.Page;
 import com.github.ygimenez.model.ThrowingFunction;
+import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.interactions.components.ActionRow;
+import net.dv8tion.jda.api.requests.restaction.MessageAction;
 
+import javax.annotation.Nullable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
-public class LazyPaginateHelper extends PaginateHelper {
+import static com.github.ygimenez.type.Emote.*;
+import static com.github.ygimenez.type.Emote.GOTO_LAST;
+
+public class LazyPaginateHelper extends BaseHelper<LazyPaginateHelper, List<Page>> {
 	private final ThrowingFunction<Integer, Page> pageLoader;
+	private final boolean cache;
 
-	public LazyPaginateHelper(Message message, ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) {
-		super(message, new ArrayList<>(), useButtons);
+	public LazyPaginateHelper(ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) {
+		super(LazyPaginateHelper.class, new ArrayList<>(), useButtons);
 		this.pageLoader = pageLoader;
+		this.cache = true;
+		load(0);
 	}
 
-	public LazyPaginateHelper(Message message, ThrowingFunction<Integer, Page> pageLoader, List<Page> initialPages, boolean useButtons) {
-		super(message, initialPages, useButtons);
+	public LazyPaginateHelper(ThrowingFunction<Integer, Page> pageLoader, @Nullable List<Page> initialPages, boolean useButtons) {
+		super(LazyPaginateHelper.class, initialPages, useButtons);
 		this.pageLoader = pageLoader;
+		this.cache = initialPages != null;
+		load(0);
 	}
 
 	public LazyPaginateHelper addPage(Page page) {
+		if (!cache) throw new IllegalStateException();
+
 		getContent().add(page);
 		return this;
 	}
@@ -29,8 +49,47 @@ public ThrowingFunction<Integer, Page> getPageLoader() {
 		return pageLoader;
 	}
 
-	public LazyPaginateHelper load(int page) {
-		getContent().set(page, pageLoader.apply(page));
-		return this;
+	public @Nullable Page load(int page) {
+		if (cache) {
+			int maxIndex = getContent().size() - 1;
+			while (maxIndex < page) {
+				getContent().add(null);
+				maxIndex++;
+			}
+		}
+
+		Page p = pageLoader.apply(page);
+		if (cache) getContent().set(page, p);
+		return p;
+	}
+
+	@Override
+	public MessageAction apply(MessageAction action) {
+		if (!isUsingButtons()) return action;
+
+		InteractPage p = (InteractPage) load(0);
+		if (p == null) throw new NullPageException();
+
+		return action.setActionRows(ActionRow.of(new ArrayList<>() {{
+			add(p.makeButton(PREVIOUS));
+			if (isCancellable()) add(p.makeButton(CANCEL));
+			add(p.makeButton(NEXT));
+		}}));
+	}
+
+	@Override
+	public boolean shouldUpdate(Message msg) {
+		if (!isUsingButtons()) return true;
+
+		Predicate<Set<Emote>> checks = e -> e.containsAll(Set.of(PREVIOUS, NEXT));
+		Set<Emote> emotes = msg.getButtons().stream()
+				.map(Emote::fromButton)
+				.collect(Collectors.toSet());
+
+		if (isCancellable()) {
+			checks = checks.and(e -> e.contains(CANCEL));
+		}
+
+		return !checks.test(emotes);
 	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
index 16394e3..3ff9b84 100644
--- a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
@@ -1,21 +1,33 @@
 package com.github.ygimenez.model.helper;
 
+import com.github.ygimenez.exception.NullPageException;
+import com.github.ygimenez.model.InteractPage;
 import com.github.ygimenez.model.Page;
+import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.interactions.components.ActionRow;
+import net.dv8tion.jda.api.interactions.components.Component;
+import net.dv8tion.jda.api.requests.restaction.MessageAction;
 
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import static com.github.ygimenez.type.Emote.*;
 
 public class PaginateHelper extends BaseHelper<PaginateHelper, List<Page>> {
 	private int skipAmount = 0;
 	private boolean fastForward = false;
 
-	public PaginateHelper(Message message, boolean useButtons) {
-		super(PaginateHelper.class, message, new ArrayList<>(), useButtons);
+	public PaginateHelper(boolean useButtons) {
+		super(PaginateHelper.class, new ArrayList<>(), useButtons);
 	}
 
-	public PaginateHelper(Message message, List<Page> pages, boolean useButtons) {
-		super(PaginateHelper.class, message, pages, useButtons);
+	public PaginateHelper(List<Page> pages, boolean useButtons) {
+		super(PaginateHelper.class, pages, useButtons);
 	}
 
 	public PaginateHelper addPage(Page page) {
@@ -40,4 +52,65 @@ public PaginateHelper setFastForward(boolean fastForward) {
 		this.fastForward = fastForward;
 		return this;
 	}
+
+	@Override
+	public MessageAction apply(MessageAction action) {
+		if (!isUsingButtons()) return action;
+
+		if (getContent().isEmpty()) throw new NullPageException();
+		InteractPage p = (InteractPage) getContent().get(0);
+
+		List<ActionRow> rows = new ArrayList<>();
+
+		LinkedList<Component> row = new LinkedList<>() {{
+			add(p.makeButton(PREVIOUS));
+			if (isCancellable()) add(p.makeButton(CANCEL));
+			add(p.makeButton(NEXT));
+		}};
+		if (skipAmount > 1 && fastForward) {
+			row.addFirst(p.makeButton(NONE));
+			row.addLast(p.makeButton(NONE));
+		} else if (skipAmount > 1) {
+			row.addFirst(p.makeButton(SKIP_BACKWARD));
+			row.addLast(p.makeButton(SKIP_FORWARD));
+		} else if (fastForward) {
+			row.addFirst(p.makeButton(GOTO_FIRST));
+			row.addLast(p.makeButton(GOTO_LAST));
+		}
+		rows.add(ActionRow.of(row));
+
+		if (skipAmount > 1 && fastForward) {
+			rows.add(ActionRow.of(new ArrayList<>() {{
+				add(p.makeButton(GOTO_FIRST));
+				add(p.makeButton(SKIP_BACKWARD));
+				if (isCancellable()) add(p.makeButton(NONE));
+				add(p.makeButton(SKIP_FORWARD));
+				add(p.makeButton(GOTO_LAST));
+			}}));
+		}
+
+		return action.setActionRows(rows);
+	}
+
+	@Override
+	public boolean shouldUpdate(Message msg) {
+		if (isUsingButtons()) return true;
+
+		Predicate<Set<Emote>> checks = e -> e.containsAll(Set.of(PREVIOUS, NEXT));
+		Set<Emote> emotes = msg.getButtons().stream()
+				.map(Emote::fromButton)
+				.collect(Collectors.toSet());
+
+		if (isCancellable()) {
+			checks = checks.and(e -> e.contains(CANCEL));
+		}
+		if (skipAmount > 1) {
+			checks = checks.and(e -> e.containsAll(Set.of(SKIP_BACKWARD, SKIP_FORWARD)));
+		}
+		if (fastForward) {
+			checks = checks.and(e -> e.containsAll(Set.of(GOTO_FIRST, GOTO_LAST)));
+		}
+
+		return !checks.test(emotes);
+	}
 }
diff --git a/src/main/java/com/github/ygimenez/type/Emote.java b/src/main/java/com/github/ygimenez/type/Emote.java
index 4962722..1b02994 100644
--- a/src/main/java/com/github/ygimenez/type/Emote.java
+++ b/src/main/java/com/github/ygimenez/type/Emote.java
@@ -7,6 +7,7 @@
 import net.dv8tion.jda.api.interactions.components.Button;
 import net.dv8tion.jda.api.interactions.components.ButtonStyle;
 
+import java.util.Arrays;
 import java.util.Map;
 import java.util.Objects;
 
@@ -134,4 +135,10 @@ public static boolean isNative(MessageReaction react) {
 	public static String getId(Emoji emj) {
 			return emj.isCustom() ? emj.getId() : emj.getName();
 	}
+
+	public static Emote fromButton(Button btn) {
+		return Arrays.stream(values())
+				.filter(e -> btn.getId() != null && btn.getId().contains(e.name()))
+				.findFirst().orElse(null);
+	}
 }

From 741ebb38af3d6ffaedad67dee012b3d26278e350 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Wed, 23 Mar 2022 09:42:04 -0300
Subject: [PATCH 09/31] Methods now return a WeakReference of their actions,
 allowing tracking of whether an event is still ongoing or was already removed
 and collected.

---
 .../ygimenez/listener/MessageHandler.java     |   7 +-
 .../com/github/ygimenez/method/Pages.java     | 181 +++++++++++-------
 2 files changed, 113 insertions(+), 75 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/listener/MessageHandler.java b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
index 1b594dd..18aff89 100644
--- a/src/main/java/com/github/ygimenez/listener/MessageHandler.java
+++ b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
@@ -18,6 +18,7 @@
 import org.jetbrains.annotations.NotNull;
 
 import javax.annotation.Nonnull;
+import java.lang.ref.WeakReference;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.Map;
@@ -40,11 +41,15 @@ public class MessageHandler extends ListenerAdapter {
 	 *
 	 * @param msg The {@link Message} to hold the event.
 	 * @param act The action to be executed when the button is pressed.
+	 * @return A {@link WeakReference} pointing to this event. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 */
-	public void addEvent(Message msg, ThrowingBiConsumer<User, PaginationEventWrapper> act) {
+	public WeakReference<String> addEvent(Message msg, ThrowingBiConsumer<User, PaginationEventWrapper> act) {
 		String id = getEventId(msg);
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_3, "Added event with ID " + id + " and Consumer hash " + Integer.toHexString(act.hashCode()));
 		events.put(id, act);
+
+		return new WeakReference<>(id);
 	}
 
 	/**
diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 8bd42ef..4ddcc48 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -26,6 +26,7 @@
 import net.dv8tion.jda.api.sharding.ShardManager;
 
 import javax.annotation.Nonnull;
+import java.lang.ref.WeakReference;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.function.Consumer;
@@ -126,6 +127,8 @@ public static MessageHandler getHandler() {
 	 *                   define the order of the pages.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                   {@link Message} was not sent by the bot.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -133,8 +136,8 @@ public static MessageHandler getHandler() {
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, 0, null, 0, false, null);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, 0, null, 0, false, null);
 	}
 
 	/**
@@ -152,6 +155,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                   for further events (recommended: 60).
 	 * @param unit       The time's {@link TimeUnit} (recommended:
 	 *                   {@link TimeUnit#SECONDS}).
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -159,8 +164,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, time, unit, 0, false, null);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, time, unit, 0, false, null);
 	}
 
 	/**
@@ -174,6 +179,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                    {@link Message} was not sent by the bot.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -181,8 +188,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, 0, null, 0, false, canInteract);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, 0, null, 0, false, canInteract);
 	}
 
 	/**
@@ -202,6 +209,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                    {@link TimeUnit#SECONDS}).
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -209,8 +218,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, time, unit, 0, false, canInteract);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, time, unit, 0, false, canInteract);
 	}
 
 	/**
@@ -223,6 +232,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 * @param useButtons  Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                    {@link Message} was not sent by the bot.
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -230,8 +241,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, 0, null, 0, fastForward, null);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, 0, null, 0, fastForward, null);
 	}
 
 	/**
@@ -250,6 +261,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 * @param unit        The time's {@link TimeUnit} (recommended:
 	 *                    {@link TimeUnit#SECONDS}).
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -257,8 +270,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, time, unit, 0, fastForward, null);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, time, unit, 0, fastForward, null);
 	}
 
 	/**
@@ -273,6 +286,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -280,8 +295,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, 0, null, 0, fastForward, canInteract);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, 0, null, 0, fastForward, canInteract);
 	}
 
 	/**
@@ -302,6 +317,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -309,8 +326,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, time, unit, 0, fastForward, canInteract);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, time, unit, 0, fastForward, canInteract);
 	}
 
 	/**
@@ -324,6 +341,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                   {@link Message} was not sent by the bot.
 	 * @param skipAmount The amount of pages to be skipped when clicking {@link Emote#SKIP_BACKWARD}
 	 *                   and {@link Emote#SKIP_FORWARD} buttons.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -331,8 +350,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, 0, null, skipAmount, false, null);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, 0, null, skipAmount, false, null);
 	}
 
 	/**
@@ -352,6 +371,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                   {@link TimeUnit#SECONDS}).
 	 * @param skipAmount The amount of pages to be skipped when clicking {@link Emote#SKIP_BACKWARD}
 	 *                   and {@link Emote#SKIP_FORWARD} buttons.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -359,8 +380,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, time, unit, skipAmount, false, null);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, time, unit, skipAmount, false, null);
 	}
 
 	/**
@@ -376,6 +397,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                    and {@link Emote#SKIP_FORWARD} buttons.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -383,8 +406,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, 0, null, skipAmount, false, canInteract);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, 0, null, skipAmount, false, canInteract);
 	}
 
 	/**
@@ -406,6 +429,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                    and {@link Emote#SKIP_FORWARD} buttons.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -413,8 +438,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, time, unit, skipAmount, false, canInteract);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, time, unit, skipAmount, false, canInteract);
 	}
 
 	/**
@@ -431,6 +456,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -438,8 +465,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, 0, null, skipAmount, fastForward, canInteract);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, 0, null, skipAmount, fastForward, canInteract);
 	}
 
 	/**
@@ -460,6 +487,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 * @param skipAmount  The amount of pages to be skipped when clicking {@link Emote#SKIP_BACKWARD}
 	 *                    and {@link Emote#SKIP_FORWARD} buttons.
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -467,8 +496,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, pages, useButtons, time, unit, skipAmount, fastForward, null);
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, pages, useButtons, time, unit, skipAmount, fastForward, null);
 	}
 
 	/**
@@ -491,6 +520,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -498,8 +529,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		paginate(msg, new PaginateHelper(pages, useButtons)
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return paginate(msg, new PaginateHelper(pages, useButtons)
 				.setTimeUnit(time, unit)
 				.setSkipAmount(skipAmount)
 				.setFastForward(fastForward)
@@ -514,6 +545,8 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *
 	 * @param msg    The {@link Message} sent which will be paginated.
 	 * @param helper A {@link PaginateHelper} holding desired pagination settings.
+	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -521,7 +554,7 @@ public static void paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boo
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static void paginate(@Nonnull Message msg, @Nonnull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated() || helper.getContent().isEmpty()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		List<Page> pgs = Collections.unmodifiableList(helper.getContent());
@@ -534,7 +567,7 @@ public static void paginate(@Nonnull Message msg, @Nonnull PaginateHelper helper
 			addReactions(msg, helper.getSkipAmount() > 1, helper.isFastForward());
 		}
 
-		handler.addEvent(msg, new ThrowingBiConsumer<>() {
+		return handler.addEvent(msg, new ThrowingBiConsumer<>() {
 			private final int maxP = pgs.size() - 1;
 			private int p = 0;
 			private ScheduledFuture<?> timeout;
@@ -667,8 +700,8 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
-		categorize(msg, categories, useButtons, 0, null, null);
+	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+		return categorize(msg, categories, useButtons, 0, null, null);
 	}
 
 	/**
@@ -696,8 +729,8 @@ public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> ca
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
-		categorize(msg, categories, useButtons, time, unit, null);
+	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+		return categorize(msg, categories, useButtons, time, unit, null);
 	}
 
 	/**
@@ -721,8 +754,8 @@ public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> ca
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		categorize(msg, categories, useButtons, 0, null, canInteract);
+	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return categorize(msg, categories, useButtons, 0, null, canInteract);
 	}
 
 	/**
@@ -752,8 +785,8 @@ public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> ca
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		categorize(msg, new CategorizeHelper(categories, useButtons)
+	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return categorize(msg, new CategorizeHelper(categories, useButtons)
 				.setTimeUnit(time, unit)
 				.setCanInteract(canInteract)
 		);
@@ -775,7 +808,7 @@ public static void categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> ca
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void categorize(@Nonnull Message msg, @Nonnull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
@@ -794,7 +827,7 @@ public static void categorize(@Nonnull Message msg, @Nonnull CategorizeHelper he
 			msg.addReaction(paginator.getStringEmote(CANCEL)).submit();
 		}
 
-		handler.addEvent(msg, new ThrowingBiConsumer<>() {
+		return handler.addEvent(msg, new ThrowingBiConsumer<>() {
 			private Emoji currCat = null;
 			private ScheduledFuture<?> timeout;
 			private final Consumer<Void> success = s -> {
@@ -884,8 +917,8 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton) throws ErrorResponseException, InsufficientPermissionException {
-		buttonize(msg, buttons, useButtons, showCancelButton, 0, null, null, null);
+	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton) throws ErrorResponseException, InsufficientPermissionException {
+		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, null, null);
 	}
 
 	/**
@@ -914,8 +947,8 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
-		buttonize(msg, buttons, useButtons, showCancelButton, time, unit, null, null);
+	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+		return buttonize(msg, buttons, useButtons, showCancelButton, time, unit, null, null);
 	}
 
 	/**
@@ -942,8 +975,8 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		buttonize(msg, buttons, useButtons, showCancelButton, 0, null, canInteract, null);
+	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, canInteract, null);
 	}
 
 	/**
@@ -975,8 +1008,8 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		buttonize(msg, buttons, useButtons, showCancelButton, time, unit, canInteract, null);
+	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return buttonize(msg, buttons, useButtons, showCancelButton, time, unit, canInteract, null);
 	}
 
 	/**
@@ -1004,8 +1037,8 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
-		buttonize(msg, buttons, useButtons, showCancelButton, 0, null, canInteract, onCancel);
+	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
+		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, canInteract, onCancel);
 	}
 
 	/**
@@ -1038,8 +1071,8 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean cancellable, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
-		buttonize(msg, new ButtonizeHelper(buttons, useButtons)
+	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean cancellable, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
+		return buttonize(msg, new ButtonizeHelper(buttons, useButtons)
 				.setCancellable(cancellable)
 				.setTimeUnit(time, unit)
 				.setCanInteract(canInteract)
@@ -1063,7 +1096,7 @@ public static void buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingC
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static void buttonize(@Nonnull Message msg, @Nonnull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
@@ -1084,7 +1117,7 @@ public static void buttonize(@Nonnull Message msg, @Nonnull ButtonizeHelper help
 			}
 		}
 
-		handler.addEvent(msg, new ThrowingBiConsumer<>() {
+		return handler.addEvent(msg, new ThrowingBiConsumer<>() {
 			private ScheduledFuture<?> timeout;
 			private final Consumer<Void> success = s -> {
 				if (timeout != null)
@@ -1169,8 +1202,8 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, null, pageLoader, useButtons, 0, null, null);
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+		return lazyPaginate(msg, null, pageLoader, useButtons, 0, null, null);
 	}
 
 	/**
@@ -1196,8 +1229,8 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, null, pageLoader, useButtons, time, unit, null);
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+		return lazyPaginate(msg, null, pageLoader, useButtons, time, unit, null);
 	}
 
 	/**
@@ -1219,8 +1252,8 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, null, pageLoader, useButtons, 0, null, canInteract);
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return lazyPaginate(msg, null, pageLoader, useButtons, 0, null, canInteract);
 	}
 
 	/**
@@ -1248,8 +1281,8 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, null, pageLoader, useButtons, time, unit, canInteract);
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return lazyPaginate(msg, null, pageLoader, useButtons, time, unit, canInteract);
 	}
 
 	/**
@@ -1270,8 +1303,8 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, null);
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+		return lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, null);
 	}
 
 	/**
@@ -1298,8 +1331,8 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageCache, pageLoader, useButtons, time, unit, null);
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+		return lazyPaginate(msg, pageCache, pageLoader, useButtons, time, unit, null);
 	}
 
 	/**
@@ -1322,8 +1355,8 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, canInteract);
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, canInteract);
 	}
 
 	/**
@@ -1352,8 +1385,8 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
-		lazyPaginate(msg, new LazyPaginateHelper(pageLoader, pageCache, useButtons)
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+		return lazyPaginate(msg, new LazyPaginateHelper(pageLoader, pageCache, useButtons)
 				.setTimeUnit(time, unit)
 				.setCanInteract(canInteract)
 		);
@@ -1374,7 +1407,7 @@ public static void lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Non
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static void lazyPaginate(@Nonnull Message msg, @Nonnull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		boolean cache = helper.getContent() != null;
@@ -1387,7 +1420,7 @@ public static void lazyPaginate(@Nonnull Message msg, @Nonnull LazyPaginateHelpe
 			addReactions(msg, false, false);
 		}
 
-		handler.addEvent(msg, new ThrowingBiConsumer<>() {
+		return handler.addEvent(msg, new ThrowingBiConsumer<>() {
 			private int p = 0;
 			private ScheduledFuture<?> timeout;
 			private final Consumer<Void> success = s -> {

From c6b6a2544213d5194b46f061e86b2e8f625f0c64 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Wed, 23 Mar 2022 10:38:38 -0300
Subject: [PATCH 10/31] Replaced WeakReference with a custom ActionReference
 that checks for not-collected-yet cases.

---
 .../ygimenez/listener/MessageHandler.java     |   7 +-
 .../com/github/ygimenez/method/Pages.java     | 106 +++++++++---------
 .../ygimenez/model/ActionReference.java       |  26 +++++
 3 files changed, 83 insertions(+), 56 deletions(-)
 create mode 100644 src/main/java/com/github/ygimenez/model/ActionReference.java

diff --git a/src/main/java/com/github/ygimenez/listener/MessageHandler.java b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
index 18aff89..f662f8e 100644
--- a/src/main/java/com/github/ygimenez/listener/MessageHandler.java
+++ b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
@@ -1,6 +1,7 @@
 package com.github.ygimenez.listener;
 
 import com.github.ygimenez.method.Pages;
+import com.github.ygimenez.model.ActionReference;
 import com.github.ygimenez.model.PUtilsConfig;
 import com.github.ygimenez.model.PaginationEventWrapper;
 import com.github.ygimenez.model.ThrowingBiConsumer;
@@ -41,15 +42,15 @@ public class MessageHandler extends ListenerAdapter {
 	 *
 	 * @param msg The {@link Message} to hold the event.
 	 * @param act The action to be executed when the button is pressed.
-	 * @return A {@link WeakReference} pointing to this event. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this event. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 */
-	public WeakReference<String> addEvent(Message msg, ThrowingBiConsumer<User, PaginationEventWrapper> act) {
+	public ActionReference addEvent(Message msg, ThrowingBiConsumer<User, PaginationEventWrapper> act) {
 		String id = getEventId(msg);
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_3, "Added event with ID " + id + " and Consumer hash " + Integer.toHexString(act.hashCode()));
 		events.put(id, act);
 
-		return new WeakReference<>(id);
+		return new ActionReference(id);
 	}
 
 	/**
diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 4ddcc48..0533199 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -127,7 +127,7 @@ public static MessageHandler getHandler() {
 	 *                   define the order of the pages.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                   {@link Message} was not sent by the bot.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -136,7 +136,7 @@ public static MessageHandler getHandler() {
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, 0, false, null);
 	}
 
@@ -155,7 +155,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                   for further events (recommended: 60).
 	 * @param unit       The time's {@link TimeUnit} (recommended:
 	 *                   {@link TimeUnit#SECONDS}).
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -164,7 +164,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, 0, false, null);
 	}
 
@@ -179,7 +179,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                    {@link Message} was not sent by the bot.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -188,7 +188,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, 0, false, canInteract);
 	}
 
@@ -209,7 +209,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                    {@link TimeUnit#SECONDS}).
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -218,7 +218,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, 0, false, canInteract);
 	}
 
@@ -232,7 +232,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 * @param useButtons  Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                    {@link Message} was not sent by the bot.
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -241,7 +241,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, 0, fastForward, null);
 	}
 
@@ -261,7 +261,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 * @param unit        The time's {@link TimeUnit} (recommended:
 	 *                    {@link TimeUnit#SECONDS}).
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -270,7 +270,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, 0, fastForward, null);
 	}
 
@@ -286,7 +286,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -295,7 +295,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, 0, fastForward, canInteract);
 	}
 
@@ -317,7 +317,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -326,7 +326,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, 0, fastForward, canInteract);
 	}
 
@@ -341,7 +341,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                   {@link Message} was not sent by the bot.
 	 * @param skipAmount The amount of pages to be skipped when clicking {@link Emote#SKIP_BACKWARD}
 	 *                   and {@link Emote#SKIP_FORWARD} buttons.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -350,7 +350,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, skipAmount, false, null);
 	}
 
@@ -371,7 +371,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                   {@link TimeUnit#SECONDS}).
 	 * @param skipAmount The amount of pages to be skipped when clicking {@link Emote#SKIP_BACKWARD}
 	 *                   and {@link Emote#SKIP_FORWARD} buttons.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -380,7 +380,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, skipAmount, false, null);
 	}
 
@@ -397,7 +397,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                    and {@link Emote#SKIP_FORWARD} buttons.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -406,7 +406,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, skipAmount, false, canInteract);
 	}
 
@@ -429,7 +429,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                    and {@link Emote#SKIP_FORWARD} buttons.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -438,7 +438,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, skipAmount, false, canInteract);
 	}
 
@@ -456,7 +456,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -465,7 +465,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, skipAmount, fastForward, canInteract);
 	}
 
@@ -487,7 +487,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 * @param skipAmount  The amount of pages to be skipped when clicking {@link Emote#SKIP_BACKWARD}
 	 *                    and {@link Emote#SKIP_FORWARD} buttons.
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -496,7 +496,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, skipAmount, fastForward, null);
 	}
 
@@ -520,7 +520,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 * @param fastForward Whether the {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons should be shown.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -529,7 +529,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, new PaginateHelper(pages, useButtons)
 				.setTimeUnit(time, unit)
 				.setSkipAmount(skipAmount)
@@ -545,7 +545,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *
 	 * @param msg    The {@link Message} sent which will be paginated.
 	 * @param helper A {@link PaginateHelper} holding desired pagination settings.
-	 * @return A {@link WeakReference} pointing to this action. This is useful if you need to track whether an event
+	 * @return An {@link ActionReference} pointing to this action. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
@@ -554,7 +554,7 @@ public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull List
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static WeakReference<String> paginate(@Nonnull Message msg, @Nonnull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@Nonnull Message msg, @Nonnull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated() || helper.getContent().isEmpty()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		List<Page> pgs = Collections.unmodifiableList(helper.getContent());
@@ -700,7 +700,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, categories, useButtons, 0, null, null);
 	}
 
@@ -729,7 +729,7 @@ public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Ma
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, categories, useButtons, time, unit, null);
 	}
 
@@ -754,7 +754,7 @@ public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Ma
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, categories, useButtons, 0, null, canInteract);
 	}
 
@@ -785,7 +785,7 @@ public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Ma
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, new CategorizeHelper(categories, useButtons)
 				.setTimeUnit(time, unit)
 				.setCanInteract(canInteract)
@@ -808,7 +808,7 @@ public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull Ma
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> categorize(@Nonnull Message msg, @Nonnull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@Nonnull Message msg, @Nonnull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
@@ -917,7 +917,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, null, null);
 	}
 
@@ -947,7 +947,7 @@ public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, time, unit, null, null);
 	}
 
@@ -975,7 +975,7 @@ public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, canInteract, null);
 	}
 
@@ -1008,7 +1008,7 @@ public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, time, unit, canInteract, null);
 	}
 
@@ -1037,7 +1037,7 @@ public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, canInteract, onCancel);
 	}
 
@@ -1071,7 +1071,7 @@ public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean cancellable, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean cancellable, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, new ButtonizeHelper(buttons, useButtons)
 				.setCancellable(cancellable)
 				.setTimeUnit(time, unit)
@@ -1096,7 +1096,7 @@ public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull Map
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static WeakReference<String> buttonize(@Nonnull Message msg, @Nonnull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
@@ -1202,7 +1202,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, null, pageLoader, useButtons, 0, null, null);
 	}
 
@@ -1229,7 +1229,7 @@ public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, null, pageLoader, useButtons, time, unit, null);
 	}
 
@@ -1252,7 +1252,7 @@ public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, null, pageLoader, useButtons, 0, null, canInteract);
 	}
 
@@ -1281,7 +1281,7 @@ public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, null, pageLoader, useButtons, time, unit, canInteract);
 	}
 
@@ -1303,7 +1303,7 @@ public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, null);
 	}
 
@@ -1331,7 +1331,7 @@ public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, pageCache, pageLoader, useButtons, time, unit, null);
 	}
 
@@ -1355,7 +1355,7 @@ public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, canInteract);
 	}
 
@@ -1385,7 +1385,7 @@ public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, new LazyPaginateHelper(pageLoader, pageCache, useButtons)
 				.setTimeUnit(time, unit)
 				.setCanInteract(canInteract)
@@ -1407,7 +1407,7 @@ public static WeakReference<String> lazyPaginate(@Nonnull Message msg, List<Page
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static WeakReference<String> lazyPaginate(@Nonnull Message msg, @Nonnull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		boolean cache = helper.getContent() != null;
diff --git a/src/main/java/com/github/ygimenez/model/ActionReference.java b/src/main/java/com/github/ygimenez/model/ActionReference.java
new file mode 100644
index 0000000..f67ecc4
--- /dev/null
+++ b/src/main/java/com/github/ygimenez/model/ActionReference.java
@@ -0,0 +1,26 @@
+package com.github.ygimenez.model;
+
+import com.github.ygimenez.method.Pages;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+public class ActionReference extends WeakReference<String> {
+	public ActionReference(String referent) {
+		super(referent);
+	}
+
+	public ActionReference(String referent, ReferenceQueue<? super String> q) {
+		super(referent, q);
+	}
+
+	@Nullable
+	@Override
+	public String get() {
+		if (!Pages.getHandler().getEventMap().containsKey(super.get()))
+			enqueue();
+
+		return super.get();
+	}
+}

From 8635ee7f4c8eccef4aec9127530dc337def711e1 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Wed, 23 Mar 2022 10:48:13 -0300
Subject: [PATCH 11/31] Replaced WeakReference with a custom ActionReference
 that checks for not-collected-yet cases.

---
 .../ygimenez/listener/MessageHandler.java     | 24 ++++++++++++++-----
 .../ygimenez/model/ActionReference.java       |  2 +-
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/listener/MessageHandler.java b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
index f662f8e..23b14d8 100644
--- a/src/main/java/com/github/ygimenez/listener/MessageHandler.java
+++ b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
@@ -19,6 +19,7 @@
 import org.jetbrains.annotations.NotNull;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.lang.ref.WeakReference;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
@@ -45,7 +46,7 @@ public class MessageHandler extends ListenerAdapter {
 	 * @return An {@link ActionReference} pointing to this event. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 */
-	public ActionReference addEvent(Message msg, ThrowingBiConsumer<User, PaginationEventWrapper> act) {
+	public ActionReference addEvent(@Nonnull Message msg, @Nonnull ThrowingBiConsumer<User, PaginationEventWrapper> act) {
 		String id = getEventId(msg);
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_3, "Added event with ID " + id + " and Consumer hash " + Integer.toHexString(act.hashCode()));
 		events.put(id, act);
@@ -58,12 +59,23 @@ public ActionReference addEvent(Message msg, ThrowingBiConsumer<User, Pagination
 	 *
 	 * @param msg The {@link Message} which had attached events.
 	 */
-	public void removeEvent(Message msg) {
+	public void removeEvent(@Nonnull Message msg) {
 		String id = getEventId(msg);
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_3, "Removed event with ID " + id);
 		events.remove(id);
 	}
 
+	/**
+	 * Checks if an event hash is still present in the map.
+	 *
+	 * @param hash The event hash.
+	 * @return Whether the hash exists in the events map (will be always false if hash is null).
+	 */
+	public boolean checkEvent(@Nullable String hash) {
+		if (hash == null) return false;
+		return events.containsKey(hash);
+	}
+
 	/**
 	 * Retrieves the event handler map. This will contain all currently active events being handled by
 	 * the library mapped by {@link Guild} ID ({@link PrivateChannel} ID for DM) plus the {@link Message} ID.
@@ -84,21 +96,21 @@ public void clear() {
 		events.clear();
 	}
 
-	private void lock(String id) {
+	private void lock(@Nonnull String id) {
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Locked event with ID " + id);
 		locks.add(id);
 	}
 
-	private void unlock(String id) {
+	private void unlock(@Nonnull String id) {
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Unlocked event with ID " + id);
 		locks.remove(id);
 	}
 
-	private boolean isLocked(GenericMessageReactionEvent evt) {
+	private boolean isLocked(@Nonnull GenericMessageReactionEvent evt) {
 		return locks.contains(getEventId(evt));
 	}
 
-	private boolean isLocked(String id) {
+	private boolean isLocked(@Nonnull String id) {
 		return locks.contains(id);
 	}
 
diff --git a/src/main/java/com/github/ygimenez/model/ActionReference.java b/src/main/java/com/github/ygimenez/model/ActionReference.java
index f67ecc4..e5fc5a2 100644
--- a/src/main/java/com/github/ygimenez/model/ActionReference.java
+++ b/src/main/java/com/github/ygimenez/model/ActionReference.java
@@ -18,7 +18,7 @@ public ActionReference(String referent, ReferenceQueue<? super String> q) {
 	@Nullable
 	@Override
 	public String get() {
-		if (!Pages.getHandler().getEventMap().containsKey(super.get()))
+		if (!Pages.getHandler().checkEvent(super.get()))
 			enqueue();
 
 		return super.get();

From 2953cb2ca67309ce34f2b6a372d351eb732623a4 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Wed, 23 Mar 2022 11:02:01 -0300
Subject: [PATCH 12/31] Added method to check ActionReference validity without
 risking creating a new strong reference to it.

---
 src/main/java/com/github/ygimenez/model/ActionReference.java | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/main/java/com/github/ygimenez/model/ActionReference.java b/src/main/java/com/github/ygimenez/model/ActionReference.java
index e5fc5a2..69a517a 100644
--- a/src/main/java/com/github/ygimenez/model/ActionReference.java
+++ b/src/main/java/com/github/ygimenez/model/ActionReference.java
@@ -23,4 +23,8 @@ public String get() {
 
 		return super.get();
 	}
+
+	public boolean check() {
+		return get() != null;
+	}
 }

From 58f0f6aee48ad4184bc6d2bc60d4af8423334df7 Mon Sep 17 00:00:00 2001
From: ygimenez <yagogimenez1@hotmail.com>
Date: Tue, 19 Apr 2022 10:11:02 -0300
Subject: [PATCH 13/31] Added missing `createPaginator` signatures

---
 .idea/misc.xml                                |  5 +++++
 pom.xml                                       |  4 ++--
 .../ygimenez/model/PaginatorBuilder.java      | 20 +++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/.idea/misc.xml b/.idea/misc.xml
index e2b9406..caf365b 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -85,4 +85,9 @@
   <component name="ProjectType">
     <option name="id" value="jpab" />
   </component>
+  <component name="SwUserDefinedSpecifications">
+    <option name="specTypeByUrl">
+      <map />
+    </option>
+  </component>
 </project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 548c0c6..867be46 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
 
     <groupId>com.github.ygimenez</groupId>
     <artifactId>Pagination-Utils</artifactId>
-    <version>3.0.8</version>
+    <version>4.0.0</version>
     <packaging>jar</packaging>
 
     <name>Pagination Utils</name>
@@ -33,7 +33,7 @@
         <url>https://github.com/ygimenez/Pagination-Utils</url>
         <connection>scm:git:git@github.com:ygimenez/Pagination-Utils.git</connection>
         <developerConnection>scm:git:git@github.com:ygimenez/Pagination-Utils.git</developerConnection>
-        <tag>Pagination-Utils-3.0.8</tag>
+        <tag>Pagination-Utils-4.0.0</tag>
     </scm>
 
     <distributionManagement>
diff --git a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
index 6698b5b..1b200e9 100644
--- a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
+++ b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
@@ -42,6 +42,26 @@ public static PaginatorBuilder createPaginator() {
 		return new PaginatorBuilder(new Paginator());
 	}
 
+	/**
+	 * Creates a new {@link PaginatorBuilder} instance and begin customization, use {@link #build()} to finish.
+	 *
+	 * @param handler The {@link JDA} instance that'll be used for event processing.
+	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
+	 */
+	public static PaginatorBuilder createPaginator(@Nonnull JDA handler) {
+		return new PaginatorBuilder(new Paginator(handler));
+	}
+
+	/**
+	 * Creates a new {@link PaginatorBuilder} instance and begin customization, use {@link #build()} to finish.
+	 *
+	 * @param handler The {@link ShardManager} instance that'll be used for event processing.
+	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
+	 */
+	public static PaginatorBuilder createPaginator(@Nonnull ShardManager handler) {
+		return new PaginatorBuilder(new Paginator(handler));
+	}
+
 	/**
 	 * Creates a new {@link Paginator} instance using default settings.
 	 *

From 1c18ecb446a4e065b118e9414701581908016ea7 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Fri, 6 Jan 2023 01:42:36 -0300
Subject: [PATCH 14/31] Initial migration of library to JDA 5.

---
 .idea/jpa-buddy.xml                           |   6 +
 .idea/misc.xml                                |   5 -
 pom.xml                                       |   8 +-
 .../ygimenez/listener/MessageHandler.java     |  43 ++---
 .../com/github/ygimenez/method/Pages.java     | 170 +++++++++---------
 .../github/ygimenez/model/InteractPage.java   |  21 ++-
 .../java/com/github/ygimenez/model/Page.java  |   5 +-
 .../model/PaginationEventWrapper.java         |  14 +-
 .../com/github/ygimenez/model/Paginator.java  |  22 +--
 .../ygimenez/model/PaginatorBuilder.java      |  22 +--
 .../ygimenez/model/helper/BaseHelper.java     |   4 +-
 .../model/helper/ButtonizeHelper.java         |  20 +--
 .../model/helper/CategorizeHelper.java        |  20 +--
 .../model/helper/LazyPaginateHelper.java      |  10 +-
 .../ygimenez/model/helper/PaginateHelper.java |  10 +-
 .../ygimenez/model/helper/ReadyMessage.java   |   7 +
 .../ygimenez/model/helper/SendWrapper.java    |  72 ++++++++
 .../java/com/github/ygimenez/type/Emote.java  |  16 +-
 18 files changed, 277 insertions(+), 198 deletions(-)
 create mode 100644 .idea/jpa-buddy.xml
 create mode 100644 src/main/java/com/github/ygimenez/model/helper/ReadyMessage.java
 create mode 100644 src/main/java/com/github/ygimenez/model/helper/SendWrapper.java

diff --git a/.idea/jpa-buddy.xml b/.idea/jpa-buddy.xml
new file mode 100644
index 0000000..966d5f5
--- /dev/null
+++ b/.idea/jpa-buddy.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="JpaBuddyIdeaProjectConfig">
+    <option name="renamerInitialized" value="true" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index caf365b..e2b9406 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -85,9 +85,4 @@
   <component name="ProjectType">
     <option name="id" value="jpab" />
   </component>
-  <component name="SwUserDefinedSpecifications">
-    <option name="specTypeByUrl">
-      <map />
-    </option>
-  </component>
 </project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 867be46..85d7fe7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,9 +118,9 @@
 
     <repositories>
         <repository>
-            <id>jcenter</id>
-            <name>jcenter-bintray</name>
-            <url>https://jcenter.bintray.com</url>
+            <id>central</id>
+            <name>maven-central</name>
+            <url>https://repo1.maven.org/maven2/</url>
         </repository>
         <repository>
             <id>dv8tion</id>
@@ -133,7 +133,7 @@
         <dependency>
             <groupId>net.dv8tion</groupId>
             <artifactId>JDA</artifactId>
-            <version>4.4.0_350</version>
+            <version>5.0.0-beta.2</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
diff --git a/src/main/java/com/github/ygimenez/listener/MessageHandler.java b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
index 23b14d8..518574f 100644
--- a/src/main/java/com/github/ygimenez/listener/MessageHandler.java
+++ b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
@@ -5,11 +5,10 @@
 import com.github.ygimenez.model.PUtilsConfig;
 import com.github.ygimenez.model.PaginationEventWrapper;
 import com.github.ygimenez.model.ThrowingBiConsumer;
-import net.dv8tion.jda.api.entities.Guild;
 import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.entities.PrivateChannel;
 import net.dv8tion.jda.api.entities.User;
-import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
+import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
 import net.dv8tion.jda.api.events.message.GenericMessageEvent;
 import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
 import net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent;
@@ -17,10 +16,8 @@
 import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveEvent;
 import net.dv8tion.jda.api.hooks.ListenerAdapter;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import java.lang.ref.WeakReference;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.Map;
@@ -46,7 +43,7 @@ public class MessageHandler extends ListenerAdapter {
 	 * @return An {@link ActionReference} pointing to this event. This is useful if you need to track whether an event
 	 * is still being processed or was already removed (ie. garbage collected).
 	 */
-	public ActionReference addEvent(@Nonnull Message msg, @Nonnull ThrowingBiConsumer<User, PaginationEventWrapper> act) {
+	public ActionReference addEvent(@NotNull Message msg, @NotNull ThrowingBiConsumer<User, PaginationEventWrapper> act) {
 		String id = getEventId(msg);
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_3, "Added event with ID " + id + " and Consumer hash " + Integer.toHexString(act.hashCode()));
 		events.put(id, act);
@@ -59,7 +56,7 @@ public ActionReference addEvent(@Nonnull Message msg, @Nonnull ThrowingBiConsume
 	 *
 	 * @param msg The {@link Message} which had attached events.
 	 */
-	public void removeEvent(@Nonnull Message msg) {
+	public void removeEvent(@NotNull Message msg) {
 		String id = getEventId(msg);
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_3, "Removed event with ID " + id);
 		events.remove(id);
@@ -78,7 +75,7 @@ public boolean checkEvent(@Nullable String hash) {
 
 	/**
 	 * Retrieves the event handler map. This will contain all currently active events being handled by
-	 * the library mapped by {@link Guild} ID ({@link PrivateChannel} ID for DM) plus the {@link Message} ID.
+	 * the library mapped by {@link MessageChannel} ID plus the {@link Message} ID.
 	 *
 	 * @return An unmodifiable {@link Map} containing events handled by the library.
 	 */
@@ -96,37 +93,37 @@ public void clear() {
 		events.clear();
 	}
 
-	private void lock(@Nonnull String id) {
+	private void lock(@NotNull String id) {
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Locked event with ID " + id);
 		locks.add(id);
 	}
 
-	private void unlock(@Nonnull String id) {
+	private void unlock(@NotNull String id) {
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Unlocked event with ID " + id);
 		locks.remove(id);
 	}
 
-	private boolean isLocked(@Nonnull GenericMessageReactionEvent evt) {
+	private boolean isLocked(@NotNull GenericMessageReactionEvent evt) {
 		return locks.contains(getEventId(evt));
 	}
 
-	private boolean isLocked(@Nonnull String id) {
+	private boolean isLocked(@NotNull String id) {
 		return locks.contains(id);
 	}
 
 	@Override
-	public void onMessageReactionAdd(@Nonnull MessageReactionAddEvent evt) {
+	public void onMessageReactionAdd(@NotNull MessageReactionAddEvent evt) {
 		execute(evt);
 	}
 
 	@Override
-	public void onMessageReactionRemove(@Nonnull MessageReactionRemoveEvent evt) {
+	public void onMessageReactionRemove(@NotNull MessageReactionRemoveEvent evt) {
 		if (!Pages.getPaginator().isRemoveOnReact() || !evt.isFromGuild())
 			execute(evt);
 	}
 
 	@Override
-	public void onMessageDelete(@Nonnull MessageDeleteEvent evt) {
+	public void onMessageDelete(@NotNull MessageDeleteEvent evt) {
 		events.remove(getEventId(evt));
 	}
 
@@ -136,15 +133,13 @@ private void execute(GenericMessageReactionEvent evt) {
 
 		evt.retrieveUser().submit()
 				.whenComplete((u, t) -> processEvent(
-						t,
-						id,
-						u,
+						t, id, u,
 						new PaginationEventWrapper(evt, u, evt.getChannel(), evt.getMessageId(), evt.getReaction(), evt.isFromGuild())
 				));
 	}
 
 	@Override
-	public void onButtonClick(@NotNull ButtonClickEvent evt) {
+	public void onButtonInteraction(@NotNull ButtonInteractionEvent evt) {
 		User u = evt.getUser();
 		String id = getEventId(evt);
 		if (!events.containsKey(id)) return;
@@ -191,15 +186,15 @@ private void processEvent(Throwable t, String id, User u, PaginationEventWrapper
 
 	private String getEventId(GenericMessageEvent evt) {
 		crc.reset();
-		String rawId = (evt.isFromGuild() ? "GUILD_" + evt.getGuild().getId() : "PRIVATE_" + evt.getPrivateChannel().getId()) + "_" + evt.getMessageId();
+		String rawId = (evt.isFromGuild() ? "GUILD_" : "PRIVATE_") + evt.getChannel().getId() + "_" + evt.getMessageId();
 		crc.update(rawId.getBytes(StandardCharsets.UTF_8));
 
 		return Long.toHexString(crc.getValue());
 	}
 
-	private String getEventId(ButtonClickEvent evt) {
+	private String getEventId(ButtonInteractionEvent evt) {
 		crc.reset();
-		String rawId = (evt.getGuild() != null ? "GUILD_" + evt.getGuild().getId() : "PRIVATE_" + evt.getPrivateChannel().getId()) + "_" + evt.getMessageId();
+		String rawId = (evt.isFromGuild() ? "GUILD_" : "PRIVATE_") + evt.getChannel().getId() + "_" + evt.getId();
 		crc.update(rawId.getBytes(StandardCharsets.UTF_8));
 
 		return Long.toHexString(crc.getValue());
@@ -207,7 +202,7 @@ private String getEventId(ButtonClickEvent evt) {
 
 	private String getEventId(Message msg) {
 		crc.reset();
-		String rawId = (msg.isFromGuild() ? "GUILD_" + msg.getGuild().getId() : "PRIVATE_" + msg.getPrivateChannel().getId()) + "_" + msg.getId();
+		String rawId = (msg.isFromGuild() ? "GUILD_" : "PRIVATE_") + msg.getChannel().getId() + "_" + msg.getId();
 		crc.update(rawId.getBytes(StandardCharsets.UTF_8));
 
 		return Long.toHexString(crc.getValue());
diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 0533199..c35a871 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -13,20 +13,23 @@
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.JDA;
 import net.dv8tion.jda.api.entities.*;
-import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
 import net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent;
 import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
 import net.dv8tion.jda.api.exceptions.ErrorResponseException;
 import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
 import net.dv8tion.jda.api.interactions.InteractionHook;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
-import net.dv8tion.jda.api.interactions.components.Button;
-import net.dv8tion.jda.api.interactions.components.Component;
+import net.dv8tion.jda.api.interactions.components.ItemComponent;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.requests.RestAction;
 import net.dv8tion.jda.api.sharding.ShardManager;
+import net.dv8tion.jda.api.utils.messages.MessageEditBuilder;
+import net.dv8tion.jda.api.utils.messages.MessageEditData;
+import org.jetbrains.annotations.NotNull;
 
-import javax.annotation.Nonnull;
-import java.lang.ref.WeakReference;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.function.Consumer;
@@ -57,7 +60,7 @@ public class Pages {
 	 * @throws InvalidHandlerException   Thrown if the handler isn't either a {@link JDA}
 	 *                                   or {@link ShardManager} object.
 	 */
-	public static void activate(@Nonnull Paginator paginator) throws InvalidHandlerException {
+	public static void activate(@NotNull Paginator paginator) throws InvalidHandlerException {
 		if (isActivated())
 			throw new AlreadyActivatedException();
 
@@ -136,7 +139,7 @@ public static MessageHandler getHandler() {
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, 0, false, null);
 	}
 
@@ -164,7 +167,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, 0, false, null);
 	}
 
@@ -188,7 +191,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, 0, false, canInteract);
 	}
 
@@ -218,7 +221,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, 0, false, canInteract);
 	}
 
@@ -241,7 +244,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, 0, fastForward, null);
 	}
 
@@ -270,7 +273,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, 0, fastForward, null);
 	}
 
@@ -295,7 +298,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, 0, fastForward, canInteract);
 	}
 
@@ -326,7 +329,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, 0, fastForward, canInteract);
 	}
 
@@ -350,7 +353,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, skipAmount, false, null);
 	}
 
@@ -380,7 +383,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, skipAmount, false, null);
 	}
 
@@ -406,7 +409,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, skipAmount, false, canInteract);
 	}
 
@@ -438,7 +441,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, skipAmount, false, canInteract);
 	}
 
@@ -465,7 +468,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, 0, null, skipAmount, fastForward, canInteract);
 	}
 
@@ -496,7 +499,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, pages, useButtons, time, unit, skipAmount, fastForward, null);
 	}
 
@@ -529,7 +532,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, new PaginateHelper(pages, useButtons)
 				.setTimeUnit(time, unit)
 				.setSkipAmount(skipAmount)
@@ -554,7 +557,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull List<Page>
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or the page list is empty.
 	 */
-	public static ActionReference paginate(@Nonnull Message msg, @Nonnull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference paginate(@NotNull Message msg, @NotNull PaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated() || helper.getContent().isEmpty()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		List<Page> pgs = Collections.unmodifiableList(helper.getContent());
@@ -587,7 +590,7 @@ public static ActionReference paginate(@Nonnull Message msg, @Nonnull PaginateHe
 			}
 
 			@Override
-			public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
+			public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
 				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
@@ -596,7 +599,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 
 					Emote emt = NONE;
 					if (wrapper.getContent() instanceof MessageReaction) {
-						MessageReaction.ReactionEmote reaction = ((MessageReaction) wrapper.getContent()).getReactionEmote();
+						EmojiUnion reaction = ((MessageReaction) wrapper.getContent()).getEmoji();
 						emt = toEmote(reaction);
 					} else if (wrapper.getContent() instanceof Button) {
 						Button btn = (Button) wrapper.getContent();
@@ -700,7 +703,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoji, Page> categories, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, categories, useButtons, 0, null, null);
 	}
 
@@ -729,7 +732,7 @@ public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoj
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, categories, useButtons, time, unit, null);
 	}
 
@@ -754,7 +757,7 @@ public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoj
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoji, Page> categories, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, categories, useButtons, 0, null, canInteract);
 	}
 
@@ -785,7 +788,7 @@ public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoj
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, new CategorizeHelper(categories, useButtons)
 				.setTimeUnit(time, unit)
 				.setCanInteract(canInteract)
@@ -808,7 +811,7 @@ public static ActionReference categorize(@Nonnull Message msg, @Nonnull Map<Emoj
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference categorize(@Nonnull Message msg, @Nonnull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference categorize(@NotNull Message msg, @NotNull CategorizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
@@ -821,10 +824,10 @@ public static ActionReference categorize(@Nonnull Message msg, @Nonnull Categori
 			clearReactions(msg);
 
 			for (Emoji k : cats.keySet()) {
-				msg.addReaction(k.getAsMention().replaceAll("[<>]", "")).submit();
+				msg.addReaction(k).submit();
 			}
 
-			msg.addReaction(paginator.getStringEmote(CANCEL)).submit();
+			msg.addReaction(paginator.getEmoji(CANCEL)).submit();
 		}
 
 		return handler.addEvent(msg, new ThrowingBiConsumer<>() {
@@ -843,7 +846,7 @@ public static ActionReference categorize(@Nonnull Message msg, @Nonnull Categori
 			}
 
 			@Override
-			public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
+			public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
 				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
@@ -853,7 +856,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 					Emoji emoji = null;
 					Emote emt = NONE;
 					if (wrapper.getContent() instanceof MessageReaction) {
-						MessageReaction.ReactionEmote reaction = ((MessageReaction) wrapper.getContent()).getReactionEmote();
+						EmojiUnion reaction = ((MessageReaction) wrapper.getContent()).getEmoji();
 						emoji = toEmoji(reaction);
 						emt = toEmote(reaction);
 					} else if (wrapper.getContent() instanceof Button) {
@@ -917,7 +920,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, null, null);
 	}
 
@@ -947,7 +950,7 @@ public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, time, unit, null, null);
 	}
 
@@ -975,7 +978,7 @@ public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, canInteract, null);
 	}
 
@@ -1008,7 +1011,7 @@ public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, time, unit, canInteract, null);
 	}
 
@@ -1037,7 +1040,7 @@ public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean showCancelButton, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, buttons, useButtons, showCancelButton, 0, null, canInteract, onCancel);
 	}
 
@@ -1071,7 +1074,7 @@ public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean cancellable, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean cancellable, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, new ButtonizeHelper(buttons, useButtons)
 				.setCancellable(cancellable)
 				.setTimeUnit(time, unit)
@@ -1096,7 +1099,7 @@ public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Map<Emoji
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated.
 	 */
-	public static ActionReference buttonize(@Nonnull Message msg, @Nonnull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference buttonize(@NotNull Message msg, @NotNull ButtonizeHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
@@ -1109,11 +1112,11 @@ public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Buttonize
 			clearReactions(msg);
 
 			for (Emoji k : btns.keySet()) {
-				msg.addReaction(k.getAsMention().replaceAll("[<>]", "")).submit();
+				msg.addReaction(k).submit();
 			}
 
-			if (!btns.containsKey(paginator.getEmote(CANCEL)) && helper.isCancellable()) {
-				msg.addReaction(paginator.getStringEmote(CANCEL)).submit();
+			if (!btns.containsKey(paginator.getEmoji(CANCEL)) && helper.isCancellable()) {
+				msg.addReaction(paginator.getEmoji(CANCEL)).submit();
 			}
 		}
 
@@ -1133,7 +1136,7 @@ public static ActionReference buttonize(@Nonnull Message msg, @Nonnull Buttonize
 			}
 
 			@Override
-			public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
+			public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
 				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
@@ -1143,7 +1146,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 					Emoji emoji = null;
 					Emote emt = NONE;
 					if (wrapper.getContent() instanceof MessageReaction) {
-						MessageReaction.ReactionEmote reaction = ((MessageReaction) wrapper.getContent()).getReactionEmote();
+						EmojiUnion reaction = ((MessageReaction) wrapper.getContent()).getEmoji();
 						emoji = toEmoji(reaction);
 						emt = toEmote(reaction);
 					} else if (wrapper.getContent() instanceof Button) {
@@ -1155,14 +1158,14 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 						}
 					}
 
-					if ((!btns.containsKey(paginator.getEmote(CANCEL)) && helper.isCancellable()) && emt == CANCEL) {
+					if ((!btns.containsKey(paginator.getEmoji(CANCEL)) && helper.isCancellable()) && emt == CANCEL) {
 						finalizeEvent(m, success);
 						return;
 					}
 
 					InteractionHook hook;
-					if (wrapper.getSource() instanceof ButtonClickEvent) {
-						hook = ((ButtonClickEvent) wrapper.getSource()).getHook();
+					if (wrapper.getSource() instanceof ButtonInteractionEvent) {
+						hook = ((ButtonInteractionEvent) wrapper.getSource()).getHook();
 					} else {
 						hook = null;
 					}
@@ -1202,7 +1205,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, null, pageLoader, useButtons, 0, null, null);
 	}
 
@@ -1229,7 +1232,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull Throwi
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, null, pageLoader, useButtons, time, unit, null);
 	}
 
@@ -1252,7 +1255,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull Throwi
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, null, pageLoader, useButtons, 0, null, canInteract);
 	}
 
@@ -1281,7 +1284,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull Throwi
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, null, pageLoader, useButtons, time, unit, canInteract);
 	}
 
@@ -1303,7 +1306,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull Throwi
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> pageCache, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, null);
 	}
 
@@ -1331,7 +1334,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> page
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> pageCache, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, pageCache, pageLoader, useButtons, time, unit, null);
 	}
 
@@ -1355,7 +1358,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> page
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> pageCache, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, pageCache, pageLoader, useButtons, 0, null, canInteract);
 	}
 
@@ -1385,7 +1388,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> page
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> pageCache, @Nonnull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> pageCache, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, new LazyPaginateHelper(pageLoader, pageCache, useButtons)
 				.setTimeUnit(time, unit)
 				.setCanInteract(canInteract)
@@ -1407,7 +1410,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, List<Page> page
 	 *                                         due to lack of bot permission.
 	 * @throws InvalidStateException           Thrown if the library wasn't activated or first page cannot be generated.
 	 */
-	public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
+	public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull LazyPaginateHelper helper) throws ErrorResponseException, InsufficientPermissionException {
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		boolean cache = helper.getContent() != null;
@@ -1436,7 +1439,7 @@ public static ActionReference lazyPaginate(@Nonnull Message msg, @Nonnull LazyPa
 			}
 
 			@Override
-			public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrapper) {
+			public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
 				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
@@ -1445,7 +1448,7 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 
 					Emote emt = NONE;
 					if (wrapper.getContent() instanceof MessageReaction) {
-						MessageReaction.ReactionEmote reaction = ((MessageReaction) wrapper.getContent()).getReactionEmote();
+						EmojiUnion reaction = ((MessageReaction) wrapper.getContent()).getEmoji();
 						emt = toEmote(reaction);
 					} else if (wrapper.getContent() instanceof Button) {
 						Button btn = (Button) wrapper.getContent();
@@ -1515,17 +1518,21 @@ public void acceptThrows(@Nonnull User u, @Nonnull PaginationEventWrapper wrappe
 	 * @param msg The current {@link Message} object.
 	 * @param p   The current {@link Page}.
 	 */
-	private static void updatePage(@Nonnull Message msg, Page p) {
+	private static void updatePage(@NotNull Message msg, Page p) {
 		if (p == null) throw new NullPageException(msg);
 
 		if (p.getContent() instanceof Message) {
-			msg.editMessage((Message) p.getContent()).submit();
+			MessageEditData data = MessageEditBuilder.fromMessage((Message) p.getContent()).build();
+
+			try (data) {
+				msg.editMessage(data).submit();
+			}
 		} else if (p.getContent() instanceof MessageEmbed) {
 			msg.editMessageEmbeds((MessageEmbed) p.getContent()).submit();
 		}
 	}
 
-	private static void updateButtons(Message msg, PaginateHelper helper) {
+	private static void updateButtons(@NotNull Message msg, @NotNull PaginateHelper helper) {
 		if (helper.isUsingButtons()) {
 			helper.apply(msg.editMessageComponents()).submit();
 		} else {
@@ -1533,7 +1540,7 @@ private static void updateButtons(Message msg, PaginateHelper helper) {
 		}
 	}
 
-	private static void updateButtons(Message msg, LazyPaginateHelper helper) {
+	private static void updateButtons(@NotNull Message msg, @NotNull LazyPaginateHelper helper) {
 		if (helper.isUsingButtons()) {
 			helper.apply(msg.editMessageComponents()).submit();
 		} else {
@@ -1547,7 +1554,7 @@ private static void updateButtons(Message msg, LazyPaginateHelper helper) {
 	 * @param msg The {@link Message} to be reloaded.
 	 * @return The updated message instance.
 	 */
-	public static Message reloadMessage(Message msg) {
+	public static Message reloadMessage(@NotNull Message msg) {
 		return subGet(msg.getChannel().retrieveMessageById(msg.getId()), msg);
 	}
 
@@ -1558,7 +1565,7 @@ public static Message reloadMessage(Message msg) {
 	 * @param <T>    Return type for the {@link RestAction}.
 	 * @return The {@link RestAction} result, or null should it fail.
 	 */
-	public static <T> T subGet(RestAction<T> future) {
+	public static <T> T subGet(@NotNull RestAction<T> future) {
 		try {
 			return future.submit().get();
 		} catch (InterruptedException | ExecutionException e) {
@@ -1575,7 +1582,7 @@ public static <T> T subGet(RestAction<T> future) {
 	 * @param <T>    Return type for the {@link RestAction}.
 	 * @return The {@link RestAction} result.
 	 */
-	public static <T> T subGet(RestAction<T> future, T or) {
+	public static <T> T subGet(@NotNull RestAction<T> future, @NotNull T or) {
 		try {
 			return future.submit().get();
 		} catch (InterruptedException | ExecutionException e) {
@@ -1584,12 +1591,12 @@ public static <T> T subGet(RestAction<T> future, T or) {
 		}
 	}
 
-	private static Emote toEmote(MessageReaction.ReactionEmote reaction) {
+	private static Emote toEmote(EmojiUnion reaction) {
 		return Emote.getByEmoji(toEmoji(reaction));
 	}
 
-	private static Emoji toEmoji(MessageReaction.ReactionEmote reaction) {
-		return reaction.isEmoji() ? Emoji.fromUnicode(reaction.getEmoji()) : Emoji.fromEmote(reaction.getEmote());
+	private static Emoji toEmoji(EmojiUnion reaction) {
+		return Emoji.fromFormatted(reaction.getFormatted());
 	}
 
 	/**
@@ -1651,11 +1658,14 @@ public static void modifyButtons(Message msg, Map<String, Function<Button, Butto
 		List<ActionRow> rows = new ArrayList<>(msg.getActionRows());
 
 		for (ActionRow ar : rows) {
-			List<Component> row = ar.getComponents();
+			List<ItemComponent> row = ar.getComponents();
 			for (int i = 0; i < row.size(); i++) {
-				Component c = row.get(i);
-				if (c instanceof Button && changes.containsKey(c.getId())) {
-					row.set(i, changes.get(c.getId()).apply((Button) c));
+				ItemComponent c = row.get(i);
+				if (c instanceof Button) {
+					Button b = (Button) c;
+					if (changes.containsKey(b.getId())) {
+						row.set(i, changes.get(b.getId()).apply((Button) c));
+					}
 				}
 			}
 		}
@@ -1674,15 +1684,15 @@ public static void addReactions(Message msg, boolean withSkip, boolean withGoto)
 		clearButtons(msg);
 		List<RestAction<Void>> acts = new ArrayList<>();
 
-		if (withGoto) acts.add(msg.addReaction(paginator.getStringEmote(GOTO_FIRST)));
-		if (withSkip) acts.add(msg.addReaction(paginator.getStringEmote(SKIP_BACKWARD)));
+		if (withGoto) acts.add(msg.addReaction(paginator.getEmoji(GOTO_FIRST)));
+		if (withSkip) acts.add(msg.addReaction(paginator.getEmoji(SKIP_BACKWARD)));
 
-		acts.add(msg.addReaction(paginator.getStringEmote(PREVIOUS)));
-		acts.add(msg.addReaction(paginator.getStringEmote(CANCEL)));
-		acts.add(msg.addReaction(paginator.getStringEmote(NEXT)));
+		acts.add(msg.addReaction(paginator.getEmoji(PREVIOUS)));
+		acts.add(msg.addReaction(paginator.getEmoji(CANCEL)));
+		acts.add(msg.addReaction(paginator.getEmoji(NEXT)));
 
-		if (withSkip) acts.add(msg.addReaction(paginator.getStringEmote(SKIP_FORWARD)));
-		if (withGoto) acts.add(msg.addReaction(paginator.getStringEmote(GOTO_LAST)));
+		if (withSkip) acts.add(msg.addReaction(paginator.getEmoji(SKIP_FORWARD)));
+		if (withGoto) acts.add(msg.addReaction(paginator.getEmoji(GOTO_LAST)));
 
 		RestAction.allOf(acts).submit();
 	}
diff --git a/src/main/java/com/github/ygimenez/model/InteractPage.java b/src/main/java/com/github/ygimenez/model/InteractPage.java
index 13fa559..5a02458 100644
--- a/src/main/java/com/github/ygimenez/model/InteractPage.java
+++ b/src/main/java/com/github/ygimenez/model/InteractPage.java
@@ -2,14 +2,13 @@
 
 import com.github.ygimenez.method.Pages;
 import com.github.ygimenez.type.Emote;
-import net.dv8tion.jda.api.entities.Emoji;
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.entities.MessageEmbed;
-import net.dv8tion.jda.api.interactions.components.Button;
-import net.dv8tion.jda.api.interactions.components.ButtonStyle;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
 import org.jetbrains.annotations.NotNull;
 
-import javax.annotation.Nonnull;
 import java.util.EnumMap;
 import java.util.Map;
 import java.util.Objects;
@@ -70,13 +69,13 @@ public Map<Emote, String> getCaptions() {
 	 *            If you supply {@link Emote#NONE} a blank disabled button will be created.
 	 * @return The created {@link Button}.
 	 */
-	public Button makeButton(@Nonnull Emote emt) {
-		ButtonStyle style = styles.getOrDefault(emt.getStyle(), emt.getStyle());
+	public Button makeButton(@NotNull Emote emt) {
+		ButtonStyle style = styles.getOrDefault(emt.getStyle(), ButtonStyle.SECONDARY);
 
 		if (emt == Emote.NONE) {
 			return Button.secondary(emt.name() + "." + Objects.hash(Math.random()), "\u200B").asDisabled();
 		} else {
-			return Button.of(style, (ephemeral ? "*" : "") + emt.name(), caption.get(emt), Pages.getPaginator().getEmote(emt));
+			return Button.of(style, (ephemeral ? "*" : "") + emt.name(), caption.get(emt), Pages.getPaginator().getEmoji(emt));
 		}
 	}
 
@@ -86,8 +85,8 @@ public Button makeButton(@Nonnull Emote emt) {
 	 * @param emj The {@link Emoji} representing the {@link Button}, must never be null since it is also the ID.
 	 * @return The created {@link Button}.
 	 */
-	public Button makeButton(@Nonnull Emoji emj) {
-		return Button.secondary((ephemeral ? "*" : "") + emj.getId(), emj);
+	public Button makeButton(@NotNull Emoji emj) {
+		return Button.secondary((ephemeral ? "*" : "") + Emote.getId(emj), emj);
 	}
 
 	/**
@@ -97,8 +96,8 @@ public Button makeButton(@Nonnull Emoji emj) {
 	 * @param caption The desired caption for the {@link Button}.
 	 * @return The created {@link Button}.
 	 */
-	public Button makeButton(@Nonnull Emoji emj, String caption) {
-		return Button.of(ButtonStyle.SECONDARY, (ephemeral ? "*" : "") + emj.getId(), caption, emj);
+	public Button makeButton(@NotNull Emoji emj, String caption) {
+		return Button.of(ButtonStyle.SECONDARY, (ephemeral ? "*" : "") + Emote.getId(emj), caption, emj);
 	}
 
 	/**
diff --git a/src/main/java/com/github/ygimenez/model/Page.java b/src/main/java/com/github/ygimenez/model/Page.java
index b6c88ea..d80b887 100644
--- a/src/main/java/com/github/ygimenez/model/Page.java
+++ b/src/main/java/com/github/ygimenez/model/Page.java
@@ -2,8 +2,7 @@
 
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.entities.MessageEmbed;
-
-import javax.annotation.Nonnull;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Class representing either a {@link Message} or {@link MessageEmbed} object.
@@ -18,7 +17,7 @@ public class Page {
 	 * @param content The {@link Message}/{@link MessageEmbed} object to be used as pages.
 	 * @throws IllegalArgumentException Thrown if argument is not a {@link Message} nor {@link MessageEmbed}.
 	 */
-	public Page(@Nonnull Object content) throws IllegalArgumentException {
+	public Page(@NotNull Object content) throws IllegalArgumentException {
 		if (!(content instanceof Message) && !(content instanceof MessageEmbed))
 			throw new IllegalArgumentException("Page content must be either a Message or a MessageEmbed");
 
diff --git a/src/main/java/com/github/ygimenez/model/PaginationEventWrapper.java b/src/main/java/com/github/ygimenez/model/PaginationEventWrapper.java
index 8d97e80..a99a88e 100644
--- a/src/main/java/com/github/ygimenez/model/PaginationEventWrapper.java
+++ b/src/main/java/com/github/ygimenez/model/PaginationEventWrapper.java
@@ -1,9 +1,13 @@
 package com.github.ygimenez.model;
 
-import net.dv8tion.jda.api.entities.*;
-import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.MessageReaction;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
 import net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent;
-import net.dv8tion.jda.api.interactions.components.Button;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.requests.RestAction;
 
 /**
@@ -20,9 +24,9 @@ public class PaginationEventWrapper {
 	/**
 	 * Constructs a new {@link PaginationEventWrapper} instance. You probably shouldn't be creating one yourself.
 	 *
-	 * @param source      The source event, will be either a {@link GenericMessageReactionEvent} or a {@link ButtonClickEvent}.
+	 * @param source      The source event, will be either a {@link GenericMessageReactionEvent} or a {@link ButtonInteractionEvent}.
 	 * @param user        The {@link User} who triggered the event.
-	 * @param channel     The {@link TextChannel} where the event happened.
+	 * @param channel     The {@link MessageChannel} where the event happened.
 	 * @param messageId   The {@link Message} ID.
 	 * @param content     The button which was pressed, will be either a {@link MessageReaction} or a {@link Button}.
 	 * @param isFromGuild Whether the event happened on a {@link Guild} or not.
diff --git a/src/main/java/com/github/ygimenez/model/Paginator.java b/src/main/java/com/github/ygimenez/model/Paginator.java
index b021392..6652794 100644
--- a/src/main/java/com/github/ygimenez/model/Paginator.java
+++ b/src/main/java/com/github/ygimenez/model/Paginator.java
@@ -4,13 +4,15 @@
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.JDA;
 import net.dv8tion.jda.api.Permission;
-import net.dv8tion.jda.api.entities.Emoji;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.sharding.ShardManager;
 import net.dv8tion.jda.internal.utils.JDALogger;
 import org.slf4j.Logger;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.Map;
 
 /**
  * This is the core object for Pagination-Utils' settings.<br>
@@ -138,27 +140,15 @@ public Map<Emote, Emoji> getEmotes() {
 	}
 
 	/**
-	 * Same as {@link #getEmotes()} but this method will turn {@link net.dv8tion.jda.api.entities.Emote} mentions
-	 * into IDs.
+	 * Retrieves the {@link Emoji} assigned to the supplied {@link Emote}.
 	 *
 	 * @param emote The {@link Emote} to be defined.
 	 * @return The {@link Emoji} representing this {@link Emote}.
 	 */
-	public Emoji getEmote(Emote emote) {
+	public Emoji getEmoji(Emote emote) {
 		return emotes.getOrDefault(emote, emote.getDefault());
 	}
 
-	/**
-	 * Same as {@link #getEmotes()} but this method will turn {@link net.dv8tion.jda.api.entities.Emote} mentions
-	 * into IDs.
-	 *
-	 * @param emote The {@link Emote} to be defined.
-	 * @return The {@link Emoji} representing this {@link Emote}.
-	 */
-	public String getStringEmote(Emote emote) {
-		return getEmote(emote).getAsMention().replaceAll("[<>]", "");
-	}
-
 	/**
 	 * Make configured {@link Emote}s final.
 	 * <strong>This must only be called by {@link PaginatorBuilder}</strong>.
diff --git a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
index 1b200e9..c291a5b 100644
--- a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
+++ b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
@@ -29,7 +29,7 @@ public class PaginatorBuilder {
 	 *
 	 * @param paginator The raw {@link Paginator} object to start building.
 	 */
-	private PaginatorBuilder(@Nonnull Paginator paginator) {
+	private PaginatorBuilder(@NotNull Paginator paginator) {
 		this.paginator = paginator;
 	}
 
@@ -48,7 +48,7 @@ public static PaginatorBuilder createPaginator() {
 	 * @param handler The {@link JDA} instance that'll be used for event processing.
 	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
 	 */
-	public static PaginatorBuilder createPaginator(@Nonnull JDA handler) {
+	public static PaginatorBuilder createPaginator(@NotNull JDA handler) {
 		return new PaginatorBuilder(new Paginator(handler));
 	}
 
@@ -58,7 +58,7 @@ public static PaginatorBuilder createPaginator(@Nonnull JDA handler) {
 	 * @param handler The {@link ShardManager} instance that'll be used for event processing.
 	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
 	 */
-	public static PaginatorBuilder createPaginator(@Nonnull ShardManager handler) {
+	public static PaginatorBuilder createPaginator(@NotNull ShardManager handler) {
 		return new PaginatorBuilder(new Paginator(handler));
 	}
 
@@ -68,7 +68,7 @@ public static PaginatorBuilder createPaginator(@Nonnull ShardManager handler) {
 	 * @param handler The {@link JDA} instance that'll be used for event processing.
 	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
 	 */
-	public static Paginator createSimplePaginator(@Nonnull JDA handler) {
+	public static Paginator createSimplePaginator(@NotNull JDA handler) {
 		Paginator p = new Paginator(handler);
 		p.finishEmotes();
 
@@ -81,7 +81,7 @@ public static Paginator createSimplePaginator(@Nonnull JDA handler) {
 	 * @param handler The {@link ShardManager} instance that'll be used for event processing.
 	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
 	 */
-	public static Paginator createSimplePaginator(@Nonnull ShardManager handler) {
+	public static Paginator createSimplePaginator(@NotNull ShardManager handler) {
 		Paginator p = new Paginator(handler);
 		p.finishEmotes();
 
@@ -103,7 +103,7 @@ public Object getHandler() {
 	 * @param handler The {@link JDA} instance that'll be used for event processing.
 	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
 	 */
-	public PaginatorBuilder setHandler(@Nonnull JDA handler) {
+	public PaginatorBuilder setHandler(@NotNull JDA handler) {
 		paginator.setHandler(handler);
 		return this;
 	}
@@ -114,7 +114,7 @@ public PaginatorBuilder setHandler(@Nonnull JDA handler) {
 	 * @param handler The {@link ShardManager} instance that'll be used for event processing.
 	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
 	 */
-	public PaginatorBuilder setHandler(@Nonnull ShardManager handler) {
+	public PaginatorBuilder setHandler(@NotNull ShardManager handler) {
 		paginator.setHandler(handler);
 		return this;
 	}
@@ -193,8 +193,8 @@ public PaginatorBuilder setDeleteOnCancel(boolean deleteOnCancel) {
 	 * @param emote The {@link Emote} to be retrieved.
 	 * @return The {@link Emote}'s code.
 	 */
-	public Emoji getEmote(@Nonnull Emote emote) {
-		return paginator.getEmote(emote);
+	public Emoji getEmote(@NotNull Emote emote) {
+		return paginator.getEmoji(emote);
 	}
 
 	/**
@@ -208,7 +208,7 @@ public Emoji getEmote(@Nonnull Emote emote) {
 	 * @throws InvalidHandlerException If the configured handler is not a {@link JDA} or {@link ShardManager}
 	 * object.
 	 */
-	public PaginatorBuilder setEmote(@Nonnull Emote emote, @Nonnull String code) throws InvalidHandlerException {
+	public PaginatorBuilder setEmote(@NotNull Emote emote, @NotNull String code) throws InvalidHandlerException {
 		return setEmote(emote, Emoji.fromMarkdown(code));
 	}
 
@@ -221,7 +221,7 @@ public PaginatorBuilder setEmote(@Nonnull Emote emote, @Nonnull String code) thr
 	 * @throws InvalidHandlerException If the configured handler is not a {@link JDA} or {@link ShardManager}
 	 * object.
 	 */
-	public PaginatorBuilder setEmote(@Nonnull Emote emote, @Nonnull Emoji emoji) throws InvalidHandlerException {
+	public PaginatorBuilder setEmote(@NotNull Emote emote, @NotNull Emoji emoji) throws InvalidHandlerException {
 		if (paginator.getHandler() == null) throw new InvalidHandlerException();
 		else if (paginator.getEmotes().containsValue(emoji)) throw new AlreadyAssignedException();
 
diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
index 48ea6d5..d4b192a 100644
--- a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -2,7 +2,7 @@
 
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.entities.User;
-import net.dv8tion.jda.api.requests.restaction.MessageAction;
+import net.dv8tion.jda.api.utils.messages.MessageRequest;
 
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
@@ -74,7 +74,7 @@ public Sub setCanInteract(Predicate<User> canInteract) {
 		return subClass.cast(this);
 	}
 
-	public abstract MessageAction apply(MessageAction action);
+	public abstract <Out extends MessageRequest<Out>> Out apply(Out action);
 
 	public abstract boolean shouldUpdate(Message msg);
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
index 931d382..c434d61 100644
--- a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
@@ -4,12 +4,12 @@
 import com.github.ygimenez.model.ButtonWrapper;
 import com.github.ygimenez.model.ThrowingConsumer;
 import com.github.ygimenez.type.Emote;
-import net.dv8tion.jda.api.entities.Emoji;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
-import net.dv8tion.jda.api.interactions.components.Button;
-import net.dv8tion.jda.api.interactions.components.Component;
-import net.dv8tion.jda.api.requests.restaction.MessageAction;
+import net.dv8tion.jda.api.interactions.components.ItemComponent;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.utils.messages.MessageRequest;
 
 import java.util.*;
 import java.util.function.Consumer;
@@ -44,12 +44,12 @@ public ButtonizeHelper setOnCancel(Consumer<Message> onCancel) {
 	}
 
 	@Override
-	public MessageAction apply(MessageAction action) {
+	public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (!isUsingButtons()) return action;
 
 		List<ActionRow> rows = new ArrayList<>();
 
-		List<Component> row = new ArrayList<>();
+		List<ItemComponent> row = new ArrayList<>();
 		for (Emoji k : getContent().keySet()) {
 			if (row.size() == 5) {
 				rows.add(ActionRow.of(row));
@@ -59,8 +59,8 @@ public MessageAction apply(MessageAction action) {
 			row.add(Button.secondary(Emote.getId(k), k));
 		}
 
-		if (!getContent().containsKey(Pages.getPaginator().getEmote(CANCEL)) && isCancellable()) {
-			Button button = Button.danger(CANCEL.name(), Pages.getPaginator().getEmote(CANCEL));
+		if (!getContent().containsKey(Pages.getPaginator().getEmoji(CANCEL)) && isCancellable()) {
+			Button button = Button.danger(CANCEL.name(), Pages.getPaginator().getEmoji(CANCEL));
 
 			if (rows.size() == 5 && row.size() == 5) {
 				row.set(4, button);
@@ -76,14 +76,14 @@ public MessageAction apply(MessageAction action) {
 
 		rows.add(ActionRow.of(row));
 
-		return action.setActionRows(rows);
+		return action.setComponents(rows);
 	}
 
 	@Override
 	public boolean shouldUpdate(Message msg) {
 		if (!isUsingButtons()) return false;
 
-		Predicate<Set<Emoji>> checks = e -> !isCancellable() || e.contains(Pages.getPaginator().getEmote(CANCEL));
+		Predicate<Set<Emoji>> checks = e -> !isCancellable() || e.contains(Pages.getPaginator().getEmoji(CANCEL));
 		Set<Emoji> emojis = msg.getButtons().stream()
 				.map(Button::getEmoji)
 				.collect(Collectors.toSet());
diff --git a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
index 3057d96..c392af7 100644
--- a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
@@ -3,18 +3,18 @@
 import com.github.ygimenez.method.Pages;
 import com.github.ygimenez.model.Page;
 import com.github.ygimenez.type.Emote;
-import net.dv8tion.jda.api.entities.Emoji;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
-import net.dv8tion.jda.api.interactions.components.Button;
-import net.dv8tion.jda.api.interactions.components.Component;
-import net.dv8tion.jda.api.requests.restaction.MessageAction;
+import net.dv8tion.jda.api.interactions.components.ItemComponent;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.utils.messages.MessageRequest;
 
 import java.util.*;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
-import static com.github.ygimenez.type.Emote.*;
+import static com.github.ygimenez.type.Emote.CANCEL;
 
 public class CategorizeHelper extends BaseHelper<CategorizeHelper, Map<Emoji, Page>> {
 	public CategorizeHelper(boolean useButtons) {
@@ -31,12 +31,12 @@ public CategorizeHelper addCategory(Emoji emoji, Page page) {
 	}
 
 	@Override
-	public MessageAction apply(MessageAction action) {
+	public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (!isUsingButtons()) return action;
 
 		List<ActionRow> rows = new ArrayList<>();
 
-		List<Component> row = new ArrayList<>();
+		List<ItemComponent> row = new ArrayList<>();
 		for (Emoji k : getContent().keySet()) {
 			if (row.size() == 5) {
 				rows.add(ActionRow.of(row));
@@ -47,7 +47,7 @@ public MessageAction apply(MessageAction action) {
 		}
 
 		if (isCancellable()) {
-			Button button = Button.danger(CANCEL.name(), Pages.getPaginator().getEmote(CANCEL));
+			Button button = Button.danger(CANCEL.name(), Pages.getPaginator().getEmoji(CANCEL));
 			if (rows.size() == 5 && row.size() == 5) {
 				row.set(4, button);
 			} else if (row.size() == 5) {
@@ -62,14 +62,14 @@ public MessageAction apply(MessageAction action) {
 
 		rows.add(ActionRow.of(row));
 
-		return action.setActionRows(rows);
+		return action.setComponents(rows);
 	}
 
 	@Override
 	public boolean shouldUpdate(Message msg) {
 		if (!isUsingButtons()) return false;
 
-		Predicate<Set<Emoji>> checks = e -> !isCancellable() || e.contains(Pages.getPaginator().getEmote(CANCEL));
+		Predicate<Set<Emoji>> checks = e -> !isCancellable() || e.contains(Pages.getPaginator().getEmoji(CANCEL));
 		Set<Emoji> emojis = msg.getButtons().stream()
 				.map(Button::getEmoji)
 				.collect(Collectors.toSet());
diff --git a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
index 848b529..b9b7471 100644
--- a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
@@ -1,6 +1,5 @@
 package com.github.ygimenez.model.helper;
 
-import com.github.ygimenez.exception.InvalidStateException;
 import com.github.ygimenez.exception.NullPageException;
 import com.github.ygimenez.model.InteractPage;
 import com.github.ygimenez.model.Page;
@@ -8,9 +7,9 @@
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
-import net.dv8tion.jda.api.requests.restaction.MessageAction;
+import net.dv8tion.jda.api.utils.messages.MessageRequest;
+import org.jetbrains.annotations.Nullable;
 
-import javax.annotation.Nullable;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -18,7 +17,6 @@
 import java.util.stream.Collectors;
 
 import static com.github.ygimenez.type.Emote.*;
-import static com.github.ygimenez.type.Emote.GOTO_LAST;
 
 public class LazyPaginateHelper extends BaseHelper<LazyPaginateHelper, List<Page>> {
 	private final ThrowingFunction<Integer, Page> pageLoader;
@@ -64,13 +62,13 @@ public ThrowingFunction<Integer, Page> getPageLoader() {
 	}
 
 	@Override
-	public MessageAction apply(MessageAction action) {
+	public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (!isUsingButtons()) return action;
 
 		InteractPage p = (InteractPage) load(0);
 		if (p == null) throw new NullPageException();
 
-		return action.setActionRows(ActionRow.of(new ArrayList<>() {{
+		return action.setComponents(ActionRow.of(new ArrayList<>() {{
 			add(p.makeButton(PREVIOUS));
 			if (isCancellable()) add(p.makeButton(CANCEL));
 			add(p.makeButton(NEXT));
diff --git a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
index 3ff9b84..161b446 100644
--- a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
@@ -6,8 +6,8 @@
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
-import net.dv8tion.jda.api.interactions.components.Component;
-import net.dv8tion.jda.api.requests.restaction.MessageAction;
+import net.dv8tion.jda.api.interactions.components.ItemComponent;
+import net.dv8tion.jda.api.utils.messages.MessageRequest;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -54,7 +54,7 @@ public PaginateHelper setFastForward(boolean fastForward) {
 	}
 
 	@Override
-	public MessageAction apply(MessageAction action) {
+	public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (!isUsingButtons()) return action;
 
 		if (getContent().isEmpty()) throw new NullPageException();
@@ -62,7 +62,7 @@ public MessageAction apply(MessageAction action) {
 
 		List<ActionRow> rows = new ArrayList<>();
 
-		LinkedList<Component> row = new LinkedList<>() {{
+		LinkedList<ItemComponent> row = new LinkedList<>() {{
 			add(p.makeButton(PREVIOUS));
 			if (isCancellable()) add(p.makeButton(CANCEL));
 			add(p.makeButton(NEXT));
@@ -89,7 +89,7 @@ public MessageAction apply(MessageAction action) {
 			}}));
 		}
 
-		return action.setActionRows(rows);
+		return action.setComponents(rows);
 	}
 
 	@Override
diff --git a/src/main/java/com/github/ygimenez/model/helper/ReadyMessage.java b/src/main/java/com/github/ygimenez/model/helper/ReadyMessage.java
new file mode 100644
index 0000000..ccc4c91
--- /dev/null
+++ b/src/main/java/com/github/ygimenez/model/helper/ReadyMessage.java
@@ -0,0 +1,7 @@
+package com.github.ygimenez.model.helper;
+
+import net.dv8tion.jda.api.entities.Message;
+
+public interface ReadyMessage extends Message {
+
+}
diff --git a/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java b/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java
new file mode 100644
index 0000000..b685038
--- /dev/null
+++ b/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java
@@ -0,0 +1,72 @@
+package com.github.ygimenez.model.helper;
+
+import com.github.ygimenez.exception.InvalidStateException;
+import com.github.ygimenez.method.Pages;
+import com.github.ygimenez.model.InteractPage;
+import com.github.ygimenez.model.Page;
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.MessageEmbed;
+import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
+import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
+import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
+import net.dv8tion.jda.api.utils.messages.MessageCreateData;
+
+public class SendWrapper<T extends BaseHelper<T, ?>> {
+	private final T helper;
+	private final Op type;
+	private MessageCreateAction action;
+
+	private enum Op {
+		PAGINATE, LAZY_PAGINATE, CATEGORIZE, BUTTONIZE
+	}
+
+	public SendWrapper(T helper) {
+		this.helper = helper;
+
+		if (helper instanceof LazyPaginateHelper) {
+			this.type = Op.LAZY_PAGINATE;
+		} else if (helper instanceof PaginateHelper) {
+			this.type = Op.PAGINATE;
+		} else if (helper instanceof CategorizeHelper) {
+			this.type = Op.CATEGORIZE;
+		} else if (helper instanceof ButtonizeHelper) {
+			this.type = Op.BUTTONIZE;
+		} else {
+			this.type = null;
+		}
+	}
+
+	public T getHelper() {
+		return helper;
+	}
+
+	public Message send(MessageChannel channel) throws IllegalCallerException {
+		InteractPage page;
+		if (type == Op.PAGINATE) {
+			PaginateHelper helper = (PaginateHelper) this.helper;
+			page = (InteractPage) helper.getContent().get(0);
+		} else if (type == Op.LAZY_PAGINATE) {
+			LazyPaginateHelper helper = (LazyPaginateHelper) this.helper;
+			Page pg = helper.getPageLoader().apply(0);
+			if (pg == null) {
+				throw new InvalidStateException();
+			}
+
+			page = (InteractPage) helper.getContent().get(0);
+		} else {
+			throw new IllegalCallerException("This method cannot be used for categories or buttons. Use '" + helper.getClass().getSimpleName() + ".apply(MessageCreateEvent)' instead.");
+		}
+
+		if (page.getContent() instanceof Message) {
+			MessageCreateData data = MessageCreateBuilder.fromMessage((Message) page.getContent()).build();
+
+			try (data) {
+				action = helper.apply(channel.sendMessage(data));
+			}
+		} else if (page.getContent() instanceof MessageEmbed) {
+			action = helper.apply(channel.sendMessageEmbeds((MessageEmbed) page.getContent()));
+		}
+
+		return Pages.subGet(action);
+	}
+}
diff --git a/src/main/java/com/github/ygimenez/type/Emote.java b/src/main/java/com/github/ygimenez/type/Emote.java
index 1b02994..94a087b 100644
--- a/src/main/java/com/github/ygimenez/type/Emote.java
+++ b/src/main/java/com/github/ygimenez/type/Emote.java
@@ -1,11 +1,11 @@
 package com.github.ygimenez.type;
 
 import com.github.ygimenez.method.Pages;
-import com.github.ygimenez.model.Paginator;
-import net.dv8tion.jda.api.entities.Emoji;
 import net.dv8tion.jda.api.entities.MessageReaction;
-import net.dv8tion.jda.api.interactions.components.Button;
-import net.dv8tion.jda.api.interactions.components.ButtonStyle;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
 
 import java.util.Arrays;
 import java.util.Map;
@@ -118,7 +118,7 @@ else for (Emote emt : values()) {
 	 * @return Whether it uses a {@link Emote} value or not.
 	 */
 	public static boolean isNative(MessageReaction react) {
-		Emoji emj = Emoji.fromMarkdown(react.getReactionEmote().getAsReactionCode());
+		Emoji emj = Emoji.fromFormatted(react.getEmoji().getAsReactionCode());
 		for (Emote emt : values()) {
 			if (emt.emj.equals(emj)) return false;
 		}
@@ -133,7 +133,11 @@ public static boolean isNative(MessageReaction react) {
 	 * @return The supplied {@link Emoji}'s effective ID.
 	 */
 	public static String getId(Emoji emj) {
-			return emj.isCustom() ? emj.getId() : emj.getName();
+		if (emj instanceof CustomEmoji) {
+			return ((CustomEmoji) emj).getId();
+		} else {
+			return emj.getName();
+		}
 	}
 
 	public static Emote fromButton(Button btn) {

From c634fdc36241c190b04279b5585227c8a9c75bb1 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Sat, 7 Jan 2023 16:25:22 -0300
Subject: [PATCH 15/31] Fixed build issues.

---
 .../java/com/github/ygimenez/model/ButtonWrapper.java    | 7 +++++--
 .../java/com/github/ygimenez/model/PaginatorBuilder.java | 9 +++++----
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/model/ButtonWrapper.java b/src/main/java/com/github/ygimenez/model/ButtonWrapper.java
index 0a205ad..b8880d7 100644
--- a/src/main/java/com/github/ygimenez/model/ButtonWrapper.java
+++ b/src/main/java/com/github/ygimenez/model/ButtonWrapper.java
@@ -1,9 +1,12 @@
 package com.github.ygimenez.model;
 
 import com.github.ygimenez.method.Pages;
-import net.dv8tion.jda.api.entities.*;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
 import net.dv8tion.jda.api.interactions.InteractionHook;
-import net.dv8tion.jda.api.interactions.components.Button;
 
 /**
  * Wrapper for {@link Pages#buttonize} arguments containing necessary data for processing.
diff --git a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
index c291a5b..ec26193 100644
--- a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
+++ b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
@@ -8,11 +8,12 @@
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.JDA;
 import net.dv8tion.jda.api.Permission;
-import net.dv8tion.jda.api.entities.Emoji;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.sharding.ShardManager;
+import org.jetbrains.annotations.NotNull;
 
-import javax.annotation.Nonnull;
 import java.util.Map;
 
 /**
@@ -199,7 +200,7 @@ public Emoji getEmote(@NotNull Emote emote) {
 
 	/**
 	 * Modify an {@link Emote}'s code from the {@link Map}. Beware, the code must be either unicode or
-	 * {@link net.dv8tion.jda.api.entities.Emote}'s mention,
+	 * {@link CustomEmoji}'s mention,
 	 * else the buttons <strong>WILL NOT BE ADDED</strong> and will lead to errors.
 	 *
 	 * @param emote The {@link Emote} to be set.
@@ -209,7 +210,7 @@ public Emoji getEmote(@NotNull Emote emote) {
 	 * object.
 	 */
 	public PaginatorBuilder setEmote(@NotNull Emote emote, @NotNull String code) throws InvalidHandlerException {
-		return setEmote(emote, Emoji.fromMarkdown(code));
+		return setEmote(emote, Emoji.fromFormatted(code));
 	}
 
 	/**

From 11622f63abc3618399d1d035d088921a7b5e5428 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 10:40:25 -0300
Subject: [PATCH 16/31] Updated to JDA beta 5

---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 85d7fe7..d2430c3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -133,7 +133,7 @@
         <dependency>
             <groupId>net.dv8tion</groupId>
             <artifactId>JDA</artifactId>
-            <version>5.0.0-beta.2</version>
+            <version>5.0.0-beta.5</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>

From 18ea245074e8952bab0c0f520fb8f79ba968b597 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 10:44:03 -0300
Subject: [PATCH 17/31] Moved try-with-resources variables to local scope

---
 src/main/java/com/github/ygimenez/method/Pages.java           | 4 +---
 .../java/com/github/ygimenez/model/helper/SendWrapper.java    | 4 +---
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index c35a871..23c8d22 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -1522,9 +1522,7 @@ private static void updatePage(@NotNull Message msg, Page p) {
 		if (p == null) throw new NullPageException(msg);
 
 		if (p.getContent() instanceof Message) {
-			MessageEditData data = MessageEditBuilder.fromMessage((Message) p.getContent()).build();
-
-			try (data) {
+			try (MessageEditData data = MessageEditBuilder.fromMessage((Message) p.getContent()).build()) {
 				msg.editMessage(data).submit();
 			}
 		} else if (p.getContent() instanceof MessageEmbed) {
diff --git a/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java b/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java
index b685038..1b51563 100644
--- a/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java
@@ -58,9 +58,7 @@ public Message send(MessageChannel channel) throws IllegalCallerException {
 		}
 
 		if (page.getContent() instanceof Message) {
-			MessageCreateData data = MessageCreateBuilder.fromMessage((Message) page.getContent()).build();
-
-			try (data) {
+			try (MessageCreateData data = MessageCreateBuilder.fromMessage((Message) page.getContent()).build()) {
 				action = helper.apply(channel.sendMessage(data));
 			}
 		} else if (page.getContent() instanceof MessageEmbed) {

From 51295bdf9e29239d872570de3a4260aa8e69bc7e Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 13:54:38 -0300
Subject: [PATCH 18/31] Added missing javadocs; Removed unused ReadyMessage and
 SendWrapper.

---
 .../ygimenez/listener/MessageHandler.java     |   9 +-
 .../com/github/ygimenez/method/Pages.java     | 188 ++++++++++++------
 .../ygimenez/model/ActionReference.java       |  36 +++-
 .../github/ygimenez/model/ButtonWrapper.java  |   1 +
 .../github/ygimenez/model/PUtilsConfig.java   |   5 +-
 .../java/com/github/ygimenez/model/Page.java  |   3 +-
 .../com/github/ygimenez/model/Paginator.java  |   6 +-
 .../ygimenez/model/PaginatorBuilder.java      |   6 +-
 .../ygimenez/model/helper/BaseHelper.java     | 107 +++++++---
 .../model/helper/ButtonizeHelper.java         |  46 ++++-
 .../model/helper/CategorizeHelper.java        |  23 +++
 .../model/helper/LazyPaginateHelper.java      |  38 ++++
 .../ygimenez/model/helper/PaginateHelper.java |  52 ++++-
 .../ygimenez/model/helper/ReadyMessage.java   |   7 -
 .../ygimenez/model/helper/SendWrapper.java    |  70 -------
 .../java/com/github/ygimenez/type/Emote.java  |  23 ++-
 16 files changed, 421 insertions(+), 199 deletions(-)
 delete mode 100644 src/main/java/com/github/ygimenez/model/helper/ReadyMessage.java
 delete mode 100644 src/main/java/com/github/ygimenez/model/helper/SendWrapper.java

diff --git a/src/main/java/com/github/ygimenez/listener/MessageHandler.java b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
index 518574f..3b750eb 100644
--- a/src/main/java/com/github/ygimenez/listener/MessageHandler.java
+++ b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
@@ -34,6 +34,12 @@ public class MessageHandler extends ListenerAdapter {
 	private final Set<String> locks = ConcurrentHashMap.newKeySet();
 	private final CRC32 crc = new CRC32();
 
+	/**
+	 * Creates a new {@link MessageHandler} instance.
+	 */
+	public MessageHandler() {
+	}
+
 	/**
 	 * Adds an event to the handler, which will be executed whenever a button with the same
 	 * ID is pressed.
@@ -118,8 +124,9 @@ public void onMessageReactionAdd(@NotNull MessageReactionAddEvent evt) {
 
 	@Override
 	public void onMessageReactionRemove(@NotNull MessageReactionRemoveEvent evt) {
-		if (!Pages.getPaginator().isRemoveOnReact() || !evt.isFromGuild())
+		if (!Pages.getPaginator().isRemoveOnReact() || !evt.isFromGuild()) {
 			execute(evt);
+		}
 	}
 
 	@Override
diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 23c8d22..e8b1fd9 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -42,14 +42,17 @@
  * The main class containing all pagination-related methods, including but not limited
  * to {@link #paginate}, {@link #categorize}, {@link #buttonize} and {@link #lazyPaginate}.
  */
-public class Pages {
+public abstract class Pages {
 	private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
 	private static final MessageHandler handler = new MessageHandler();
 	private static Paginator paginator;
 
+	private Pages() {
+	}
+
 	/**
-	 * Sets a {@link Paginator} object to handle incoming reactions. This is
-	 * required only once unless you want to use another client as the handler. <br>
+	 * Sets a {@link Paginator} object to handle incoming events. This is
+	 * required only once unless you want to change which client is handling events. <br>
 	 * <br>
 	 * Before calling this method again, you must use {@link #deactivate()} to
 	 * remove current {@link Paginator}, else this method will throw
@@ -61,15 +64,16 @@ public class Pages {
 	 *                                   or {@link ShardManager} object.
 	 */
 	public static void activate(@NotNull Paginator paginator) throws InvalidHandlerException {
-		if (isActivated())
-			throw new AlreadyActivatedException();
+		if (isActivated()) throw new AlreadyActivatedException();
 
 		Object hand = paginator.getHandler();
-		if (hand instanceof JDA)
+		if (hand instanceof JDA) {
 			((JDA) hand).addEventListener(handler);
-		else if (hand instanceof ShardManager)
+		} else if (hand instanceof ShardManager) {
 			((ShardManager) hand).addEventListener(handler);
-		else throw new InvalidHandlerException();
+		} else {
+			throw new InvalidHandlerException();
+		}
 
 		Pages.paginator = paginator;
 		paginator.log(PUtilsConfig.LogLevel.LEVEL_2, "Pagination Utils activated successfully");
@@ -81,14 +85,14 @@ else if (hand instanceof ShardManager)
 	 * Using this method without activating beforehand will do nothing.
 	 */
 	public static void deactivate() {
-		if (!isActivated())
-			return;
+		if (!isActivated()) return;
 
 		Object hand = paginator.getHandler();
-		if (hand instanceof JDA)
+		if (hand instanceof JDA) {
 			((JDA) hand).removeEventListener(handler);
-		else if (hand instanceof ShardManager)
+		} else if (hand instanceof ShardManager) {
 			((ShardManager) hand).removeEventListener(handler);
+		}
 
 		paginator.log(PUtilsConfig.LogLevel.LEVEL_2, "Pagination Utils deactivated successfully");
 		paginator = null;
@@ -534,7 +538,7 @@ public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page>
 	 */
 	public static ActionReference paginate(@NotNull Message msg, @NotNull List<Page> pages, boolean useButtons, int time, TimeUnit unit, int skipAmount, boolean fastForward, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return paginate(msg, new PaginateHelper(pages, useButtons)
-				.setTimeUnit(time, unit)
+				.setTimeout(time, unit)
 				.setSkipAmount(skipAmount)
 				.setFastForward(fastForward)
 				.setCanInteract(canInteract)
@@ -562,9 +566,9 @@ public static ActionReference paginate(@NotNull Message msg, @NotNull PaginateHe
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		List<Page> pgs = Collections.unmodifiableList(helper.getContent());
 
-		if (useBtns && helper.shouldUpdate(msg)) {
+		if (useBtns) {
 			helper.apply(msg.editMessageComponents()).submit();
-		} else if (!useBtns) {
+		} else {
 			clearButtons(msg);
 			clearReactions(msg);
 			addReactions(msg, helper.getSkipAmount() > 1, helper.isFastForward());
@@ -575,8 +579,10 @@ public static ActionReference paginate(@NotNull Message msg, @NotNull PaginateHe
 			private int p = 0;
 			private ScheduledFuture<?> timeout;
 			private final Consumer<Void> success = s -> {
-				if (timeout != null)
+				if (timeout != null) {
 					timeout.cancel(true);
+				}
+
 				handler.removeEvent(msg);
 				if (paginator.isDeleteOnCancel()) msg.delete().submit();
 			};
@@ -585,17 +591,17 @@ public static ActionReference paginate(@NotNull Message msg, @NotNull PaginateHe
 			private final Function<Button, Button> UPPER_BOUNDARY_CHECK = b -> b.withDisabled(p == maxP);
 
 			{
-				if (helper.getTime() > 0 && helper.getUnit() != null)
-					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
+				if (helper.getTimeout() > 0) {
+					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
+				}
 			}
 
 			@Override
 			public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
-				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
-					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
-						return;
+				if (helper.canInteract(u)) {
+					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId())) return;
 
 					Emote emt = NONE;
 					if (wrapper.getContent() instanceof MessageReaction) {
@@ -671,10 +677,12 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 						}
 					}
 
-					if (timeout != null)
+					if (timeout != null) {
 						timeout.cancel(true);
-					if (helper.getTime() > 0 && helper.getUnit() != null)
-						timeout = executor.schedule(() -> finalizeEvent(m, success), helper.getTime(), helper.getUnit());
+					}
+					if (helper.getTimeout() > 0) {
+						timeout = executor.schedule(() -> finalizeEvent(m, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
+					}
 
 					if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
 						subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
@@ -696,6 +704,8 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 	 *                   {@link Pages} as values.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                   {@link Message} was not sent by the bot.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -725,6 +735,8 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoj
 	 *                   for further events (recommended: 60).
 	 * @param unit       The time's {@link TimeUnit} (recommended:
 	 *                   {@link TimeUnit#SECONDS}).
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -750,6 +762,8 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoj
 	 *                    {@link Message} was not sent by the bot.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -781,6 +795,8 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoj
 	 *                    {@link TimeUnit#SECONDS}).
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -790,7 +806,7 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoj
 	 */
 	public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoji, Page> categories, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return categorize(msg, new CategorizeHelper(categories, useButtons)
-				.setTimeUnit(time, unit)
+				.setTimeout(time, unit)
 				.setCanInteract(canInteract)
 		);
 	}
@@ -804,6 +820,8 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Map<Emoj
 	 *
 	 * @param msg    The {@link Message} sent which will be categorized.
 	 * @param helper A {@link CategorizeHelper} holding desired categorization settings.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -834,24 +852,26 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Categori
 			private Emoji currCat = null;
 			private ScheduledFuture<?> timeout;
 			private final Consumer<Void> success = s -> {
-				if (timeout != null)
+				if (timeout != null) {
 					timeout.cancel(true);
+				}
+
 				handler.removeEvent(msg);
 				if (paginator.isDeleteOnCancel()) msg.delete().submit();
 			};
 
 			{
-				if (helper.getTime() > 0 && helper.getUnit() != null)
-					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
+				if (helper.getTimeout() > 0) {
+					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
+				}
 			}
 
 			@Override
 			public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
-				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
-					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
-						return;
+				if (helper.canInteract(u)) {
+					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId())) return;
 
 					Emoji emoji = null;
 					Emote emt = NONE;
@@ -886,10 +906,12 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 						}
 					}
 
-					if (timeout != null)
+					if (timeout != null) {
 						timeout.cancel(true);
-					if (helper.getTime() > 0 && helper.getUnit() != null)
-						timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
+					}
+					if (helper.getTimeout() > 0) {
+						timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
+					}
 
 					if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
 						subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
@@ -913,6 +935,8 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 	 * @param useButtons       Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                         {@link Message} was not sent by the bot.
 	 * @param showCancelButton Should the {@link Emote#CANCEL} button be created automatically?
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -943,6 +967,8 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji
 	 *                         listening for further events (recommended: 60).
 	 * @param unit             The time's {@link TimeUnit} (recommended:
 	 *                         {@link TimeUnit#SECONDS}).
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -971,6 +997,8 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji
 	 * @param canInteract      {@link Predicate} to determine whether the
 	 *                         {@link User} that pressed the button can interact
 	 *                         with it or not.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1004,6 +1032,8 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji
 	 * @param canInteract      {@link Predicate} to determine whether the
 	 *                         {@link User} that pressed the button can interact
 	 *                         with it or not.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1033,6 +1063,8 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji
 	 *                         {@link User} that pressed the button can interact
 	 *                         with it or not.
 	 * @param onCancel         Action to be run after the listener is removed.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1067,6 +1099,8 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji
 	 *                    {@link User} that pressed the button can interact
 	 *                    with it or not.
 	 * @param onCancel    Action to be run after the listener is removed.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1077,9 +1111,9 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji
 	public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons, boolean cancellable, int time, TimeUnit unit, Predicate<User> canInteract, Consumer<Message> onCancel) throws ErrorResponseException, InsufficientPermissionException {
 		return buttonize(msg, new ButtonizeHelper(buttons, useButtons)
 				.setCancellable(cancellable)
-				.setTimeUnit(time, unit)
+				.setTimeout(time, unit)
 				.setCanInteract(canInteract)
-				.setOnCancel(onCancel)
+				.setOnFinalization(onCancel)
 		);
 	}
 
@@ -1092,6 +1126,8 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Map<Emoji
 	 *
 	 * @param msg    The {@link Message} sent which will be buttoned.
 	 * @param helper A {@link ButtonizeHelper} holding desired buttonization settings.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1123,25 +1159,27 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Buttonize
 		return handler.addEvent(msg, new ThrowingBiConsumer<>() {
 			private ScheduledFuture<?> timeout;
 			private final Consumer<Void> success = s -> {
-				if (timeout != null)
+				if (timeout != null) {
 					timeout.cancel(true);
+				}
+
 				handler.removeEvent(msg);
-				if (helper.getOnCancel() != null) helper.getOnCancel().accept(msg);
+				if (helper.getOnFinalization() != null) helper.getOnFinalization().accept(msg);
 				if (paginator.isDeleteOnCancel()) msg.delete().submit();
 			};
 
 			{
-				if (helper.getTime() > 0 && helper.getUnit() != null)
-					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
+				if (helper.getTimeout() > 0) {
+					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
+				}
 			}
 
 			@Override
 			public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
-				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
-					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
-						return;
+				if (helper.canInteract(u)) {
+					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId())) return;
 
 					Emoji emoji = null;
 					Emote emt = NONE;
@@ -1175,10 +1213,12 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 						act.accept(new ButtonWrapper(wrapper.getUser(), hook, m));
 					}
 
-					if (timeout != null)
+					if (timeout != null) {
 						timeout.cancel(true);
-					if (helper.getTime() > 0 && helper.getUnit() != null)
-						timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
+					}
+					if (helper.getTimeout() > 0) {
+						timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
+					}
 
 					if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
 						subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
@@ -1198,6 +1238,8 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 	 *                   returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                   {@link Message} was not sent by the bot.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1225,6 +1267,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull Throwi
 	 *                   for further events (recommended: 60).
 	 * @param unit       The time's {@link TimeUnit} (recommended:
 	 *                   {@link TimeUnit#SECONDS}).
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1248,6 +1292,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull Throwi
 	 *                    {@link Message} was not sent by the bot.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1277,6 +1323,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull Throwi
 	 *                    {@link TimeUnit#SECONDS}).
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1299,6 +1347,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull Throwi
 	 *                   returns null the method will treat it as last page, preventing unnecessary updates.
 	 * @param useButtons Whether to use interaction {@link Button} or reactions. Will fallback to false if the supplied
 	 *                   {@link Message} was not sent by the bot.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1327,6 +1377,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> page
 	 *                   for further events (recommended: 60).
 	 * @param unit       The time's {@link TimeUnit} (recommended:
 	 *                   {@link TimeUnit#SECONDS}).
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1351,6 +1403,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> page
 	 *                    {@link Message} was not sent by the bot.
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1381,6 +1435,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> page
 	 *                    {@link TimeUnit#SECONDS}).
 	 * @param canInteract {@link Predicate} to determine whether the {@link User}
 	 *                    that pressed the button can interact with it or not.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1390,7 +1446,7 @@ public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> page
 	 */
 	public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> pageCache, @NotNull ThrowingFunction<Integer, Page> pageLoader, boolean useButtons, int time, TimeUnit unit, Predicate<User> canInteract) throws ErrorResponseException, InsufficientPermissionException {
 		return lazyPaginate(msg, new LazyPaginateHelper(pageLoader, pageCache, useButtons)
-				.setTimeUnit(time, unit)
+				.setTimeout(time, unit)
 				.setCanInteract(canInteract)
 		);
 	}
@@ -1403,6 +1459,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, List<Page> page
 	 *
 	 * @param msg    The {@link Message} sent which will be paginated.
 	 * @param helper A {@link LazyPaginateHelper} holding desired lazy pagination settings.
+	 * @return an {@link ActionReference} pointing to the newly created event, can be used for checking when it gets
+	 * disposed of.
 	 * @throws ErrorResponseException          Thrown if the {@link Message} no longer exists
 	 *                                         or cannot be accessed when triggering a
 	 *                                         {@link GenericMessageReactionEvent}.
@@ -1415,9 +1473,9 @@ public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull LazyPa
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		boolean cache = helper.getContent() != null;
 
-		if (useBtns && helper.shouldUpdate(msg)) {
+		if (useBtns) {
 			helper.apply(msg.editMessageComponents()).submit();
-		} else if (!useBtns) {
+		} else {
 			clearButtons(msg);
 			clearReactions(msg);
 			addReactions(msg, false, false);
@@ -1427,24 +1485,26 @@ public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull LazyPa
 			private int p = 0;
 			private ScheduledFuture<?> timeout;
 			private final Consumer<Void> success = s -> {
-				if (timeout != null)
+				if (timeout != null) {
 					timeout.cancel(true);
+				}
+
 				handler.removeEvent(msg);
 				if (paginator.isDeleteOnCancel()) msg.delete().submit();
 			};
 
 			{
-				if (helper.getTime() > 0 && helper.getUnit() != null)
-					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTime(), helper.getUnit());
+				if (helper.getTimeout() > 0) {
+					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
+				}
 			}
 
 			@Override
 			public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrapper) {
 				Message m = subGet(wrapper.retrieveMessage());
 
-				if (helper.getCanInteract() == null || helper.getCanInteract().test(u)) {
-					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId()))
-						return;
+				if (helper.canInteract(u)) {
+					if (u.isBot() || m == null || !wrapper.getMessageId().equals(msg.getId())) return;
 
 					Emote emt = NONE;
 					if (wrapper.getContent() instanceof MessageReaction) {
@@ -1498,10 +1558,12 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 							return;
 					}
 
-					if (timeout != null)
+					if (timeout != null) {
 						timeout.cancel(true);
-					if (helper.getTime() > 0 && helper.getUnit() != null)
-						timeout = executor.schedule(() -> finalizeEvent(m, success), helper.getTime(), helper.getUnit());
+					}
+					if (helper.getTimeout() > 0) {
+						timeout = executor.schedule(() -> finalizeEvent(m, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
+					}
 
 					if (wrapper.isFromGuild() && wrapper.getSource() instanceof MessageReactionAddEvent && paginator.isRemoveOnReact()) {
 						subGet(((MessageReaction) wrapper.getContent()).removeReaction(u));
@@ -1567,7 +1629,7 @@ public static <T> T subGet(@NotNull RestAction<T> future) {
 		try {
 			return future.submit().get();
 		} catch (InterruptedException | ExecutionException e) {
-			Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Exception during future execution:", e);
+			paginator.log(PUtilsConfig.LogLevel.LEVEL_4, "Exception during future execution:", e);
 			return null;
 		}
 	}
@@ -1584,7 +1646,7 @@ public static <T> T subGet(@NotNull RestAction<T> future, @NotNull T or) {
 		try {
 			return future.submit().get();
 		} catch (InterruptedException | ExecutionException e) {
-			Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Exception during future execution:", e);
+			paginator.log(PUtilsConfig.LogLevel.LEVEL_4, "Exception during future execution:", e);
 			return or;
 		}
 	}
@@ -1606,9 +1668,9 @@ public static void clearReactions(Message msg) {
 		if (msg.getReactions().isEmpty()) return;
 
 		try {
-			if (msg.getChannel().getType().isGuild())
+			if (msg.getChannel().getType().isGuild()) {
 				msg.clearReactions().submit();
-			else for (MessageReaction r : msg.getReactions()) {
+			} else for (MessageReaction r : msg.getReactions()) {
 				r.removeReaction().submit();
 			}
 		} catch (InsufficientPermissionException | IllegalStateException e) {
@@ -1629,7 +1691,7 @@ public static void clearButtons(Message msg) {
 		try {
 			subGet(msg.editMessageComponents());
 		} catch (InsufficientPermissionException | IllegalStateException e) {
-			Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_3, "Not enough permissions to clear message reactions:", e);
+			paginator.log(PUtilsConfig.LogLevel.LEVEL_3, "Not enough permissions to clear message reactions:", e);
 		}
 	}
 
diff --git a/src/main/java/com/github/ygimenez/model/ActionReference.java b/src/main/java/com/github/ygimenez/model/ActionReference.java
index 69a517a..80fa58b 100644
--- a/src/main/java/com/github/ygimenez/model/ActionReference.java
+++ b/src/main/java/com/github/ygimenez/model/ActionReference.java
@@ -1,29 +1,51 @@
 package com.github.ygimenez.model;
 
 import com.github.ygimenez.method.Pages;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
 
+/**
+ * Class used for checking whether a library action (read: paginate, categorize, buttonize or lazy-paginate action)
+ * was already disposed of.
+ * <br>
+ * This is a weak reference, so its value might become null at any moment.
+ * @see java.lang.ref.WeakReference
+ */
 public class ActionReference extends WeakReference<String> {
-	public ActionReference(String referent) {
-		super(referent);
-	}
 
-	public ActionReference(String referent, ReferenceQueue<? super String> q) {
-		super(referent, q);
+	/**
+	 * Creates a new {@link ActionReference} for tracking a specific event key. Not for external usage.
+	 *
+	 * @param referent The key referring to an existing library event.
+	 */
+	public ActionReference(@NotNull String referent) {
+		super(referent);
 	}
 
+	/**
+	 * Retrieves the referred action key if it is still active, or null otherwise.
+	 *
+	 * @return They key used to represent the library action in the event map.
+	 */
 	@Nullable
 	@Override
 	public String get() {
-		if (!Pages.getHandler().checkEvent(super.get()))
+		if (!Pages.getHandler().checkEvent(super.get())) {
 			enqueue();
+		}
 
 		return super.get();
 	}
 
+	/**
+	 * Utility method to check whether the referred action is still active.
+	 * <br>
+	 * Same as doing {@code get() != null}.
+	 *
+	 * @return Whether the action is still active or not.
+	 */
 	public boolean check() {
 		return get() != null;
 	}
diff --git a/src/main/java/com/github/ygimenez/model/ButtonWrapper.java b/src/main/java/com/github/ygimenez/model/ButtonWrapper.java
index b8880d7..3f76ad8 100644
--- a/src/main/java/com/github/ygimenez/model/ButtonWrapper.java
+++ b/src/main/java/com/github/ygimenez/model/ButtonWrapper.java
@@ -7,6 +7,7 @@
 import net.dv8tion.jda.api.entities.User;
 import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
 import net.dv8tion.jda.api.interactions.InteractionHook;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
 
 /**
  * Wrapper for {@link Pages#buttonize} arguments containing necessary data for processing.
diff --git a/src/main/java/com/github/ygimenez/model/PUtilsConfig.java b/src/main/java/com/github/ygimenez/model/PUtilsConfig.java
index baea1d2..0a7353d 100644
--- a/src/main/java/com/github/ygimenez/model/PUtilsConfig.java
+++ b/src/main/java/com/github/ygimenez/model/PUtilsConfig.java
@@ -3,9 +3,12 @@
 /**
  * Utility class holding library-wide settings.
  */
-public class PUtilsConfig {
+public abstract class PUtilsConfig {
 	private static LogLevel logLevel = LogLevel.LEVEL_1;
 
+	private PUtilsConfig() {
+	}
+
 	/**
 	 * Levels used to filter what events are logged to the console by the library.
 	 */
diff --git a/src/main/java/com/github/ygimenez/model/Page.java b/src/main/java/com/github/ygimenez/model/Page.java
index d80b887..ca986ae 100644
--- a/src/main/java/com/github/ygimenez/model/Page.java
+++ b/src/main/java/com/github/ygimenez/model/Page.java
@@ -18,8 +18,9 @@ public class Page {
 	 * @throws IllegalArgumentException Thrown if argument is not a {@link Message} nor {@link MessageEmbed}.
 	 */
 	public Page(@NotNull Object content) throws IllegalArgumentException {
-		if (!(content instanceof Message) && !(content instanceof MessageEmbed))
+		if (!(content instanceof Message) && !(content instanceof MessageEmbed)) {
 			throw new IllegalArgumentException("Page content must be either a Message or a MessageEmbed");
+		}
 
 		this.content = content;
 	}
diff --git a/src/main/java/com/github/ygimenez/model/Paginator.java b/src/main/java/com/github/ygimenez/model/Paginator.java
index 6652794..ec15afa 100644
--- a/src/main/java/com/github/ygimenez/model/Paginator.java
+++ b/src/main/java/com/github/ygimenez/model/Paginator.java
@@ -177,8 +177,9 @@ public Logger getLogger() {
 	 * @param t The {@link Throwable} to be added for more detailed information.
 	 */
 	public void log(LogLevel level, String msg, Throwable t) {
-		if (PUtilsConfig.getLogLevel().compareTo(level) >= 0)
+		if (PUtilsConfig.getLogLevel().compareTo(level) >= 0) {
 			logger.error("[" + level.name().replace("_", " ") + "] " + msg, t);
+		}
 	}
 
 	/**
@@ -190,7 +191,8 @@ public void log(LogLevel level, String msg, Throwable t) {
 	 * @param msg The message to be logged.
 	 */
 	public void log(LogLevel level, String msg) {
-		if (PUtilsConfig.getLogLevel().compareTo(level) >= 0)
+		if (PUtilsConfig.getLogLevel().compareTo(level) >= 0) {
 			logger.error("[" + level.name().replace("_", " ") + "] " + msg);
+		}
 	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
index ec26193..fb31552 100644
--- a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
+++ b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
@@ -236,8 +236,9 @@ public PaginatorBuilder setEmote(@NotNull Emote emote, @NotNull Emoji emoji) thr
 	 * @return The {@link Paginator} instance.
 	 */
 	public Paginator build() {
-		if (paginator.getHandler() == null)
+		if (paginator.getHandler() == null) {
 			throw new InvalidStateException();
+		}
 
 		paginator.finishEmotes();
 		return paginator;
@@ -250,8 +251,9 @@ public Paginator build() {
 	 * @throws InvalidHandlerException Thrown if the handler isn't either a {@link JDA} or {@link ShardManager} object.
 	 */
 	public void activate() throws InvalidHandlerException {
-		if (paginator.getHandler() == null)
+		if (paginator.getHandler() == null) {
 			throw new InvalidStateException();
+		}
 
 		paginator.finishEmotes();
 		Pages.activate(paginator);
diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
index d4b192a..90a46f1 100644
--- a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -1,80 +1,131 @@
 package com.github.ygimenez.model.helper;
 
+import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.entities.User;
 import net.dv8tion.jda.api.utils.messages.MessageRequest;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 
-abstract class BaseHelper<Sub extends BaseHelper<Sub, T>, T> {
-	private final Class<Sub> subClass;
+abstract class BaseHelper<Helper extends BaseHelper<Helper, T>, T> {
+	private final Class<Helper> subClass;
 
 	private final T content;
 	private final boolean useButtons;
 
 	private boolean cancellable = true;
-	private int time = 0;
-	private TimeUnit unit = null;
+	private long time = 0;
 	private Predicate<User> canInteract = null;
 
-	protected BaseHelper(Class<Sub> subClass, T buttons, boolean useButtons) {
+	protected BaseHelper(Class<Helper> subClass, T buttons, boolean useButtons) {
 		this.subClass = subClass;
 		this.content = buttons;
 		this.useButtons = useButtons;
 	}
 
+	/**
+	 * Retrieves the collection used by this helper to store the pages.
+	 *
+	 * @return The underlying collection.
+	 */
 	public T getContent() {
 		return content;
 	}
 
+	/**
+	 * Returns whether the event is configured to use buttons or not.
+	 *
+	 * @return Whether the event is configured to use buttons or not.
+	 */
 	public boolean isUsingButtons() {
 		return useButtons;
 	}
 
+	/**
+	 * Returns whether the {@link Emote#CANCEL} button will be included or not.
+	 *
+	 * @return Whether the event is cancellable or not.
+	 */
 	public boolean isCancellable() {
 		return cancellable;
 	}
 
-	public int getTime() {
-		return time;
-	}
-
-	public TimeUnit getUnit() {
-		return unit;
-	}
-
-	public Predicate<User> getCanInteract() {
-		return canInteract;
-	}
-
-	public Sub setCancellable(boolean cancellable) {
+	/**
+	 * Sets whether the event is cancellable through {@link Emote#CANCEL}.
+	 *
+	 * @param cancellable Whether the event can be cancelled or not (default: true).
+	 * @return The {@link Helper} instance for chaining convenience.
+	 */
+	public Helper setCancellable(boolean cancellable) {
 		this.cancellable = cancellable;
 		return subClass.cast(this);
 	}
 
-	public Sub setTime(int time) {
-		this.time = time;
-		return subClass.cast(this);
+	/**
+	 * Retrieves the timeout for the event, in milliseconds.
+	 *
+	 * @return The timeout for the event.
+	 */
+	public long getTimeout() {
+		return time;
 	}
 
-	public Sub setUnit(TimeUnit unit) {
-		this.unit = unit;
+	/**
+	 * Sets the timeout for automatically cancelling the event. Values less than or equal to zero will disable the
+	 * timeout.
+	 *
+	 * @param time The time for the timeout.
+	 * @param unit The unit for the timeout.
+	 * @return The {@link Helper} instance for chaining convenience.
+	 */
+	public Helper setTimeout(int time, TimeUnit unit) {
+		this.time = TimeUnit.MILLISECONDS.convert(time, unit);
 		return subClass.cast(this);
 	}
 
-	public Sub setTimeUnit(int time, TimeUnit unit) {
-		this.time = time;
-		this.unit = unit;
-		return subClass.cast(this);
+	/**
+	 * Checks whether the supplied {@link User} can interact with the event.
+	 *
+	 * @param user The {@link User} to check.
+	 * @return Whether the suppied user can interact with the event.
+	 */
+	public boolean canInteract(User user) {
+		return canInteract == null || canInteract.test(user);
 	}
 
-	public Sub setCanInteract(Predicate<User> canInteract) {
+	/**
+	 * Sets the condition used to check if a given user can interact with the event buttons.
+	 *
+	 * @param canInteract A {@link Predicate} for checking if a given user can interact with the buttons (default: null).
+	 * @return The {@link Helper} instance for chaining convenience.
+	 */
+	public Helper setCanInteract(@Nullable Predicate<User> canInteract) {
 		this.canInteract = canInteract;
 		return subClass.cast(this);
 	}
 
+	/**
+	 * Prepares the message for being used by the library. This doesn't need to be called manually, this will
+	 * be called during normal flow.
+	 * <br>
+	 * This is no-op when using reaction buttons.
+	 * <br><br>
+	 * Example:
+	 * <pre>{@code helper.apply(channel.sendMessage("Hello world!")).queue();}</pre>
+	 *
+	 * @param action A message event (either create or edit).
+	 * @return The same event, but modified to include the buttons.
+	 * @param <Out> Generic for a {@link MessageRequest}
+	 */
 	public abstract <Out extends MessageRequest<Out>> Out apply(Out action);
 
+	/**
+	 * Calculates whether the {@link Message} needs to have buttons applied onto or not.
+	 *
+	 * @param msg The {@link Message} to be checked.
+	 * @return Whether it needs to be updated or not.
+	 */
 	public abstract boolean shouldUpdate(Message msg);
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
index c434d61..9a111ef 100644
--- a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
@@ -18,31 +18,64 @@
 
 import static com.github.ygimenez.type.Emote.CANCEL;
 
+/**
+ * Helper class for building buttonize events, safe for reuse.
+ */
 public class ButtonizeHelper extends BaseHelper<ButtonizeHelper, Map<Emoji, ThrowingConsumer<ButtonWrapper>>> {
-	private Consumer<Message> onCancel = null;
+	private Consumer<Message> onFinalization = null;
 
+	/**
+	 * Creates a new buttonize event helper with the default map implementation ({@link LinkedHashMap}).
+	 *
+	 * @param useButtons Whether to use interaction buttons or legacy reaction-based buttons.
+	 */
 	public ButtonizeHelper(boolean useButtons) {
 		super(ButtonizeHelper.class, new LinkedHashMap<>(), useButtons);
 	}
 
+	/**
+	 * Creates a new buttonize event helper with the supplied map.
+	 *
+	 * @param buttons A map containing the initial buttons.
+	 * @param useButtons Whether to use interaction buttons or legacy reaction-based buttons.
+	 */
 	public ButtonizeHelper(Map<Emoji, ThrowingConsumer<ButtonWrapper>> buttons, boolean useButtons) {
 		super(ButtonizeHelper.class, buttons, useButtons);
 	}
 
-	public ButtonizeHelper addCategory(Emoji emoji, ThrowingConsumer<ButtonWrapper> action) {
+	/**
+	 * Adds a new button to the map.
+	 *
+	 * @param emoji The emoji representing this button.
+	 * @param action The action to be performed on click.
+	 * @return The {@link ButtonizeHelper} instance for chaining convenience.
+	 */
+	public ButtonizeHelper addAction(Emoji emoji, ThrowingConsumer<ButtonWrapper> action) {
 		getContent().put(emoji, action);
 		return this;
 	}
 
-	public Consumer<Message> getOnCancel() {
-		return onCancel;
+	/**
+	 * Retrieves the {@link Consumer} that'll be executed when the event ends.
+	 *
+	 * @return The action to be performed during finalization.
+	 */
+	public Consumer<Message> getOnFinalization() {
+		return onFinalization;
 	}
 
-	public ButtonizeHelper setOnCancel(Consumer<Message> onCancel) {
-		this.onCancel = onCancel;
+	/**
+	 * Defines an action to be executed when the event finishes, either by user action or timed finalization.
+	 *
+	 * @param onFinalization The action to be performed.
+	 * @return The {@link ButtonizeHelper} instance for chaining convenience.
+	 */
+	public ButtonizeHelper setOnFinalization(Consumer<Message> onFinalization) {
+		this.onFinalization = onFinalization;
 		return this;
 	}
 
+	/** {@inheritDoc} **/
 	@Override
 	public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (!isUsingButtons()) return action;
@@ -79,6 +112,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		return action.setComponents(rows);
 	}
 
+	/** {@inheritDoc} **/
 	@Override
 	public boolean shouldUpdate(Message msg) {
 		if (!isUsingButtons()) return false;
diff --git a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
index c392af7..f6bbe58 100644
--- a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
@@ -16,20 +16,42 @@
 
 import static com.github.ygimenez.type.Emote.CANCEL;
 
+/**
+ * Helper class for building categorize events, safe for reuse.
+ */
 public class CategorizeHelper extends BaseHelper<CategorizeHelper, Map<Emoji, Page>> {
+	/**
+	 * Creates a new categorize event helper with the default map implementation ({@link LinkedHashMap}).
+	 *
+	 * @param useButtons Whether to use interaction buttons or legacy reaction-based buttons.
+	 */
 	public CategorizeHelper(boolean useButtons) {
 		super(CategorizeHelper.class, new LinkedHashMap<>(), useButtons);
 	}
 
+	/**
+	 * Creates a new categorize event helper with the supplied map.
+	 *
+	 * @param categories A map containing the initial categories.
+	 * @param useButtons Whether to use interaction buttons or legacy reaction-based buttons.
+	 */
 	public CategorizeHelper(Map<Emoji, Page> categories, boolean useButtons) {
 		super(CategorizeHelper.class, categories, useButtons);
 	}
 
+	/**
+	 * Adds a new category to the map.
+	 *
+	 * @param emoji The emoji representing this category.
+	 * @param page The page linked to this category.
+	 * @return The {@link CategorizeHelper} instance for chaining convenience.
+	 */
 	public CategorizeHelper addCategory(Emoji emoji, Page page) {
 		getContent().put(emoji, page);
 		return this;
 	}
 
+	/** {@inheritDoc} **/
 	@Override
 	public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (!isUsingButtons()) return action;
@@ -65,6 +87,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		return action.setComponents(rows);
 	}
 
+	/** {@inheritDoc} **/
 	@Override
 	public boolean shouldUpdate(Message msg) {
 		if (!isUsingButtons()) return false;
diff --git a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
index b9b7471..648be25 100644
--- a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
@@ -13,15 +13,26 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 import static com.github.ygimenez.type.Emote.*;
 
+/**
+ * Helper class for building lazy-paginate events, safe for reuse.
+ */
 public class LazyPaginateHelper extends BaseHelper<LazyPaginateHelper, List<Page>> {
 	private final ThrowingFunction<Integer, Page> pageLoader;
 	private final boolean cache;
 
+	/**
+	 * Creates a new lazy-paginate event helper with the supplied page loader and default list implementation
+	 * ({@link ArrayList}).
+	 *
+	 * @param pageLoader The lazy loader used to generate pages. The value supplied is the current page number.
+	 * @param useButtons Whether to use interaction buttons or legacy reaction-based buttons.
+	 */
 	public LazyPaginateHelper(ThrowingFunction<Integer, Page> pageLoader, boolean useButtons) {
 		super(LazyPaginateHelper.class, new ArrayList<>(), useButtons);
 		this.pageLoader = pageLoader;
@@ -29,6 +40,13 @@ public LazyPaginateHelper(ThrowingFunction<Integer, Page> pageLoader, boolean us
 		load(0);
 	}
 
+	/**
+	 * Creates a new lazy-paginate event helper with the supplied page loader and a list of initially loaded pages.
+	 *
+	 * @param pageLoader The lazy loader used to generate pages. The value supplied is the current page number.
+	 * @param initialPages A {@link List} containing the initially available pages.
+	 * @param useButtons Whether to use interaction buttons or legacy reaction-based buttons.
+	 */
 	public LazyPaginateHelper(ThrowingFunction<Integer, Page> pageLoader, @Nullable List<Page> initialPages, boolean useButtons) {
 		super(LazyPaginateHelper.class, initialPages, useButtons);
 		this.pageLoader = pageLoader;
@@ -36,6 +54,12 @@ public LazyPaginateHelper(ThrowingFunction<Integer, Page> pageLoader, @Nullable
 		load(0);
 	}
 
+	/**
+	 * Adds a new page to the list.
+	 *
+	 * @param page The page to be added.
+	 * @return The {@link LazyPaginateHelper} instance for chaining convenience.
+	 */
 	public LazyPaginateHelper addPage(Page page) {
 		if (!cache) throw new IllegalStateException();
 
@@ -43,10 +67,22 @@ public LazyPaginateHelper addPage(Page page) {
 		return this;
 	}
 
+	/**
+	 * Retrieves the configured page loader for this helper.
+	 *
+	 * @return The page loader {@link Function}
+	 */
 	public ThrowingFunction<Integer, Page> getPageLoader() {
 		return pageLoader;
 	}
 
+	/**
+	 * Loads the page represented by the specified index. Might be null, meaning there's no page available for that
+	 * index.
+	 *
+	 * @param page The page index.
+	 * @return The page returned by the loader.
+	 */
 	public @Nullable Page load(int page) {
 		if (cache) {
 			int maxIndex = getContent().size() - 1;
@@ -61,6 +97,7 @@ public ThrowingFunction<Integer, Page> getPageLoader() {
 		return p;
 	}
 
+	/** {@inheritDoc} **/
 	@Override
 	public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (!isUsingButtons()) return action;
@@ -75,6 +112,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		}}));
 	}
 
+	/** {@inheritDoc} **/
 	@Override
 	public boolean shouldUpdate(Message msg) {
 		if (!isUsingButtons()) return true;
diff --git a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
index 161b446..3c61ba8 100644
--- a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
@@ -9,50 +9,93 @@
 import net.dv8tion.jda.api.interactions.components.ItemComponent;
 import net.dv8tion.jda.api.utils.messages.MessageRequest;
 
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 import static com.github.ygimenez.type.Emote.*;
 
+/**
+ * Helper class for building paginate events, safe for reuse.
+ */
 public class PaginateHelper extends BaseHelper<PaginateHelper, List<Page>> {
 	private int skipAmount = 0;
 	private boolean fastForward = false;
 
+	/**
+	 * Creates a new paginate event helper with the default list implementation ({@link ArrayList}).
+	 *
+	 * @param useButtons Whether to use interaction buttons or legacy reaction-based buttons.
+	 */
 	public PaginateHelper(boolean useButtons) {
 		super(PaginateHelper.class, new ArrayList<>(), useButtons);
 	}
 
+	/**
+	 * Creates a new paginate event helper with the supplied list.
+	 *
+	 * @param pages A list containing the initial pages.
+	 * @param useButtons Whether to use interaction buttons or legacy reaction-based buttons.
+	 */
 	public PaginateHelper(List<Page> pages, boolean useButtons) {
 		super(PaginateHelper.class, pages, useButtons);
 	}
 
+	/**
+	 * Adds a new page to the list.
+	 *
+	 * @param page The page to be added.
+	 * @return The {@link ButtonizeHelper} instance for chaining convenience.
+	 */
 	public PaginateHelper addPage(Page page) {
 		getContent().add(page);
 		return this;
 	}
 
+	/**
+	 * Retrieves the configured amount of pages to be skipped on pressing {@link Emote#SKIP_BACKWARD} or
+	 * {@link Emote#SKIP_FORWARD}.
+	 *
+	 * @return The configured amount of pages to skip.
+	 */
 	public int getSkipAmount() {
 		return skipAmount;
 	}
 
+	/**
+	 * Sets the amount of pages to be skipped on pressing {@link Emote#SKIP_BACKWARD} or {@link Emote#SKIP_FORWARD}.
+	 *
+	 * @param skipAmount The amount of pages to skip (default: 0).
+	 * @return The {@link ButtonizeHelper} instance for chaining convenience.
+	 */
 	public PaginateHelper setSkipAmount(int skipAmount) {
 		this.skipAmount = skipAmount;
 		return this;
 	}
 
+	/**
+	 * Retrives whether this helper is configured to include {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST}
+	 * buttons.
+	 *
+	 * @return Whether to include fast-forward buttons.
+	 */
 	public boolean isFastForward() {
 		return fastForward;
 	}
 
+	/**
+	 * Sets whether to include {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons for quick navigation
+	 * through the pages.
+	 *
+	 * @param fastForward Whether to include fast-forward buttons (default: false).
+	 * @return The {@link ButtonizeHelper} instance for chaining convenience.
+	 */
 	public PaginateHelper setFastForward(boolean fastForward) {
 		this.fastForward = fastForward;
 		return this;
 	}
 
+	/** {@inheritDoc} **/
 	@Override
 	public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (!isUsingButtons()) return action;
@@ -92,6 +135,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		return action.setComponents(rows);
 	}
 
+	/** {@inheritDoc} **/
 	@Override
 	public boolean shouldUpdate(Message msg) {
 		if (isUsingButtons()) return true;
diff --git a/src/main/java/com/github/ygimenez/model/helper/ReadyMessage.java b/src/main/java/com/github/ygimenez/model/helper/ReadyMessage.java
deleted file mode 100644
index ccc4c91..0000000
--- a/src/main/java/com/github/ygimenez/model/helper/ReadyMessage.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.github.ygimenez.model.helper;
-
-import net.dv8tion.jda.api.entities.Message;
-
-public interface ReadyMessage extends Message {
-
-}
diff --git a/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java b/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java
deleted file mode 100644
index 1b51563..0000000
--- a/src/main/java/com/github/ygimenez/model/helper/SendWrapper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.github.ygimenez.model.helper;
-
-import com.github.ygimenez.exception.InvalidStateException;
-import com.github.ygimenez.method.Pages;
-import com.github.ygimenez.model.InteractPage;
-import com.github.ygimenez.model.Page;
-import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.entities.MessageEmbed;
-import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
-import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
-import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
-import net.dv8tion.jda.api.utils.messages.MessageCreateData;
-
-public class SendWrapper<T extends BaseHelper<T, ?>> {
-	private final T helper;
-	private final Op type;
-	private MessageCreateAction action;
-
-	private enum Op {
-		PAGINATE, LAZY_PAGINATE, CATEGORIZE, BUTTONIZE
-	}
-
-	public SendWrapper(T helper) {
-		this.helper = helper;
-
-		if (helper instanceof LazyPaginateHelper) {
-			this.type = Op.LAZY_PAGINATE;
-		} else if (helper instanceof PaginateHelper) {
-			this.type = Op.PAGINATE;
-		} else if (helper instanceof CategorizeHelper) {
-			this.type = Op.CATEGORIZE;
-		} else if (helper instanceof ButtonizeHelper) {
-			this.type = Op.BUTTONIZE;
-		} else {
-			this.type = null;
-		}
-	}
-
-	public T getHelper() {
-		return helper;
-	}
-
-	public Message send(MessageChannel channel) throws IllegalCallerException {
-		InteractPage page;
-		if (type == Op.PAGINATE) {
-			PaginateHelper helper = (PaginateHelper) this.helper;
-			page = (InteractPage) helper.getContent().get(0);
-		} else if (type == Op.LAZY_PAGINATE) {
-			LazyPaginateHelper helper = (LazyPaginateHelper) this.helper;
-			Page pg = helper.getPageLoader().apply(0);
-			if (pg == null) {
-				throw new InvalidStateException();
-			}
-
-			page = (InteractPage) helper.getContent().get(0);
-		} else {
-			throw new IllegalCallerException("This method cannot be used for categories or buttons. Use '" + helper.getClass().getSimpleName() + ".apply(MessageCreateEvent)' instead.");
-		}
-
-		if (page.getContent() instanceof Message) {
-			try (MessageCreateData data = MessageCreateBuilder.fromMessage((Message) page.getContent()).build()) {
-				action = helper.apply(channel.sendMessage(data));
-			}
-		} else if (page.getContent() instanceof MessageEmbed) {
-			action = helper.apply(channel.sendMessageEmbeds((MessageEmbed) page.getContent()));
-		}
-
-		return Pages.subGet(action);
-	}
-}
diff --git a/src/main/java/com/github/ygimenez/type/Emote.java b/src/main/java/com/github/ygimenez/type/Emote.java
index 94a087b..62be207 100644
--- a/src/main/java/com/github/ygimenez/type/Emote.java
+++ b/src/main/java/com/github/ygimenez/type/Emote.java
@@ -6,6 +6,8 @@
 import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Arrays;
 import java.util.Map;
@@ -84,7 +86,7 @@ public ButtonStyle getStyle() {
 	 * @param emoji The {@link Emoji} to be searched for.
 	 * @return The respective {@link Emote}, or {@link #NONE} if it didn't match any.
 	 */
-	public static Emote getByEmoji(Emoji emoji) {
+	public static Emote getByEmoji(@NotNull Emoji emoji) {
 		for (Map.Entry<Emote, Emoji> entry : Pages.getPaginator().getEmotes().entrySet()) {
 			if (Objects.equals(entry.getValue(), emoji)) return entry.getKey();
 		}
@@ -97,12 +99,12 @@ public static Emote getByEmoji(Emoji emoji) {
 	}
 
 	/**
-	 * Checks whether the supplied {@link Button} is referenced by a library native emote or not.
+	 * Checks whether the supplied {@link Button} is referenced by a library emote or not.
 	 *
 	 * @param btn The {@link Button} to be checked.
 	 * @return Whether it uses a {@link Emote} value or not.
 	 */
-	public static boolean isNative(Button btn) {
+	public static boolean isNative(@NotNull Button btn) {
 		if (btn.getId() == null) return false;
 		else for (Emote emt : values()) {
 			if (emt.name().equals(btn.getId())) return true;
@@ -112,12 +114,12 @@ else for (Emote emt : values()) {
 	}
 
 	/**
-	 * Checks whether the supplied {@link MessageReaction} is referenced by a library native emote or not.
+	 * Checks whether the supplied {@link MessageReaction} is referenced by a library emote or not.
 	 *
 	 * @param react The {@link MessageReaction} to be checked.
 	 * @return Whether it uses a {@link Emote} value or not.
 	 */
-	public static boolean isNative(MessageReaction react) {
+	public static boolean isNative(@NotNull MessageReaction react) {
 		Emoji emj = Emoji.fromFormatted(react.getEmoji().getAsReactionCode());
 		for (Emote emt : values()) {
 			if (emt.emj.equals(emj)) return false;
@@ -132,7 +134,7 @@ public static boolean isNative(MessageReaction react) {
 	 * @param emj The {@link Emoji} to be used.
 	 * @return The supplied {@link Emoji}'s effective ID.
 	 */
-	public static String getId(Emoji emj) {
+	public static String getId(@NotNull Emoji emj) {
 		if (emj instanceof CustomEmoji) {
 			return ((CustomEmoji) emj).getId();
 		} else {
@@ -140,7 +142,14 @@ public static String getId(Emoji emj) {
 		}
 	}
 
-	public static Emote fromButton(Button btn) {
+	/**
+	 * Returns the {@link Emote} represented by the supplied {@link Button}, if any.
+	 *
+	 * @param btn The {@link Button} to be checked.
+	 * @return The {@link Emote} linked to the supplied {@link Button}, or null if none.
+	 */
+	@Nullable
+	public static Emote fromButton(@NotNull Button btn) {
 		return Arrays.stream(values())
 				.filter(e -> btn.getId() != null && btn.getId().contains(e.name()))
 				.findFirst().orElse(null);

From 53298feac045ed1dff9167802b2af193fa598f1c Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 15:04:29 -0300
Subject: [PATCH 19/31] Fixed minor issues

---
 .../ygimenez/listener/MessageHandler.java     | 35 +++++++++++--------
 .../com/github/ygimenez/method/Pages.java     | 16 ++++-----
 2 files changed, 29 insertions(+), 22 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/listener/MessageHandler.java b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
index 3b750eb..973a637 100644
--- a/src/main/java/com/github/ygimenez/listener/MessageHandler.java
+++ b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
@@ -99,21 +99,21 @@ public void clear() {
 		events.clear();
 	}
 
-	private void lock(@NotNull String id) {
+	private synchronized void lock(@NotNull String id) {
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Locked event with ID " + id);
 		locks.add(id);
 	}
 
-	private void unlock(@NotNull String id) {
+	private synchronized void unlock(@NotNull String id) {
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Unlocked event with ID " + id);
 		locks.remove(id);
 	}
 
-	private boolean isLocked(@NotNull GenericMessageReactionEvent evt) {
+	private synchronized boolean isLocked(@NotNull GenericMessageReactionEvent evt) {
 		return locks.contains(getEventId(evt));
 	}
 
-	private boolean isLocked(@NotNull String id) {
+	private synchronized boolean isLocked(@NotNull String id) {
 		return locks.contains(id);
 	}
 
@@ -136,7 +136,11 @@ public void onMessageDelete(@NotNull MessageDeleteEvent evt) {
 
 	private void execute(GenericMessageReactionEvent evt) {
 		String id = getEventId(evt);
-		if (!events.containsKey(id)) return;
+		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Received event with ID " + id);
+		if (!events.containsKey(id)) {
+			Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Event not mapped, skipping");
+			return;
+		}
 
 		evt.retrieveUser().submit()
 				.whenComplete((u, t) -> processEvent(
@@ -147,17 +151,21 @@ private void execute(GenericMessageReactionEvent evt) {
 
 	@Override
 	public void onButtonInteraction(@NotNull ButtonInteractionEvent evt) {
-		User u = evt.getUser();
 		String id = getEventId(evt);
-		if (!events.containsKey(id)) return;
+		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Received event with ID " + id);
+		if (!events.containsKey(id)) {
+			Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Event not mapped, skipping");
+			return;
+		}
 
 		evt.deferEdit().submit()
-				.whenComplete((hook, t) -> processEvent(
-						t,
-						id,
-						u,
-						new PaginationEventWrapper(evt, u, evt.getChannel(), evt.getMessageId(), evt.getButton(), evt.isFromGuild())
-				));
+				.whenComplete((hook, t) -> {
+					User u = hook.getInteraction().getUser();
+					processEvent(
+							t, id, u,
+							new PaginationEventWrapper(evt, u, evt.getChannel(), evt.getMessageId(), evt.getButton(), evt.isFromGuild())
+					);
+				});
 	}
 
 	private void processEvent(Throwable t, String id, User u, PaginationEventWrapper evt) {
@@ -166,7 +174,6 @@ private void processEvent(Throwable t, String id, User u, PaginationEventWrapper
 			return;
 		}
 
-		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Received event with ID " + id);
 		if (u.isBot() || isLocked(id)) {
 			Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Event" + id + " was triggered by a bot or is locked. Ignored");
 			return;
diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index e8b1fd9..29b4922 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -566,9 +566,9 @@ public static ActionReference paginate(@NotNull Message msg, @NotNull PaginateHe
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		List<Page> pgs = Collections.unmodifiableList(helper.getContent());
 
-		if (useBtns) {
+		if (useBtns && helper.shouldUpdate(msg)) {
 			helper.apply(msg.editMessageComponents()).submit();
-		} else {
+		} else if (!useBtns) {
 			clearButtons(msg);
 			clearReactions(msg);
 			addReactions(msg, helper.getSkipAmount() > 1, helper.isFastForward());
@@ -835,9 +835,9 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Categori
 
 		Map<Emoji, Page> cats = Collections.unmodifiableMap(helper.getContent());
 
-		if (useBtns) {
+		if (useBtns && helper.shouldUpdate(msg)) {
 			helper.apply(msg.editMessageComponents()).submit();
-		} else {
+		} else if (!useBtns) {
 			clearButtons(msg);
 			clearReactions(msg);
 
@@ -1141,9 +1141,9 @@ public static ActionReference buttonize(@NotNull Message msg, @NotNull Buttonize
 
 		Map<Emoji, ThrowingConsumer<ButtonWrapper>> btns = Collections.unmodifiableMap(helper.getContent());
 
-		if (useBtns) {
+		if (useBtns && helper.shouldUpdate(msg)) {
 			helper.apply(msg.editMessageComponents()).submit();
-		} else {
+		} else if (!useBtns) {
 			clearButtons(msg);
 			clearReactions(msg);
 
@@ -1473,9 +1473,9 @@ public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull LazyPa
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 		boolean cache = helper.getContent() != null;
 
-		if (useBtns) {
+		if (useBtns && helper.shouldUpdate(msg)) {
 			helper.apply(msg.editMessageComponents()).submit();
-		} else {
+		} else if (!useBtns) {
 			clearButtons(msg);
 			clearReactions(msg);
 			addReactions(msg, false, false);

From a688d1c951379d686ad8b46c0101eed2da939e47 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 15:20:04 -0300
Subject: [PATCH 20/31] Fixed minor issues

---
 .../ygimenez/listener/MessageHandler.java     |  1 +
 .../com/github/ygimenez/method/Pages.java     |  2 +-
 .../github/ygimenez/model/PUtilsConfig.java   | 22 +++++++++++++++++++
 .../com/github/ygimenez/model/Paginator.java  |  8 +++----
 .../ygimenez/model/PaginatorBuilder.java      | 10 ++++-----
 .../ygimenez/model/helper/BaseHelper.java     |  6 ++---
 .../model/helper/ButtonizeHelper.java         |  2 +-
 .../model/helper/CategorizeHelper.java        |  2 +-
 .../ygimenez/model/helper/PaginateHelper.java |  4 ++--
 9 files changed, 40 insertions(+), 17 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/listener/MessageHandler.java b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
index 973a637..d21e24d 100644
--- a/src/main/java/com/github/ygimenez/listener/MessageHandler.java
+++ b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
@@ -154,6 +154,7 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent evt) {
 		String id = getEventId(evt);
 		Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Received event with ID " + id);
 		if (!events.containsKey(id)) {
+			evt.deferEdit().submit().whenComplete((hook, t) -> PUtilsConfig.getOnRemove().accept(evt.getHook()));
 			Pages.getPaginator().log(PUtilsConfig.LogLevel.LEVEL_4, "Event not mapped, skipping");
 			return;
 		}
diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 29b4922..593ebc0 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -51,7 +51,7 @@ private Pages() {
 	}
 
 	/**
-	 * Sets a {@link Paginator} object to handle incoming events. This is
+	 * Set a {@link Paginator} object to handle incoming events. This is
 	 * required only once unless you want to change which client is handling events. <br>
 	 * <br>
 	 * Before calling this method again, you must use {@link #deactivate()} to
diff --git a/src/main/java/com/github/ygimenez/model/PUtilsConfig.java b/src/main/java/com/github/ygimenez/model/PUtilsConfig.java
index 0a7353d..6e93229 100644
--- a/src/main/java/com/github/ygimenez/model/PUtilsConfig.java
+++ b/src/main/java/com/github/ygimenez/model/PUtilsConfig.java
@@ -1,10 +1,13 @@
 package com.github.ygimenez.model;
 
+import net.dv8tion.jda.api.interactions.InteractionHook;
+
 /**
  * Utility class holding library-wide settings.
  */
 public abstract class PUtilsConfig {
 	private static LogLevel logLevel = LogLevel.LEVEL_1;
+	private static ThrowingConsumer<InteractionHook> onRemove = hook -> hook.editOriginalComponents().submit();
 
 	private PUtilsConfig() {
 	}
@@ -52,4 +55,23 @@ public static LogLevel getLogLevel() {
 	public static void setLogLevel(LogLevel logLevel) {
 		PUtilsConfig.logLevel = logLevel;
 	}
+
+	/**
+	 * Retrieve the action performed when encounteing an unmapped event.
+	 *
+	 * @return The action to be performed.
+	 */
+	public static ThrowingConsumer<InteractionHook> getOnRemove() {
+		return onRemove;
+	}
+
+	/**
+	 * Set the action to be performed when encountering an unmapped event. This defaults to simply removing the
+	 * message buttons.
+	 *
+	 * @param onRemove The action to be performed (the interaction is automatically acknowledged).
+	 */
+	public static void setOnRemove(ThrowingConsumer<InteractionHook> onRemove) {
+		PUtilsConfig.onRemove = onRemove;
+	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/Paginator.java b/src/main/java/com/github/ygimenez/model/Paginator.java
index ec15afa..cf7e4d1 100644
--- a/src/main/java/com/github/ygimenez/model/Paginator.java
+++ b/src/main/java/com/github/ygimenez/model/Paginator.java
@@ -56,7 +56,7 @@ public Object getHandler() {
 	}
 
 	/**
-	 * Sets the handler used for event processing.
+	 * Set the handler used for event processing.
 	 * <strong>This must only be called by {@link PaginatorBuilder}</strong>.
 	 *
 	 * @param handler The handler that'll be used for event processing
@@ -79,7 +79,7 @@ public boolean isRemoveOnReact() {
 	}
 
 	/**
-	 * Sets whether user reactions will be removed after pressing the button or not.
+	 * Set whether user reactions will be removed after pressing the button or not.
 	 * <strong>This must only be called by {@link PaginatorBuilder}</strong>.
 	 *
 	 * @param removeOnReact Whether reactions will be removed on press or not.
@@ -99,7 +99,7 @@ public boolean isEventLocked() {
 	}
 
 	/**
-	 * Sets whether evens should be locked to prevent double-activation.
+	 * Set whether evens should be locked to prevent double-activation.
 	 * <strong>This must only be called by {@link PaginatorBuilder}</strong>.
 	 *
 	 * @param hashLocking Whether events should be locked.
@@ -120,7 +120,7 @@ public boolean isDeleteOnCancel() {
 	}
 
 	/**
-	 * Sets whether {@link Message} should be deleted or not when the button handler is removed.
+	 * Set whether {@link Message} should be deleted or not when the button handler is removed.
 	 * <strong>This must only be called by {@link PaginatorBuilder}</strong>.
 	 *
 	 * @param deleteOnCancel Whether the {@link Message} will be deleted or not.
diff --git a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
index fb31552..ba939b4 100644
--- a/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
+++ b/src/main/java/com/github/ygimenez/model/PaginatorBuilder.java
@@ -99,7 +99,7 @@ public Object getHandler() {
 	}
 
 	/**
-	 * Sets the handler used for event processing.
+	 * Set the handler used for event processing.
 	 *
 	 * @param handler The {@link JDA} instance that'll be used for event processing.
 	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
@@ -110,7 +110,7 @@ public PaginatorBuilder setHandler(@NotNull JDA handler) {
 	}
 
 	/**
-	 * Sets the handler used for event processing.
+	 * Set the handler used for event processing.
 	 *
 	 * @param handler The {@link ShardManager} instance that'll be used for event processing.
 	 * @return The {@link PaginatorBuilder} instance for chaining convenience.
@@ -132,7 +132,7 @@ public boolean willRemoveOnReact() {
 	}
 
 	/**
-	 * Sets whether user reactions will be removed after pressing the button or not.
+	 * Set whether user reactions will be removed after pressing the button or not.
 	 * If this is enabled, the bot will require {@link Permission#MESSAGE_MANAGE} permission
 	 * for the buttons to work.
 	 *
@@ -154,7 +154,7 @@ public boolean isEventLocking() {
 	}
 
 	/**
-	 * Sets whether evens should be locked to prevent double-activation of buttons before
+	 * Set whether evens should be locked to prevent double-activation of buttons before
 	 * it finished previous processing (can help if experiencing race condition).
 	 *
 	 * @param shouldLock Whether events should be locked (default: false).
@@ -177,7 +177,7 @@ public boolean shouldDeleteOnCancel() {
 	}
 
 	/**
-	 * Sets whether {@link Message} should be deleted or not when the button handler is removed.
+	 * Set whether {@link Message} should be deleted or not when the button handler is removed.
 	 * <strong>This must only be called by {@link PaginatorBuilder}</strong>.
 	 *
 	 * @param deleteOnCancel Whether the {@link Message} will be deleted or not (default: false).
diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
index 90a46f1..0950ddf 100644
--- a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -53,7 +53,7 @@ public boolean isCancellable() {
 	}
 
 	/**
-	 * Sets whether the event is cancellable through {@link Emote#CANCEL}.
+	 * Set whether the event is cancellable through {@link Emote#CANCEL}.
 	 *
 	 * @param cancellable Whether the event can be cancelled or not (default: true).
 	 * @return The {@link Helper} instance for chaining convenience.
@@ -73,7 +73,7 @@ public long getTimeout() {
 	}
 
 	/**
-	 * Sets the timeout for automatically cancelling the event. Values less than or equal to zero will disable the
+	 * Set the timeout for automatically cancelling the event. Values less than or equal to zero will disable the
 	 * timeout.
 	 *
 	 * @param time The time for the timeout.
@@ -96,7 +96,7 @@ public boolean canInteract(User user) {
 	}
 
 	/**
-	 * Sets the condition used to check if a given user can interact with the event buttons.
+	 * Set the condition used to check if a given user can interact with the event buttons.
 	 *
 	 * @param canInteract A {@link Predicate} for checking if a given user can interact with the buttons (default: null).
 	 * @return The {@link Helper} instance for chaining convenience.
diff --git a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
index 9a111ef..f440315 100644
--- a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
@@ -124,6 +124,6 @@ public boolean shouldUpdate(Message msg) {
 
 		checks = checks.and(e -> e.containsAll(getContent().keySet()));
 
-		return checks.test(emojis);
+		return !checks.test(emojis);
 	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
index f6bbe58..328779f 100644
--- a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
@@ -99,6 +99,6 @@ public boolean shouldUpdate(Message msg) {
 
 		checks = checks.and(e -> e.containsAll(getContent().keySet()));
 
-		return checks.test(emojis);
+		return !checks.test(emojis);
 	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
index 3c61ba8..2af3e0e 100644
--- a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
@@ -63,7 +63,7 @@ public int getSkipAmount() {
 	}
 
 	/**
-	 * Sets the amount of pages to be skipped on pressing {@link Emote#SKIP_BACKWARD} or {@link Emote#SKIP_FORWARD}.
+	 * Set the amount of pages to be skipped on pressing {@link Emote#SKIP_BACKWARD} or {@link Emote#SKIP_FORWARD}.
 	 *
 	 * @param skipAmount The amount of pages to skip (default: 0).
 	 * @return The {@link ButtonizeHelper} instance for chaining convenience.
@@ -84,7 +84,7 @@ public boolean isFastForward() {
 	}
 
 	/**
-	 * Sets whether to include {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons for quick navigation
+	 * Set whether to include {@link Emote#GOTO_FIRST} and {@link Emote#GOTO_LAST} buttons for quick navigation
 	 * through the pages.
 	 *
 	 * @param fastForward Whether to include fast-forward buttons (default: false).

From 5af0a1d8ea7edea49354cb2cb3668ba9df2b0481 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 15:56:52 -0300
Subject: [PATCH 21/31] Fixed minor issues

---
 src/main/java/com/github/ygimenez/listener/MessageHandler.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/com/github/ygimenez/listener/MessageHandler.java b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
index d21e24d..d5ab40b 100644
--- a/src/main/java/com/github/ygimenez/listener/MessageHandler.java
+++ b/src/main/java/com/github/ygimenez/listener/MessageHandler.java
@@ -209,7 +209,7 @@ private String getEventId(GenericMessageEvent evt) {
 
 	private String getEventId(ButtonInteractionEvent evt) {
 		crc.reset();
-		String rawId = (evt.isFromGuild() ? "GUILD_" : "PRIVATE_") + evt.getChannel().getId() + "_" + evt.getId();
+		String rawId = (evt.isFromGuild() ? "GUILD_" : "PRIVATE_") + evt.getChannel().getId() + "_" + evt.getMessageId();
 		crc.update(rawId.getBytes(StandardCharsets.UTF_8));
 
 		return Long.toHexString(crc.getValue());

From aa3ffd40857c4925fccf698cd528c27527f67508 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 18:01:34 -0300
Subject: [PATCH 22/31] Fixed minor issues

---
 src/main/java/com/github/ygimenez/method/Pages.java          | 5 ++++-
 .../java/com/github/ygimenez/model/helper/BaseHelper.java    | 5 ++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 593ebc0..28496cd 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -35,6 +35,7 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 import static com.github.ygimenez.type.Emote.*;
 
@@ -833,7 +834,9 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Categori
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
-		Map<Emoji, Page> cats = Collections.unmodifiableMap(helper.getContent());
+		Map<Emoji, Page> cats = helper.getContent().entrySet().stream()
+				.map(e -> Map.entry(e.getKey().getFormatted(), e.getValue()))
+				.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
 
 		if (useBtns && helper.shouldUpdate(msg)) {
 			helper.apply(msg.editMessageComponents()).submit();
diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
index 0950ddf..eaa6986 100644
--- a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -81,7 +81,10 @@ public long getTimeout() {
 	 * @return The {@link Helper} instance for chaining convenience.
 	 */
 	public Helper setTimeout(int time, TimeUnit unit) {
-		this.time = TimeUnit.MILLISECONDS.convert(time, unit);
+		if (unit != null) {
+			this.time = TimeUnit.MILLISECONDS.convert(time, unit);
+		}
+
 		return subClass.cast(this);
 	}
 

From 852e6772e23fb6a53b3386997a2e1e88b4577947 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 19:02:35 -0300
Subject: [PATCH 23/31] Fixed build issues.

---
 .../com/github/ygimenez/method/Pages.java     | 31 +++++++++++++++----
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 28496cd..e9073b5 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -13,6 +13,7 @@
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.JDA;
 import net.dv8tion.jda.api.entities.*;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
 import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
 import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
@@ -35,7 +36,6 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
-import java.util.stream.Collectors;
 
 import static com.github.ygimenez.type.Emote.*;
 
@@ -834,9 +834,7 @@ public static ActionReference categorize(@NotNull Message msg, @NotNull Categori
 		if (!isActivated()) throw new InvalidStateException();
 		boolean useBtns = helper.isUsingButtons() && msg.getAuthor().getId().equals(msg.getJDA().getSelfUser().getId());
 
-		Map<Emoji, Page> cats = helper.getContent().entrySet().stream()
-				.map(e -> Map.entry(e.getKey().getFormatted(), e.getValue()))
-				.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+		Map<Emoji, Page> cats = Collections.unmodifiableMap(helper.getContent());
 
 		if (useBtns && helper.shouldUpdate(msg)) {
 			helper.apply(msg.editMessageComponents()).submit();
@@ -895,7 +893,7 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 						finalizeEvent(m, success);
 						return;
 					} else if (emoji != null && !Objects.equals(emoji, currCat)) {
-						Page pg = cats.get(emoji);
+						Page pg = lookupValue(cats, emoji);
 						if (pg != null) {
 							if (currCat != null && pg instanceof InteractPage) {
 								modifyButtons(m, Map.of(Emote.getId(currCat), Button::asEnabled));
@@ -1211,7 +1209,7 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 						hook = null;
 					}
 
-					ThrowingConsumer<ButtonWrapper> act = btns.get(emoji);
+					ThrowingConsumer<ButtonWrapper> act = lookupValue(btns, emoji);
 					if (act != null) {
 						act.accept(new ButtonWrapper(wrapper.getUser(), hook, m));
 					}
@@ -1662,6 +1660,27 @@ private static Emoji toEmoji(EmojiUnion reaction) {
 		return Emoji.fromFormatted(reaction.getFormatted());
 	}
 
+	private static <T> T lookupValue(Map<Emoji, T> map, Emoji emoji) {
+		String id;
+		if (emoji instanceof CustomEmoji) {
+			id = ((CustomEmoji) emoji).getId();
+		} else {
+			id = emoji.getFormatted();
+		}
+
+		return map.entrySet().stream()
+				.filter(e -> {
+					Emoji emj = e.getKey();
+					if (emj instanceof CustomEmoji) {
+						return ((CustomEmoji) emj).getId().equals(id);
+					}
+
+					return emj.getFormatted().equals(id);
+				})
+				.map(Map.Entry::getValue)
+				.findFirst().orElse(null);
+	}
+
 	/**
 	 * Utility method to clear all reactions of a message.
 	 *

From 7cd6825dfd988dc4fb5d968ed44d5f474d8fb7b2 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Mon, 6 Mar 2023 21:39:39 -0300
Subject: [PATCH 24/31] Fixed build issues.

---
 .../github/ygimenez/model/InteractPage.java    | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/model/InteractPage.java b/src/main/java/com/github/ygimenez/model/InteractPage.java
index 5a02458..bc69aa2 100644
--- a/src/main/java/com/github/ygimenez/model/InteractPage.java
+++ b/src/main/java/com/github/ygimenez/model/InteractPage.java
@@ -20,7 +20,6 @@
 public class InteractPage extends Page {
 	private final Map<ButtonStyle, ButtonStyle> styles = new EnumMap<>(ButtonStyle.class);
 	private final Map<Emote, String> caption = new EnumMap<>(Emote.class);
-	private final boolean ephemeral;
 
 	/**
 	 * An {@link InteractPage} object to be used in this library's methods. Currently, only {@link Message}
@@ -31,7 +30,6 @@ public class InteractPage extends Page {
 	 */
 	public InteractPage(@NotNull Object content) throws IllegalArgumentException {
 		super(content);
-		this.ephemeral = false; //Attribute currently unused
 	}
 
 	/**
@@ -75,7 +73,7 @@ public Button makeButton(@NotNull Emote emt) {
 		if (emt == Emote.NONE) {
 			return Button.secondary(emt.name() + "." + Objects.hash(Math.random()), "\u200B").asDisabled();
 		} else {
-			return Button.of(style, (ephemeral ? "*" : "") + emt.name(), caption.get(emt), Pages.getPaginator().getEmoji(emt));
+			return Button.of(style,  emt.name(), caption.get(emt), Pages.getPaginator().getEmoji(emt));
 		}
 	}
 
@@ -86,7 +84,7 @@ public Button makeButton(@NotNull Emote emt) {
 	 * @return The created {@link Button}.
 	 */
 	public Button makeButton(@NotNull Emoji emj) {
-		return Button.secondary((ephemeral ? "*" : "") + Emote.getId(emj), emj);
+		return Button.secondary( Emote.getId(emj), emj);
 	}
 
 	/**
@@ -97,16 +95,6 @@ public Button makeButton(@NotNull Emoji emj) {
 	 * @return The created {@link Button}.
 	 */
 	public Button makeButton(@NotNull Emoji emj, String caption) {
-		return Button.of(ButtonStyle.SECONDARY, (ephemeral ? "*" : "") + Emote.getId(emj), caption, emj);
-	}
-
-	/**
-	 * Whether the button is intended to be used in ephemeral messages or not. Currently, it serves no purpose other
-	 * than a placeholder for future features.
-	 *
-	 * @return Whether the {@link Button} will be used in ephemeral messages or not.
-	 */
-	public boolean isEphemeral() {
-		return ephemeral;
+		return Button.of(ButtonStyle.SECONDARY,  Emote.getId(emj), caption, emj);
 	}
 }

From 7a1cbb302c7bbf65fdd27baaf341aef057a3bb75 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Tue, 7 Mar 2023 00:36:49 -0300
Subject: [PATCH 25/31] Fixed build issues.

---
 .../github/ygimenez/model/InteractPage.java   |  6 +++---
 .../model/helper/CategorizeHelper.java        | 20 ++++++++++++++++---
 .../model/helper/LazyPaginateHelper.java      |  2 +-
 .../ygimenez/model/helper/PaginateHelper.java | 10 +++++-----
 4 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/model/InteractPage.java b/src/main/java/com/github/ygimenez/model/InteractPage.java
index bc69aa2..de09a87 100644
--- a/src/main/java/com/github/ygimenez/model/InteractPage.java
+++ b/src/main/java/com/github/ygimenez/model/InteractPage.java
@@ -73,7 +73,7 @@ public Button makeButton(@NotNull Emote emt) {
 		if (emt == Emote.NONE) {
 			return Button.secondary(emt.name() + "." + Objects.hash(Math.random()), "\u200B").asDisabled();
 		} else {
-			return Button.of(style,  emt.name(), caption.get(emt), Pages.getPaginator().getEmoji(emt));
+			return Button.of(style, emt.name(), caption.get(emt), Pages.getPaginator().getEmoji(emt));
 		}
 	}
 
@@ -84,7 +84,7 @@ public Button makeButton(@NotNull Emote emt) {
 	 * @return The created {@link Button}.
 	 */
 	public Button makeButton(@NotNull Emoji emj) {
-		return Button.secondary( Emote.getId(emj), emj);
+		return Button.secondary(Emote.getId(emj), emj);
 	}
 
 	/**
@@ -95,6 +95,6 @@ public Button makeButton(@NotNull Emoji emj) {
 	 * @return The created {@link Button}.
 	 */
 	public Button makeButton(@NotNull Emoji emj, String caption) {
-		return Button.of(ButtonStyle.SECONDARY,  Emote.getId(emj), caption, emj);
+		return Button.of(ButtonStyle.SECONDARY, Emote.getId(emj), caption, emj);
 	}
 }
diff --git a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
index 328779f..e1aead5 100644
--- a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
@@ -1,9 +1,10 @@
 package com.github.ygimenez.model.helper;
 
 import com.github.ygimenez.method.Pages;
+import com.github.ygimenez.model.InteractPage;
 import com.github.ygimenez.model.Page;
-import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.MessageEmbed;
 import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
 import net.dv8tion.jda.api.interactions.components.ItemComponent;
@@ -59,13 +60,26 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		List<ActionRow> rows = new ArrayList<>();
 
 		List<ItemComponent> row = new ArrayList<>();
-		for (Emoji k : getContent().keySet()) {
+		for (Map.Entry<Emoji, Page> e : getContent().entrySet()) {
 			if (row.size() == 5) {
 				rows.add(ActionRow.of(row));
 				row = new ArrayList<>();
 			}
 
-			row.add(Button.secondary(Emote.getId(k), k));
+			InteractPage p = (InteractPage) e.getValue();
+			Button b = p.makeButton(e.getKey());
+			if (p.getContent() instanceof MessageEmbed) {
+				for (MessageEmbed embed : action.getEmbeds()) {
+					if (embed.equals(p.getContent())) {
+						b = b.asDisabled();
+						break;
+					}
+				}
+			} else if (action.getContent().equals(p.getContent())) {
+				b = b.asDisabled();
+			}
+
+			row.add(b);
 		}
 
 		if (isCancellable()) {
diff --git a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
index 648be25..45d2169 100644
--- a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
@@ -106,7 +106,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		if (p == null) throw new NullPageException();
 
 		return action.setComponents(ActionRow.of(new ArrayList<>() {{
-			add(p.makeButton(PREVIOUS));
+			add(p.makeButton(PREVIOUS).asDisabled());
 			if (isCancellable()) add(p.makeButton(CANCEL));
 			add(p.makeButton(NEXT));
 		}}));
diff --git a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
index 2af3e0e..0af9783 100644
--- a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
@@ -106,7 +106,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 		List<ActionRow> rows = new ArrayList<>();
 
 		LinkedList<ItemComponent> row = new LinkedList<>() {{
-			add(p.makeButton(PREVIOUS));
+			add(p.makeButton(PREVIOUS).asDisabled());
 			if (isCancellable()) add(p.makeButton(CANCEL));
 			add(p.makeButton(NEXT));
 		}};
@@ -114,18 +114,18 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 			row.addFirst(p.makeButton(NONE));
 			row.addLast(p.makeButton(NONE));
 		} else if (skipAmount > 1) {
-			row.addFirst(p.makeButton(SKIP_BACKWARD));
+			row.addFirst(p.makeButton(SKIP_BACKWARD).asDisabled());
 			row.addLast(p.makeButton(SKIP_FORWARD));
 		} else if (fastForward) {
-			row.addFirst(p.makeButton(GOTO_FIRST));
+			row.addFirst(p.makeButton(GOTO_FIRST).asDisabled());
 			row.addLast(p.makeButton(GOTO_LAST));
 		}
 		rows.add(ActionRow.of(row));
 
 		if (skipAmount > 1 && fastForward) {
 			rows.add(ActionRow.of(new ArrayList<>() {{
-				add(p.makeButton(GOTO_FIRST));
-				add(p.makeButton(SKIP_BACKWARD));
+				add(p.makeButton(GOTO_FIRST).asDisabled());
+				add(p.makeButton(SKIP_BACKWARD).asDisabled());
 				if (isCancellable()) add(p.makeButton(NONE));
 				add(p.makeButton(SKIP_FORWARD));
 				add(p.makeButton(GOTO_LAST));

From 2dfb597c8aa21a4c09b8ebc54c8a3d71751f74be Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Tue, 7 Mar 2023 00:59:38 -0300
Subject: [PATCH 26/31] Fixed build issues.

---
 .../com/github/ygimenez/method/Pages.java     | 29 ++++++++++++++-----
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index e9073b5..0b9806e 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -616,7 +616,7 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 						}
 					}
 
-					Page pg;
+					Page pg = null;
 					boolean update = false;
 					switch (emt) {
 						case PREVIOUS:
@@ -1494,6 +1494,8 @@ public static ActionReference lazyPaginate(@NotNull Message msg, @NotNull LazyPa
 				if (paginator.isDeleteOnCancel()) msg.delete().submit();
 			};
 
+			private final Function<Button, Button> LOWER_BOUNDARY_CHECK = b -> b.withDisabled(p == 0);
+
 			{
 				if (helper.getTimeout() > 0) {
 					timeout = executor.schedule(() -> finalizeEvent(msg, success), helper.getTimeout(), TimeUnit.MILLISECONDS);
@@ -1519,19 +1521,20 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 						}
 					}
 
-					Page pg;
+					Page pg = null;
+					boolean update = false;
 					switch (emt) {
 						case PREVIOUS:
 							if (p > 0) {
 								p--;
+								update = true;
 								pg = cache ? helper.getContent().get(p) : helper.getPageLoader().apply(p);
-
-								updatePage(m, pg);
-								updateButtons(m, helper);
 							}
 							break;
 						case NEXT:
 							p++;
+							update = true;
+
 							if (cache && helper.getContent().size() > p) {
 								pg = helper.getContent().get(p);
 								if (pg == null) {
@@ -1549,9 +1552,6 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 								}
 							}
 
-							updatePage(m, pg);
-							updateButtons(m, helper);
-
 							if (cache) helper.getContent().add(pg);
 							break;
 						case CANCEL:
@@ -1559,6 +1559,19 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 							return;
 					}
 
+					if (update) {
+						updatePage(m, pg);
+						updateButtons(m, helper);
+
+						if (pg instanceof InteractPage) {
+							modifyButtons(m, Map.of(
+									PREVIOUS.name(), LOWER_BOUNDARY_CHECK,
+									SKIP_BACKWARD.name(), LOWER_BOUNDARY_CHECK,
+									GOTO_FIRST.name(), LOWER_BOUNDARY_CHECK
+							));
+						}
+					}
+
 					if (timeout != null) {
 						timeout.cancel(true);
 					}

From 5d08acc6d063e7fcdba38cf31c182f581893e1af Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Tue, 7 Mar 2023 09:43:29 -0300
Subject: [PATCH 27/31] Removed unnecessary API calls

---
 .../com/github/ygimenez/method/Pages.java     | 129 ++++++------------
 .../ygimenez/model/helper/BaseHelper.java     |  24 +++-
 .../model/helper/ButtonizeHelper.java         |  10 +-
 .../model/helper/CategorizeHelper.java        |  10 +-
 .../model/helper/LazyPaginateHelper.java      |  18 +--
 .../ygimenez/model/helper/PaginateHelper.java |  17 +--
 6 files changed, 92 insertions(+), 116 deletions(-)

diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 0b9806e..c9efa96 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -3,13 +3,9 @@
 import com.github.ygimenez.exception.AlreadyActivatedException;
 import com.github.ygimenez.exception.InvalidHandlerException;
 import com.github.ygimenez.exception.InvalidStateException;
-import com.github.ygimenez.exception.NullPageException;
 import com.github.ygimenez.listener.MessageHandler;
 import com.github.ygimenez.model.*;
-import com.github.ygimenez.model.helper.ButtonizeHelper;
-import com.github.ygimenez.model.helper.CategorizeHelper;
-import com.github.ygimenez.model.helper.LazyPaginateHelper;
-import com.github.ygimenez.model.helper.PaginateHelper;
+import com.github.ygimenez.model.helper.*;
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.JDA;
 import net.dv8tion.jda.api.entities.*;
@@ -22,13 +18,12 @@
 import net.dv8tion.jda.api.exceptions.ErrorResponseException;
 import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
 import net.dv8tion.jda.api.interactions.InteractionHook;
-import net.dv8tion.jda.api.interactions.components.ActionRow;
 import net.dv8tion.jda.api.interactions.components.ItemComponent;
+import net.dv8tion.jda.api.interactions.components.LayoutComponent;
 import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.requests.RestAction;
+import net.dv8tion.jda.api.requests.restaction.MessageEditAction;
 import net.dv8tion.jda.api.sharding.ShardManager;
-import net.dv8tion.jda.api.utils.messages.MessageEditBuilder;
-import net.dv8tion.jda.api.utils.messages.MessageEditData;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.*;
@@ -662,20 +657,15 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 
 					if (update) {
 						pg = pgs.get(p);
-						updatePage(m, pg);
-						updateButtons(m, helper);
-
-						if (pg instanceof InteractPage) {
-							modifyButtons(m, Map.of(
-									PREVIOUS.name(), LOWER_BOUNDARY_CHECK,
-									SKIP_BACKWARD.name(), LOWER_BOUNDARY_CHECK,
-									GOTO_FIRST.name(), LOWER_BOUNDARY_CHECK,
-
-									NEXT.name(), UPPER_BOUNDARY_CHECK,
-									SKIP_FORWARD.name(), UPPER_BOUNDARY_CHECK,
-									GOTO_LAST.name(), UPPER_BOUNDARY_CHECK
-							));
-						}
+						modifyButtons(m, pg, helper, Map.of(
+								PREVIOUS.name(), LOWER_BOUNDARY_CHECK,
+								SKIP_BACKWARD.name(), LOWER_BOUNDARY_CHECK,
+								GOTO_FIRST.name(), LOWER_BOUNDARY_CHECK,
+
+								NEXT.name(), UPPER_BOUNDARY_CHECK,
+								SKIP_FORWARD.name(), UPPER_BOUNDARY_CHECK,
+								GOTO_LAST.name(), UPPER_BOUNDARY_CHECK
+						));
 					}
 
 					if (timeout != null) {
@@ -895,15 +885,8 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 					} else if (emoji != null && !Objects.equals(emoji, currCat)) {
 						Page pg = lookupValue(cats, emoji);
 						if (pg != null) {
-							if (currCat != null && pg instanceof InteractPage) {
-								modifyButtons(m, Map.of(Emote.getId(currCat), Button::asEnabled));
-							}
-
-							updatePage(m, pg);
 							currCat = emoji;
-							if (pg instanceof InteractPage) {
-								modifyButtons(m, Map.of(Emote.getId(currCat), Button::asDisabled));
-							}
+							modifyButtons(m, pg, helper, Map.of(Emote.getId(currCat), Button::asDisabled));
 						}
 					}
 
@@ -1560,16 +1543,11 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 					}
 
 					if (update) {
-						updatePage(m, pg);
-						updateButtons(m, helper);
-
-						if (pg instanceof InteractPage) {
-							modifyButtons(m, Map.of(
-									PREVIOUS.name(), LOWER_BOUNDARY_CHECK,
-									SKIP_BACKWARD.name(), LOWER_BOUNDARY_CHECK,
-									GOTO_FIRST.name(), LOWER_BOUNDARY_CHECK
-							));
-						}
+						modifyButtons(m, pg, helper, Map.of(
+								PREVIOUS.name(), LOWER_BOUNDARY_CHECK,
+								SKIP_BACKWARD.name(), LOWER_BOUNDARY_CHECK,
+								GOTO_FIRST.name(), LOWER_BOUNDARY_CHECK
+						));
 					}
 
 					if (timeout != null) {
@@ -1587,41 +1565,6 @@ public void acceptThrows(@NotNull User u, @NotNull PaginationEventWrapper wrappe
 		});
 	}
 
-	/**
-	 * Method used to update the current page.
-	 * <strong>Must not be called outside of {@link Pages}</strong>.
-	 *
-	 * @param msg The current {@link Message} object.
-	 * @param p   The current {@link Page}.
-	 */
-	private static void updatePage(@NotNull Message msg, Page p) {
-		if (p == null) throw new NullPageException(msg);
-
-		if (p.getContent() instanceof Message) {
-			try (MessageEditData data = MessageEditBuilder.fromMessage((Message) p.getContent()).build()) {
-				msg.editMessage(data).submit();
-			}
-		} else if (p.getContent() instanceof MessageEmbed) {
-			msg.editMessageEmbeds((MessageEmbed) p.getContent()).submit();
-		}
-	}
-
-	private static void updateButtons(@NotNull Message msg, @NotNull PaginateHelper helper) {
-		if (helper.isUsingButtons()) {
-			helper.apply(msg.editMessageComponents()).submit();
-		} else {
-			addReactions(msg, helper.getSkipAmount() > 1, helper.isFastForward());
-		}
-	}
-
-	private static void updateButtons(@NotNull Message msg, @NotNull LazyPaginateHelper helper) {
-		if (helper.isUsingButtons()) {
-			helper.apply(msg.editMessageComponents()).submit();
-		} else {
-			addReactions(msg, false, false);
-		}
-	}
-
 	/**
 	 * Utility method for re-fetching a message.
 	 *
@@ -1744,28 +1687,38 @@ public static void finalizeEvent(Message msg, Consumer<Void> callback) {
 	}
 
 	/**
-	 * Utility method for modifying message buttons.
+	 * Utility method for switching pages and applying message button states.
 	 *
 	 * @param msg     The {@link Message} holding the buttons.
 	 * @param changes {@link Map} containing desired changes, indexed by {@link Button} ID.
 	 */
-	public static void modifyButtons(Message msg, Map<String, Function<Button, Button>> changes) {
-		List<ActionRow> rows = new ArrayList<>(msg.getActionRows());
-
-		for (ActionRow ar : rows) {
-			List<ItemComponent> row = ar.getComponents();
-			for (int i = 0; i < row.size(); i++) {
-				ItemComponent c = row.get(i);
-				if (c instanceof Button) {
-					Button b = (Button) c;
-					if (changes.containsKey(b.getId())) {
-						row.set(i, changes.get(b.getId()).apply((Button) c));
+	public static void modifyButtons(Message msg, Page p, BaseHelper<?, ?> helper, Map<String, Function<Button, Button>> changes) {
+		MessageEditAction act = msg.editMessageComponents();
+
+		if (p.getContent() instanceof Message) {
+			act = act.setContent(((Message) p.getContent()).getContentRaw());
+		} else if (p.getContent() instanceof MessageEmbed) {
+			act = act.setEmbeds((MessageEmbed) p.getContent());
+		}
+
+		if (p instanceof InteractPage) {
+			List<LayoutComponent> rows = helper.getComponents(act);
+
+			for (LayoutComponent lc : rows) {
+				List<ItemComponent> row = lc.getComponents();
+				for (int i = 0; i < row.size(); i++) {
+					ItemComponent c = row.get(i);
+					if (c instanceof Button) {
+						Button b = (Button) c;
+						if (changes.containsKey(b.getId())) {
+							row.set(i, changes.get(b.getId()).apply((Button) c));
+						}
 					}
 				}
 			}
 		}
 
-		subGet(msg.editMessageComponents(rows));
+		act.submit();
 	}
 
 	/**
diff --git a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
index eaa6986..46f4408 100644
--- a/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/BaseHelper.java
@@ -1,15 +1,26 @@
 package com.github.ygimenez.model.helper;
 
+import com.github.ygimenez.method.Pages;
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.interactions.components.Component;
+import net.dv8tion.jda.api.interactions.components.LayoutComponent;
 import net.dv8tion.jda.api.utils.messages.MessageRequest;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 
-abstract class BaseHelper<Helper extends BaseHelper<Helper, T>, T> {
+/**
+ * Abstract class meant to be extended by builder-like classes, allowing reusability of parameters passed to
+ * {@link Pages} methods.
+ *
+ * @param <Helper> A class that extends {@link BaseHelper}.
+ * @param <T> The type of collection used to store pages.
+ */
+public abstract class BaseHelper<Helper extends BaseHelper<Helper, T>, T> {
 	private final Class<Helper> subClass;
 
 	private final T content;
@@ -109,6 +120,13 @@ public Helper setCanInteract(@Nullable Predicate<User> canInteract) {
 		return subClass.cast(this);
 	}
 
+	/**
+	 * Retrieves the {@link List} of {@link Component}s generated by this helper.
+	 *
+	 * @return The list of components.
+	 */
+	public abstract <Out extends MessageRequest<Out>> List<LayoutComponent> getComponents(Out action);
+
 	/**
 	 * Prepares the message for being used by the library. This doesn't need to be called manually, this will
 	 * be called during normal flow.
@@ -122,7 +140,9 @@ public Helper setCanInteract(@Nullable Predicate<User> canInteract) {
 	 * @return The same event, but modified to include the buttons.
 	 * @param <Out> Generic for a {@link MessageRequest}
 	 */
-	public abstract <Out extends MessageRequest<Out>> Out apply(Out action);
+	public <Out extends MessageRequest<Out>> Out apply(Out action) {
+		return action.setComponents(getComponents(action));
+	}
 
 	/**
 	 * Calculates whether the {@link Message} needs to have buttons applied onto or not.
diff --git a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
index f440315..863c36f 100644
--- a/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/ButtonizeHelper.java
@@ -8,6 +8,7 @@
 import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
 import net.dv8tion.jda.api.interactions.components.ItemComponent;
+import net.dv8tion.jda.api.interactions.components.LayoutComponent;
 import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.utils.messages.MessageRequest;
 
@@ -75,12 +76,11 @@ public ButtonizeHelper setOnFinalization(Consumer<Message> onFinalization) {
 		return this;
 	}
 
-	/** {@inheritDoc} **/
 	@Override
-	public <Out extends MessageRequest<Out>> Out apply(Out action) {
-		if (!isUsingButtons()) return action;
+	public <Out extends MessageRequest<Out>> List<LayoutComponent> getComponents(Out action) {
+		if (!isUsingButtons()) return List.of();
 
-		List<ActionRow> rows = new ArrayList<>();
+		List<LayoutComponent> rows = new ArrayList<>();
 
 		List<ItemComponent> row = new ArrayList<>();
 		for (Emoji k : getContent().keySet()) {
@@ -109,7 +109,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 
 		rows.add(ActionRow.of(row));
 
-		return action.setComponents(rows);
+		return rows;
 	}
 
 	/** {@inheritDoc} **/
diff --git a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
index e1aead5..85653c3 100644
--- a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
@@ -8,6 +8,7 @@
 import net.dv8tion.jda.api.entities.emoji.Emoji;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
 import net.dv8tion.jda.api.interactions.components.ItemComponent;
+import net.dv8tion.jda.api.interactions.components.LayoutComponent;
 import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.utils.messages.MessageRequest;
 
@@ -52,12 +53,11 @@ public CategorizeHelper addCategory(Emoji emoji, Page page) {
 		return this;
 	}
 
-	/** {@inheritDoc} **/
 	@Override
-	public <Out extends MessageRequest<Out>> Out apply(Out action) {
-		if (!isUsingButtons()) return action;
+	public <Out extends MessageRequest<Out>> List<LayoutComponent> getComponents(Out action) {
+		if (!isUsingButtons()) return List.of();
 
-		List<ActionRow> rows = new ArrayList<>();
+		List<LayoutComponent> rows = new ArrayList<>();
 
 		List<ItemComponent> row = new ArrayList<>();
 		for (Map.Entry<Emoji, Page> e : getContent().entrySet()) {
@@ -98,7 +98,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 
 		rows.add(ActionRow.of(row));
 
-		return action.setComponents(rows);
+		return rows;
 	}
 
 	/** {@inheritDoc} **/
diff --git a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
index 45d2169..a156488 100644
--- a/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/LazyPaginateHelper.java
@@ -7,6 +7,7 @@
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
+import net.dv8tion.jda.api.interactions.components.LayoutComponent;
 import net.dv8tion.jda.api.utils.messages.MessageRequest;
 import org.jetbrains.annotations.Nullable;
 
@@ -97,19 +98,20 @@ public ThrowingFunction<Integer, Page> getPageLoader() {
 		return p;
 	}
 
-	/** {@inheritDoc} **/
 	@Override
-	public <Out extends MessageRequest<Out>> Out apply(Out action) {
-		if (!isUsingButtons()) return action;
+	public <Out extends MessageRequest<Out>> List<LayoutComponent> getComponents(Out action) {
+		if (!isUsingButtons()) return List.of();
 
 		InteractPage p = (InteractPage) load(0);
 		if (p == null) throw new NullPageException();
 
-		return action.setComponents(ActionRow.of(new ArrayList<>() {{
-			add(p.makeButton(PREVIOUS).asDisabled());
-			if (isCancellable()) add(p.makeButton(CANCEL));
-			add(p.makeButton(NEXT));
-		}}));
+		return List.of(
+				ActionRow.of(new ArrayList<>() {{
+					add(p.makeButton(PREVIOUS).asDisabled());
+					if (isCancellable()) add(p.makeButton(CANCEL));
+					add(p.makeButton(NEXT));
+				}})
+		);
 	}
 
 	/** {@inheritDoc} **/
diff --git a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
index 0af9783..2ae3812 100644
--- a/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/PaginateHelper.java
@@ -1,15 +1,18 @@
 package com.github.ygimenez.model.helper;
 
-import com.github.ygimenez.exception.NullPageException;
 import com.github.ygimenez.model.InteractPage;
 import com.github.ygimenez.model.Page;
 import com.github.ygimenez.type.Emote;
 import net.dv8tion.jda.api.entities.Message;
 import net.dv8tion.jda.api.interactions.components.ActionRow;
 import net.dv8tion.jda.api.interactions.components.ItemComponent;
+import net.dv8tion.jda.api.interactions.components.LayoutComponent;
 import net.dv8tion.jda.api.utils.messages.MessageRequest;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -95,15 +98,13 @@ public PaginateHelper setFastForward(boolean fastForward) {
 		return this;
 	}
 
-	/** {@inheritDoc} **/
 	@Override
-	public <Out extends MessageRequest<Out>> Out apply(Out action) {
-		if (!isUsingButtons()) return action;
+	public <Out extends MessageRequest<Out>> List<LayoutComponent> getComponents(Out action) {
+		if (!isUsingButtons()) return List.of();
 
-		if (getContent().isEmpty()) throw new NullPageException();
 		InteractPage p = (InteractPage) getContent().get(0);
 
-		List<ActionRow> rows = new ArrayList<>();
+		List<LayoutComponent> rows = new ArrayList<>();
 
 		LinkedList<ItemComponent> row = new LinkedList<>() {{
 			add(p.makeButton(PREVIOUS).asDisabled());
@@ -132,7 +133,7 @@ public <Out extends MessageRequest<Out>> Out apply(Out action) {
 			}}));
 		}
 
-		return action.setComponents(rows);
+		return rows;
 	}
 
 	/** {@inheritDoc} **/

From 796ae0e2de51e5adc2d56f6138e76a3cca01d4c6 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Tue, 7 Mar 2023 09:53:39 -0300
Subject: [PATCH 28/31] Removed unnecessary API calls

---
 .../java/com/github/ygimenez/model/helper/CategorizeHelper.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
index 85653c3..9789462 100644
--- a/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
+++ b/src/main/java/com/github/ygimenez/model/helper/CategorizeHelper.java
@@ -67,6 +67,8 @@ public <Out extends MessageRequest<Out>> List<LayoutComponent> getComponents(Out
 			}
 
 			InteractPage p = (InteractPage) e.getValue();
+			if (p == null) continue;
+
 			Button b = p.makeButton(e.getKey());
 			if (p.getContent() instanceof MessageEmbed) {
 				for (MessageEmbed embed : action.getEmbeds()) {

From 390295b8105d7dcc9f563b8e05d789d63c5d36df Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Tue, 7 Mar 2023 09:56:06 -0300
Subject: [PATCH 29/31] Removed unnecessary API calls

---
 src/main/java/com/github/ygimenez/method/Pages.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index c9efa96..4eaa193 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -1716,6 +1716,8 @@ public static void modifyButtons(Message msg, Page p, BaseHelper<?, ?> helper, M
 					}
 				}
 			}
+
+			act.setComponents(rows);
 		}
 
 		act.submit();

From e2958ca9ae0455d86825a70ce3297f4d7f4f97f9 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Tue, 7 Mar 2023 10:31:38 -0300
Subject: [PATCH 30/31] Changed Page builder to use String instead of Message

---
 README.md                                     | 97 +++++++++----------
 .../com/github/ygimenez/method/Pages.java     |  4 +-
 .../java/com/github/ygimenez/model/Page.java  | 12 +--
 3 files changed, 54 insertions(+), 59 deletions(-)

diff --git a/README.md b/README.md
index 9bc0045..6f2a9e0 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,23 @@
-[build]: https://github.com/ygimenez/PaginationUtils/tree/master
+[mvncentral]: https://mvnrepository.com/artifact/com.github.ygimenez/Pagination-Utils
 
-[jitpack]: https://jitpack.io/#ygimenez/PaginationUtils
+[jitpack]: https://jitpack.io/#ygimenez/Pagination-Utils
 
-[mvncentral]: https://mvnrepository.com/artifact/com.github.ygimenez/Pagination-Utils
+[build]: https://github.com/ygimenez/Pagination-Utils/tree/master
 
-[license]: https://github.com/ygimenez/PaginationUtils/blob/master/LICENSE
+[license]: https://github.com/ygimenez/Pagination-Utils/blob/master/LICENSE
 
-[issue]: https://github.com/ygimenez/PaginationUtils/issues
+[issue]: https://github.com/ygimenez/Pagination-Utils/issues
 
-[build-shield]: https://img.shields.io/github/workflow/status/ygimenez/PaginationUtils/Java%20CI?label=Build
+[mvncentral-shield]: https://img.shields.io/maven-central/v/com.github.ygimenez/Pagination-Utils?label=Maven%20Central
 
 [jitpack-shield]: https://img.shields.io/badge/Download-Jitpack-success
 
-[mvncentral-shield]: https://img.shields.io/maven-central/v/com.github.ygimenez/Pagination-Utils?label=Maven%20Central
+[build-shield]: https://img.shields.io/github/workflow/status/ygimenez/Pagination-Utils/Java%20CI?label=Build
 
-[license-shield]: https://img.shields.io/github/license/ygimenez/PaginationUtils?color=lightgrey&label=License
+[license-shield]: https://img.shields.io/github/license/ygimenez/Pagination-Utils?color=lightgrey&label=License
+
+[issue-shield]: https://img.shields.io/github/issues/ygimenez/Pagination-Utils?label=Issues
 
-[issue-shield]: https://img.shields.io/github/issues/ygimenez/PaginationUtils?label=Issues
 [ ![mvncentral-shield][] ][mvncentral]
 [ ![jitpack-shield][] ][jitpack]
 [ ![build-shield][] ][build]
@@ -31,35 +32,34 @@ With this library you will be using pages, categories and buttons in your bot in
 
 ## What is a page/category/button?
 
-![Pagination Example](https://i.imgur.com/5Cain0U.gif)
-
-![Categorization Example](https://i.imgur.com/AEusZQ1.gif)
+![Pagination Example](https://i.imgur.com/k5zA0ix.gif)
 
-![Buttonization Example](https://i.imgur.com/4PBVoTn.gif)
+![Categorization Example](https://i.imgur.com/9xhs4Gf.gif)
 
-Have you been using a bot and came across one of those three GIFs and thought: "That must've been hard to make." or "I'd
+Have you been using a bot and came across one of those GIFs and thought: "That must've been hard to make." or "I'd
 like one of those in my bot!"? Fear no more, Pagination Utils to the rescue!
 
 ## How do I paginate?
 
-Before we start the fun stuff, there're a few things we need to check:
+Before we start the fun stuff, there are a few things we need to check:
 
 - You're using Java JDK 9 or above.
 - Your bot has the following permissions:
-	- MESSAGE_ADD_REACTION
-	- MESSAGE_EXT_EMOJI
-	- MESSAGE_READ/WRITE
-	- VIEW_CHANNEL
+  - MESSAGE_READ/WRITE
+  - VIEW_CHANNEL 
+  - If using reactions:
+    - MESSAGE_ADD_REACTION
+    - MESSAGE_EXT_EMOJI
 - If using `JDABuilder.createLight()`, you added the following gateway intents:
-	- GUILD_MESSAGES
-	- GUILD_MESSAGE_REACTIONS
+  - GUILD_MESSAGES
+  - GUILD_MESSAGE_REACTIONS
 
-Now we can finally start, which is easier than it seems! The first step is to set a JDA client object as the event
+Now we can finally start, which is easier than it seems! The first step is to set a JDA/SharmManager client object as the event
 holder, which can be done in a single line:
 
 ```java
 JDA bot = ... // Creation of bot client
-		
+
 Pages.activate(PaginatorBuilder.createSimplePaginator(bot));
 ```
 
@@ -68,13 +68,13 @@ But if you want some customization of the library's behaviour, you can opt to us
 ```java
 JDA bot = ... // Creation of bot client
 
-Paginator paginator = PaginatorBuilder.createPaginator()
-		// Defines which handler will be used
-		.setHandler(bot)
-		// Whether reactions will be removed on click
-		.shouldRemoveOnReaction(false)
+Paginator paginator = PaginatorBuilder.createPaginator(bot)
+        // Whether reactions will be removed on click
+        .shouldRemoveOnReaction(false)
 		// Prevents double-click on buttons and guarantee an event will only happen when previous processing has finished
 		.shouldEventLock(true)
+        // Whether to delete the message when the event ends (such as pressing CANCEL or timeout)
+        .shouldDeleteOnCancel(true)
 		// Finish configuration and activate the library
 		.activate();
 ```
@@ -84,17 +84,17 @@ If you want to go even further and change the default buttons' emotes, don't wor
 ```java
 JDA bot = ... // Creation of bot client
 
-Paginator paginator = PaginatorBuilder.createPaginator()
-		// Defines which handler will be used
-		.setHandler(bot)
+Paginator paginator = PaginatorBuilder.createPaginator(bot)
 		// Whether reactions will be removed on click
 		.shouldRemoveOnReaction(false)
 		// Prevents double-click on buttons and guarantee an event will only happen when previous processing has finished
 		.shouldEventLock(true)
+        // Whether to delete the message when the event ends (such as pressing CANCEL or timeout)
+        .shouldDeleteOnCancel(true)
 		// Changes the next button to πŸ˜™
-		.setEmote(Emote.NEXT, Emoji.fromMarkdown("πŸ˜™"))
+		.setEmote(Emote.NEXT, Emoji.fromFormatted("πŸ˜™"))
 		// Changes the previous button to 😩
-		.setEmote(Emote.PREVIOUS, Emoji.fromMarkdown("😩"))
+		.setEmote(Emote.PREVIOUS, Emoji.fromFormatted("😩"))
 		// Finish configuration and activate the library
 		.activate();
 ```
@@ -111,24 +111,21 @@ mb.setContent("Hello World!");
 Page messagePage = new Page(mb.build());
 
 // Example using EmbedBuilder
-EmbedBuilder eb = new EmbedBuilder();
-eb.setTitle("Example Embed");
-eb.setDescription("Hello World!");
+EmbedBuilder eb = new EmbedBuilder()
+        .setTitle("Example Embed")
+        .setDescription("Hello World");
 
 Page embedPage = new InteractPage(eb.build());
 ```
 
-That said, you might want to create an `ArrayList` of pages to use the pagination, since a single page does not need to be paginated at all:
+That said, you might want to create a `List` of pages to use the pagination, since a single page does not need to be paginated at all:
 
 ```java
-ArrayList<Page> pages = new ArrayList<>();
-MessageBuilder mb = new MessageBuilder();
+List<Page> pages = new ArrayList<>();
 
 // Adding 10 pages to the list
 for (int i = 0; i < 10; i++) {
-	mb.clear();
-	mb.setContent("This is entry NΒΊ " + i);
-	pages.add(new InteractPage(mb.build()));
+	pages.add(new InteractPage("This is entry NΒΊ " + (i + 1)));
 }
 ```
 
@@ -144,6 +141,8 @@ exampleChannel.sendMessage((Message) pages.get(0).getContent()).queue(success ->
 });
 ```
 
+
+
 That's everything you have to do, the library will automatically add the navigation buttons to the target message, which
 will change its content based on the list's order.
 
@@ -153,25 +152,24 @@ To categorize it's almost the same process as paginating, however, the type of c
 of `ArrayList`:
 
 ```java
-HashMap<Emoji, Page> categories = new HashMap<>();
+Map<Emoji, Page> categories = new HashMap<>();
 MessageBuilder mb = new MessageBuilder();
 
 // Manually adding 3 categories to the map, you could use some kind of loop to fill it (see https://emojipedia.org/ for unicodes)
 mb.setContent("This is category 1");
-categories.put(Emoji.fromMarkdown("\u26f3"), new InteractPage(mb.build()));
+categories.put(Emoji.fromFormatted("\u26f3"), new InteractPage(mb.build()));
 
 mb.setContent("This is category 2");
-categories.put(Emoji.fromMarkdown("\u26bd"), new InteractPage(mb.build()));
+categories.put(Emoji.fromFormatted("\u26bd"), new InteractPage(mb.build()));
 
 mb.setContent("This is category 3");
-categories.put(Emoji.fromMarkdown("\u270f"), new InteractPage(mb.build()));
+categories.put(Emoji.fromFormatted("\u270f"), new InteractPage(mb.build()));
 ```
 
 Then just call `Pages.categorize()` method just like you did before:
 
 ```java
 exampleChannel.sendMessage("This is a menu message").queue(success -> {
-	// Third argument is whether you want to use reactions (false) or interaction buttons (true).
 	Pages.categorize(success, categories, /* Use buttons? */ true);
 });
 ```
@@ -189,10 +187,7 @@ ThrowingConsumer<ButtonWrapper> customFunction = (wrapper) -> {
 };
 
 exampleChannel.sendMessage("This is a sample message").queue(success -> {
-	// Same arguments, except the second that must extend map collection
-	// Third argument is whether you want to use reactions (false) or interaction buttons (true).
-	// The last argument defines whether to show cancel button or not
-	Pages.buttonize(success, Collections.singletonMap(Emoji.fromMarkdown("βœ…"), customFunction), /* Use buttons? */ true, /* Show cancel? */false);
+	Pages.buttonize(success, Collections.singletonMap(Emoji.fromFormatted("βœ…"), customFunction), /* Use buttons? */ true, /* Show cancel? */ true);
 });
 ```
 
diff --git a/src/main/java/com/github/ygimenez/method/Pages.java b/src/main/java/com/github/ygimenez/method/Pages.java
index 4eaa193..bdbe3a6 100644
--- a/src/main/java/com/github/ygimenez/method/Pages.java
+++ b/src/main/java/com/github/ygimenez/method/Pages.java
@@ -1695,8 +1695,8 @@ public static void finalizeEvent(Message msg, Consumer<Void> callback) {
 	public static void modifyButtons(Message msg, Page p, BaseHelper<?, ?> helper, Map<String, Function<Button, Button>> changes) {
 		MessageEditAction act = msg.editMessageComponents();
 
-		if (p.getContent() instanceof Message) {
-			act = act.setContent(((Message) p.getContent()).getContentRaw());
+		if (p.getContent() instanceof String) {
+			act = act.setContent((String) p.getContent());
 		} else if (p.getContent() instanceof MessageEmbed) {
 			act = act.setEmbeds((MessageEmbed) p.getContent());
 		}
diff --git a/src/main/java/com/github/ygimenez/model/Page.java b/src/main/java/com/github/ygimenez/model/Page.java
index ca986ae..a51f866 100644
--- a/src/main/java/com/github/ygimenez/model/Page.java
+++ b/src/main/java/com/github/ygimenez/model/Page.java
@@ -5,21 +5,21 @@
 import org.jetbrains.annotations.NotNull;
 
 /**
- * Class representing either a {@link Message} or {@link MessageEmbed} object.
+ * Class representing either a {@link String} or {@link MessageEmbed} object.
  */
 public class Page {
 	private final Object content;
 
 	/**
-	 * A {@link Page} object to be used in this library's methods. Currently, only {@link Message}
+	 * A {@link Page} object to be used in this library's methods. Currently, only {@link String}
 	 * and {@link MessageEmbed} are supported.
 	 * 
-	 * @param content The {@link Message}/{@link MessageEmbed} object to be used as pages.
-	 * @throws IllegalArgumentException Thrown if argument is not a {@link Message} nor {@link MessageEmbed}.
+	 * @param content The {@link String}/{@link MessageEmbed} object to be used as pages.
+	 * @throws IllegalArgumentException Thrown if argument is not a {@link String} nor {@link MessageEmbed}.
 	 */
 	public Page(@NotNull Object content) throws IllegalArgumentException {
-		if (!(content instanceof Message) && !(content instanceof MessageEmbed)) {
-			throw new IllegalArgumentException("Page content must be either a Message or a MessageEmbed");
+		if (!(content instanceof String) && !(content instanceof MessageEmbed)) {
+			throw new IllegalArgumentException("Page content must be either a String or a MessageEmbed");
 		}
 
 		this.content = content;

From 661f5d30b3dfc71c5323515fccb38eff7721d755 Mon Sep 17 00:00:00 2001
From: Ygimenez <yagogimenez1@hotmail.com>
Date: Tue, 7 Mar 2023 11:01:42 -0300
Subject: [PATCH 31/31] Updated README

---
 README.md | 120 +++++++++++++++++++++++++++++-------------------------
 1 file changed, 64 insertions(+), 56 deletions(-)

diff --git a/README.md b/README.md
index 6f2a9e0..19f202a 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ Before we start the fun stuff, there are a few things we need to check:
 - You're using Java JDK 9 or above.
 - Your bot has the following permissions:
   - MESSAGE_READ/WRITE
-  - VIEW_CHANNEL 
+  - VIEW_CHANNEL
   - If using reactions:
     - MESSAGE_ADD_REACTION
     - MESSAGE_EXT_EMOJI
@@ -60,7 +60,7 @@ holder, which can be done in a single line:
 ```java
 JDA bot = ... // Creation of bot client
 
-Pages.activate(PaginatorBuilder.createSimplePaginator(bot));
+        Pages.activate(PaginatorBuilder.createSimplePaginator(bot));
 ```
 
 But if you want some customization of the library's behaviour, you can opt to use the full builder:
@@ -68,15 +68,15 @@ But if you want some customization of the library's behaviour, you can opt to us
 ```java
 JDA bot = ... // Creation of bot client
 
-Paginator paginator = PaginatorBuilder.createPaginator(bot)
+        Paginator paginator = PaginatorBuilder.createPaginator(bot)
         // Whether reactions will be removed on click
         .shouldRemoveOnReaction(false)
-		// Prevents double-click on buttons and guarantee an event will only happen when previous processing has finished
-		.shouldEventLock(true)
+        // Prevents double-click on buttons and guarantee an event will only happen when previous processing has finished
+        .shouldEventLock(true)
         // Whether to delete the message when the event ends (such as pressing CANCEL or timeout)
         .shouldDeleteOnCancel(true)
-		// Finish configuration and activate the library
-		.activate();
+        // Finish configuration and activate the library
+        .activate();
 ```
 
 If you want to go even further and change the default buttons' emotes, don't worry, we got you covered:
@@ -84,19 +84,19 @@ If you want to go even further and change the default buttons' emotes, don't wor
 ```java
 JDA bot = ... // Creation of bot client
 
-Paginator paginator = PaginatorBuilder.createPaginator(bot)
-		// Whether reactions will be removed on click
-		.shouldRemoveOnReaction(false)
-		// Prevents double-click on buttons and guarantee an event will only happen when previous processing has finished
-		.shouldEventLock(true)
+        Paginator paginator = PaginatorBuilder.createPaginator(bot)
+        // Whether reactions will be removed on click
+        .shouldRemoveOnReaction(false)
+        // Prevents double-click on buttons and guarantee an event will only happen when previous processing has finished
+        .shouldEventLock(true)
         // Whether to delete the message when the event ends (such as pressing CANCEL or timeout)
         .shouldDeleteOnCancel(true)
-		// Changes the next button to πŸ˜™
-		.setEmote(Emote.NEXT, Emoji.fromFormatted("πŸ˜™"))
-		// Changes the previous button to 😩
-		.setEmote(Emote.PREVIOUS, Emoji.fromFormatted("😩"))
-		// Finish configuration and activate the library
-		.activate();
+        // Changes the next button to πŸ˜™
+        .setEmote(Emote.NEXT, Emoji.fromFormatted("πŸ˜™"))
+        // Changes the previous button to 😩
+        .setEmote(Emote.PREVIOUS, Emoji.fromFormatted("😩"))
+        // Finish configuration and activate the library
+        .activate();
 ```
 
 Then all you need to do is create a `Page` (or `InteractPage` for interaction buttons) collection containing the type of the content and the `Message`/`MessageEmbed` object that you just created.
@@ -106,16 +106,16 @@ Example:
 ```java
 // Example using MessageBuilder
 MessageBuilder mb = new MessageBuilder();
-mb.setContent("Hello World!");
+        mb.setContent("Hello World!");
 
-Page messagePage = new Page(mb.build());
+        Page messagePage = new Page(mb.build());
 
 // Example using EmbedBuilder
-EmbedBuilder eb = new EmbedBuilder()
+        EmbedBuilder eb = new EmbedBuilder()
         .setTitle("Example Embed")
         .setDescription("Hello World");
 
-Page embedPage = new InteractPage(eb.build());
+        Page embedPage = new InteractPage(eb.build());
 ```
 
 That said, you might want to create a `List` of pages to use the pagination, since a single page does not need to be paginated at all:
@@ -124,24 +124,23 @@ That said, you might want to create a `List` of pages to use the pagination, sin
 List<Page> pages = new ArrayList<>();
 
 // Adding 10 pages to the list
-for (int i = 0; i < 10; i++) {
-	pages.add(new InteractPage("This is entry NΒΊ " + (i + 1)));
-}
+        for (int i = 0; i < 10; i++) {
+        pages.add(new InteractPage("This is entry NΒΊ " + (i + 1)));
+        }
 ```
 
 Then all you have to do is call `Pages.paginate()` method:
 
 ```java
-// This method requires 3 arguments:
-// The target message
-// The list of pages
-// Whether you want to use reactions (false) or interaction buttons (true).
 exampleChannel.sendMessage((Message) pages.get(0).getContent()).queue(success -> {
 	Pages.paginate(success, pages, /* Use buttons? */ true);
 });
 ```
 
-
+<figure class="image">
+  <img src="https://i.imgur.com/Ms6ECNY.png" alt="Result">
+  <figcaption><i style="color: gray">Wait, that's it?</i></figcaption>
+</figure>
 
 That's everything you have to do, the library will automatically add the navigation buttons to the target message, which
 will change its content based on the list's order.
@@ -153,82 +152,91 @@ of `ArrayList`:
 
 ```java
 Map<Emoji, Page> categories = new HashMap<>();
-MessageBuilder mb = new MessageBuilder();
 
 // Manually adding 3 categories to the map, you could use some kind of loop to fill it (see https://emojipedia.org/ for unicodes)
 mb.setContent("This is category 1");
-categories.put(Emoji.fromFormatted("\u26f3"), new InteractPage(mb.build()));
+categories.put(Emoji.fromFormatted("\u26f3"), new InteractPage("This is category 1"));
 
 mb.setContent("This is category 2");
-categories.put(Emoji.fromFormatted("\u26bd"), new InteractPage(mb.build()));
+categories.put(Emoji.fromFormatted("\u26bd"), new InteractPage("This is category 2"));
 
 mb.setContent("This is category 3");
-categories.put(Emoji.fromFormatted("\u270f"), new InteractPage(mb.build()));
+categories.put(Emoji.fromFormatted("\u270f"), new InteractPage("This is category 3"));
 ```
 
 Then just call `Pages.categorize()` method just like you did before:
 
 ```java
-exampleChannel.sendMessage("This is a menu message").queue(success -> {
+exampleChannel.sendMessage("This is the main menu").queue(success -> {
 	Pages.categorize(success, categories, /* Use buttons? */ true);
 });
 ```
 
+<figure class="image">
+  <img src="https://i.imgur.com/MeqRUPp.png" alt="Result">
+  <figcaption><i style="color: gray">Of course you could be more elaborate.</i></figcaption>
+</figure>
+
 ## How do I buttonize?
 
 To do it, you first need to setup a few things:
 
 ```java
 // A Consumer is a callback function that uses one arguments and returns nothing
-// Here, the member is the one that pressed the button, and message is the buttonized message itself
+// Here, wrapper is a class containing useful data related to the click event
 ThrowingConsumer<ButtonWrapper> customFunction = (wrapper) -> {
 	// Example of giving a role to anyone who presses this button
 	guild.addRoleToMember(wrapper.getMember(), guild.getRoleById("123456789")).queue();
 };
 
-exampleChannel.sendMessage("This is a sample message").queue(success -> {
-	Pages.buttonize(success, Collections.singletonMap(Emoji.fromFormatted("βœ…"), customFunction), /* Use buttons? */ true, /* Show cancel? */ true);
+exampleChannel.sendMessage("Click to get role").queue(success -> {
+	Pages.buttonize(success, Collections.singletonMap(Emoji.fromFormatted("βœ…"), customFunction), /* Use buttons? */ true, /* Show cancel? */ false);
 });
 ```
 
+<figure class="image">
+  <img src="https://i.imgur.com/fDF6MdO.png" alt="Result">
+  <figcaption><i style="color: gray">Useful for self-assigned roles.</i></figcaption>
+</figure>
+
 ## I have low memory, what about me?
 
-Yet again, don't worry, Pagination-Utils to the rescue!
+Yet again, don't worry, Pagination Utils to the rescue!
 
 ```java
 // Could be anything, this is just an example.
 List<String> data = new ArrayList<>();
-// Adding 10 values to the list
-for (int i = 0; i < 10; i++) {
-	data.add("This is entry NΒΊ " + i);
+// Adding 10 values pages to the list
+for (int i = 0; i < 2; i++) {
+	data.add("This is page number " + (i + 1));
 }
 
-MessageBuilder mb = new MessageBuilder();
 ThrowingFunction<Integer, Page> func = i -> {
-	mb.setContent("This is entry NΒΊ " + i);
-	return new InteractPage(mb.build());
+	return new InteractPage(data.get(i));
 };
 ```
 
 Then just call `Pages.lazyPaginate()` method:
 
 ```java
-// Second argument must be a function that takes an integer and returns a Page.
-// Third argument is whether you want to use reactions (false) or interaction buttons (true).
-// The last argument defines whether pages should be cached or not (will keep previously visited pages in memory).
-exampleChannel.sendMessage((Message) pages.get(0).getContent()).queue(success -> {
+// You can disable page caching, which will prevent the library from saving previously visited pages
+exampleChannel.sendMessage((String) pages.get(0).getContent()).queue(success -> {
 	Pages.lazyPaginate(success, func, /* Use buttons? */ true, /* Cache? */ false);
 });
 ```
 
+<figure class="image">
+  <img src="https://i.imgur.com/Ms6ECNY.png" alt="Result">
+  <figcaption><i style="color: gray">Same image because...well...both are paginators</i></figcaption>
+</figure>
+
 ## Is it really that easy?
 
-Yes, you can focus on creating epic menus, ranking, lists, whatever and leave the boring part for the library to do its
-job, isn't that awesome?
+Yes, you can focus on creating epic menus, ranking, lists, games, *et cetera* and leave the boring part for the library to do its job, isn't that awesome?
 
 ## How do I get it?
 
-This library is available for manual installation and through Jitpack:
+This library is available for manual installation and through Maven Central:
 
 ### To install manually
 
@@ -255,9 +263,9 @@ Maven:
 ```xml
 
 <dependency>
-    <groupId>com.github.ygimenez</groupId>
-    <artifactId>Pagination-Utils</artifactId>
-    <version>VERSION</version>
+  <groupId>com.github.ygimenez</groupId>
+  <artifactId>Pagination-Utils</artifactId>
+  <version>VERSION</version>
 </dependency>
 ```
 
@@ -266,4 +274,4 @@ Maven:
 
 ## Feedback
 
-If you have any issues using this library, feel free to create a new issue and I'll review it as soon as possible!
+If you have any issues using this library, feel free to create a new issue and I'll review it as soon as possible!
\ No newline at end of file