Compare commits
No commits in common. "c456837148582ab296480233aa4a8754dc84e92e" and "53262acf09de5f06d40aa9545dc1006455d8104c" have entirely different histories.
c456837148
...
53262acf09
86
build.gradle
86
build.gradle
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* This build file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* This generated file contains a sample Java Library project to get you started.
|
||||
* For more details take a look at the Java Libraries chapter in the Gradle
|
||||
* user guide available at https://docs.gradle.org/4.3/userguide/java_library_plugin.html
|
||||
*/
|
||||
|
||||
// Apply the java-library plugin to add support for Java Library
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'java'
|
||||
|
||||
compileJava.options.encoding = 'UTF-8'
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
// Use jcenter for resolving your dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir '/src/main/java'
|
||||
|
||||
exclude 'com/bernard/juliabot/internalddon/**'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task apiJar(type: Jar) {
|
||||
archiveName = "JuliabotAPI.jar"
|
||||
group 'build'
|
||||
description "Fait un jar avec juste l'api"
|
||||
from(sourceSets.main.output) {
|
||||
include "com/bernard/juliabot/api/**"
|
||||
}
|
||||
}
|
||||
|
||||
task internalddonJar(type: Jar) {
|
||||
archiveName = "JuliabotInternaddon_beta.jar"
|
||||
group 'build'
|
||||
description "Fait un jar avec juste l'addon interne"
|
||||
from(sourceSets.main.output) {
|
||||
include "com/bernard/juliabot/internaddon/**"
|
||||
}
|
||||
}
|
||||
|
||||
task execute(type:JavaExec) {
|
||||
group 'execution'
|
||||
description "Compile et execute le fichier jar"
|
||||
main = 'com.bernard.juliabot.Julia'
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
}
|
||||
|
||||
task copyDependencies(type: Copy) {
|
||||
group 'build'
|
||||
from configurations.compile
|
||||
into 'dependencies'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// This dependency is exported to consumers, that is to say found on their compile classpath.
|
||||
api 'org.apache.commons:commons-math3:3.6.1'
|
||||
|
||||
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
|
||||
implementation 'com.google.guava:guava:23.0'
|
||||
|
||||
// Use JUnit test framework
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
||||
compile 'org.slf4j:slf4j-nop:1.7.25'
|
||||
|
||||
compile 'net.dv8tion:JDA:4.2.0_189'
|
||||
|
||||
compile 'com.thedeanda:lorem:2.1'
|
||||
|
||||
compile 'commons-io:commons-io:2.6'
|
||||
|
||||
// https://mvnrepository.com/artifact/mysql/mysql-connector-java
|
||||
compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21'
|
||||
|
||||
}
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
*
|
||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||
* in the user guide at https://docs.gradle.org/4.8.1/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
rootProject.name = 'Juliabot'
|
||||
@ -1,59 +0,0 @@
|
||||
package com.bernard.juliabot;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.bernard.juliabot.api.CCommande;
|
||||
|
||||
public class CommandCalled {
|
||||
|
||||
Method called;
|
||||
CCommande argument;
|
||||
String name;
|
||||
String cname;
|
||||
Object caller;
|
||||
Thread commandThread;
|
||||
Throwable exitValue = null;
|
||||
volatile boolean running;
|
||||
volatile boolean started;
|
||||
|
||||
public CommandCalled(Method called, CCommande argument, String name, String cname, Object caller) {
|
||||
this.called = called;
|
||||
this.argument = argument;
|
||||
this.name = name;
|
||||
this.cname = cname;
|
||||
this.caller = caller;
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setThread(Thread commandThread) {
|
||||
this.commandThread = commandThread;
|
||||
}
|
||||
|
||||
public void setExitValue(Throwable t) {
|
||||
this.exitValue = t;
|
||||
}
|
||||
|
||||
public void ended() {
|
||||
running = false;
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
public void waitForExecution() {
|
||||
while(running) {
|
||||
try {
|
||||
Thread.sleep(42);
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("Icapacité de pauser le thread : ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,87 +0,0 @@
|
||||
package com.bernard.juliabot;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.bernard.juliabot.api.CCommande;
|
||||
import com.bernard.juliabot.api.Command;
|
||||
|
||||
public class CommandeSurchargee {
|
||||
|
||||
String name;
|
||||
Command command;
|
||||
|
||||
Map<Set<Class<?>>,Method> versions = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
public CommandeSurchargee(Command c) {
|
||||
this.name = c.name();
|
||||
this.command = c;
|
||||
}
|
||||
|
||||
public Method getExecutor(CCommande commande) {
|
||||
Set<Class<?>> critargs = checkFiliature(Stream.of(commande.getClass()).collect(Collectors.toSet()));
|
||||
System.out.println("////////"+critargs);
|
||||
return versions.get(versions.keySet().stream().filter(cr -> critargs.containsAll(cr)).findAny().orElse(null));
|
||||
}
|
||||
|
||||
public void surcharger(Set<Class<?>> discriminant, Method m) {
|
||||
|
||||
Set<Class<?>> critargs = checkFiliature(discriminant);
|
||||
|
||||
versions.put(critargs, m);
|
||||
}
|
||||
|
||||
public static Set<Class<?>> checkFiliature(Set<Class<?>> unorderedDiscriminant){
|
||||
|
||||
return unorderedDiscriminant.stream()
|
||||
.map(CommandeSurchargee::getAllMamans)
|
||||
.flatMap(Set::stream)
|
||||
.filter(CCommande.class::isAssignableFrom)
|
||||
.filter(c->c.isInterface())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getAllMamans(Class<?> clazz) {
|
||||
Set<Class<?>> res = new HashSet<>();
|
||||
|
||||
res.add(clazz);
|
||||
|
||||
if(clazz == Object.class)return res;
|
||||
|
||||
// First, add all the interfaces implemented by this class
|
||||
Class<?>[] interfaces = clazz.getInterfaces();
|
||||
res.addAll(Arrays.asList(interfaces));
|
||||
for (Class<?> interfaze : interfaces) {
|
||||
res.addAll(getAllMamans(interfaze));
|
||||
}
|
||||
|
||||
|
||||
// Add the super class
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
|
||||
// Interfaces does not have java,lang.Object as superclass, they have null, so break the cycle and return
|
||||
if (superClass == null) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Now inspect the superclass
|
||||
res.addAll(getAllMamans(superClass));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CommandeSurchargee [name=" + name + ", versions=" + versions + "]";
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return command.description();
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,7 @@
|
||||
package com.bernard.juliabot;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@ -15,196 +11,111 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.output.TeeOutputStream;
|
||||
|
||||
import com.bernard.juliabot.JuliaAddon.JarWithMultipleAddonsException;
|
||||
import com.bernard.juliabot.JuliaAddon.JuliaClassLoader;
|
||||
import com.bernard.juliabot.api.CCommande;
|
||||
import com.bernard.juliabot.api.Command;
|
||||
import com.bernard.juliabot.api.CommandCall;
|
||||
import com.bernard.juliabot.api.Discord;
|
||||
import com.thedeanda.lorem.LoremIpsum;
|
||||
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.JDABuilder;
|
||||
import net.dv8tion.jda.api.events.Event;
|
||||
import net.dv8tion.jda.api.events.GenericEvent;
|
||||
import net.dv8tion.jda.core.AccountType;
|
||||
import net.dv8tion.jda.core.JDA;
|
||||
import net.dv8tion.jda.core.JDABuilder;
|
||||
import net.dv8tion.jda.core.events.Event;
|
||||
|
||||
public class Julia {
|
||||
|
||||
public static final String juliaddonsFolder = "/home/julia/juliaddons/";
|
||||
|
||||
public static final String sysinPipe = "/home/julia/entree";
|
||||
|
||||
public static final String CONNECTION_DATA_FILEPATH = "/var/julia/julia.conn";
|
||||
private static final String token = "";
|
||||
|
||||
static Julia theJulia;
|
||||
|
||||
JDA jda;
|
||||
|
||||
Map<String,JuliaAddon> avalivableAddons;// pkg+version->addon
|
||||
Map<String,JuliaAddon> avalivableAddons;//pkg+version->addon
|
||||
Map<Long,Character> laboratoriesIdentifieurs;//Store channels IDs ...
|
||||
|
||||
Map<Character,Laboratory> laboratoires;
|
||||
|
||||
Map<String,Long> fileTrack;//<File name in juliaddonFolder, lastModified>
|
||||
|
||||
EcouteurDEvents lecouteur;
|
||||
ReadLoop sysinator;
|
||||
|
||||
Connection eventDatabase;
|
||||
Connection juliaDatabase;
|
||||
|
||||
JuliaErrPrintStream syserr;
|
||||
|
||||
|
||||
public Julia() {
|
||||
|
||||
avalivableAddons = new HashMap<>();
|
||||
laboratoriesIdentifieurs = new HashMap<>();
|
||||
laboratoires = new HashMap<>();
|
||||
|
||||
fileTrack = new HashMap<>();
|
||||
|
||||
}
|
||||
|
||||
public synchronized void startup() {
|
||||
|
||||
BufferedReader bis;
|
||||
try {
|
||||
bis = new BufferedReader(new FileReader(CONNECTION_DATA_FILEPATH));
|
||||
String token = bis.readLine();
|
||||
|
||||
//Set up mysql cnnections (events & data)
|
||||
Properties connectionProps = new Properties();
|
||||
connectionProps.put("user", bis.readLine());
|
||||
connectionProps.put("password", bis.readLine());
|
||||
connectionProps.put("serverTimezone", "UTC");
|
||||
connectionProps.put("verifyServerCertificate", "false");
|
||||
connectionProps.put("useSSL", "true");
|
||||
connectionProps.put("requireSSL", "true");
|
||||
String urlAndPort = bis.readLine();
|
||||
try {
|
||||
eventDatabase = DriverManager.getConnection("jdbc:mysql://"+urlAndPort+"/juliaEvents", connectionProps);
|
||||
juliaDatabase = DriverManager.getConnection("jdbc:mysql://"+urlAndPort+"/julia", connectionProps);
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Impossible de se connecter a la BDD, ca ne sers a rien de lancer JuL'IA du coup ... Bonne nuit");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
bis.close();
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("La BDD est chargée" + eventDatabase+","+juliaDatabase);
|
||||
|
||||
|
||||
// Démarrage de JDA et du Bot
|
||||
try {
|
||||
lecouteur = new EcouteurDEvents(this);
|
||||
jda = JDABuilder.createDefault(token).addEventListeners(getLecouteur()).build();
|
||||
getJda().awaitReady();
|
||||
} catch(Exception e) {
|
||||
System.err.println("Impossible de démarrer JuL'IA");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
bis.close();
|
||||
return;
|
||||
}
|
||||
|
||||
long guildHello = Long.parseLong(bis.readLine());
|
||||
long textChannelHello = Long.parseLong(bis.readLine());
|
||||
getJda().getGuildById(guildHello).getTextChannelById(textChannelHello).sendMessage(LoremIpsum.getInstance().getWords(10, 15)).complete();
|
||||
|
||||
long guildErr = Long.parseLong(bis.readLine());
|
||||
long textChannelErr = Long.parseLong(bis.readLine());
|
||||
|
||||
syserr = new JuliaErrPrintStream(getJda().getGuildById(guildErr).getTextChannelById(textChannelErr));
|
||||
|
||||
TeeOutputStream tos = new TeeOutputStream(System.err, syserr.printStream());
|
||||
System.setErr(new PrintStream(tos));
|
||||
|
||||
Timer syserrtimer = new Timer("Syserr-refresh", true);
|
||||
syserrtimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {Julia.theJulia().syserr.flushMessage();}
|
||||
} , 0, 1000);
|
||||
|
||||
bis.close();
|
||||
} catch (FileNotFoundException e1) {
|
||||
System.err.println("Euhhhhh je n'ai pas trouvé le fichier "+CONNECTION_DATA_FILEPATH+" et je ne peux donc pas lire ma carte d'identitée");
|
||||
e1.printStackTrace();
|
||||
} catch (IOException e1) {
|
||||
System.err.println("Euhhhhh je n'ai pas réussi à lire le fichier "+CONNECTION_DATA_FILEPATH+" et je ne peux donc pas lire ma carte d'identitée");
|
||||
e1.printStackTrace();
|
||||
//Set up mysql cnnections (events & data)
|
||||
Properties connectionProps = new Properties();
|
||||
connectionProps.put("user", "julia");
|
||||
connectionProps.put("password", "juliabestbotever");
|
||||
connectionProps.put("serverTimezone", "UTC");
|
||||
connectionProps.put("verifyServerCertificate", "false");
|
||||
connectionProps.put("useSSL", "true");
|
||||
connectionProps.put("requireSSL", "true");
|
||||
try {
|
||||
eventDatabase = DriverManager.getConnection("jdbc:mysql://localhost:3306/juliaEvents", connectionProps);
|
||||
juliaDatabase = DriverManager.getConnection("jdbc:mysql://localhost:3306/julia", connectionProps);
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Impossible de se connecter a la BDD, ca ne sers a rien de lancer JuL'IA du coup ... Bonne nuit");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
//XXX sSet up JDA and Bot
|
||||
|
||||
try {
|
||||
jda = new JDABuilder(AccountType.BOT).setToken(token).buildBlocking();
|
||||
} catch(Exception e) {
|
||||
System.err.println("Impossible de démarrer JuL'IA");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Launch update to see every addon in juliaddon/
|
||||
update();//Va remplir la map avalivableAddons
|
||||
|
||||
|
||||
|
||||
//Démarrage du sysin
|
||||
sysinator = new ReadLoop();
|
||||
Thread sysinThread = new Thread(sysinator, "sysin-reader");
|
||||
sysinThread.start();
|
||||
|
||||
System.out.println("Sont disponibles :"+avalivableAddons);
|
||||
//Loader l'internalddon (hard-coded)
|
||||
//laboratoires.get('#').loadAddon("com.bernard.juliabot.internaddon", "beta", false);//Pas besoin d'update, il viens d'etre fait
|
||||
|
||||
//Load addons in # and in $ (récupere ce qu'il faut dans la BDD)
|
||||
Set<String> toLoad = new HashSet<>();
|
||||
try {
|
||||
Statement statement = juliaDatabase.createStatement();
|
||||
ResultSet result = statement.executeQuery("SELECT * FROM loadedJuliaddons");
|
||||
while(result.next()) {
|
||||
do {
|
||||
char laboratory = result.getString("laboratory").charAt(0);
|
||||
String pkg = result.getString("pkg");
|
||||
String version = result.getString("version");
|
||||
toLoad.add(laboratory+pkg+":"+version);
|
||||
}
|
||||
if(!laboratoires.containsKey(laboratory))
|
||||
laboratoires.put(laboratory, new Laboratory(laboratory));
|
||||
Laboratory labo = laboratoires.get(laboratory);
|
||||
labo.loadAddon(pkg, version, false);//Pas besoin d'update, il viens d'etre fait
|
||||
}while(result.next());
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Impossible de charger les plugins, vous aurez tout a faire a la main !");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
}
|
||||
System.out.println("Les addons à charger : "+toLoad);
|
||||
try {
|
||||
juliaDatabase.createStatement().executeUpdate("DELETE FROM loadedJuliaddons");
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Je n'ai pas pu vider la table ... atention aux doublons !");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
}
|
||||
|
||||
for(String l : toLoad) {
|
||||
if(!getLaboratoires().containsKey(l.charAt(0)))
|
||||
getLaboratoires().put(l.charAt(0), new Laboratory(l.charAt(0)));
|
||||
Laboratory labo = getLaboratoires().get(l.charAt(0));
|
||||
labo.loadAddon(l.substring(1, l.lastIndexOf(":")), l.substring(l.lastIndexOf(":")+1), false);//Pas besoin d'update, il viens d'etre fait
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public synchronized void update() {
|
||||
Map<String,JuliaAddon> avalivableAddons = new HashMap<>();
|
||||
File juliaddonFolder = new File(juliaddonsFolder);
|
||||
for(File f : juliaddonFolder.listFiles((parent,name)->name.toLowerCase().endsWith(".jar"))){
|
||||
if(fileTrack.containsKey(f.getName()) && fileTrack.get(f.getName()) == f.lastModified())
|
||||
if(fileTrack.get(f.getName()) == f.lastModified())
|
||||
continue;//Le fichier n'a pas bougé, pas besoin de le relire
|
||||
fileTrack.put(f.getName(), f.lastModified());
|
||||
try {
|
||||
@ -213,7 +124,7 @@ public class Julia {
|
||||
JuliaAddon addon = new JuliaAddon(jar);
|
||||
String id = addon.pkg+":"+addon.version;
|
||||
if(avalivableAddons.containsKey(id))
|
||||
System.err.println("L'addon "+id+" a déjà été chargée dans les fichiers "+avalivableAddons.get(id).jarFile.getName()+" et "+jar.getName()+", je garde que le deuxi<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>me !");
|
||||
System.err.println("L'addon "+id+" a déjà été chargé dans les fichiers "+avalivableAddons.get(id).jarFile.getName()+" et "+jar.getName()+", je garde que le deuxième !");
|
||||
avalivableAddons.put(id, addon);
|
||||
}catch(JarWithMultipleAddonsException e) {
|
||||
Set<Set<JarEntry>> addonsEntries = e.getAddonsEntries();
|
||||
@ -222,82 +133,36 @@ public class Julia {
|
||||
JuliaAddon addon = new JuliaAddon(jar, entry);
|
||||
String id = addon.pkg+":"+addon.version;
|
||||
if(avalivableAddons.containsKey(id))
|
||||
System.err.println("L'addon "+id+" a déjà été chargée dans les fichiers "+avalivableAddons.get(id).jarFile.getName()+" et "+jar.getName()+", je garde que le deuxi<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>me !");
|
||||
System.err.println("L'addon "+id+" a déjà été chargé dans les fichiers "+avalivableAddons.get(id).jarFile.getName()+" et "+jar.getName()+", je garde que le deuxième !");
|
||||
avalivableAddons.put(id, addon);
|
||||
} catch (JarWithMultipleAddonsException e1) {
|
||||
System.err.println("THIS SHOULD NOT HAPPEN");
|
||||
System.err.println("TOUT EST CASSÉ ALERTE ROUGE !");
|
||||
System.err.println("C'est problematique, j'éteint tout, c'est mieux");
|
||||
syserr.flush();
|
||||
System.err.println("C'est problematique, j'eteint tout, c'est mieux");
|
||||
System.exit(31415926);
|
||||
}
|
||||
}
|
||||
}catch(IllegalStateException e) {
|
||||
System.err.println(e.getMessage());
|
||||
syserr.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Impossible de lire le fichier jar "+f.getName());
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
}
|
||||
syserr.flush();
|
||||
}
|
||||
this.avalivableAddons = avalivableAddons;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Connection getJuliaDatabase() {
|
||||
return juliaDatabase;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class ReadLoop implements Runnable{
|
||||
|
||||
boolean running = false;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
running = true;
|
||||
try {
|
||||
Scanner sc = new Scanner(new File(sysinPipe));
|
||||
while(running) {
|
||||
String request = sc.nextLine();
|
||||
|
||||
System.out.println("Je suis censée avoir lu la commande "+request);
|
||||
//TODO réagir ...
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
sc.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("Erreur de lecture du sysin, je deviens sourd");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
running=false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class Laboratory{
|
||||
char laboratory;
|
||||
Map<String,JuliaAddon> loadedAddons;//<pkg,JuliaAddon> : les addons chargés dans ce laboratoire
|
||||
Map<String,CommandeSurchargee> loadedCommands;//<commandName,Calling method> : les commandes chargées
|
||||
Map<Class<?>,Object> callerObjects; // <Classe, objet de cette classe> : Les objets instanciés dans ce laboratoire
|
||||
Map<String,String> aliases;// <alias, vrainom>
|
||||
Map<Class<? extends Event>,Set<Method>> loadedEvents;// Les méthodes à appeler quand un event de cette classe est lancé
|
||||
Map<String,JuliaAddon> loadedAddons;//<pkg,JuliaAddon>
|
||||
Map<String,Method> loadedCommands;
|
||||
Map<Class<?>,Object> callerObjects;
|
||||
Map<String,String> aliases;
|
||||
Map<Class<? extends Event>,Set<Method>> loadedEvents;
|
||||
Map<String,JuliaClassLoader> clazzTrack;//<className,JuliaClassLoader which loaded ths class in this laboratory>
|
||||
|
||||
|
||||
|
||||
public Laboratory(char laboratory) {
|
||||
this.laboratory = laboratory;
|
||||
loadedAddons = new HashMap<>();
|
||||
@ -305,7 +170,6 @@ public class Julia {
|
||||
aliases = new HashMap<>();
|
||||
loadedEvents = new HashMap<>();
|
||||
clazzTrack = new HashMap<>();
|
||||
callerObjects = new HashMap<>();
|
||||
}
|
||||
|
||||
public JuliaClassLoader findClassLoader(String className) {
|
||||
@ -316,7 +180,6 @@ public class Julia {
|
||||
unloadAddon(pkg);
|
||||
loadAddon(pkg, version);
|
||||
}
|
||||
|
||||
public void loadAddon(String pkg,String version) {
|
||||
this.loadAddon(pkg, version, true);
|
||||
}
|
||||
@ -324,9 +187,9 @@ public class Julia {
|
||||
public synchronized void loadAddon(String pkg,String version,boolean update) {
|
||||
if(update)Julia.this.update();
|
||||
if(loadedAddons.containsKey(pkg))
|
||||
throw new IllegalStateException("Impossible de charger le juliaddon "+pkg+" dans le laboratoire "+laboratory+", il est d<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> charg<72><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||||
throw new IllegalStateException("Impossible de charger le juliaddon "+pkg+" dans le laboratoire "+laboratory+", il est déjà chargé");
|
||||
try {
|
||||
PreparedStatement s = juliaDatabase.prepareStatement("INSERT INTO loadedJuliaddons (ID,laboratory,pkg,version) VALUES (NULL,?,?,?)");
|
||||
PreparedStatement s = juliaDatabase.prepareStatement("INSERT INTO juliaddons (laboratory,pkg,version) VALUES (?,?,?)");
|
||||
s.setString(1, Character.toString(laboratory));
|
||||
s.setString(2, pkg);
|
||||
s.setString(3, version);
|
||||
@ -334,7 +197,6 @@ public class Julia {
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Je ne peux pas notifier la BDD que je load le plugin, je le load pas du coup ...");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -359,7 +221,6 @@ public class Julia {
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Je ne peux pas notifier la BDD que je unload le plugin, je l'unload mais vous risquez d'avoir des problemes ...");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
return;
|
||||
}
|
||||
JuliaAddon addon = loadedAddons.get(pkg);
|
||||
@ -368,44 +229,32 @@ public class Julia {
|
||||
}
|
||||
|
||||
public synchronized void registerCommand(Method m,Command c) {
|
||||
if(!loadedCommands.containsKey(c.name()))
|
||||
loadedCommands.put(c.name(), new CommandeSurchargee(c));
|
||||
|
||||
if(loadedCommands.containsKey(c.name()))
|
||||
throw new IllegalStateException("Une commade "+c.name()+" a déjà été enregistrée !");
|
||||
//Verify that commands asks for good argument
|
||||
if(!Arrays.stream(m.getParameterTypes()).map(CCommande.class::isAssignableFrom).reduce(Boolean::logicalAnd).get())
|
||||
throw new IllegalArgumentException("Les paramètres d'une commande doivent tous implémenter CCommande");
|
||||
|
||||
try {
|
||||
m.setAccessible(true);
|
||||
}catch(SecurityException e) {
|
||||
throw new IllegalArgumentException("Impossible de me donner le droit d'éxecuter "+m.toGenericString());
|
||||
}
|
||||
|
||||
Class<?>[] parameters = m.getParameterTypes();
|
||||
if(parameters.length > 1)
|
||||
throw new IllegalArgumentException("La méthode d'une commande ne peux prendre au maximum qu'un argument (de type CommandCall), la méthode fautive étant "+m.toGenericString());
|
||||
if(parameters.length == 1 && parameters[0] == CommandCall.class)
|
||||
throw new IllegalArgumentException("La méthode d'une commande, si elle possede un argument, ce dernier doit tre de type CommandCall, la méthode fautive étant "+m.toGenericString());
|
||||
// Argument OK
|
||||
//Register aliases
|
||||
// print un message d'erreur si un alias a déjà été enregistré pour une autre commande
|
||||
Arrays.stream(c.aliases())
|
||||
.filter(aliases::containsKey).filter(alias -> !aliases.get(alias).equals(c.name()))
|
||||
.forEach(alias -> System.err.println("Faut remplacer l'alias "+alias+", plus de deux addons l'utilisent"));
|
||||
Arrays.stream(c.aliases())
|
||||
.filter(a -> !aliases.containsKey(a)).forEach(alias -> aliases.put(alias, c.name()));
|
||||
|
||||
|
||||
|
||||
for(String alias:c.aliases()) {
|
||||
if(aliases.containsKey(alias))
|
||||
System.err.println("Faut remplacer l'alias "+alias+", plus de deux addons l'utilisent");
|
||||
aliases.put(alias, c.name());
|
||||
}
|
||||
//Création de l'objet si ca n'a pas été fait
|
||||
checkObject(m.getDeclaringClass());
|
||||
|
||||
//Enregistre la nouvelle surcharge
|
||||
loadedCommands.get(c.name()).surcharger(Arrays.stream(m.getParameterTypes()).collect(Collectors.toSet()), m);
|
||||
|
||||
loadedCommands.put(c.name(), m);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")//It is, in reallity checked
|
||||
public synchronized void registerEvent(Method m, Discord d) {
|
||||
Class<?>[] parameters = m.getParameterTypes();
|
||||
if(parameters.length != 1)
|
||||
throw new IllegalArgumentException("Les catcheurs d'events ne doivent avoir qu'un seul paramétre, extends Event, la méthode fautive étant "+m.toGenericString());
|
||||
if(!Event.class.isAssignableFrom(parameters[0]))
|
||||
throw new IllegalArgumentException("Les catcheurs d'events ne doivent avoir qu'un seul paramètre, extends Event, la méthde fautive étant "+m.toGenericString());
|
||||
if(Event.class.isAssignableFrom(parameters[0]))
|
||||
throw new IllegalArgumentException("Les catcheur d'events ne doivent avoir qu'un paramètre, qui doit extends Event, la méthode fautive étant "+m.toGenericString());
|
||||
//La méthode est vérifiée
|
||||
if(!loadedEvents.containsKey(parameters[0]))
|
||||
@ -445,14 +294,6 @@ public class Julia {
|
||||
case "java.lang.Character":
|
||||
params[i] = this.laboratory;
|
||||
break;
|
||||
case "java.sql.Connection":
|
||||
params[i] = Julia.this.juliaDatabase;
|
||||
break;
|
||||
case "net.dv8tion.jda.core.JDA":
|
||||
params[i] = Julia.this.getJda();
|
||||
break;
|
||||
//TODO completer les paramètres
|
||||
|
||||
default:
|
||||
continue constLoop;
|
||||
}
|
||||
@ -462,117 +303,21 @@ public class Julia {
|
||||
//Tant pis, constructeur suivant
|
||||
continue constLoop;
|
||||
}
|
||||
if(o != null)break;//Sortir de la boucle, on a notre joli objet
|
||||
if(o != null)break;//Sortir de la boucle, on a notre juli objet
|
||||
}
|
||||
if(o == null) {
|
||||
System.err.println("Je ne peux pas créer l'objet, faudait mettre un costructeur valide (en mon sens :P)");
|
||||
System.err.println("Je fais tout planter du coup, votrez addon sera pas chargé !");
|
||||
throw new IllegalStateException("Pas de constructeur valable");
|
||||
}
|
||||
callerObjects.put(clazz, o);
|
||||
}
|
||||
}
|
||||
|
||||
public void trigger(GenericEvent event) {
|
||||
Class<? extends GenericEvent> eventClass = event.getClass();
|
||||
Set<Method> toCall = loadedEvents.get(eventClass);
|
||||
for(Method m : toCall) {
|
||||
Object callable = callerObjects.get(m.getDeclaringClass());
|
||||
try {
|
||||
m.invoke(callable, event);
|
||||
} catch (IllegalAccessException e) {
|
||||
System.err.println("C'est pas joli joli, je suis censé lancer une méthode à laquelle je n'ai pas accès : "+m.toGenericString());
|
||||
throw new IllegalStateException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.println("La méthode n'est pas censée recevoir de tels erreurs, je devrai avoir chécké la méthode, mais elle ne veut pas de mes arguments ... : "+m.toGenericString());
|
||||
throw new IllegalStateException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("La méthode à lancé cette exception ... je la relance derrière du coup : "+m.toGenericString());
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
public void trigger(Event event) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public CommandCalled executeCommand(String name, CCommande content) {
|
||||
|
||||
String cname = name;
|
||||
|
||||
if(aliases.containsKey(name))
|
||||
cname = aliases.get(name);
|
||||
if(!loadedCommands.containsKey(cname))
|
||||
throw new IllegalArgumentException("Je ne connais ni la commande, ni l'alias "+cname);
|
||||
|
||||
|
||||
CommandeSurchargee scommande = loadedCommands.get(cname);
|
||||
Method m = scommande.getExecutor(content);
|
||||
if(m==null)
|
||||
throw new IllegalArgumentException("La commande "+cname+" alias "+name+" n'est pas prévue pour s'éxecuter avec un "+content.getClass().getCanonicalName());
|
||||
final Object[] parameters = new Object[m.getParameterCount()];
|
||||
Arrays.fill(parameters, content);
|
||||
final Object caller = callerObjects.get(m.getDeclaringClass());
|
||||
|
||||
final CommandCalled called = new CommandCalled(m, content, name, cname, caller);
|
||||
|
||||
|
||||
Thread t = new Thread(() -> {
|
||||
|
||||
try {
|
||||
|
||||
m.invoke(caller, parameters);
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
System.err.println("Problème d'accès à la méthode "+m.toGenericString()+" ... c'est embêtant");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
called.setExitValue(e.getCause());
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.println("Étrange, je pensais avoir check les arguments");
|
||||
e.printStackTrace();
|
||||
syserr.flush();
|
||||
called.setExitValue(e.getCause());
|
||||
} catch (InvocationTargetException e) {
|
||||
//Lui a planté
|
||||
called.setExitValue(e.getCause());
|
||||
System.err.println("L'appel a la commande a planté ...");
|
||||
e.getCause().printStackTrace();
|
||||
}
|
||||
syserr.flush();
|
||||
called.ended();
|
||||
|
||||
}, "commande-"+cname+".aka."+name+"-"+System.nanoTime());
|
||||
|
||||
called.setThread(t);
|
||||
|
||||
t.start();
|
||||
|
||||
return called;
|
||||
}
|
||||
|
||||
|
||||
public Map<String, JuliaAddon> getLoadedAddons() {
|
||||
return loadedAddons;
|
||||
}
|
||||
|
||||
public Map<String, CommandeSurchargee> getLoadedCommands() {
|
||||
return loadedCommands;
|
||||
}
|
||||
|
||||
public Map<String, String> getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
public Map<Class<? extends Event>, Set<Method>> getLoadedEvents() {
|
||||
return loadedEvents;
|
||||
}
|
||||
|
||||
public char getL() {
|
||||
return laboratory;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -582,23 +327,10 @@ public class Julia {
|
||||
|
||||
public static void main(String[] args) {
|
||||
theJulia = new Julia();
|
||||
theJulia.startup();
|
||||
}
|
||||
|
||||
public static Julia theJulia() {
|
||||
return theJulia;
|
||||
}
|
||||
|
||||
public JDA getJda() {
|
||||
return jda;
|
||||
}
|
||||
|
||||
public Map<Character,Laboratory> getLaboratoires() {
|
||||
return laboratoires;
|
||||
}
|
||||
|
||||
public EcouteurDEvents getLecouteur() {
|
||||
return lecouteur;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
@ -16,15 +15,15 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.bernard.juliabot.Julia.Laboratory;
|
||||
import com.bernard.juliabot.api.Command;
|
||||
import com.bernard.juliabot.api.Discord;
|
||||
import com.bernard.juliabot.Julia.Laboratory;
|
||||
import com.bernard.juliabot.api.JuLIAddon;
|
||||
|
||||
public class JuliaAddon {
|
||||
|
||||
private static final Pattern pkgFromClassName = Pattern.compile("^(\\w+(\\.\\w+){2,})\\.\\w+(\\$\\w+)*$");
|
||||
private static final Pattern jarNameParser = Pattern.compile("^([^_]+)_([^_]+)(_(.+))?.jar$");
|
||||
private static final Pattern pkgFromClassName = Pattern.compile("^(\\w(\\.\\w){2,})\\.\\w(\\$\\w)*$");
|
||||
private static final Pattern jarNameParser = Pattern.compile("^([^_])_([^_])(_(.*))?.jar$");
|
||||
|
||||
|
||||
String pkg;
|
||||
@ -52,30 +51,27 @@ public class JuliaAddon {
|
||||
|
||||
//Parsing du nom du fichier
|
||||
Matcher jarMatcher = jarNameParser.matcher(jar.getName());
|
||||
if(!jarMatcher.matches())
|
||||
throw new IllegalStateException("Le fichier n'a pas un nom valide, je ne peux pas récupérer la version du juliaddon : "+jar.getName().split("/")[jar.getName().split("/").length-1]);
|
||||
jarMatcher.matches();
|
||||
//String jarAddonName = jarMatcher.group(1);
|
||||
String jarVersion = jarMatcher.group(2);
|
||||
//String jarExtra = jarMatcher.group(3);
|
||||
version = jarVersion;
|
||||
|
||||
|
||||
//Sets addon,pkg,version(si redefini) et addonClass
|
||||
unassignedClassLoader = new JuliaClassLoader(jar, entriesToRead,new DummyLaboratory());
|
||||
|
||||
unassignedClassLoader = new JuliaClassLoader(jar, entriesToRead);
|
||||
}
|
||||
|
||||
public synchronized JuliaClassLoader newClassLoader(Laboratory laboratory) {
|
||||
if(unassignedClassLoader==null)
|
||||
if(unassignedClassLoader==null)
|
||||
try {
|
||||
JuliaClassLoader cl = new JuliaClassLoader(jarFile, loaderEntries,laboratory);
|
||||
JuliaClassLoader cl = new JuliaClassLoader(jarFile, loaderEntries);
|
||||
cl.laboratory = laboratory;
|
||||
classLoaders.put(laboratory.laboratory, cl);
|
||||
return cl;
|
||||
} catch (JarWithMultipleAddonsException e) {
|
||||
System.err.println("Cette erreur n'est pas censée arriver, alerte rouge");
|
||||
System.exit(685533990);
|
||||
}
|
||||
|
||||
JuliaClassLoader cl = unassignedClassLoader;
|
||||
unassignedClassLoader = null;
|
||||
cl.laboratory = laboratory;
|
||||
@ -83,34 +79,21 @@ public class JuliaAddon {
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getName() {
|
||||
return addon.name();
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class JuliaClassLoader extends ClassLoader {
|
||||
|
||||
Map<String,Class<?>> loadedClasses;
|
||||
Set<JarEntry> entries;
|
||||
JarFile jar;
|
||||
Laboratory laboratory = null;
|
||||
|
||||
HashSet<Method> registeredCommands;
|
||||
HashSet<Method> registeredEvents;
|
||||
|
||||
public JuliaClassLoader(JarFile jar,Set<JarEntry> entriesToRead,Laboratory labo) throws JarWithMultipleAddonsException {
|
||||
public JuliaClassLoader(JarFile jar,Set<JarEntry> entriesToRead) throws JarWithMultipleAddonsException {
|
||||
super();
|
||||
entries = entriesToRead;
|
||||
this.jar = jar;
|
||||
loadedClasses = new HashMap<>();
|
||||
this.laboratory = labo;
|
||||
|
||||
Set<Class<?>> readClasses = new HashSet<>();
|
||||
Map<String,JarEntry> juliaddons = new HashMap<>();
|
||||
for(JarEntry entry : entriesToRead) {
|
||||
@ -121,12 +104,11 @@ public class JuliaAddon {
|
||||
//Le fichier est un .class
|
||||
try {
|
||||
String className = entry.getName().replaceAll("/", ".").substring(0, entry.getName().length()-".class".length());
|
||||
Class<?> clazz;
|
||||
try {
|
||||
clazz = loadClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException("J'ai demandé a charger une classe sachant que je l'ai dans le jar, mais j'ai quand meme pas réussi à la charger ...", e);
|
||||
}
|
||||
byte[] classData = new byte[(int) entry.getSize()];
|
||||
InputStream reader = jar.getInputStream(entry);
|
||||
reader.read(classData);
|
||||
reader.close();
|
||||
Class<?> clazz = defineClass(className,classData,0,(int) entry.getSize());
|
||||
readClasses.add(clazz);
|
||||
//Instantiated class
|
||||
|
||||
@ -137,7 +119,7 @@ public class JuliaAddon {
|
||||
throw new IllegalArgumentException("Le nom de la classe est invalide pour un Juliaddon (il faut au moins trois de profondeur dans le package) : "+clazz.getName());
|
||||
String pkg = m.group(1);
|
||||
if(juliaddons.containsKey(pkg))
|
||||
throw new IllegalArgumentException("Il existe deja un juliaddon dans le package "+pkg+" , d<EFBFBD><EFBFBD>placez "+clazz.getName()+" ou "+juliaddons.get(pkg).getName());
|
||||
throw new IllegalArgumentException("Il existe deja un juliaddon dans le package "+pkg+" , déplacez "+clazz.getName()+" ou "+juliaddons.get(pkg).getName());
|
||||
juliaddons.put(pkg, entry);
|
||||
//If overwritten, will JarWithMultipleAddonsException
|
||||
JuliaAddon.this.addon = clazz.getAnnotation(JuLIAddon.class);
|
||||
@ -154,8 +136,12 @@ public class JuliaAddon {
|
||||
System.err.println("Vous essayez de mettre cette classe dans un package interdit ! Honte a vous");
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
} catch (IOException e) {
|
||||
System.err.println("Impossible de lire les données du fichier "+entry.getName()+" dans le jar "+jar.getName());
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.println("Le fichier "+entry.getName()+" ne d<><64>cris pas un Juliaddon valide, il n'a donc pas <20><>t<EFBFBD><74> charg<72><67>, mais faites attention !");
|
||||
System.err.println("Le fichier "+entry.getName()+" ne décris pas un Juliaddon valide, il n'a donc pas été chargé, mais faites attention !");
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
@ -181,7 +167,7 @@ public class JuliaAddon {
|
||||
while((lastPoint = pkg.lastIndexOf(".")) != -1) {//Il y a encore des dossier a monter
|
||||
pkg = pkg.substring(0, lastPoint+1);//Recule de un dossier
|
||||
if(addonsEntriesVector.containsKey(pkg)) {
|
||||
//Pas besoin de tester la validite du pkg car si invalide il ne serai pas rentr<EFBFBD><EFBFBD> dans le Set juliaddons
|
||||
//Pas besoin de tester la validite du pkg car si invalide il ne serai pas rentré dans le Set juliaddons
|
||||
addonsEntriesVector.get(pkg).add(entry);
|
||||
continue eLoop;
|
||||
}
|
||||
@ -195,7 +181,10 @@ public class JuliaAddon {
|
||||
}
|
||||
|
||||
//Initialisation du JuliaClassloader
|
||||
//Les parametres addon, pkg,version et addonCLass ont d<EFBFBD><EFBFBD>j<EFBFBD><EFBFBD> <EFBFBD><EFBFBD>t<EFBFBD><EFBFBD> initialis<EFBFBD><EFBFBD>s lors de l'it<EFBFBD><EFBFBD>ration des fichiers du jar
|
||||
//Les parametres addon, pkg,version et addonCLass ont déjà été initialisés lors de l'itération des fichiers du jar
|
||||
loadedClasses = new HashMap<>();
|
||||
for(Class<?> clazz : readClasses)
|
||||
loadedClasses.put(clazz.getName(), clazz);
|
||||
|
||||
|
||||
}
|
||||
@ -204,24 +193,7 @@ public class JuliaAddon {
|
||||
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if(loadedClasses.containsKey(name))
|
||||
return loadedClasses.get(name);
|
||||
///Recherche d'une entry qui collerai
|
||||
String fileName = name.replaceAll("\\.", "/")+".class";
|
||||
Optional<JarEntry> oentry = entries.stream().filter(je -> je.getName().equals(fileName)).findAny();
|
||||
if(oentry.isPresent()) {
|
||||
try {
|
||||
JarEntry entry = oentry.get();
|
||||
byte[] classData = new byte[(int) entry.getSize()];
|
||||
InputStream reader = jar.getInputStream(entry);
|
||||
reader.read(classData);
|
||||
reader.close();
|
||||
Class<?> clazz = defineClass(name,classData,0,(int) entry.getSize());
|
||||
loadedClasses.put(name, clazz);
|
||||
return clazz;
|
||||
} catch (IOException e) {
|
||||
System.err.println("Impossible de lire les donn<6E><6E>es du fichier "+oentry.get().getName()+" dans le jar "+jar.getName()+" je peux vous dire adieu je pense");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
JuliaClassLoader cl = laboratory.findClassLoader(name);
|
||||
if(cl != null)
|
||||
try {
|
||||
@ -299,12 +271,4 @@ public class JuliaAddon {
|
||||
|
||||
}
|
||||
|
||||
public static final class DummyLaboratory extends Julia.Laboratory{
|
||||
|
||||
public DummyLaboratory() {
|
||||
Julia.theJulia().super(Character.MIN_VALUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
package com.bernard.juliabot;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
|
||||
public class JuliaErrPrintStream extends OutputStream {
|
||||
|
||||
StringBuilder tas = new StringBuilder(2000);// Les 2000 caractères de Discord
|
||||
|
||||
Lock cadenas;
|
||||
|
||||
MessageChannel logChannel;
|
||||
|
||||
public static final int maxlength = 1900;
|
||||
|
||||
public JuliaErrPrintStream(MessageChannel logChan) {
|
||||
this.cadenas = new ReentrantLock();
|
||||
this.logChannel = logChan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int i) throws IOException {
|
||||
tas.append((char)(i));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void flushMessage() {
|
||||
if(tas.length()==0)return;
|
||||
this.cadenas.lock();
|
||||
String str = tas.toString();
|
||||
for(int i = 0; i*maxlength < tas.length();i++) {
|
||||
MessageBuilder builder = new MessageBuilder();
|
||||
builder.appendCodeBlock(str.substring(i*maxlength, Math.min((i+1)*maxlength,tas.length())), "");
|
||||
logChannel.sendMessage(builder.build()).queue();
|
||||
}
|
||||
tas = new StringBuilder();
|
||||
this.cadenas.unlock();
|
||||
|
||||
}
|
||||
|
||||
PrintStream ps = null;
|
||||
public PrintStream printStream() {
|
||||
if(ps == null)
|
||||
ps = new PrintStream(this);
|
||||
return ps;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package com.bernard.juliabot.api;
|
||||
|
||||
import com.bernard.juliabot.Julia.Laboratory;
|
||||
|
||||
public interface CCommande {
|
||||
|
||||
public Laboratory getLabo();
|
||||
|
||||
}
|
||||
@ -9,7 +9,6 @@ public @interface Command {
|
||||
public String name();
|
||||
public String[] aliases() default {};
|
||||
public String description();
|
||||
public String synopsis() default "";
|
||||
public boolean admin();//TODO a remplacer par les permissions
|
||||
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
package com.bernard.juliabot.api;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class CommandArguments {
|
||||
|
||||
List<String> nommes;
|
||||
Map<String,String> arguments;
|
||||
Set<String> flags;
|
||||
|
||||
public CommandArguments(List<String> nommes, Map<String, String> arguments, Set<String> flags) {
|
||||
this.nommes = nommes;
|
||||
this.arguments = arguments;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public List<String> getNommes() {
|
||||
return nommes;
|
||||
}
|
||||
|
||||
public Map<String, String> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public Set<String> getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public boolean hasTag(String tag) {
|
||||
return flags.contains(tag);
|
||||
}
|
||||
|
||||
public String getArgument(String name) {
|
||||
return arguments.get(name);
|
||||
}
|
||||
|
||||
public String getNomme(int pos) {
|
||||
return nommes.get(pos);
|
||||
}
|
||||
|
||||
public int getNommeCount() {
|
||||
return nommes.size();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package com.bernard.juliabot.api;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
public interface DiscordCCommande extends StringCCommande {
|
||||
|
||||
public Message getMessage();
|
||||
|
||||
public MessageChannel getChannel();
|
||||
|
||||
public User getUser();
|
||||
|
||||
public JDA getJDA();
|
||||
|
||||
public String getContentStripped();
|
||||
|
||||
public OffsetDateTime getPostDate();
|
||||
|
||||
}
|
||||
@ -11,20 +11,9 @@ import java.lang.annotation.Target;
|
||||
@Retention(RUNTIME)
|
||||
@Target(TYPE)
|
||||
public @interface JuLIAddon {
|
||||
/**
|
||||
* Le nom de l'addon
|
||||
*/
|
||||
String name();
|
||||
/**
|
||||
* La version de l'addon
|
||||
*/
|
||||
String version() default "";
|
||||
/**
|
||||
* Différentes classes, en plus de celle là, dans laquelle chercher des méthodes définissant des événements ou des commandes
|
||||
*/
|
||||
Class<?>[] searchPath() default {};
|
||||
/**
|
||||
* La liste des personnes ayant dévellopé cet addon
|
||||
*/
|
||||
public String[] devs();
|
||||
public boolean important() default false;
|
||||
}
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
package com.bernard.juliabot.api;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.bernard.juliabot.Julia;
|
||||
|
||||
public class JuliaConfig {
|
||||
|
||||
public static final String get(String name) {
|
||||
try {
|
||||
PreparedStatement st = Julia.theJulia().getJuliaDatabase().prepareStatement("SELECT * FROM juliaConfig WHERE strID=?");
|
||||
st.setString(1, name);
|
||||
ResultSet r = st.executeQuery();
|
||||
if(r.getFetchSize() == 0)
|
||||
throw new IllegalArgumentException("La configuration "+name+" n'existe pas ... veuillez la rentrer avant de la demander");
|
||||
String value = r.getString("value");
|
||||
return value;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException("Impossible de faire des requetes à la bdd de julia. Est-elle initialisée au moins ?");
|
||||
}
|
||||
}
|
||||
|
||||
public static final void set(String name, String value) {
|
||||
try {
|
||||
PreparedStatement st = Julia.theJulia().getJuliaDatabase().prepareStatement("UPDATE juliaConfig SET value=? WHERE strID=?");
|
||||
st.setString(1, value);
|
||||
st.setString(2, value);
|
||||
int r = st.executeUpdate();
|
||||
if(r == 0)
|
||||
throw new IllegalArgumentException("La configuration "+name+" n'a pas pu être modifiée ... existe-elle ?");
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException("Impossible de faire des requetes à la bdd de julia. Est-elle initialisée au moins ?");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package com.bernard.juliabot.api;
|
||||
|
||||
public interface StringCCommande extends CCommande{
|
||||
|
||||
public String getStringCommand();
|
||||
|
||||
public CommandArguments getArguments();
|
||||
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package com.bernard.juliabot.api;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import com.bernard.juliabot.Julia;
|
||||
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
|
||||
public class Trukilie {
|
||||
|
||||
public static JDA jda() {
|
||||
return Julia.theJulia().getJda();
|
||||
}
|
||||
|
||||
public static Connection juliaDB() {
|
||||
return Julia.theJulia().getJuliaDatabase();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,335 +0,0 @@
|
||||
package com.bernard.juliabot.internaddon;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import com.bernard.juliabot.CommandCalled;
|
||||
import com.bernard.juliabot.Julia;
|
||||
import com.bernard.juliabot.Julia.Laboratory;
|
||||
import com.bernard.juliabot.JuliaAddon;
|
||||
import com.bernard.juliabot.api.Command;
|
||||
import com.bernard.juliabot.api.CommandArguments;
|
||||
import com.bernard.juliabot.api.Discord;
|
||||
import com.bernard.juliabot.api.DiscordCCommande;
|
||||
import com.bernard.juliabot.api.JuLIAddon;
|
||||
import com.bernard.juliabot.api.StringCCommande;
|
||||
import com.thedeanda.lorem.LoremIpsum;
|
||||
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
|
||||
@JuLIAddon(name="internaddon", devs = "Bernard", version="beta")
|
||||
public class Internaddon {
|
||||
|
||||
public static final String COMMANDEUR = "!!";
|
||||
|
||||
@Discord(description = "LE catcheur des commandes discords. Les messages recus sont lus puis executes ici si ce sont des commandes")
|
||||
public void getCommand(MessageReceivedEvent e) {
|
||||
if(e.getMessage().getContentRaw().startsWith(COMMANDEUR)) {
|
||||
String name = e.getMessage().getContentRaw().split(" ")[0].substring(COMMANDEUR.length());
|
||||
|
||||
Laboratory labo = Julia.theJulia().getLaboratoires().get(Julia.theJulia().getLecouteur().getLabo(e));//Récupére le labo de l'évent
|
||||
InternalddonCCommande ccommande = new InternalddonCCommande(e,labo);
|
||||
try {
|
||||
CommandCalled called = labo.executeCommand(name, ccommande);
|
||||
System.out.println(called);
|
||||
}catch(IllegalArgumentException ex) {
|
||||
// La commande n'existe pas
|
||||
e.getChannel().sendMessage("Moi pas connaitre `"+name+"`. Vous apprendre moi ?").queue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Command(name = "julia", aliases="juju", description = "Répond à l'appel", admin = true)
|
||||
public void julia(DiscordCCommande commande) {
|
||||
User user = commande.getUser();
|
||||
MessageChannel channel = commande.getChannel();
|
||||
String[] julias = new String[]{"Présent !", "Présente !", "Présentbleu !", "Présentavion !", "Présent(e) !", "Présent(bleu) !",
|
||||
"Présent(avion) !", "Présent(e)(bleu) !", "Présent(e)(avion) !", "Présent(bleu)(avion) !", "Présent(e)(bleu)(avion) !",
|
||||
"Oui, c'est moi", user.getName(), "ailuJ", "42 ... oups", "C'est à moi que tu parle ?!", "Entrez c'est ouvert", "Derrière toi !!!",
|
||||
"J'ai tujorous pas cropmis a qoui ca sret l'otrahhgrope ...", "Laissez moi préparer la domination du monde en paix s'il vous plaét !",
|
||||
"Je SuIS Un RObot BZzzBzZZZbZZbZZ", "Juliaaaa dadedidadeda dedadedi dadeda", "Tutturu", "Tadaaaaaaa !"};
|
||||
String out = julias[(int)Math.floor(Math.random() * julias.length)];
|
||||
channel.sendMessage(out).queue();
|
||||
}
|
||||
|
||||
@Command(name = "help", aliases= {"ausecours","?","allahuakbar"}, description = "Laissez-vous aider par le meilleur bot du monde", admin = true)
|
||||
public void help(DiscordCCommande commande) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("```");
|
||||
|
||||
Laboratory l = commande.getLabo();
|
||||
s.append("Vous étes actuellement dans le laboratoire '"+l.getL()+"'\n");
|
||||
s.append("Liste des addons chargés :\n");
|
||||
for(JuliaAddon e : l.getLoadedAddons().values())
|
||||
s.append("\t- "+e.getName()+" en version "+e.getVersion()+"\n");
|
||||
s.append("\nListe des commandes chargées :\n");
|
||||
for(String c : l.getLoadedCommands().keySet()) {
|
||||
s.append("\t- "+c);
|
||||
String collected = l.getAliases().entrySet().stream()
|
||||
.filter(e->e.getValue().equals(c))
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.joining(", "));
|
||||
if(!collected.isEmpty())
|
||||
s.append(" a.k.a "+collected);
|
||||
if(l.getLoadedCommands().get(c).getDesc() != null)
|
||||
s.append(" :\n\t\t"+l.getLoadedCommands().get(c).getDesc());
|
||||
s.append('\n');
|
||||
}
|
||||
s.append("```");
|
||||
|
||||
commande.getChannel().sendMessage(s).queue();
|
||||
|
||||
}
|
||||
|
||||
@Command(name = "blabla", aliases= {}, description = "Pour vous prouver que je parle", admin = true)
|
||||
public void blabla(DiscordCCommande commande) {
|
||||
Message m = commande.getMessage();
|
||||
m.getChannel().sendMessage("```"+LoremIpsum.getInstance().getWords(150, 200)+"```").queue();
|
||||
m.delete();
|
||||
}
|
||||
|
||||
@Command(name = "tuerBebePhoque", aliases= {}, description = "Pour votre plaisir", admin = true)
|
||||
public void tuerBebePhoque(DiscordCCommande commande) {
|
||||
Message m = commande.getMessage();
|
||||
m.getChannel().sendMessage("http://toni.mi.free.fr/vanhebdo/actions/phoques/im_phoque_coupGourdinAssomme_Sang.jpg").queue();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Discord(description = "Arthur, par-ce que vous n'étes pas qu'une caricature")
|
||||
public void shutUp(MessageReceivedEvent e) {
|
||||
if(e.getAuthor().getIdLong() == 187677269626585089L) {//Yukimyo = L'Orchidoclaste
|
||||
|
||||
e.getChannel().sendMessage(e.getAuthor().getAsMention() +" dis du caca").queue();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Command(name = "args", description = "Décompose les messages à la Discord'", admin = true)
|
||||
public void args(DiscordCCommande commande) {
|
||||
CommandArguments ca = commande.getArguments();
|
||||
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("```"+commande.getStringCommand()+"```");
|
||||
s.append("Liste des nommes : \n");
|
||||
s.append(IntStream.range(0, ca.getNommeCount()).mapToObj(i -> "\t"+i+" : `"+ca.getNomme(i)+"`").collect(Collectors.joining("\n")));
|
||||
s.append("\nListe des flags : \n");
|
||||
s.append(ca.getFlags().stream().map(f->"\t`"+f+"`").collect(Collectors.joining("\n")));
|
||||
s.append("\nListe des arguments : \n");
|
||||
|
||||
commande.getMessage().getChannel().sendMessage(s).queue();
|
||||
|
||||
}
|
||||
|
||||
@Command(name="guilds", description = "Liste les guildes disponibles",admin=true)
|
||||
public void guilds(DiscordCCommande commande) {
|
||||
MessageBuilder mb = new MessageBuilder();
|
||||
mb.append("Liste des serveurs :\n");
|
||||
Julia.theJulia().getJda().getGuilds()
|
||||
.stream()
|
||||
.map(g -> g.getName() + "(" + g.getMemberCount() + " membres, id:" + g.getId() + ")\n")
|
||||
.forEach(mb::append);;
|
||||
commande.getChannel().sendMessage(mb.build()).complete();
|
||||
}
|
||||
|
||||
@Command(name="update",description = "Met a jour le dossier des addons",admin=true)
|
||||
public void update(StringCCommande commande) {
|
||||
|
||||
Julia.theJulia().update();
|
||||
|
||||
}
|
||||
|
||||
@Command(name="load",description = "Charge l'addon dans ce laboratoire",admin=true)
|
||||
public void load(DiscordCCommande commande) {
|
||||
|
||||
CommandArguments cc = commande.getArguments();
|
||||
|
||||
String addonName = cc.getNomme(1);
|
||||
String version = cc.getNomme(2);
|
||||
|
||||
Laboratory l = commande.getLabo();
|
||||
|
||||
String out = "Terminé avec succés";
|
||||
try {
|
||||
l.loadAddon(addonName, version);
|
||||
}catch (Exception e) {
|
||||
out = "```"+e.getClass().toString()+"\n"+e.getMessage()+"```";
|
||||
}
|
||||
commande.getChannel().sendMessage(out);
|
||||
}
|
||||
|
||||
@Command(name="unload",description = "Décharge l'addon de ce laboratoire",admin=true)
|
||||
public void unload(DiscordCCommande commande) {
|
||||
|
||||
CommandArguments cc = commande.getArguments();
|
||||
|
||||
String addonName = cc.getNomme(1);
|
||||
|
||||
Laboratory l = commande.getLabo();
|
||||
|
||||
String out = "Terminé avec succés";
|
||||
try {
|
||||
l.unloadAddon(addonName);
|
||||
}catch (Exception e) {
|
||||
out = "```"+e.getClass().toString()+"\n"+e.getMessage()+"```";
|
||||
}
|
||||
commande.getChannel().sendMessage(out);
|
||||
|
||||
}
|
||||
|
||||
@Command(name="caca",description = "Déclanche une exception ... Faut bien tester, hein !",admin=true)
|
||||
public void caca(DiscordCCommande commande) {
|
||||
throw new IllegalStateException("Nan mais tout va bien ... je fait ce qu'on m'a demandé ^^");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class InternalddonCCommande implements DiscordCCommande,StringCCommande{
|
||||
|
||||
Message m;
|
||||
Laboratory labo;
|
||||
|
||||
public InternalddonCCommande(MessageReceivedEvent e,Laboratory labo) {
|
||||
m = e.getMessage();
|
||||
this.labo = labo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringCommand() {
|
||||
return m.getContentRaw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandArguments getArguments() {
|
||||
return parseCommandArguments(getStringCommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessage() {
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageChannel getChannel() {
|
||||
return m.getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUser() {
|
||||
return m.getAuthor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JDA getJDA() {
|
||||
return m.getJDA();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentStripped() {
|
||||
return m.getContentStripped();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffsetDateTime getPostDate() {
|
||||
return m.getTimeCreated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Laboratory getLabo() {
|
||||
return labo;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static CommandArguments parseCommandArguments(String raw) {
|
||||
|
||||
List<String> nommes = new ArrayList<String>();
|
||||
Map<String,String> arguments = new HashMap<>();
|
||||
Set<String> flags = new HashSet<>();
|
||||
|
||||
String state = "n";
|
||||
String reading = "";
|
||||
|
||||
List<String> stringized = new ArrayList<>();
|
||||
|
||||
for(String morceau : raw.split(" ")) {
|
||||
|
||||
if(state.equals("n")) {
|
||||
|
||||
if(morceau.isEmpty())
|
||||
continue;
|
||||
if(morceau.startsWith("\"") || morceau.startsWith("`")) {
|
||||
state = String.valueOf(morceau.charAt(0));
|
||||
morceau = morceau.substring(1);
|
||||
}else {
|
||||
stringized.add(morceau);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
if(state.equals("\"") || state.equals("`")) {
|
||||
if(morceau.isEmpty()) {
|
||||
reading += " ";
|
||||
continue;
|
||||
|
||||
}
|
||||
if(morceau.endsWith(state)) {
|
||||
reading += morceau.substring(0, morceau.length()-1);
|
||||
stringized.add(reading);
|
||||
reading = "";
|
||||
state = "n";
|
||||
continue;
|
||||
}
|
||||
reading += morceau + " ";
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
for(String morceau : stringized) {
|
||||
|
||||
if(state.equals("n")) {
|
||||
|
||||
if(morceau.isEmpty())
|
||||
continue;
|
||||
|
||||
if(morceau.startsWith("--")) {
|
||||
state = "#"+morceau.substring(2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(morceau.startsWith("-")) {
|
||||
flags.add(morceau.substring(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
nommes.add(morceau);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(state.startsWith("#")) {
|
||||
arguments.put(state.substring(1), morceau);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new CommandArguments(nommes, arguments, flags);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
package com.bernard.juliabot.internaddon;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
public class UnstableMessage extends OutputStream{
|
||||
|
||||
MConsumer thisConsumer = new MConsumer();
|
||||
|
||||
public UnstableMessage(Message m) {
|
||||
// TODO Auto-generated constructor stub
|
||||
m.editMessage(""/* a préciser */).queue(thisConsumer, (e) -> {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(int arg0) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public class MConsumer implements Consumer<Message>{
|
||||
@Override
|
||||
public void accept(Message arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user