Merge pull request from Fuzzlemann/master

PR for 3.6.0 (Fuzzlemann) (6)
This commit is contained in:
Rsl1122 2017-07-30 14:20:54 +03:00 committed by GitHub
commit f9af3eee03
23 changed files with 242 additions and 129 deletions

@ -32,6 +32,7 @@ import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.cache.AnalysisCacheHandler;
import main.java.com.djrapitops.plan.data.cache.DataCacheHandler;
import main.java.com.djrapitops.plan.data.cache.InspectCacheHandler;
import main.java.com.djrapitops.plan.data.cache.PageCacheHandler;
import main.java.com.djrapitops.plan.data.listeners.*;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.databases.MySQLDB;
@ -223,25 +224,32 @@ public class Plan extends BukkitPlugin<Plan> {
*/
@Override
public void onDisable() {
//Clears the page cache
PageCacheHandler.clearCache();
// Stop the UI Server
if (uiServer != null) {
uiServer.stop();
}
getServer().getScheduler().cancelTasks(this);
if (Verify.notNull(handler, db)) {
Benchmark.start("Disable: DataCache Save");
// Saves the DataCache to the database without Bukkit's Schedulers.
Log.info(Phrase.CACHE_SAVE + "");
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Log.info(Phrase.CACHE_SAVE.toString());
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.execute(() -> {
handler.saveCacheOnDisable();
taskStatus().cancelAllKnownTasks();
Benchmark.stop("Disable: DataCache Save");
});
scheduler.shutdown(); // Schedules the save to shutdown after it has ran the execute method.
scheduler.shutdown(); // Schedules the save to shutdown after it has ran the execute method.
}
Log.info(Phrase.DISABLED + "");
Log.info(Phrase.DISABLED.toString());
}
private void registerListeners() {

@ -176,12 +176,7 @@ public class DataCacheHandler extends SessionCache {
UserData uData = dataCache.get(uuid);
if (uData == null) {
if (cache) {
DBCallableProcessor cacher = new DBCallableProcessor() {
@Override
public void process(UserData data) {
cache(data);
}
};
DBCallableProcessor cacher = this::cache;
getTask.scheduleForGet(uuid, cacher, processor);
} else {
getTask.scheduleForGet(uuid, processor);

@ -4,6 +4,7 @@ import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.ui.webserver.response.InspectPageResponse;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.ExportUtility;
@ -48,6 +49,7 @@ public class InspectCacheHandler {
public void process(UserData data) {
cache.put(uuid, new UserData(data));
cacheTimes.put(uuid, MiscUtils.getTime());
PageCacheHandler.cachePage("inspectPage: " + uuid.toString(), () -> new InspectPageResponse(Plan.getInstance().getUiServer().getDataReqHandler(), uuid));
try {
ExportUtility.writeInspectHtml(data, ExportUtility.getPlayersFolder(ExportUtility.getFolder()));
} catch (IOException ex) {

@ -0,0 +1,75 @@
package main.java.com.djrapitops.plan.data.cache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import main.java.com.djrapitops.plan.ui.webserver.response.Response;
/**
* This class contains the page cache.
* <p>
* It caches all Responses with their matching identifiers.
* This reduces CPU cycles and the time to wait for loading the pages.
* This is especially useful in situations where multiple clients are accessing the server.
* <p>
* This cache uses the Google Guava {@link Cache}.
*
* @author Fuzzlemann
*/
public class PageCacheHandler {
/**
* Constructor used to hide the public constructor
*/
private PageCacheHandler() {
throw new IllegalStateException("Utility class");
}
private static final Cache<String, Response> pageCache = CacheBuilder.newBuilder()
.build();
/**
* Loads the page from the page cache.
* <p>
* If the {@link Response} isn't cached, {@link PageLoader#createResponse()} in the {@code loader}
* is called to create the Response.
* <p>
* If the Response is created, it's automatically cached.
*
* @param identifier The identifier of the page
* @param loader The {@link PageLoader} (How should it load the page if it's not cached)
* @return The Response that was cached or created by the {@link PageLoader loader}
*/
public static Response loadPage(String identifier, PageLoader loader) {
Response response = pageCache.asMap().get(identifier);
if (response != null) {
return response;
}
response = loader.createResponse();
pageCache.put(identifier, response);
return response;
}
/**
* Puts the page into the page cache.
* <p>
* If the cache already inherits that {@code identifier}, it's renewed.
*
* @param identifier The identifier of the page
* @param loader The {@link PageLoader} (How it should load the page)
*/
public static void cachePage(String identifier, PageLoader loader) {
Response response = loader.createResponse();
pageCache.put(identifier, response);
}
/**
* Clears the cache from all its contents.
*/
public static void clearCache() {
pageCache.asMap().clear();
}
}

@ -0,0 +1,14 @@
package main.java.com.djrapitops.plan.data.cache;
import main.java.com.djrapitops.plan.ui.webserver.response.Response;
/**
* This interface is used for providing the method to load the page.
*
* @author Fuzzlemann
*/
public interface PageLoader {
Response createResponse();
}

@ -1,7 +1,6 @@
package main.java.com.djrapitops.plan.data.cache.queue;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor;
import main.java.com.djrapitops.plan.data.cache.DataCacheHandler;
import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo;
@ -89,12 +88,9 @@ class ProcessConsumer extends Consumer<HandlingInfo> {
return;
}
Log.debug(info.getUuid() + ": Processing type: " + info.getType().name());
DBCallableProcessor p = new DBCallableProcessor() {
@Override
public void process(UserData data) {
if (!info.process(data)) {
Log.error("Attempted to process data for wrong uuid: W:" + data.getUuid() + " | R:" + info.getUuid() + " Type:" + info.getType().name());
}
DBCallableProcessor p = data -> {
if (!info.process(data)) {
Log.error("Attempted to process data for wrong uuid: W:" + data.getUuid() + " | R:" + info.getUuid() + " Type:" + info.getType().name());
}
};
handler.getUserDataForProcessing(p, info.getUuid());

@ -14,19 +14,16 @@ import java.util.UUID;
public class ChatInfo extends HandlingInfo {
private final String nickname;
private final String message;
/**
* Constructor.
*
* @param uuid UUID of the player.
* @param nickname Nickname of the player.
* @param message Message the player sent.
*/
public ChatInfo(UUID uuid, String nickname, String message) {
public ChatInfo(UUID uuid, String nickname) {
super(uuid, InfoType.CHAT, 0L);
this.nickname = nickname;
this.message = message;
}
@Override

@ -37,7 +37,8 @@ public class PlanChatListener implements Listener {
if (event.isCancelled()) {
return;
}
Player p = event.getPlayer();
handler.addToPool(new ChatInfo(p.getUniqueId(), p.getDisplayName(), event.getMessage()));
handler.addToPool(new ChatInfo(p.getUniqueId(), p.getDisplayName()));
}
}

@ -93,14 +93,14 @@ public class CommandUseTable extends Table {
Map<String, Integer> updateData = new HashMap<>(data);
updateData.keySet().removeAll(newData.keySet());
for (String cmd : saved.keySet()) {
for (Map.Entry<String, Integer> entrySet : saved.entrySet()) {
String cmd = entrySet.getKey();
// IMPORTANT - not using saved as value
Integer toSave = updateData.get(cmd);
if (toSave == null || toSave > saved.get(cmd)) {
continue;
if (toSave != null && toSave <= entrySet.getValue()) {
updateData.remove(cmd);
}
updateData.remove(cmd);
}
updateCommands(updateData);

@ -199,6 +199,7 @@ public class NicknamesTable extends Table {
lastNicks.put(id, nickname);
}
}
for (Map.Entry<Integer, String> entry : lastNicks.entrySet()) {
Integer id = entry.getKey();
String lastNick = entry.getValue();
@ -208,8 +209,7 @@ public class NicknamesTable extends Table {
// Moves the last known nickname to the end of the List.
// This is due to the way nicknames are added to UserData,
// Nicknames are stored as a Set and last Nickname is a separate String.
list.remove(lastNick);
list.add(lastNick);
list.set(list.size() - 1, lastNick);
}
return nicks;

@ -72,8 +72,7 @@ public class DataRequestHandler {
}
return HtmlUtils.replacePlaceholders(
HtmlUtils.getStringFromResource("analysis.html"),
PlaceholderUtils.getAnalysisReplaceRules(analysisCache.getData())
);
PlaceholderUtils.getAnalysisReplaceRules(analysisCache.getData()));
} catch (FileNotFoundException ex) {
return "<h1>404 analysis.html was not found</h1>";
}

@ -118,7 +118,7 @@ public class PunchCardGraphCreator {
}
}
double size = array.length * array[0].length;
int size = array.length * array[0].length;
double sum = sum(valueMinusAvg);
return Math.sqrt(sum / size);
}

@ -5,15 +5,11 @@
*/
package main.java.com.djrapitops.plan.ui.html.graphs;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.utilities.analysis.DouglasPeuckerAlgorithm;
import main.java.com.djrapitops.plan.utilities.analysis.Point;
import main.java.com.djrapitops.plan.utilities.comparators.PointComparator;
import main.java.com.djrapitops.plan.utilities.analysis.ReduceGapTriangles;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Abstract scatter graph creator used by other graph creators.
@ -42,26 +38,7 @@ public class ScatterGraphCreator {
}
if (reduceGapTriangles) {
Point lastPoint = null;
Set<Point> toAdd = new HashSet<>();
for (Point point : points) {
if (Verify.notNull(point, lastPoint)) {
long date = (long) point.getX();
long lastDate = (long) lastPoint.getX();
double y = point.getY();
double lastY = lastPoint.getY();
if (Double.compare(y, lastY) != 0 && Math.abs(lastY - y) > 0.5) {
if (lastDate < date - TimeAmount.MINUTE.ms() * 10L) {
toAdd.add(new Point(lastDate + 1, lastY));
toAdd.add(new Point(date - 1, lastY));
}
}
}
lastPoint = point;
}
points.addAll(toAdd);
points.sort(new PointComparator());
points = ReduceGapTriangles.reduce(points);
}
int size = points.size();

@ -5,15 +5,11 @@
*/
package main.java.com.djrapitops.plan.ui.html.graphs;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.utilities.analysis.DouglasPeuckerAlgorithm;
import main.java.com.djrapitops.plan.utilities.analysis.Point;
import main.java.com.djrapitops.plan.utilities.comparators.PointComparator;
import main.java.com.djrapitops.plan.utilities.analysis.ReduceGapTriangles;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Abstract scatter graph creator used by other graph creators.
@ -42,26 +38,7 @@ public class SeriesCreator {
}
if (reduceGapTriangles) {
Point lastPoint = null;
Set<Point> toAdd = new HashSet<>();
for (Point point : points) {
if (Verify.notNull(point, lastPoint)) {
long date = (long) point.getX();
long lastDate = (long) lastPoint.getX();
double y = point.getY();
double lastY = lastPoint.getY();
if (Double.compare(y, lastY) != 0 && Math.abs(lastY - y) > 0.5) {
if (lastDate < date - TimeAmount.MINUTE.ms() * 10L) {
toAdd.add(new Point(lastDate + 1, lastY));
toAdd.add(new Point(date - 1, lastY));
}
}
}
lastPoint = point;
}
points.addAll(toAdd);
points.sort(new PointComparator());
points = ReduceGapTriangles.reduce(points);
}
int size = points.size();
@ -74,6 +51,7 @@ public class SeriesCreator {
arrayBuilder.append(",");
}
}
arrayBuilder.append("]");
return arrayBuilder.toString();
}

@ -22,13 +22,14 @@ public class TPSGraphCreator {
}
public static String buildSeriesDataString(List<TPS> tpsData) {
long now = MiscUtils.getTime();
List<Point> points = tpsData.stream()
.map(tps -> new Point(tps.getDate(), tps.getTps()))
.collect(Collectors.toList());
return ScatterGraphCreator.scatterGraph(points, true);
}public static String buildScatterDataStringTPS(List<TPS> tpsData, long scale) {
}
public static String buildScatterDataStringTPS(List<TPS> tpsData, long scale) {
long now = MiscUtils.getTime();
List<Point> points = tpsData.stream()
.filter(tps -> tps.getDate() >= now - scale)

@ -7,6 +7,7 @@ import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.data.cache.PageCacheHandler;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.ui.html.DataRequestHandler;
import main.java.com.djrapitops.plan.ui.webserver.response.*;
@ -224,11 +225,11 @@ public class WebServer {
private Response getResponse(String target, WebUser user) {
if ("/favicon.ico".equals(target)) {
return new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico");
return PageCacheHandler.loadPage("Redirect: favicon", () -> new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico"));
}
if (usingHttps) {
if (user == null) {
return new PromptAuthorizationResponse();
return PageCacheHandler.loadPage("promptAuthorization", PromptAuthorizationResponse::new);
}
int permLevel = user.getPermLevel(); // Lower number has higher clearance.
@ -245,7 +246,7 @@ public class WebServer {
String page = args[1];
switch (page) {
case "players":
return new PlayersPageResponse(plugin);
return PageCacheHandler.loadPage("players", () -> new PlayersPageResponse(plugin));
case "player":
return playerResponse(args);
case "server":
@ -255,15 +256,17 @@ public class WebServer {
}
}
private ForbiddenResponse forbiddenResponse(int permLevel, int required) {
ForbiddenResponse response403 = new ForbiddenResponse();
String content = "<h1>403 Forbidden - Access Denied</h1>"
+ "<p>Unauthorized User.<br>"
+ "Make sure your user has the correct access level.<br>"
+ "This page requires permission level of " + String.valueOf(required) + ",<br>"
+ "This user has permission level of " + String.valueOf(permLevel) + "</p>";
response403.setContent(content);
return response403;
private Response forbiddenResponse(int permLevel, int required) {
return PageCacheHandler.loadPage("forbidden", () -> {
ForbiddenResponse response403 = new ForbiddenResponse();
String content = "<h1>403 Forbidden - Access Denied</h1>"
+ "<p>Unauthorized User.<br>"
+ "Make sure your user has the correct access level.<br>"
+ "This page requires permission level of " + String.valueOf(required) + ",<br>"
+ "This user has permission level of " + String.valueOf(permLevel) + "</p>";
response403.setContent(content);
return response403;
});
}
private Response rootPageResponse(WebUser user) {
@ -274,7 +277,7 @@ public class WebServer {
case 0:
return serverResponse();
case 1:
return new PlayersPageResponse(plugin);
return PageCacheHandler.loadPage("players", () -> new PlayersPageResponse(plugin));
case 2:
return playerResponse(new String[]{"", "", user.getName()});
default:
@ -284,34 +287,45 @@ public class WebServer {
private Response serverResponse() {
if (!dataReqHandler.checkIfAnalysisIsCached()) {
return new NotFoundResponse("Analysis Data was not cached.<br>Use /plan analyze to cache the Data.");
String error = "Analysis Data was not cached.<br>Use /plan analyze to cache the Data.";
PageCacheHandler.loadPage("notFound: " + error, () -> new NotFoundResponse(error));
}
return new AnalysisPageResponse(dataReqHandler);
return PageCacheHandler.loadPage("analysisPage", () -> new AnalysisPageResponse(dataReqHandler));
}
private Response playerResponse(String[] args) {
if (args.length < 3) {
return new NotFoundResponse();
return PageCacheHandler.loadPage("notFound", NotFoundResponse::new);
}
String playerName = args[2].trim();
UUID uuid = UUIDUtility.getUUIDOf(playerName);
if (uuid == null) {
return new NotFoundResponse("Player has no UUID");
String error = "Player has no UUID";
return PageCacheHandler.loadPage("notFound: " + error, () -> new NotFoundResponse(error));
}
if (!dataReqHandler.checkIfCached(uuid)) {
return new NotFoundResponse("Player's data was not cached.<br>Use /plan inspect " + playerName + " to cache the Data.");
String error = "Player's data was not cached.<br>Use /plan inspect " + playerName + " to cache the Data.";
return PageCacheHandler.loadPage("notFound: " + error, () -> new NotFoundResponse(error));
}
return new InspectPageResponse(dataReqHandler, uuid);
return PageCacheHandler.loadPage("inspectPage: " + uuid.toString(), () -> new InspectPageResponse(dataReqHandler, uuid));
}
private Response notFoundResponse() {
NotFoundResponse response404 = new NotFoundResponse();
String content = "<h1>404 Not Found</h1>"
String error = "<h1>404 Not Found</h1>"
+ "<p>Make sure you're accessing a link given by a command, Examples:</p>"
+ "<p>" + getProtocol() + HtmlUtils.getInspectUrl("<player>") + " or<br>"
+ getProtocol() + HtmlUtils.getServerAnalysisUrl() + "</p>";
response404.setContent(content);
return response404;
return PageCacheHandler.loadPage("notFound: " + error, () -> {
Response response404 = new NotFoundResponse();
response404.setContent(error);
return response404;
});
}
/**
@ -357,13 +371,11 @@ public class WebServer {
if (t.length < 3) {
return 1;
}
final String wantedUser = t[2].toLowerCase().trim();
final String theUser = user.trim().toLowerCase();
if (wantedUser.equals(theUser)) {
return 2;
} else {
return 1;
}
return wantedUser.equals(theUser) ? 2 : 1;
default:
return 0;
}

@ -36,10 +36,6 @@ public abstract class Response {
}
public int getCode() {
if (header == null) {
return 500;
} else {
return Integer.parseInt(header.split(" ")[1]);
}
return header == null ? 500 : Integer.parseInt(header.split(" ")[1]);
}
}

@ -14,8 +14,11 @@ import main.java.com.djrapitops.plan.data.analysis.*;
import main.java.com.djrapitops.plan.data.cache.AnalysisCacheHandler;
import main.java.com.djrapitops.plan.data.cache.DataCacheHandler;
import main.java.com.djrapitops.plan.data.cache.InspectCacheHandler;
import main.java.com.djrapitops.plan.data.cache.PageCacheHandler;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.ui.html.tables.PlayersTableCreator;
import main.java.com.djrapitops.plan.ui.webserver.response.AnalysisPageResponse;
import main.java.com.djrapitops.plan.ui.webserver.response.PlayersPageResponse;
import main.java.com.djrapitops.plan.utilities.Benchmark;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
@ -47,7 +50,7 @@ public class Analysis {
* Analyzes the data of all offline players on the server.
* <p>
* First retrieves all offline players and checks those that are in the
* database. Then Runs a new Analysis Task Asynchronously. Saves AnalysisData
* database. Then runs a new Analysis Task asynchronously. Saves AnalysisData
* to the provided Cache. Saves all UserData to InspectCache for 15 minutes.
*
* @param analysisCache Cache that the data is saved to.
@ -56,6 +59,7 @@ public class Analysis {
if (isAnalysisBeingRun()) {
return;
}
plugin.processStatus().startExecution("Analysis");
log(Phrase.ANALYSIS_START.toString());
// Async task for Analysis
@ -79,8 +83,9 @@ public class Analysis {
* @return Whether or not analysis was successful.
*/
public boolean analyze(AnalysisCacheHandler analysisCache, Database db) {
log(Phrase.ANALYSIS_FETCH_DATA + "");
log(Phrase.ANALYSIS_FETCH_DATA.toString());
Benchmark.start("Analysis: Fetch Phase");
plugin.processStatus().setStatus("Analysis", "Analysis Fetch Phase");
try {
inspectCache.cacheAllUserData(db);
@ -88,18 +93,22 @@ public class Analysis {
Log.toLog(this.getClass().getName(), ex);
Log.error(Phrase.ERROR_ANALYSIS_FETCH_FAIL.toString());
}
List<UserData> rawData = inspectCache.getCachedUserData();
if (rawData.isEmpty()) {
Log.info(Phrase.ANALYSIS_FAIL_NO_DATA.toString());
return false;
}
List<TPS> tpsData = new ArrayList<>();
try {
tpsData = db.getTpsTable().getTPSData();
Log.debug("TPS Data Size: " + tpsData.size());
} catch (Exception ex) {
Log.toLog(this.getClass().getName(), ex);
}
return analyzeData(rawData, tpsData, analysisCache);
}
@ -150,7 +159,10 @@ public class Analysis {
if (Settings.ANALYSIS_LOG_FINISHED.isTrue()) {
Log.info(Phrase.ANALYSIS_COMPLETE.parse(String.valueOf(time), HtmlUtils.getServerAnalysisUrlWithProtocol()));
}
ExportUtility.export(plugin, analysisData, rawData);
PageCacheHandler.cachePage("analysisPage", () -> new AnalysisPageResponse(plugin.getUiServer().getDataReqHandler()));
PageCacheHandler.cachePage("players", () -> new PlayersPageResponse(plugin));
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
plugin.processStatus().setStatus("Analysis", "Error: " + e);

@ -24,9 +24,11 @@ public class DouglasPeuckerAlgorithm {
if (points.isEmpty()) {
return points;
}
if (Double.compare(epsilon, -1) == 0) {
epsilon = 0.002;
}
int size = points.size();
final int lastIndex = size - 1;
final Point start = points.get(0);

@ -186,11 +186,6 @@ public class MathUtils {
* @return The rounded number
*/
public static double round(double number) {
String formattedNumber = decimalFormat.format(number);
if (formattedNumber.length() > 4) {
formattedNumber = formattedNumber.substring(0, 3); //Fix for unknown reasons for not-rounding
}
return Double.valueOf(formattedNumber);
return Double.valueOf(decimalFormat.format(number));
}
}

@ -0,0 +1,53 @@
package main.java.com.djrapitops.plan.utilities.analysis;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.utilities.comparators.PointComparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Created by Fuzzlemann on 30.07.2017.
*/
public class ReduceGapTriangles {
/**
* Constructor used to hide the public constructor
*/
private ReduceGapTriangles() {
throw new IllegalStateException("Utility class");
}
public static List<Point> reduce(List<Point> points) {
Point lastPoint = null;
Set<Point> toAdd = new HashSet<>();
for (Point point : points) {
if (!Verify.notNull(point, lastPoint)) {
lastPoint = point;
continue;
}
long date = (long) point.getX();
long lastDate = (long) lastPoint.getX();
double y = point.getY();
double lastY = lastPoint.getY();
if (Double.compare(y, lastY) != 0
&& Math.abs(lastY - y) > 0.5
&& lastDate < date - TimeAmount.MINUTE.ms() * 10L) {
toAdd.add(new Point(lastDate + 1, lastY));
toAdd.add(new Point(date - 1, lastY));
}
lastPoint = point;
}
points.addAll(toAdd);
points.sort(new PointComparator());
return points;
}
}

@ -1152,13 +1152,13 @@
var dm = Math.floor(seconds / 60);
seconds -= (dm * 60);
seconds = Math.floor(seconds);
if (dd != 0) {
if (dd !== 0) {
out += dd.toString() + "d ";
}
if (dh != 0) {
if (dh !== 0) {
out += dh.toString() + "h ";
}
if (dm != 0) {
if (dm !== 0) {
out += dm.toString() + "m ";
}
out += seconds.toString() + "s ";

@ -32,7 +32,7 @@ public class ChatInfoTest {
public void testProcessNick() {
UserData data = MockUtils.mockUser();
String expected = "TestNicknameChatInfo";
ChatInfo i = new ChatInfo(data.getUuid(), expected, "im 18 male");
ChatInfo i = new ChatInfo(data.getUuid(), expected);
assertTrue("Didn't succeed", i.process(data));
assertTrue("Didn't add nickname", data.getNicknames().contains(expected));
}
@ -44,7 +44,7 @@ public class ChatInfoTest {
public void testProcessWrongUUID() {
UserData data = MockUtils.mockUser();
String expected = "TestNicknameChatInfo";
ChatInfo i = new ChatInfo(null, expected, "im 18 male");
ChatInfo i = new ChatInfo(null, expected);
assertTrue("Succeeded.", !i.process(data));
}
}