commit fc01f7fb432dacf58cee27c083a0413f5a34e558 Author: zaCade Date: Sat Mar 2 15:09:12 2019 +0100 notifier diff --git a/EventNotifier/EventNotfierDiscordBot/nbactions.xml b/EventNotifier/EventNotfierDiscordBot/nbactions.xml new file mode 100644 index 00000000..17e38b9d --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/nbactions.xml @@ -0,0 +1,49 @@ + + + + run + + jar + + + process-classes + org.codehaus.mojo:exec-maven-plugin:1.2.1:exec + + + -classpath %classpath FunctionLayer.Bottest + java + E:\java8\Projects\EventNotfierDiscordBot + + + + debug + + jar + + + process-classes + org.codehaus.mojo:exec-maven-plugin:1.2.1:exec + + + -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath FunctionLayer.Bottest + java + true + E:\java8\Projects\EventNotfierDiscordBot + + + + profile + + jar + + + process-classes + org.codehaus.mojo:exec-maven-plugin:1.2.1:exec + + + -classpath %classpath FunctionLayer.Bottest + java + E:\java8\Projects\EventNotfierDiscordBot + + + diff --git a/EventNotifier/EventNotfierDiscordBot/pom.xml b/EventNotifier/EventNotfierDiscordBot/pom.xml new file mode 100644 index 00000000..b2e1f15a --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + com.mycompany + EventNotfierDiscordBot + 1.0 + jar + + + org.javacord + javacord + 3.0.1 + pom + + + org.apache.commons + commons-dbcp2 + 2.5.0 + jar + + + mysql + mysql-connector-java + 8.0.13 + + + com.google.guava + guava + 26.0-jre + jar + + + + + UTF-8 + 1.8 + 1.8 + FunctionLayer.Bottest + + + + + maven-dependency-plugin + + + install + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + maven-jar-plugin + + + + true + lib/ + ${mainClass} + + + + + + + \ No newline at end of file diff --git a/EventNotifier/EventNotfierDiscordBot/src/main/java/DataLayer/DBCPDataSource.java b/EventNotifier/EventNotfierDiscordBot/src/main/java/DataLayer/DBCPDataSource.java new file mode 100644 index 00000000..04e26ee4 --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/src/main/java/DataLayer/DBCPDataSource.java @@ -0,0 +1,43 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package DataLayer; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.commons.dbcp2.BasicDataSource; + +/** + * + * @author install1 + */ +public class DBCPDataSource { + private static BasicDataSource ds = new BasicDataSource(); + static { + try { + ds.setDriver(new com.mysql.cj.jdbc.Driver()); + ds.setUrl("jdbc:mysql://151.80.230.149:3306/eventscss?useLegacyDatetimeCode=false&serverTimezone=UTC"); + //ds.setUrl("jdbc:mysql://localhost:3306/eventcss?useLegacyDatetimeCode=false&serverTimezone=UTC"); + ds.setUsername("eventscss"); + ds.setPassword("sdbhb2h34b2hbhbdfwbfwhber234"); + ds.setMaxTotal(-1); + ds.setMinIdle(5); + ds.setMaxIdle(-1); + ds.setMaxOpenPreparedStatements(100); + } catch (SQLException ex) { + Logger.getLogger(DBCPDataSource.class.getName()).log(Level.SEVERE, null, ex); + } + } + + public static Connection getConnection() throws SQLException { + return ds.getConnection(); + } + + private DBCPDataSource() { + } + +} diff --git a/EventNotifier/EventNotfierDiscordBot/src/main/java/DataLayer/DataMapper.java b/EventNotifier/EventNotfierDiscordBot/src/main/java/DataLayer/DataMapper.java new file mode 100644 index 00000000..b3ad9b45 --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/src/main/java/DataLayer/DataMapper.java @@ -0,0 +1,183 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package DataLayer; + +import FunctionLayer.CustomError; +import FunctionLayer.StringObject; +import com.google.common.base.Stopwatch; +import com.google.common.collect.MapMaker; +import java.beans.PropertyVetoException; +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author install1 + */ +public class DataMapper { + + public static final long EXPIRE_TIME_IN_SECONDS = TimeUnit.SECONDS.convert(15, TimeUnit.MINUTES); + public static DataMapper instance = new DataMapper(); + private volatile boolean called; + private final ConcurrentMap soEventContentCache; + private final Stopwatch stopwatch; + + public DataMapper() { + this.stopwatch = Stopwatch.createStarted(); + this.soEventContentCache = new MapMaker().concurrencyLevel(2).makeMap(); + } + + public List getAllMapValues() { + List MapColoumns = new ArrayList(soEventContentCache.values()); + return MapColoumns; + } + + private Map getCache() throws SQLException, IOException, CustomError { + List stro; + stro = GetEventContentFromDBTable(); + LinkedHashMap LHM = new LinkedHashMap(); + for (int i = 0; i < stro.size(); i++) { + LHM.put(i, stro.get(i)); + } + return LHM; + } + + public synchronized void initialization() throws SQLException, IOException, CustomError { + if (called == false) { + soEventContentCache.putAll(getCache()); + for (int i = 0; i < soEventContentCache.size(); i++) { + soEventContentCache.get(i).setEventContent(modifyEventContent(soEventContentCache.get(i).getEventContent(), i)); + } + called = true; + } + } + + public void checkUpdateTime() { + new Thread(() -> { + if (stopwatch.elapsed(TimeUnit.SECONDS) >= EXPIRE_TIME_IN_SECONDS) { + try { + soEventContentCache.clear(); + called = false; + initialization(); + stopwatch.reset(); + } catch (SQLException | IOException | CustomError ex) { + Logger.getLogger(DataMapper.class.getName()).log(Level.SEVERE, null, ex); + } + } + }).start(); + } + + public static String modifyEventContent(String str, int i) { + StringBuilder sb = new StringBuilder(); + switch (i) { + case 0: { + sb.append(str); + break; + } + case 1: { + str = str.trim(); + sb.append(str); + sb.insert(0, "Rewards: "); + break; + } + case 2: { + sb.append(str); + sb.insert(0, "Leaders: "); + break; + } + case 3: { + sb.append(str); + sb.insert(0, "Date: "); + break; + } + case 4: { + sb.append(str); + sb.insert(0, "Hour: "); + sb.append("GMT +1"); + break; + } + default: { + sb.append(str); + sb.insert(0, "Map: "); + break; + } + } + return sb.toString(); + } + + public static List GetEventContentFromDBTable() throws CustomError { + /* + 0 = title + 1 = rewards + 2 = leaders + 3 = datum + 4 = hours + 5 = maps + */ + List str = new ArrayList(); + Connection l_cCon = null; + PreparedStatement l_pStatement = null; + ResultSet l_rsSearch = null; + try { + l_cCon = DBCPDataSource.getConnection(); + String l_sSQL = "SELECT * FROM `EventContent`"; + l_pStatement = l_cCon.prepareStatement(l_sSQL); + l_rsSearch = l_pStatement.executeQuery(); + l_rsSearch.next(); + for (int i = 1; i < 6; i++) { + StringObject so = new StringObject(l_rsSearch.getString(i)); + str.add(so); + } + l_sSQL = "SELECT * FROM `Maps`"; + l_pStatement = l_cCon.prepareStatement(l_sSQL); + l_rsSearch = l_pStatement.executeQuery(); + while (l_rsSearch.next()) { + StringObject so = new StringObject(l_rsSearch.getString(1)); + str.add(so); + } + } catch (SQLException ex) { + throw new CustomError("failed in DataMapper " + ex.getMessage()); + } finally { + CloseConnections(l_pStatement, l_rsSearch, l_cCon); + } + return str; + } + + public static void CloseConnections(PreparedStatement ps, ResultSet rs, Connection con) { + if (rs != null) { + try { + rs.close(); + } catch (SQLException ex) { + Logger.getLogger(DataMapper.class.getName()).log(Level.SEVERE, null, ex); + } + } + if (ps != null) { + try { + ps.close(); + } catch (SQLException ex) { + Logger.getLogger(DataMapper.class.getName()).log(Level.SEVERE, null, ex); + } + } + if (con != null) { + try { + con.close(); + } catch (SQLException ex) { + Logger.getLogger(DataMapper.class.getName()).log(Level.SEVERE, null, ex); + } + } + } +} diff --git a/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/Bottest.java b/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/Bottest.java new file mode 100644 index 00000000..d920baf0 --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/Bottest.java @@ -0,0 +1,57 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package FunctionLayer; +//https://github.com/Javacord/Javacord +//https://discordapp.com/developers/applications/ +//https://docs.javacord.org/api/v/3.0.1/org/javacord/api/DiscordApi.html +//https://stackoverflow.com/questions/17654213/how-do-i-create-a-netbeans-style-jar-with-all-dependencies-in-a-lib-folder +//ps ax | grep EventNotfierDiscordBot-1.0 +//kill $pid (number) +/* +screen -d -m -S nonRoot java -jar /home/sourcemodextensionstest/EventNotfierDiscordBot/EventNotfierDiscordBot-1.0.jar +screen -ls (number1) +screen -X -S (number1) quit + */ + +import DataLayer.DataMapper; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.javacord.api.DiscordApi; +import org.javacord.api.DiscordApiBuilder; +import org.javacord.api.event.message.MessageCreateEvent; + +/** + * + * @author install1 + */ +public class Bottest { + + public static void main(String[] args) { + // Insert your bot's token here + String token = "NTI5MDIyODgwOTU3MDcxMzk5.Dwqy6w.sgbRejEzZOLdTqyqzDmktSTBDpM"; + DiscordApi api = new DiscordApiBuilder().setToken(token).login().join(); + api.addMessageCreateListener((MessageCreateEvent event) -> { + DataMapper.instance.checkUpdateTime(); + if (event.getMessageContent().equalsIgnoreCase("!event")) { + try { + event.getChannel().sendMessage("Event Information: "); + DataMapper.instance.initialization(); + List EventContent = DataMapper.instance.getAllMapValues(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < EventContent.size(); i++) { + sb.append(EventContent.get(i).getEventContent()).append("\n"); + } + event.getChannel().sendMessage(sb.toString()); + } catch (SQLException | IOException | CustomError ex) { + Logger.getLogger(Bottest.class.getName()).log(Level.SEVERE, null, ex); + } + } + }); + } +} diff --git a/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/CustomError.java b/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/CustomError.java new file mode 100644 index 00000000..db596a4f --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/CustomError.java @@ -0,0 +1,18 @@ +package FunctionLayer; + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/** + * + * @author install1 + */ +public class CustomError extends Exception { + + public CustomError(String msg) { + super(msg); + } +} diff --git a/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/StringObject.java b/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/StringObject.java new file mode 100644 index 00000000..50ef4a9b --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/src/main/java/FunctionLayer/StringObject.java @@ -0,0 +1,26 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package FunctionLayer; + +/** + * + * @author install1 + */ +public class StringObject { + String EventContent; + + public String getEventContent() { + return EventContent; + } + + public void setEventContent(String EventContent) { + this.EventContent = EventContent; + } + + public StringObject(String EventContent) { + this.EventContent = EventContent; + } +} diff --git a/EventNotifier/EventNotfierDiscordBot/target/EventNotfierDiscordBot-1.0.jar b/EventNotifier/EventNotfierDiscordBot/target/EventNotfierDiscordBot-1.0.jar new file mode 100644 index 00000000..3c0eaba4 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/EventNotfierDiscordBot-1.0.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/classes/.netbeans_automatic_build b/EventNotifier/EventNotfierDiscordBot/target/classes/.netbeans_automatic_build new file mode 100644 index 00000000..e69de29b diff --git a/EventNotifier/EventNotfierDiscordBot/target/classes/DataLayer/DBCPDataSource.class b/EventNotifier/EventNotfierDiscordBot/target/classes/DataLayer/DBCPDataSource.class new file mode 100644 index 00000000..047e3a5e Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/classes/DataLayer/DBCPDataSource.class differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/classes/DataLayer/DataMapper.class b/EventNotifier/EventNotfierDiscordBot/target/classes/DataLayer/DataMapper.class new file mode 100644 index 00000000..f30a13d0 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/classes/DataLayer/DataMapper.class differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/Bottest.class b/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/Bottest.class new file mode 100644 index 00000000..8421be35 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/Bottest.class differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/CustomError.class b/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/CustomError.class new file mode 100644 index 00000000..72d3f282 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/CustomError.class differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/StringObject.class b/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/StringObject.class new file mode 100644 index 00000000..1be9ad80 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/classes/FunctionLayer/StringObject.class differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/animal-sniffer-annotations-1.14.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/animal-sniffer-annotations-1.14.jar new file mode 100644 index 00000000..fb76acf7 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/animal-sniffer-annotations-1.14.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/checker-qual-2.5.2.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/checker-qual-2.5.2.jar new file mode 100644 index 00000000..ae4e7f1f Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/checker-qual-2.5.2.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/commons-dbcp2-2.5.0.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/commons-dbcp2-2.5.0.jar new file mode 100644 index 00000000..bfe23c8a Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/commons-dbcp2-2.5.0.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/commons-logging-1.2.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/commons-logging-1.2.jar new file mode 100644 index 00000000..93a3b9f6 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/commons-logging-1.2.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/commons-pool2-2.6.0.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/commons-pool2-2.6.0.jar new file mode 100644 index 00000000..8273c7bb Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/commons-pool2-2.6.0.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/error_prone_annotations-2.1.3.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/error_prone_annotations-2.1.3.jar new file mode 100644 index 00000000..ec3b1856 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/error_prone_annotations-2.1.3.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/guava-26.0-jre.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/guava-26.0-jre.jar new file mode 100644 index 00000000..cd71a92f Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/guava-26.0-jre.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/j2objc-annotations-1.1.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/j2objc-annotations-1.1.jar new file mode 100644 index 00000000..4b6f1274 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/j2objc-annotations-1.1.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-annotations-2.9.0.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-annotations-2.9.0.jar new file mode 100644 index 00000000..c602d75d Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-annotations-2.9.0.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-core-2.9.3.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-core-2.9.3.jar new file mode 100644 index 00000000..40a04ceb Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-core-2.9.3.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-databind-2.9.3.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-databind-2.9.3.jar new file mode 100644 index 00000000..4cfc7787 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/jackson-databind-2.9.3.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-3.0.1.pom b/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-3.0.1.pom new file mode 100644 index 00000000..ca16115b --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-3.0.1.pom @@ -0,0 +1,68 @@ + + + 4.0.0 + org.javacord + javacord + 3.0.1 + pom + Javacord + An easy to use multithreaded library for creating Discord bots in Java + https://www.javacord.org + 2015 + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + A business-friendly OSS license + + + + + BtoBastian + Bastian Oppermann + bastianoppermann1997@gmail.com + https://github.com/BtoBastian + Europe/Berlin + + + + + Björn Kautler + Bjoern@Kautler.net + https://github.com/Vampire + Europe/Berlin + + + + scm:git:https://github.com/Javacord/Javacord.git + scm:git:git@github.com:Javacord/Javacord.git + https://github.com/Javacord/Javacord + + + GitHub + https://github.com/Javacord/Javacord/issues + + + TeamCity + https://ci.javacord.org/project.html?projectId=Javacord&guest=1 + + + https://github.com/Javacord/Javacord/releases + + + + org.javacord + javacord-api + 3.0.1 + compile + + + org.javacord + javacord-core + 3.0.1 + runtime + + + diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-api-3.0.1.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-api-3.0.1.jar new file mode 100644 index 00000000..f23ce619 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-api-3.0.1.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-core-3.0.1.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-core-3.0.1.jar new file mode 100644 index 00000000..b7caf1b8 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/javacord-core-3.0.1.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/jsr305-3.0.2.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/jsr305-3.0.2.jar new file mode 100644 index 00000000..59222d9c Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/jsr305-3.0.2.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/log4j-api-2.11.0.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/log4j-api-2.11.0.jar new file mode 100644 index 00000000..ac408c6f Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/log4j-api-2.11.0.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/logging-interceptor-3.9.1.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/logging-interceptor-3.9.1.jar new file mode 100644 index 00000000..04b4874c Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/logging-interceptor-3.9.1.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/mysql-connector-java-8.0.13.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/mysql-connector-java-8.0.13.jar new file mode 100644 index 00000000..a4efaf50 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/mysql-connector-java-8.0.13.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/nv-websocket-client-1.31.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/nv-websocket-client-1.31.jar new file mode 100644 index 00000000..27c31ebe Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/nv-websocket-client-1.31.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/okhttp-3.9.1.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/okhttp-3.9.1.jar new file mode 100644 index 00000000..7166f02c Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/okhttp-3.9.1.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/okio-1.13.0.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/okio-1.13.0.jar new file mode 100644 index 00000000..02c302f8 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/okio-1.13.0.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/lib/protobuf-java-3.6.1.jar b/EventNotifier/EventNotfierDiscordBot/target/lib/protobuf-java-3.6.1.jar new file mode 100644 index 00000000..8a187891 Binary files /dev/null and b/EventNotifier/EventNotfierDiscordBot/target/lib/protobuf-java-3.6.1.jar differ diff --git a/EventNotifier/EventNotfierDiscordBot/target/maven-archiver/pom.properties b/EventNotifier/EventNotfierDiscordBot/target/maven-archiver/pom.properties new file mode 100644 index 00000000..d9fb4fd3 --- /dev/null +++ b/EventNotifier/EventNotfierDiscordBot/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Fri Jan 04 22:18:34 CET 2019 +version=1.0 +groupId=com.mycompany +artifactId=EventNotfierDiscordBot diff --git a/EventNotifier/EventNotfierDiscordBot/target/test-classes/.netbeans_automatic_build b/EventNotifier/EventNotfierDiscordBot/target/test-classes/.netbeans_automatic_build new file mode 100644 index 00000000..e69de29b diff --git a/EventNotifier/Eventnotifier_v2/Eventnotifier_v2.vcxproj b/EventNotifier/Eventnotifier_v2/Eventnotifier_v2.vcxproj new file mode 100644 index 00000000..26534f42 --- /dev/null +++ b/EventNotifier/Eventnotifier_v2/Eventnotifier_v2.vcxproj @@ -0,0 +1,97 @@ + + + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + x86 + + + Release + x86 + + + Debug + x64 + + + Release + x64 + + + + {3ecf1ab2-fbd0-43c8-beb9-11ff8bb66aa2} + Linux + Eventnotifier_v2 + 15.0 + Linux + 1.0 + Generic + {D51BCBC9-82E9-4017-911E-C93873C4EA2B} + + + + true + + + false + + + true + + + false + + + true + /home/sourcemodextensionstest + + + false + + + false + + + true + + + + + + + + /home/sourcemodextensionstest/EventNotifier/boost_1_69_0;/home/sourcemodextensionstest/EventNotifier/includes/mysql;/home/sourcemodextensionstest/EventNotifier/includes/jdbc;/home/sourcemodextensionstest/EventNotifier/curl-7.62.0/include;$(IncludePath) + /home/sourcemodextensionstest/EventNotifier/boost_1_69_0/libs;/home/sourcemodextensionstest/EventNotifier/curl-7.62.0/lib;$(LibraryPath) + + + + + + + + + /home/sourcemodextensionstest/EventNotifier/boost_1_69_0;/home/sourcemodextensionstest/EventNotifier/includes/jdbc;/home/sourcemodextensionstest/EventNotifier/includes/mysql;/home/sourcemodextensionstest/EventNotifier/curl-7.62.0/include;%(AdditionalIncludeDirectories) + + + -lmysqlcppconn;-lcurl;$(StlAdditionalDependencies);%(Link.AdditionalDependencies) + + + + + \ No newline at end of file diff --git a/EventNotifier/Eventnotifier_v2/Eventnotifier_v2.vcxproj.user b/EventNotifier/Eventnotifier_v2/Eventnotifier_v2.vcxproj.user new file mode 100644 index 00000000..2a807d83 --- /dev/null +++ b/EventNotifier/Eventnotifier_v2/Eventnotifier_v2.vcxproj.user @@ -0,0 +1,6 @@ + + + + -1386263875;104.248.40.216 (username=, port=22, authentication=Password) + + \ No newline at end of file diff --git a/EventNotifier/Eventnotifier_v2/main.cpp b/EventNotifier/Eventnotifier_v2/main.cpp new file mode 100644 index 00000000..7a95c1fd --- /dev/null +++ b/EventNotifier/Eventnotifier_v2/main.cpp @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mysql_connection.h" +#include "mysql_driver.h" +#include +/* +g++ -v -x c -E - + -lmysqlcppconn +https://stackoverflow.com/questions/34057798/how-does-one-set-up-the-visual-studio-code-compiler-debugger-to-gcc +https://docs.microsoft.com/en-us/cpp/linux/deploy-run-and-debug-your-linux-project?view=vs-2017 +*/ + +using namespace std; +string data; +string mapnames[10]; +string EventContent[5]; +string pattern[10]; +int SelectMysqlEventCount(sql::Connection *con) +{ + sql::Statement *stmt; + sql::ResultSet *res; + int EventCount = 0; + try { + stmt = con->createStatement(); + res = stmt->executeQuery("SELECT * FROM `EventCount`"); + if (res->next()) { + cout << res->getInt(1) << endl; + EventCount = res->getInt(1); + } + } + catch (sql::SQLException &e) { + cout << "# ERR: SQLException in " << __FILE__; + cout << "# ERR: " << e.what(); + cout << " (MySQL error code: " << e.getErrorCode(); + cout << ", SQLState: " << e.getSQLState() << " )" << endl; + } + delete stmt; + delete res; + //cout << endl; + return EventCount; +} + +size_t writeCallback(char* buf, size_t size, size_t nmemb, void* up) +{ + for (std::size_t c = 0; c < size*nmemb; c++) + { + data.push_back(buf[c]); + } + return size * nmemb; //tell curl how many bytes we handled +} + + +string printreturn(std::string::size_type urlstringend, std::string const &s) +{ + string strreturn(""); + if (urlstringend == std::string::npos) { + strreturn = "not found sdbhabd2342d"; + } + else + { + strreturn = s.substr(0, urlstringend); + } + return strreturn; +} + +void removeSubstrs(string& s, string& p) { + string::size_type n = p.length(); + for (string::size_type i = s.find(p); + i != string::npos; + i = s.find(p)) + s.erase(i, n); +} + +void ReadForumSubSectionEvent() +{ + int index; + CURL* curl; + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, "https://unloze.com/forums/events.76/"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //tell curl to output its progress + curl_easy_perform(curl); + //check by taking the first from the top of the page, thats always the newest in order + //the needed context is always close, instead of taking the full size we only take the needed portion distance + std::string::size_type urlstringend; + urlstringend = data.find("preview\">Event #"); + std::string sdeli = ("data-previewUrl=\""); + string strf = printreturn(urlstringend, data); + size_t pos = 0; + if ((pos = strf.find(sdeli)) != std::string::npos) { + strf.erase(0, pos + sdeli.length()); + } + data.clear(); + strf.insert(0, "https://unloze.com/"); + //https://unloze.com/threads/event-54n74-15-b4ck.1324 is returned here for example + std::cout << "strf.c_str(): " << strf.c_str() << "\n"; + curl_easy_setopt(curl, CURLOPT_URL, strf.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback); + curl_easy_perform(curl); + curl_easy_cleanup(curl); + curl_global_cleanup(); + //assumes only ze event threads contain "CS:S Zombie Escape" + //mapnames collects maps specified to event + urlstringend = data.find("CS:S Zombie Escape"); + strf = printreturn(urlstringend, data); + if (strf.find("not found sdbhabd2342d") == std::string::npos) + { + urlstringend = data.find("Prize :"); + strf = printreturn(urlstringend, data); + sdeli = (""); + strf = printreturn(urlstringend, data); + sdeli = (""); + pos = 0; + if ((pos = strf.find(sdeli)) != std::string::npos) + { + strf.erase(0, pos + sdeli.length()); + EventContent[0] = strf; + } + //EventContent 1 = rewards + urlstringend = data.find("<div class=\"messageTextEndMarker\"> </div>"); + strf = printreturn(urlstringend, data); + sdeli = ("Prize :"); + pos = 0; + index = 0; + if ((pos = strf.find(sdeli)) != std::string::npos) + { + strf.erase(0, pos + sdeli.length()); + size_t index1 = 0; + pattern[0] = "</span>"; + pattern[1] = "<br/>"; + pattern[2] = "<b>"; + pattern[3] = "</b>"; + string teststr = strf; + while (!!pattern[index].size()) + { + removeSubstrs(teststr, pattern[index]); + index++; + } + //std::cout << "teststr: " << "\n" << teststr << "\n"; + strf = teststr; + EventContent[1] = strf; + } + //EventContent 2 = leader + urlstringend = data.find("Prize :"); + strf = printreturn(urlstringend, data); + sdeli = ("Leader :</span>"); + pos = 0; + if ((pos = strf.find(sdeli)) != std::string::npos) + { + strf.erase(0, pos + sdeli.length()); + //std::cout << "reached eventcontent2 strf: " << strf << "\n"; + EventContent[2] = strf.substr(0, strf.find("<")); + } + //EventContent 3 = date + urlstringend = data.find("\">Time :"); + strf = printreturn(urlstringend, data); + sdeli = ("Date :</span>"); + pos = 0; + if ((pos = strf.find(sdeli)) != std::string::npos) + { + strf.erase(0, pos + sdeli.length()); + EventContent[3] = strf.substr(0, strf.find("<")); + } + //EventContent[4] = hours + urlstringend = data.find("Leader :"); + strf = printreturn(urlstringend, data); + sdeli = ("Time :</span>"); + pos = 0; + if ((pos = strf.find(sdeli)) != std::string::npos) + { + strf.erase(0, pos + sdeli.length()); + strf = strf.substr(0, strf.find("pm GMT+1")); + } + sdeli = ("//"); + pos = 0; + if ((pos = strf.find(sdeli)) != std::string::npos) + { + strf.erase(0, pos + sdeli.length()); + EventContent[4] = strf; + } + } + else + { + std::cout << "Not found" << "\n" << "data value: " << data << "\n"; + } + +} + +void MYSQLUpdateEventMaps(sql::Connection *con) +{ + sql::Statement *stmt; + try { + stmt = con->createStatement(); + stmt->executeUpdate("delete from Maps"); + int index; + while (!!mapnames[index].size()) + { + stmt->executeUpdate("INSERT INTO `Maps` (`MapNames`) VALUES (\"" + mapnames[index] + "\")"); + index++; + } + } + catch (sql::SQLException &e) { + cout << "# ERR: SQLException in " << __FILE__; + cout << "# ERR: " << e.what(); + cout << " (MySQL error code: " << e.getErrorCode(); + cout << ", SQLState: " << e.getSQLState() << " )" << endl; + } + delete stmt; +} + +void MYSQLUpdateEventContent(sql::Connection *con) +{ + sql::Statement *stmt; + try { + stmt = con->createStatement(); + stmt->executeUpdate("UPDATE `EventContent` SET `title`=\"" + EventContent[0] +"\",`Rewards`=\"" + EventContent[1] + + "\",`Leaders`=\"" + EventContent[2] + "\",`datum`=\"" + EventContent[3] + "\",`hours`=\"" + EventContent[4] + "\""); + }catch (sql::SQLException &e) { + cout << "# ERR: SQLException in " << __FILE__; + cout << "# ERR: " << e.what(); + cout << " (MySQL error code: " << e.getErrorCode(); + cout << ", SQLState: " << e.getSQLState() << " )" << endl; + } + delete stmt; +} + +bool CloseDBConnection(sql::Connection *con) +{ + try + { + con->close(); + delete con; + return true; + } + catch (sql::SQLException &e) + { + return false; + } +} + +int main() +{ + sql::mysql::MySQL_Driver *driver; + sql::Connection *con; + driver = sql::mysql::get_driver_instance(); + con = driver->connect("tcp://151.80.230.149:3306", "eventscss", "sdbhb2h34b2hbhbdfwbfwhber234"); + con->setSchema("eventscss"); + try { + //Eventcount = SelectMysqlEventCount(con); + ReadForumSubSectionEvent(); + MYSQLUpdateEventMaps(con); + MYSQLUpdateEventContent(con); + CloseDBConnection(con); + } + catch (sql::SQLException &e) { + cout << "# ERR: SQLException in " << __FILE__; + cout << "# ERR: " << e.what(); + cout << " (MySQL error code: " << e.getErrorCode(); + cout << ", SQLState: " << e.getSQLState() << " )" << endl; + } + cout << "EventContent[0]: " << EventContent[0] << endl; + cout << "EventContent[1]: " << EventContent[1] << endl; + cout << "EventContent[2]: " << EventContent[2] << endl; + cout << "EventContent[3]: " << EventContent[3] << endl; + cout << "EventContent[4]: " << EventContent[4] << endl; + return 0; +} diff --git a/EventNotifier/scripting/unloze_eventScheduler_redux_css.sp b/EventNotifier/scripting/unloze_eventScheduler_redux_css.sp new file mode 100644 index 00000000..fcaaa942 --- /dev/null +++ b/EventNotifier/scripting/unloze_eventScheduler_redux_css.sp @@ -0,0 +1,296 @@ +#pragma semicolon 1 +#define DEBUG +#define PLUGIN_AUTHOR "jenz" +#define PLUGIN_VERSION "1.00" +#define g_dIndex 65 +#define g_dLength 256 +#include <sourcemod> +#include <sdktools> +#include <system2> +#pragma newdecls required +//64 maps in one event cuz ofc +char g_cEventMaps[g_dIndex][g_dLength]; +char g_cEventContent[g_dLength][g_dLength]; +int g_iIndexCounter; +Database g_dDatabase; +public Plugin myinfo = +{ + name = "schedule announcer", + author = PLUGIN_AUTHOR, + description = "informs players when next event takes place", + version = PLUGIN_VERSION, + url = "www.unloze.com" +}; +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnPluginStart() +{ + RegConsoleCmd("sm_event", Cmd_EventNotifier); + RegConsoleCmd("sm_events", Cmd_EventNotifier); +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Action Cmd_EventNotifier(int client, any args) +{ + EventNotifierMenu(client); + return Plugin_Handled; +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnMapStart() +{ + SQL_StartConnection(); + SQL_CreateDBIFNotExist(); + EventInfo(); +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +static void EventNotifierMenu(int client) +{ + Menu EventMenu = new Menu(MenuHandler1); + char l_cEventTimeleft[g_dLength][1]; + EventMenu.SetTitle("UNLOZE Event Information"); + CalculateTimeToNextEvent(g_cEventContent[3], g_cEventContent[4], l_cEventTimeleft[0], sizeof(l_cEventTimeleft)); + // 0 event title + EventMenu.AddItem("", g_cEventContent[0], ITEMDRAW_DISABLED); + for (int i = 0; i < g_iIndexCounter; i++) + { + if (StrContains(g_cEventMaps[i], "Map:", false) == -1) + { + Format(g_cEventMaps[i], sizeof(g_cEventMaps), "Map: %s", g_cEventMaps[i]); + } + EventMenu.AddItem("", g_cEventMaps[i], ITEMDRAW_DISABLED); + } + // 1 rewards + if (StrContains(g_cEventContent[1], "Rewards:", false) == -1) + { + TrimString(g_cEventContent[1]); + Format(g_cEventContent[1], sizeof(g_cEventContent), "Rewards: %s", g_cEventContent[1]); + } + EventMenu.AddItem("", g_cEventContent[1], ITEMDRAW_DISABLED); + // 2 leaders + if (StrContains(g_cEventContent[2], "Leaders:", false) == -1) + { + Format(g_cEventContent[2], sizeof(g_cEventContent), "Leaders: %s", g_cEventContent[2]); + } + EventMenu.AddItem("", g_cEventContent[2], ITEMDRAW_DISABLED); + // 3 timeleft + if (StrContains(l_cEventTimeleft[0], "Timeleft:", false) == -1) + { + Format(l_cEventTimeleft[0], sizeof(l_cEventTimeleft), "Timeleft: %s", l_cEventTimeleft[0]); + } + EventMenu.AddItem("", l_cEventTimeleft[0], ITEMDRAW_DISABLED); + EventMenu.ExitButton = true; + EventMenu.ExitBackButton = true; + EventMenu.Display(client, 0); +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public int MenuHandler1(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_End) + { + delete menu; + } +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void CalculateTimeToNextEvent(char[] content, char[] content1, char[]str, int maxsize) +{ + //content = 24/11/2018 + //content1 = : 6 + char sPart[2][526]; + char sYear[24]; + char sMonth[24]; + char sDay[24]; + char sHour[24]; + char sMinute[24]; + int i_Year; + int i_Month; + int i_Day; + int i_Hour; + int i_Minute; + int year; + int months; + int days; + int l_hours; + int minutes; + FormatTime(sYear, sizeof(sYear), "%Y"); + FormatTime(sMonth, sizeof(sMonth), "%m"); + FormatTime(sDay, sizeof(sDay), "%d"); + FormatTime(sHour, sizeof(sHour), "%H"); + FormatTime(sMinute, sizeof(sMinute), "%M"); + TrimString(content); + TrimString(content1); + ExplodeString(content, "/", sPart, 2, maxsize); + i_Day = StringToInt(sDay); + days = StringToInt(sPart[0]); + i_Month = StringToInt(sMonth); + ExplodeString(sPart[1], "/", sPart, 2, maxsize); + months = StringToInt(sPart[0]); + i_Hour = StringToInt(sHour); + l_hours = StringToInt(content1); + char sPart1[3][526]; + ExplodeString(content, "/", sPart1, 3, maxsize); + year = StringToInt(sPart1[2]); + i_Year = StringToInt(sYear); + i_Minute = StringToInt(sMinute); + if (days >= i_Day || months > i_Month || year > i_Year) + { + if (i_Year <= year) + { + if (year > i_Year) + { + i_Month = 1; + } + if (days >= i_Day) + { + days -= i_Day; + } + else if (i_Month == 1 || i_Month == 3 || i_Month == 5 || i_Month == 7 || i_Month == 8 || i_Month == 10 || i_Month == 12) + { + days += (31 - i_Day); + } + else if (i_Month == 2) + { + days += (28 - i_Day); + } + else + { + days += (30 - i_Day); + } + //from 12 to 24 or from 7 to 19 etc etc + l_hours += 12; + if (i_Hour > l_hours) + { + days -= 1; + l_hours = 24 - (i_Hour - l_hours); + //PrintToChatAll("if statement l_hours: %i", l_hours); + } + else + { + l_hours -= i_Hour; + //PrintToChatAll("else statement: l_hours: %i", l_hours); + } + if (l_hours != 0) + { + l_hours -= 1; + } + minutes = 60 - i_Minute; + Format(str, maxsize, "Taking Place in: %i Days, %i hours, %i Minutes", days, l_hours, minutes); + } + else + { + Format(str, maxsize, "EVENT OVER"); + } + } + else + { + Format(str, maxsize, "EVENT OVER"); + } +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void EventInfo() +{ + MYSQLGetEventContent(); +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void MYSQLGetEventContent() +{ + MYSQLGetContent(); +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void MYSQLGetContent() +{ + char sQuery[g_dLength]; + Format(sQuery, sizeof(sQuery), "SELECT * FROM `EventContent`"); + SQL_TQuery(g_dDatabase, TqueryThreadCallback, sQuery); + Format(sQuery, sizeof(sQuery), "SELECT * FROM `Maps`"); + SQL_TQuery(g_dDatabase, TqueryThreadCallbackmaps, sQuery); +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void TqueryThreadCallback(Handle db, Handle rs, const char[] error, any data) +{ + if (SQL_GetRowCount(rs) > 0 && SQL_FetchRow(rs)) + { + // 0 event title + SQL_FetchString(rs, 0, g_cEventContent[0], sizeof(g_cEventContent)); + // 1 rewards + SQL_FetchString(rs, 1, g_cEventContent[1], sizeof(g_cEventContent)); + // 2 leaders + SQL_FetchString(rs, 2, g_cEventContent[2], sizeof(g_cEventContent)); + // 3 timeleft (24/11/2018) + SQL_FetchString(rs, 3, g_cEventContent[3], sizeof(g_cEventContent)); + //4 timeleft = : 5 pm GMT+0 // 6 pm GMT+1 // 7 pm GMT+2 + SQL_FetchString(rs, 4, g_cEventContent[4], sizeof(g_cEventContent)); + } +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void TqueryThreadCallbackmaps(Handle owner, Handle rs, const char[] error, any data) +{ + g_iIndexCounter = 0; + if (SQL_GetRowCount(rs) > 0 && SQL_FetchRow(rs)) + { + g_iIndexCounter++; + int index; + SQL_FetchString(rs, 0, g_cEventMaps[index], sizeof(g_cEventMaps)); + index++; + while (SQL_FetchRow(rs)) + { + SQL_FetchString(rs, 0, g_cEventMaps[index], sizeof(g_cEventMaps)); + index++; + g_iIndexCounter++; + } + } +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void SQL_StartConnection() +{ + char error[g_dLength]; + if (SQL_CheckConfig("eventscss")) + g_dDatabase = SQL_Connect("eventscss", true, error, sizeof(error)); + if (g_dDatabase == null) + { + PrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to MYSQL-DB!"); + } +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void SQL_CreateDBIFNotExist() +{ + char sQuery[g_dLength]; + Format(sQuery, sizeof(sQuery), "CREATE TABLE IF NOT EXISTS `eventscss`.`EventContent` (`title` VARCHAR(256) NOT NULL, `Rewards` VARCHAR(256) NULL, `Leaders` VARCHAR(256) NULL, `datum` VARCHAR(128) NULL, `hours` VARCHAR(128) NULL, PRIMARY KEY (`title`)) ENGINE = InnoDB;"); + SQL_FastQuery(g_dDatabase, sQuery); + Format(sQuery, sizeof(sQuery), "CREATE TABLE IF NOT EXISTS `eventscss`.`Maps` (`MapNames` VARCHAR(45) NOT NULL, PRIMARY KEY (`MapNames`)) ENGINE = InnoDB;"); + SQL_FastQuery(g_dDatabase, sQuery); +} +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +stock bool IsValidClient(int client) +{ + if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client)) + { + return true; + } + return false; +} \ No newline at end of file