diff --git a/.classpath b/.classpath
index 9f1f1b2..7159d62 100644
--- a/.classpath
+++ b/.classpath
@@ -15,5 +15,10 @@
+
+
+
+
+
diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md
index 989ea8d..f9e35e9 100644
--- a/STYLEGUIDE.md
+++ b/STYLEGUIDE.md
@@ -31,14 +31,14 @@ if(bar)
```
#### Naming
-Class names and function names are `PascalCase`. Variable names are `camelCase`.
+Class, Interface, and Enum names are `PascalCase`. Variable and function names are `camelCase`. Interfaces in particular must begin with a capital `I`.
```java
-public class MyClass
+public class MyClass implements IClass
{
private Foo myVariable;
- public function MyFuction()
+ public function myFuction()
{
// ...
}
diff --git a/assets/commands.config b/assets/commands.config
deleted file mode 100644
index e2280cb..0000000
--- a/assets/commands.config
+++ /dev/null
@@ -1,59 +0,0 @@
-[CommandEnabler]
-beans=1
-benchmark, bench=1
-bet=1
-bethistory=1
-blur=1
-boop=1
-buildhelp=1
-c++, g++, cplus, cpp=1
-catch=1
-charactercreate=1
-charactereditbio=1
-charactereditname=1
-characterediturl=1
-choose=1
-color, colour=1
-crouton=1
-dbflush=1
-dbstats=1
-eightball, 8ball=1
-fetch=1
-givebeans=1
-guildroleadd=1
-guildroleallowed=1
-guildrolelist=1
-guildrolenotallowed=1
-guildroleremove=1
-help=1
-indicator=1
-info, about=1
-invite=1
-java, jdoodle=1
-leaderboard=1
-map=1
-perish, thenperish=1
-ping=1
-poll=1
-raffleend=1
-rafflejoin=1
-rafflespin=1
-rafflestart=1
-rating=1
-results=1
-role=1
-roll=1
-rpend=1
-rpg=1
-rpstart=1
-searchcharacter=1
-showpoll=1
-shutdown=1
-stats=1
-teey=1
-tony, stark, dontfeelgood, dontfeelsogood=1
-tweet=1
-vote=1
-wolfram=1
-work=1
-yeet=1
diff --git a/assets/config.csv b/assets/config.csv
new file mode 100644
index 0000000..1a3409e
--- /dev/null
+++ b/assets/config.csv
@@ -0,0 +1,319 @@
+"Type","Key","Value"
+"Localized Commands","beans",""
+"Localized Commands","benchmark, bench",""
+"Localized Commands","bet",""
+"Localized Commands","bethistory",""
+"Localized Commands","blur",""
+"Localized Commands","boop",""
+"Localized Commands","buildHelp",""
+"Localized Commands","c++, g++, cplus, cpp",""
+"Localized Commands","catch",""
+"Localized Commands","charactercreate",""
+"Localized Commands","charactereditbio",""
+"Localized Commands","charactereditname",""
+"Localized Commands","charactereditURL",""
+"Localized Commands","choose",""
+"Localized Commands","color, colour",""
+"Localized Commands","crouton",""
+"Localized Commands","dbflush",""
+"Localized Commands","dbstats",""
+"Localized Commands","defaultdance",""
+"Localized Commands","derp",""
+"Localized Commands","e621",""
+"Localized Commands","eightball, 8ball",""
+"Localized Commands","fetch",""
+"Localized Commands","givebeans",""
+"Localized Commands","guildroleadd",""
+"Localized Commands","guildroleallowed",""
+"Localized Commands","guildrolelist",""
+"Localized Commands","guildrolenotallowed","guildrolenotallowed, rolelistremove"
+"Localized Commands","guildroleremove",""
+"Localized Commands","help",""
+"Localized Commands","indicator",""
+"Localized Commands","info, about",""
+"Localized Commands","invite",""
+"Localized Commands","java, jdoodle",""
+"Localized Commands","kittyrole",""
+"Localized Commands","leaderboard",""
+"Localized Commands","map",""
+"Localized Commands","perish, thenperish",""
+"Localized Commands","ping",""
+"Localized Commands","poll",""
+"Localized Commands","raffleend",""
+"Localized Commands","rafflejoin",""
+"Localized Commands","rafflespin",""
+"Localized Commands","rafflestart",""
+"Localized Commands","rating",""
+"Localized Commands","remind",""
+"Localized Commands","results",""
+"Localized Commands","role",""
+"Localized Commands","roll",""
+"Localized Commands","rpend",""
+"Localized Commands","rpg",""
+"Localized Commands","rpstart",""
+"Localized Commands","searchcharacter",""
+"Localized Commands","showpoll",""
+"Localized Commands","shutdown",""
+"Localized Commands","stats",""
+"Localized Commands","teey",""
+"Localized Commands","tony, stark, dontfeelgood, dontfeelsogood","tony, stark, dontfeelgood, dontfeelsogood, snap"
+"Localized Commands","tweet",""
+"Localized Commands","vote",""
+"Localized Commands","wolfram",""
+"Localized Commands","work",""
+"Localized Commands","yeet",""
+"Localized Strings","AddGuildRoleFailure","Failed to add %s to %s"
+"Localized Strings","BeansShowDisplay","You have %s beans!"
+"Localized Strings","BeansShowInfo","Displays how many beans you have"
+"Localized Strings","BeansShowMentioned","I took a look and %sbeans!"
+"Localized Strings","BenchmarkInfo","Allows you to lookup PC component benchmarks from UserBenchmark! You can use `bench find "
+"Localized Strings","BenchmarkInvalid","The benchmark operation you were trying to perform was invalid!"
+"Localized Strings","BetBeansInfo","Allows you to bet your beans, set your amount after the command! Warning! House always wins!nSets of 3 will get 2x, 4 will get 10x, and 5 will get 1000x"
+"Localized Strings","BetBeansLose","Sorry, you didn't win, try again!"
+"Localized Strings","BetBeansLowBet","Please bet with at least 20 beans!"
+"Localized Strings","BetBeansNotEnough","You don't have enough beans!"
+"Localized Strings","BetBeansNotValid","That's not a valid bet!"
+"Localized Strings","BetBeansWin","You won %s beans!"
+"Localized Strings","BetHistoryInfo","Gives how many beans I've ~~stolen~~ won from your bets!"
+"Localized Strings","BetHistoryOutput","I have %s treats from betting!"
+"Localized Strings","BlurryInfo","Blurs your icon or the icon of a friend you mentioned"
+"Localized Strings","BoopInfo","Kitty will react with a counter"
+"Localized Strings","BoopMultiple","%s booped several others - %s!"
+"Localized Strings","BoopPerson","%s booped %s!"
+"Localized Strings","BoopStandard","Woah! %s booped me! That's %s total!"
+"Localized Strings","CatchInfo","Play catch with yourself or with a friend with @!"
+"Localized Strings","ChangeIndicatorChanged","Indicator changed to `%s`"
+"Localized Strings","ChangeIndicatorError","Please specify a letter or symbol to use!"
+"Localized Strings","ChangeIndicatorInfo","Changes the command indicator to any single character. By default, it's '!'. If more than one character is provided, the first one is used!"
+"Localized Strings","CharacterCreateDuplicate",""
+"Localized Strings","CharacterCreateInfo",""
+"Localized Strings","CharacterCreateNullInfo",""
+"Localized Strings","CharacterCreateSuccess",""
+"Localized Strings","CharacterEditBioInfo","Change the short bio for your character! "
+"Localized Strings","CharacterEditBioNotAuth","You're not authorized to change that character! "
+"Localized Strings","CharacterEditBioNotValid",""
+"Localized Strings","CharacterEditBioSuccess","Successfully changed your bio! "
+"Localized Strings","CharacterEditNameInfo","Change your character's name!"
+"Localized Strings","CharacterEditNameNotAuth","You're not authorized to change that character! "
+"Localized Strings","CharacterEditNameNotValid","That's not a vaild name!"
+"Localized Strings","CharacterEditNameSuccess","Successfully changed your name!"
+"Localized Strings","CharacterEditURLInfo","Change the image URL for your character's reference! "
+"Localized Strings","CharacterEditURLNotAuth","You're not authorized to change that character! "
+"Localized Strings","CharacterEditURLNotValid","That's not a valid url! "
+"Localized Strings","CharacterEditURLSuccess","Successfully changed your reference! "
+"Localized Strings","CharacterInfo",""
+"Localized Strings","CharacterSearchInfo","Find a character with their name or Unique ID! `charactersearch name` or `charactersearch UniqueID`"
+"Localized Strings","CharacterSearchMultipleCharacter","%s is owned by %s. Unique ID is `%s`"
+"Localized Strings","CharacterSearchMultipleCharacterHeader","I found a couple characters with that name, use `charactersearch UniqueID` with their Unique ID to find them!"
+"Localized Strings","CharacterSearchNoCharacterFound","Couldn't find a character with that name or ID!"
+"Localized Strings","CharacterSearchOneCharacter","I found one character with that name! n Owner: %s | Name: %s | Bio: %s | Ref: <%s> | Unique ID: `%s`"
+"Localized Strings","ChooseChoice","I chooooooose %s!"
+"Localized Strings","ChooseInfo","With an input of x,y,z where x y and z are all choices, kitty will choose one"
+"Localized Strings","ChooseOne","I can't choose from *one* thing!"
+"Localized Strings","ColiruError","Please provide some c++ code to attempt to compile!"
+"Localized Strings","ColiruInfo","Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++."
+"Localized Strings","ColorInfo","Looks up the provided hex color and outputs it as hex, rgb, hsl, hsv, xyz, and cmyk. Also attempts to name the color, and provies a sample of it! Usage example: `!color #365345` (the # can be omitted)"
+"Localized Strings","ColorNotSearchable","Your color couldn't be parsed! Make sure it's in hex format. Try this! `!color 3F5D54`"
+"Localized Strings","CroutonInfo","Crouton"
+"Localized Strings","DBFlushInfo","Takes all objects queued for the database and writes them to the database, then says how many were written."
+"Localized Strings","DBStatsInfo","Shows current statistics for the database"
+"Localized Strings","DefaultDanceInfo","y'all know forknife, get ready to dance, or make a friend dance with @!"
+"Localized Strings","DoWorkFinished","I finished with my work! :D"
+"Localized Strings","DoWorkInfo","Occupies a core for a few seconds"
+"Localized Strings","EightBallError","Hmm? You'll need to ask a question!"
+"Localized Strings","EightBallInfo","Answers a yes or no question! Warning: Kitty can not actually tell the future, she claims no responsibility for any lion mauling, lack of lottery wins, or felony charges."
+"Localized Strings","EightBallMaybe1","Reply hazy, try again."
+"Localized Strings","EightBallMaybe2","Ask again later."
+"Localized Strings","EightBallMaybe3","Better not tell you now."
+"Localized Strings","EightBallMaybe4","Cannot predict now."
+"Localized Strings","EightBallMaybe5","Concentrate and ask again."
+"Localized Strings","EightBallNo1","Don't count on it."
+"Localized Strings","EightBallNo2","My reply is no."
+"Localized Strings","EightBallNo3","My sources say no."
+"Localized Strings","EightBallNo4","Outlook not so good."
+"Localized Strings","EightBallNo5","Very doubtful."
+"Localized Strings","EightBallYes1","It is certain."
+"Localized Strings","EightBallYes10","Signs point to yes."
+"Localized Strings","EightBallYes2","It is decidedly so."
+"Localized Strings","EightBallYes3","Without a doubt."
+"Localized Strings","EightBallYes4","Yes - definitely."
+"Localized Strings","EightBallYes5","You may rely on it."
+"Localized Strings","EightBallYes6","As I see it, yes."
+"Localized Strings","EightBallYes7","Most likely."
+"Localized Strings","EightBallYes8","Outlook good."
+"Localized Strings","EightBallYes9","Yes."
+"Localized Strings","FetchBringBack","Got it! %s"
+"Localized Strings","FetchBringBackWrong","Got it! %s"
+"Localized Strings","FetchCatchRun","*Catches and runs away with %s*"
+"Localized Strings","FetchEat","Mine now! *munches on %s*"
+"Localized Strings","FetchError","That's not a custom emote!"
+"Localized Strings","FetchInfo","Throw a custom emote and I'll try to bring it back.... maybe"
+"Localized Strings","FetchRunAway","*Runs away and doesn't return for a long time*"
+"Localized Strings","FetchStare","*Stares at %s*"
+"Localized Strings","GiveBeansInfo","Gives beans to the mentioned users!"
+"Localized Strings","GiveBeansInvalid","That's not a valid number!"
+"Localized Strings","GiveBeansNoneMentioned","You didn't mention anyone!"
+"Localized Strings","GiveBeansSuccess","Gave %s %s beans!"
+"Localized Strings","GuildRoleAddFailure",""
+"Localized Strings","GuildRoleAddInfo","Add a role to yourself!"
+"Localized Strings","GuildRoleAddNotAllowed","You are not allowed to add %s!"
+"Localized Strings","GuildRoleAddSuccess","Added %s to %s"
+"Localized Strings","GuildRoleAllowedDuplicate","Can't add the same role twice!"
+"Localized Strings","GuildRoleAllowedInfo","Adds role to the list of roles users are allowed to add to themselves."
+"Localized Strings","GuildRoleAllowedSuccess","Added %s to the allowed roles!"
+"Localized Strings","GuildRoleInfo",""
+"Localized Strings","GuildRoleListEmpty",""
+"Localized Strings","GuildRoleListOutput","You can add these roles! %s"
+"Localized Strings","GuildRoleNotAllowedFailure","Unable to remove %s from the list!"
+"Localized Strings","GuildRoleNotAllowedInfo","Removes a role from the list that users are allowed to add to themselves."
+"Localized Strings","GuildRoleNotAllowedNoArgs",""
+"Localized Strings","GuildRoleNotAllowedSuccess","Removed %s from the allowed roles!"
+"Localized Strings","GuildRoleRemoveFailure","I wasn't able to remove %s from %s!"
+"Localized Strings","GuildRoleRemoveInfo","Removes a role from you! Just remember to spell it right!"
+"Localized Strings","GuildRoleRemoveNotAllowed","You're not allowed to add %s!"
+"Localized Strings","GuildRoleRemoveSuccess","Removed %s from %s!"
+"Localized Strings","HelpBuilderInfo","Emit help for all commands as formatted HTML"
+"Localized Strings","HelpDisplay","You can get help with a specific command by typing `!help command`! General Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`"
+"Localized Strings","HelpInfo","Lets you look up specific commands, or get a link to a list of all commands."
+"Localized Strings","InfoInfo","Provides author info and a link to Kitty's website"
+"Localized Strings","InfoResponse","I'm made by `Rin#8904` and `Reverie Wisp#3703`! You can find more info about me along with a Patreon link to support us and GitHub link for filing bugs https://kittybot.net"
+"Localized Strings","InviteInfo","Provides a direct invite link for KittyBot"
+"Localized Strings","JDoodleError","Please provide some java code to get it compiled!"
+"Localized Strings","JDoodleInfo","Will compile any java code you put in! Supports Java 1.8"
+"Localized Strings","LeaderboardInfo","Shows you the 10 users with the most beans on the server"
+"Localized Strings","LeaderboardTitle","Server Leaderboard"
+"Localized Strings","MapHeight",""
+"Localized Strings","MapInfo","Generates a map! You can pass additional information if you want with the flags `-s`. If one of the fields isn't provided, its default will be used. Note that adjusting the width and height impacts the map outcomes.nn**Defaults**nDefault Seed: Random,nDefault Width: 35(max %s),nDefault Height: 25(max %s)nn**Key**nLand: ~nMountain: ▲nBeach: "
+"Localized Strings","MapInvalid","Invalid arguments provided!"
+"Localized Strings","MapSeed","Seed"
+"Localized Strings","MapVersion","Using mapgen v0.1"
+"Localized Strings","MapWidth",""
+"Localized Strings","PerishInfo","Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned"
+"Localized Strings","PingInfo","Will respond with Pong!"
+"Localized Strings","PingResponse","Pong!"
+"Localized Strings","PollManageInfo","'start' will start a new poll with the query of the line you put after, 'choice' will add a choice to the poll, 'stop' will end the poll"
+"Localized Strings","PollResultsInfo","Will show current results of a poll and percentages of votes per choice"
+"Localized Strings","PollResultsResponse","%s people voted for %s `%s` with `%s%` !n"
+"Localized Strings","PollShowChoices","And the choices are:n"
+"Localized Strings","PollShowInfo","Will show the current poll running"
+"Localized Strings","PollShowNoPoll","There is no poll running!"
+"Localized Strings","PollShowPoll","The current poll is `%s`n"
+"Localized Strings","PollVoteAlreadyVoted","You already voted"
+"Localized Strings","PollVoteInfo","Vote in a poll with the choice number, won't work if no poll is running, you can't change your vote once you have cast it! Be careful!"
+"Localized Strings","PollVoteNoPoll","There is no poll running!"
+"Localized Strings","PollVoteNotValidNumber","That's not a vaild number!"
+"Localized Strings","PollVoteNotValidVote","%s That's not a vaild vote!"
+"Localized Strings","PollVoteSuccess","You successfully voted for"
+"Localized Strings","RaffleEndFailure","I don't think there's one going!"
+"Localized Strings","RaffleEndInfo",""
+"Localized Strings","RaffleEndSuccess",""
+"Localized Strings","RaffleJoinFailure",""
+"Localized Strings","RaffleJoinInfo",""
+"Localized Strings","RaffleJoinSuccess",""
+"Localized Strings","RaffleSpinFailure","I can't choose a winner D:"
+"Localized Strings","RaffleSpinInfo",""
+"Localized Strings","RaffleSpinSuccess","The winner issssssss %s!"
+"Localized Strings","RaffleStartFailure",""
+"Localized Strings","RaffleStartInfo",""
+"Localized Strings","RaffleStartSuccess",""
+"Localized Strings","RatingChanged","Kittybot content set to %s"
+"Localized Strings","RatingInfo","'0' is fully sfw (Derpi and e621 searches are disabled), '1' is filtered (kitty auto appends a sfw tag on any searches), '2' is nsfw (any search will go through). Some other words are supported for setting filter as well."
+"Localized Strings","RatingInvalid","Invalid content rating"
+"Localized Strings","RatingWarning","Warning: NSFW may slip through, images are only based on tags on their respective sites!"
+"Localized Strings","RemindInfo",""
+"Localized Strings","RoleChanged","Changed %s to role `%s`!"
+"Localized Strings","RoleError","You aren't allowed to do that! You must have the KittyRole '%' or higher!"
+"Localized Strings","RoleInfo","Will show the current role you have, Admins can change others roles with input of 'role x @y' with x being blacklist, general, mod, or admin. Blacklist will not allow the user to interact with kitty anymore, general mod and admin will give the user access to those commands."
+"Localized Strings","RoleNeededRole","Please enter `general`, `mod`, or `admin`!"
+"Localized Strings","RoleStandardResponse","Your role is %s"
+"Localized Strings","RollError","Didn't work ;3;"
+"Localized Strings","RollInfo","Based on input of xdy where x is number of dice and y is faces kitty will roll that amount of dice, display the individual rolls and total"
+"Localized Strings","RPEndError","You can't end this RP!"
+"Localized Strings","RPEndFileOut","Here's your file!"
+"Localized Strings","RPEndInfo","Ends RP in channel and gives you a .txt file!"
+"Localized Strings","RPGInfo","Admin+ command only right now - experimental text RPG! Format is !rpg "
+"Localized Strings","RPGInvalid","Invalid RPG Command!"
+"Localized Strings","RPStartInfo","Starts an rp, add people to it by mentioning them!"
+"Localized Strings","ShutdownInfo","Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown."
+"Localized Strings","ShutdownSafe",""
+"Localized Strings","ShutdownUnsafe",""
+"Localized Strings","StarkInfo","Snaps your icon or the icon of a friend you mentioned"
+"Localized Strings","StatsInfo","Displays the actively running KittyBot application information"
+"Localized Strings","TeeyInfo","Teey yourself back into existance, or teey a friend with @!"
+"Localized Strings","TradeBeansInfo","Give your friends some of your beans! Just don't forget to @ them!"
+"Localized Strings","TradeBeansIntParseError","That's not a real number! D:"
+"Localized Strings","TradeBeansNoTargetError","Don't forget to tag who you want to give the beans to!"
+"Localized Strings","TradeBeansNotEnoughError","You can't give more beans than you have!"
+"Localized Strings","TradeBeansStealingBeans","Hey %s! Stealing is wrong! Let's see how you like it! *steals 10 beans*"
+"Localized Strings","TradeBeansSuccess","%s gave %s %s beans!"
+"Localized Strings","TweetError","Tweet command failed!"
+"Localized Strings","TweetInfo","Kitty will tweet to her personal twitter account"
+"Localized Strings","WolframError","Something went wrong!"
+"Localized Strings","WolframInfo","Will query wolframalpha with your question and give a full image output of the answer"
+"Localized Strings","WolframNoArgs","You need to provide some arguments!"
+"Localized Strings","YeetInfo","Yeet yourself or yeet a friend with @!"
+"Command Enabler","addguildrole","1"
+"Command Enabler","allowedguildrole","1"
+"Command Enabler","beans","1"
+"Command Enabler","benchmark, bench","1"
+"Command Enabler","bet","1"
+"Command Enabler","bethistory","1"
+"Command Enabler","blur","1"
+"Command Enabler","boop","1"
+"Command Enabler","buildhelp","1"
+"Command Enabler","c++, g++, cplus, cpp","1"
+"Command Enabler","catch","1"
+"Command Enabler","charactercreate","1"
+"Command Enabler","charactereditbio","1"
+"Command Enabler","charactereditname","1"
+"Command Enabler","characterediturl","1"
+"Command Enabler","choose","1"
+"Command Enabler","color, colour","1"
+"Command Enabler","crouton","1"
+"Command Enabler","dbflush","1"
+"Command Enabler","dbstats","1"
+"Command Enabler","defaultdance","1"
+"Command Enabler","derp","1"
+"Command Enabler","e621","1"
+"Command Enabler","eightball, 8ball","1"
+"Command Enabler","fetch","1"
+"Command Enabler","givebeans","1"
+"Command Enabler","guildroleadd","1"
+"Command Enabler","guildroleallowed","1"
+"Command Enabler","guildrolelist","1"
+"Command Enabler","guildrolenotallowed","1"
+"Command Enabler","guildroleremove","1"
+"Command Enabler","help","1"
+"Command Enabler","indicator","1"
+"Command Enabler","info, about","1"
+"Command Enabler","invite","1"
+"Command Enabler","java, jdoodle","1"
+"Command Enabler","kittyrole","1"
+"Command Enabler","leaderboard","1"
+"Command Enabler","map","1"
+"Command Enabler","perish, thenperish","1"
+"Command Enabler","ping","1"
+"Command Enabler","poll","1"
+"Command Enabler","raffleend","1"
+"Command Enabler","rafflejoin","1"
+"Command Enabler","rafflespin","1"
+"Command Enabler","rafflestart","1"
+"Command Enabler","rating","1"
+"Command Enabler","remind","1"
+"Command Enabler","results","1"
+"Command Enabler","role","1"
+"Command Enabler","roll","1"
+"Command Enabler","rpend","1"
+"Command Enabler","rpg","1"
+"Command Enabler","rpstart","1"
+"Command Enabler","searchcharacter","1"
+"Command Enabler","showpoll","1"
+"Command Enabler","shutdown","1"
+"Command Enabler","stats","1"
+"Command Enabler","teey","1"
+"Command Enabler","tony, stark, dontfeelgood, dontfeelsogood","1"
+"Command Enabler","tweet","1"
+"Command Enabler","vote","1"
+"Command Enabler","wolfram","1"
+"Command Enabler","work","1"
+"Command Enabler","yeet","1"
diff --git a/assets/locCommands.config b/assets/locCommands.config
deleted file mode 100644
index 75cb78a..0000000
--- a/assets/locCommands.config
+++ /dev/null
@@ -1,61 +0,0 @@
-[ObjectBuilderFactory]
-indicator=
-yeet=
-guildroleremove=
-bethistory=
-benchmark, bench=
-rating=
-poll=
-rafflespin=
-charactereditURL=
-bet=
-guildrolelist=
-stats=
-catch=
-color, colour=
-guildroleadd=
-results=
-wolfram=
-givebeans=
-c++, g++, cplus, cpp=
-work=
-rpend=
-java, jdoodle=
-rafflejoin=
-guildroleallowed=
-leaderboard=
-buildHelp=
-dbflush=
-shutdown=
-boop=
-tony, stark, dontfeelgood, dontfeelsogood=
-role=
-raffleend=
-ping=
-charactereditbio=
-roll=
-blur=
-choose=
-rpstart=
-guildrolenotallowed=
-perish, thenperish=
-teey=
-searchcharacter=
-dbstats=
-rafflestart=
-beans=
-eightball, 8ball=
-vote=
-map=
-info, about=
-showpoll=
-rpg=
-tweet=
-charactercreate=
-help=
-charactereditname=
-fetch=
-crouton=
-invite=
-
-
diff --git a/assets/locStrings.config b/assets/locStrings.config
deleted file mode 100644
index d402f1e..0000000
--- a/assets/locStrings.config
+++ /dev/null
@@ -1,309 +0,0 @@
-[CommandBenchmark]
-BenchmarkInfo=Allows you to lookup PC component benchmarks from UserBenchmark! You can use `bench find ` to see what's in the database, `bench info ` to look at a specific component, or the experimental `bench compare` commands!
-BenchmarkInvalid=The benchmark operation you were trying to perform was invalid!
-
-[CommandPollManage]
-PollManageInfo='start' will start a new poll with the query of the line you put after, 'choice' will add a choice to the poll, 'stop' will end the poll
-
-[CommandGuildRoleNotAllowed]
-GuildRoleNotAllowedFailure=
-GuildRoleNotAllowedSuccess=
-GuildRoleNotAllowedInfo=
-
-[CommandBetHistory]
-BetHistoryOutput=Kitty has %s beans!
-BetHistoryInfo=Sees the amount of beans Kitty has earned through your bets!
-
-[CommandCatch]
-CatchInfo=Play catch with yourself or with a friend with @!
-
-[CommandLeaderboard]
-LeaderboardInfo=Shows you the 10 users with the most beans on the server
-LeaderboardTitle=Server Leaderboard
-
-[CommandGuildRoleList]
-GuildRoleListOutput=The allowed roles are %s!
-GuildRoleListEmpty=There are no roles allowed!
-GuildRoleListInfo=Outputs a list of the roles you are allowed to add to yourself!
-
-[CommandRoll]
-RollError=Didn't work ;3;
-RollInfo=Based on input of xdy where x is number of dice and y is faces kitty will roll that amount of dice, display the individual rolls and total
-
-[CommandGuildRoleAllowed]
-GuildRoleAllowedInfo=
-GuildRoleAllowedSuccess=Added %s to the allowed roles!
-GuildRoleAllowedDuplicate=Can't add the same role twice!
-
-[CommandStats]
-StatsInfo=Displays the actively running KittyBot application information
-
-[CommandRole]
-RoleInfo=Will show the current role you have, Admins can change others roles with input of 'role x @y' with x being blacklist, general, mod, or admin. Blacklist will not allow the user to interact with kitty anymore, general mod and admin will give the user access to those commands.
-RoleStandardResponse=Your role is %s
-RoleError=You aren't allowed to do that! You must have the KittyRole '%s' or higher!
-RoleChanged=Changed %s to role `%s`!
-RoleNeededRole=Please enter `general`, `mod`, or `admin`!
-
-[CommandJDoodle]
-JDoodleInfo=Will compile any java code you put in! Supports Java 1.8
-JDoodleError=Please provide some java code to get it compiled!
-
-[CommandChangeIndicator]
-ChangeIndicatorInfo=Changes the command indicator to any single character. By default, it's '!'. If more than one character is provided, the first one is used!
-ChangeIndicatorError=Please specify a letter or symbol to use!
-ChangeIndicatorChanged=Indicator changed to `%s`
-
-[CommandPerish]
-PerishInfo=Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned
-
-[CommandTradeBeans]
-TradeBeanseStealingBeans=Stealing is wrong! *Steals 10 beans from %s*
-TradeBeansNoTargetError=You have to give *someone* your beans!
-TradeBeansSuccess=%s gave %s %s of their beans!
-TradeBeansStealingBeans=
-TradeBeansInfo=Gives another person some of your beans! Use is `tradebeans amount @person`!
-TradeBeansIntParseError=That's not a real number!
-TradeBeansNotEnoughError=You don't have enough beans!
-
-[CommandPollVote]
-PollVoteNotValidNumber=That's not a vaild number!
-PollVoteInfo=Vote in a poll with the choice number, won't work if no poll is running, you can't change your vote once you have cast it! Be careful!
-PollVoteNoPoll=There is no poll running!
-PollVoteAlreadyVoted=You already voted
-PollVoteNotValidVote=%s That's not a vaild vote!
-PollVoteSuccess=You successfully voted for
-
-[CommandShutdown]
-ShutdownSafe=Shutting down, but first syncing database and finishing current threads.
-ShutdownUnsafe=Shutting down and immediately and abandoning all threads without sync.
-ShutdownInfo=Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown.
-
-[CommandRaffleSpin]
-RaffleSpinInfo=
-RaffleSpinSuccess=The winner issssssss %s!
-RaffleSpinFailure=I can't choose a winner D:
-
-[CommandRaffleEnd]
-RaffleEndSuccess=
-RaffleEndInfo=
-RaffleEndFailure=I don't think there's one going!
-
-[CommandCharacterSearch]
-CharacterSearchNoCharacterFound=Couldn't find a character with that name or ID!
-CharacterSearchMultipleCharacterHeader=I found a couple characters with that name, use `charactersearch UniqueID` with their Unique ID to find them!
-CharacterSearchMultipleCharacter=%s is owned by %s. Unique ID is `%s`
-CharacterSearchOneCharacter=I found one character with that name! \n Owner: %s | Name: %s | Bio: %s | Ref: <%s> | Unique ID: `%s`
-CharacterSearchInfo=Find a character with their name or Unique ID! `charactersearch name` or `charactersearch UniqueID`
-
-[CommandColor]
-ColorNotSearchable=Your color couldn't be parsed! Make sure it's in hex format. Try this! `!color 3F5D54`
-ColorInfo=Looks up the provided hex color and outputs it as hex, rgb, hsl, hsv, xyz, and cmyk. Also attempts to name the color, and provies a sample of it! Usage example: `!color #365345` (the # can be omitted)
-
-[CommandDoWork]
-DoWorkFinished=I finished with my work! :D
-DoWorkInfo=Occupies a core for a few seconds
-
-[CommandRPStart]
-RPStartInfo=Starts an rp, add people to it by mentioning them!
-
-[CommandBlurry]
-BlurryInfo=Blurs your icon or the icon of a friend you mentioned
-
-[CommandRating]
-RatingInfo='0' is fully sfw (Derpi and e621 searches are disabled), '1' is filtered (kitty auto appends a sfw tag on any searches), '2' is nsfw (any search will go through). Some other words are supported for setting filter as well.
-RatingWarning=Warning: NSFW may slip through, images are only based on tags on their respective sites!
-RatingChanged=Kittybot content set to
-RatingInvalid=Invalid content rating
-
-[CommandDBStats]
-DBStatsInfo=
-
-[CommandGiveBeans]
-GiveBeansNoneMentioned=You didn't mention anyone!
-GiveBeansSuccess=Gave %s %s beans!
-GiveBeansInvalid=That's not a valid number!
-GiveBeansInfo=Gives beans to the mentioned users!
-
-[CommandPollShow]
-PollShowNoPoll=There is no poll running!
-PollShowInfo=Will show the current poll running
-PollShowPoll=The current poll is `%s`\n
-PollShowChoices=And the choices are:\n
-
-[CommandHelpBuilder]
-HelpBuilderInfo=Emit help for all commands as formatted HTML
-
-[CommandCharacterEditURL]
-CharacterEditURLInfo=
-CharacterEditURLNotValid=
-CharacterEditURLSuccess=
-CharacterEditURLNotAuth=
-CharacterEditURLIDNotValid=
-
-[CommandRPG]
-RPGInfo=Admin+ command only right now - experimental text RPG! Format is !rpg
-RPGInvalid=Invalid RPG Command!
-
-[CommandFetch]
-FetchError=That no picture!
-FetchEat=Me eat now *monch %s*
-FetchInfo=Throw a custom emote and me bring it back!
-FetchCatchRun=*Catches and runs away with %s*
-FetchRunAway=*Runs away and doesn't return for a long time*
-FetchBringBack=Me gots it! %s
-FetchBringBackWrong=Me gots it! %s
-FetchStare=*Stares at %s*
-
-[CommandInfo]
-InfoResponse=I'm made by `Rin#8904` and `Reverie Wisp#3703`!\nYou can find more info about me along with a Patreon link to support us and GitHub link for filing bugs https://www.rinsnowmew.com/bot/
-InfoInfo=Provides author info and a link to Kitty's website
-
-[CommandGuildRoleRemove]
-GuildRoleRemoveNotAllowed=You're not allowed to add %s
-GuildRoleRemoveFailure=Couldn't remove %s from %s
-GuildRoleRemoveSuccess=Removed %s from %s!
-GuildRoleRemoveInfo=Removes the role specified!
-
-[CommandWolfram]
-WolframError=Something went wrong!
-WolframInfo=Will query wolframalpha with your question and give a full image output of the answer
-WolframNoArgs=You need to provide some arguments!
-
-[CommandMap]
-MapInfo=Generates a map! You can pass additional information if you want with the flags `-s -w -h`. If one of the fields isn't provided, its default will be used. Note that adjusting the width and height impacts the map outcomes.\n\n**Defaults**\nDefault Seed: Random,\nDefault Width: 35(max %s),\nDefault Height: 25(max %s)\n\n**Key**\nLand: ˶\nMountain: ▲\nBeach: =\nMarsh: ¥\nLava: #
-MapSeed=Seed
-MapInvalid=Invalid arguments provided!
-MapVersion=Using mapgen v0.1
-MapWidth=Width
-MapHeight=Height
-
-[CommandBeansShow]
-BeansShowDisplay=You have %s beans!
-BeansShowMentioned=I looked it up and %sbeans!
-BeansShowInfo=Displays how many beans you have
-
-[CommandRaffleStart]
-RaffleStartSuccess=Started a raffle with an entrance fee of %s beans!
-RaffleStartFailure=There's already a raffle going!
-RaffleStart=
-RaffleStartInfo=
-
-[CommandHelp]
-HelpInfo=Lets you look up specific commands, or get a link to a list of all commands.
-HelpDisplay=You can get help with a specific command by typing `!help command`!\nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet`
-
-[CommandCharacterEditBio]
-CharacterEditBioSuccess=
-CharacterEditBioIDNotValid=
-CharacterEditBioNotAuth=
-CharacterEditBioInfo=
-CharacterEditBioNotValid=
-
-[CommandTweet]
-TweetInfo=Kitty will tweet to her personal twitter account
-TweetError=Tweet command failed!
-
-[CommandGuildRoleAdd]
-GuildRoleAddSuccess=Added %s to %s
-GuildRoleAddFailure=Failed to add %s to %s
-GuildRoleAddNotAllowed=You are not allowed to add %s!
-GuildRoleAddInfo=Add a role to yourself!
-
-[CommandCharacterEditName]
-CharacterEditNameInfo=
-CharacterEditNameNotValid=
-CharacterEditNameIDNotValid=
-CharacterEditNameSuccess=
-CharacterEditNameNotAuth=
-
-[CommandColiru]
-ColiruError=Please provide some c++ code to attempt to compile!
-ColiruInfo=Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++.
-
-[CommandStark]
-StarkInfo=Snaps your icon or the icon of a friend you mentioned
-
-[CommandYeet]
-YeetInfo=Yeet yourself or yeet a friend with @!
-
-[CommandCrouton]
-CroutonInfo=Crouton
-
-[CommandCharacterCreate]
-CharacterCreateDuplicate=You can't create a character with the same name!
-CharacterCreateInfo=Create a character for kitty to hold onto for you! `createcharacter name, shortbio, refURL`
-CharacterCreateSuccess=You successfully created a character!
-CharacterCreateNullInfo=There's not enough info!
-
-[CommandTeey]
-TeeyInfo=Teey yourself back into existance, or teey a friend with @!
-
-[CommandBetBeans]
-BetBeansLowBet=Please bet with at least 50 beans!
-BetBeansInfo=Allows you to bet your beans, set your amount after the command! Warning! House always wins!\nSets of 3 will get 2x, 4 will get 10x, and 5 will get 1000x
-BetBeansNotValid=That's not a valid bet!
-BetBeansLose=Sorry, you didn't win, try again!
-BetBeansNotEnough=You don't have enough beans!
-BetBeansWin=You won %s beans!
-
-[CommandPollResults]
-PollResultsResponse=%s people voted for %s `%s` with `%s%` !\n
-PollResultsInfo=Will show current results of a poll and percentages of votes per choice
-
-[CommandRPEnd]
-RPEndError=You can't end this RP!
-RPEndInfo=Ends RP in channel and gives you a .txt file!
-RPEndFileOut=Here's your file!
-
-[CommandBoop]
-BoopPerson=%s booped %s!
-BoopInfo=Kitty will react with a counter
-BoopStandard=Woah! %s booped me! That's %s total!
-BoopMultiple=%s booped several others - %s!
-
-[CommandPing]
-PingResponse=Pong!
-PingInfo=Will respond with Pong!
-
-[CommandChoose]
-ChooseChoice=I chooooooose %s!
-ChooseOne=I can't choose from *one* thing!
-ChooseInfo=With an input of x,y,z where x y and z are all choices, kitty will choose one
-
-[CommandEightBall]
-EightBallYes4=Yes - definitely.
-EightBallYes3=Without a doubt.
-EightBallYes2=It is decidedly so.
-EightBallYes1=It is certain.
-EightBallYes8=Outlook good.
-EightBallYes7=Most likely.
-EightBallYes6=As I see it, yes.
-EightBallYes5=You may rely on it.
-EightBallMaybe1=Reply hazy, try again.
-EightBallMaybe2=Ask again later.
-EightBallError=Hmm? You'll need to ask a question!
-EightBallMaybe3=Better not tell you now.
-EightBallMaybe4=Cannot predict now.
-EightBallMaybe5=Concentrate and ask again.
-EightBallInfo=Answers a yes or no question! Warning: Kitty can not actually tell the future, she claims no responsibility for any lion mauling, lack of lottery wins, or felony charges.
-EightBallNo5=Very doubtful.
-EightBallNo3=My sources say no.
-EightBallNo4=Outlook not so good.
-EightBallNo1=Don't count on it.
-EightBallNo2=My reply is no.
-EightBallYes9=Yes.
-EightBallYes10=Signs point to yes.
-
-[CommandInvite]
-InviteInfo=Provides a direct invite link for KittyBot
-
-[CommandRaffleJoin]
-RaffleJoinFailure=You can't join the raffle ;3;
-RaffleJoinInfo=
-RaffleJoinSuccess=You joined the raffle!
-
-[CommandDBFlush]
-DBFlushInfo=Takes all objects queued for the database and writes them to the database, then says how many were written.
-
-
diff --git a/lib/commons-beanutils-1.9.3.jar b/lib/commons-beanutils-1.9.3.jar
new file mode 100644
index 0000000..6728154
Binary files /dev/null and b/lib/commons-beanutils-1.9.3.jar differ
diff --git a/lib/commons-beanutils-1.9.3_LICENSE.txt b/lib/commons-beanutils-1.9.3_LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/lib/commons-beanutils-1.9.3_LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lib/commons-collections4-4.3.jar b/lib/commons-collections4-4.3.jar
new file mode 100644
index 0000000..307012f
Binary files /dev/null and b/lib/commons-collections4-4.3.jar differ
diff --git a/lib/commons-collections4-4.3_LICENSE.txt b/lib/commons-collections4-4.3_LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/lib/commons-collections4-4.3_LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lib/commons-lang3-3.9.jar b/lib/commons-lang3-3.9.jar
new file mode 100644
index 0000000..0d89693
Binary files /dev/null and b/lib/commons-lang3-3.9.jar differ
diff --git a/lib/commons-lang3-3.9_LICENSE.txt b/lib/commons-lang3-3.9_LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/lib/commons-lang3-3.9_LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lib/commons-text-1.6.jar b/lib/commons-text-1.6.jar
new file mode 100644
index 0000000..63e4730
Binary files /dev/null and b/lib/commons-text-1.6.jar differ
diff --git a/lib/commons-text-1.6_LICENSE.txt b/lib/commons-text-1.6_LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/lib/commons-text-1.6_LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lib/opencsv-4.6.jar b/lib/opencsv-4.6.jar
new file mode 100644
index 0000000..a2d5d57
Binary files /dev/null and b/lib/opencsv-4.6.jar differ
diff --git a/src/commands/CommandCharacterCreate.java b/src/commands/CommandCharacterCreate.java
deleted file mode 100644
index 0933ed8..0000000
--- a/src/commands/CommandCharacterCreate.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package commands;
-
-import core.CharacterManager;
-import core.Command;
-import core.LocStrings;
-import dataStructures.KittyChannel;
-import dataStructures.KittyGuild;
-import dataStructures.KittyRating;
-import dataStructures.KittyRole;
-import dataStructures.KittyUser;
-import dataStructures.Response;
-import dataStructures.UserInput;
-
-public class CommandCharacterCreate extends Command
-{
- public CommandCharacterCreate(KittyRole level, KittyRating rating) { super(level, rating); }
-
- @Override
- public String getHelpText() { return LocStrings.stub("CharacterCreateInfo"); }
-
- @Override
- public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
- {
- String [] info = input.args.split(",");
- if(info.length < 3)
- {
- res.send(LocStrings.stub("CharacterCreateNullInfo"));
- return;
- }
- if(CharacterManager.instance.addCharacter(user, info[0], info[1], info[2]))
- {
- res.send(LocStrings.stub("CharacterCreateSuccess"));
- return;
- }
- res.send(LocStrings.stub("CharacterCreateDuplicate"));
- }
-}
\ No newline at end of file
diff --git a/src/commands/CommandGuildRoleAdd.java b/src/commands/CommandGuildRoleAdd.java
deleted file mode 100644
index b4d212e..0000000
--- a/src/commands/CommandGuildRoleAdd.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package commands;
-
-import core.Command;
-import core.LocStrings;
-import dataStructures.KittyChannel;
-import dataStructures.KittyGuild;
-import dataStructures.KittyRating;
-import dataStructures.KittyRole;
-import dataStructures.KittyUser;
-import dataStructures.Response;
-import dataStructures.UserInput;
-
-public class CommandGuildRoleAdd extends Command
-{
- public CommandGuildRoleAdd(KittyRole level, KittyRating rating) { super(level, rating); }
-
- @Override
- public String getHelpText() { return LocStrings.stub("GuildRoleAddInfo"); };
-
- @Override
- public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
- {
- String role = input.args.split(" ")[0];
- if(guild.roleList.contains(role))
- {
- if(guild.control.addRole(user.discordID, role))
- {
- res.send(String.format(LocStrings.stub("GuildRoleAddSuccess"), role, user.name));
- }
- else
- {
- res.send(String.format(LocStrings.stub("GuildRoleAddFailure"), role, user.name));
- }
- }
- else
- {
- res.send(String.format(LocStrings.stub("GuildRoleAddNotAllowed"), role));
- }
- }
-}
\ No newline at end of file
diff --git a/src/commands/CommandGuildRoleAllowed.java b/src/commands/CommandGuildRoleAllowed.java
deleted file mode 100644
index cc40bb2..0000000
--- a/src/commands/CommandGuildRoleAllowed.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package commands;
-
-import core.Command;
-import core.LocStrings;
-import dataStructures.KittyChannel;
-import dataStructures.KittyGuild;
-import dataStructures.KittyRating;
-import dataStructures.KittyRole;
-import dataStructures.KittyUser;
-import dataStructures.Response;
-import dataStructures.UserInput;
-
-public class CommandGuildRoleAllowed extends Command
-{
- public CommandGuildRoleAllowed(KittyRole level, KittyRating rating) { super(level, rating); }
-
- @Override
- public String getHelpText() { return LocStrings.stub("GuildRoleAllowedInfo"); }
-
- @Override
- public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
- {
- String [] roles = input.args.split(",");
- String role;
- for(int i = 0; i < roles.length; i++)
- {
- role = roles[i].trim();
- if(guild.roleList.contains(role))
- {
- res.send(LocStrings.stub("GuildRoleAllowedDuplicate"));
- }
- else
- {
- guild.roleList.add(role);
- res.send(String.format(LocStrings.stub("GuildRoleAllowedSuccess"), role));
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/commands/CommandGuildRoleList.java b/src/commands/CommandGuildRoleList.java
deleted file mode 100644
index f23a30e..0000000
--- a/src/commands/CommandGuildRoleList.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package commands;
-
-import core.Command;
-import core.LocStrings;
-import dataStructures.*;
-import network.NetworkColiru;
-
-public class CommandGuildRoleList extends Command
-{
- NetworkColiru compiler = new NetworkColiru();
-
- public CommandGuildRoleList(KittyRole level, KittyRating rating) { super(level, rating);}
-
- @Override
- public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
- {
- String roles = "";
- if(guild.roleList.isEmpty())
- {
- res.send(String.format(LocStrings.stub("GuildRoleListEmpty")));
- return;
- }
- for(int i = 0; i < guild.roleList.size(); i++)
- {
- if(i > 0)
- roles += " and ";
- roles += guild.roleList.get(i);
- }
- res.send(String.format(LocStrings.stub("GuildRoleListOutput"), roles));
- }
-}
\ No newline at end of file
diff --git a/src/commands/CommandGuildRoleNotAllowed.java b/src/commands/CommandGuildRoleNotAllowed.java
deleted file mode 100644
index d95c440..0000000
--- a/src/commands/CommandGuildRoleNotAllowed.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package commands;
-
-import core.Command;
-import core.LocStrings;
-import dataStructures.KittyChannel;
-import dataStructures.KittyGuild;
-import dataStructures.KittyRating;
-import dataStructures.KittyRole;
-import dataStructures.KittyUser;
-import dataStructures.Response;
-import dataStructures.UserInput;
-
-public class CommandGuildRoleNotAllowed extends Command
-{
- public CommandGuildRoleNotAllowed(KittyRole level, KittyRating rating) { super(level, rating); }
-
- @Override
- public String getHelpText() { return LocStrings.stub("GuildRoleNotAllowedInfo"); }
-
- @Override
- public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
- {
- String [] roles = input.args.split(",");
- String role;
- for(int i = 0; i < roles.length; i++)
- {
- role = roles[i].trim();
- if(guild.roleList.contains(role))
- {
- guild.roleList.remove(role);
- res.send(LocStrings.stub("GuildRoleNotAllowedSuccess"));
- }
- else
- {
- res.send(String.format(LocStrings.stub("GuildRoleNotAllowedFailure"), role));
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/commands/CommandGuildRoleRemove.java b/src/commands/CommandGuildRoleRemove.java
deleted file mode 100644
index 32ab8e6..0000000
--- a/src/commands/CommandGuildRoleRemove.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package commands;
-
-import core.Command;
-import core.LocStrings;
-import dataStructures.KittyChannel;
-import dataStructures.KittyGuild;
-import dataStructures.KittyRating;
-import dataStructures.KittyRole;
-import dataStructures.KittyUser;
-import dataStructures.Response;
-import dataStructures.UserInput;
-
-public class CommandGuildRoleRemove extends Command
-{
- public CommandGuildRoleRemove(KittyRole level, KittyRating rating) { super(level, rating); }
-
- @Override
- public String getHelpText() { return LocStrings.stub("GuildRoleRemoveInfo"); };
-
- @Override
- public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
- {
- String role = input.args.split(" ")[0];
- if(guild.roleList.contains(role))
- {
- if(guild.control.removeRole(user.discordID, role))
- {
- res.send(String.format(LocStrings.stub("GuildRoleRemoveSuccess"), role, user.name));
- }
- else
- {
- res.send(String.format(LocStrings.stub("GuildRoleRemoveFailure"), role, user.name));
- }
- }
- else
- {
- res.send(String.format(LocStrings.stub("GuildRoleRemoveNotAllowed"), role));
- }
- }
-}
\ No newline at end of file
diff --git a/src/commands/characters/CommandCharacterCreate.java b/src/commands/characters/CommandCharacterCreate.java
new file mode 100644
index 0000000..7ce5eba
--- /dev/null
+++ b/src/commands/characters/CommandCharacterCreate.java
@@ -0,0 +1,28 @@
+package commands.characters;
+
+import core.CharacterManager;
+import core.LocStrings;
+import core.SubCommand;
+import core.SubCommandFormattable;
+import dataStructures.*;
+
+public class CommandCharacterCreate extends SubCommand
+{
+ public CommandCharacterCreate(KittyRole level, KittyRating rating) { super(level, rating); }
+
+ @Override
+ public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, String input)
+ {
+ String [] info = input.split(",");
+ if(info.length < 3)
+ {
+ return new SubCommandFormattable (LocStrings.stub("CharacterCreateNullInfo"));
+ }
+ if(CharacterManager.instance.addCharacter(user, info[0], info[1], info[2]))
+ {
+ return new SubCommandFormattable (LocStrings.stub("CharacterCreateSuccess"));
+
+ }
+ return new SubCommandFormattable (LocStrings.stub("CharacterCreateDuplicate"));
+ }
+}
\ No newline at end of file
diff --git a/src/commands/CommandCharacterEditBio.java b/src/commands/characters/CommandCharacterEditBio.java
similarity index 97%
rename from src/commands/CommandCharacterEditBio.java
rename to src/commands/characters/CommandCharacterEditBio.java
index 4d42579..be786a0 100644
--- a/src/commands/CommandCharacterEditBio.java
+++ b/src/commands/characters/CommandCharacterEditBio.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.characters;
import core.CharacterManager;
import core.Command;
diff --git a/src/commands/CommandCharacterEditName.java b/src/commands/characters/CommandCharacterEditName.java
similarity index 97%
rename from src/commands/CommandCharacterEditName.java
rename to src/commands/characters/CommandCharacterEditName.java
index 7382331..e278774 100644
--- a/src/commands/CommandCharacterEditName.java
+++ b/src/commands/characters/CommandCharacterEditName.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.characters;
import core.CharacterManager;
import core.Command;
diff --git a/src/commands/CommandCharacterEditURL.java b/src/commands/characters/CommandCharacterEditURL.java
similarity index 97%
rename from src/commands/CommandCharacterEditURL.java
rename to src/commands/characters/CommandCharacterEditURL.java
index 39a8c5c..5d2b6c8 100644
--- a/src/commands/CommandCharacterEditURL.java
+++ b/src/commands/characters/CommandCharacterEditURL.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.characters;
import core.CharacterManager;
import core.Command;
diff --git a/src/commands/characters/CommandCharacterMain.java b/src/commands/characters/CommandCharacterMain.java
new file mode 100644
index 0000000..6a4bdce
--- /dev/null
+++ b/src/commands/characters/CommandCharacterMain.java
@@ -0,0 +1,33 @@
+package commands.characters;
+
+import core.Command;
+import core.LocStrings;
+import core.SubCommandFramework;
+import dataStructures.KittyChannel;
+import dataStructures.KittyGuild;
+import dataStructures.KittyRating;
+import dataStructures.KittyRole;
+import dataStructures.KittyUser;
+import dataStructures.Response;
+import dataStructures.UserInput;
+
+public class CommandCharacterMain extends Command
+{
+ SubCommandFramework framework = new SubCommandFramework();
+ public CommandCharacterMain(KittyRole level, KittyRating rating)
+ {
+ super(level, rating);
+ }
+
+ @Override
+ public String getHelpText() { return LocStrings.stub("CharacterInfo"); }
+
+
+
+
+ @Override
+ public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
+ {
+ framework.run(guild, channel, user, input.args).Call(res);
+ }
+}
\ No newline at end of file
diff --git a/src/commands/CommandCharacterSearch.java b/src/commands/characters/CommandCharacterSearch.java
similarity index 97%
rename from src/commands/CommandCharacterSearch.java
rename to src/commands/characters/CommandCharacterSearch.java
index 5cabef0..79d44c7 100644
--- a/src/commands/CommandCharacterSearch.java
+++ b/src/commands/characters/CommandCharacterSearch.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.characters;
import java.util.ArrayList;
diff --git a/src/commands/CommandBeansShow.java b/src/commands/general/CommandBeansShow.java
similarity index 93%
rename from src/commands/CommandBeansShow.java
rename to src/commands/general/CommandBeansShow.java
index 8f25af7..f87b862 100644
--- a/src/commands/CommandBeansShow.java
+++ b/src/commands/general/CommandBeansShow.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandBenchmark.java b/src/commands/general/CommandBenchmark.java
similarity index 97%
rename from src/commands/CommandBenchmark.java
rename to src/commands/general/CommandBenchmark.java
index bd66977..eca0f4a 100644
--- a/src/commands/CommandBenchmark.java
+++ b/src/commands/general/CommandBenchmark.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandBetBeans.java b/src/commands/general/CommandBetBeans.java
similarity index 93%
rename from src/commands/CommandBetBeans.java
rename to src/commands/general/CommandBetBeans.java
index 19618a6..25e0eb9 100644
--- a/src/commands/CommandBetBeans.java
+++ b/src/commands/general/CommandBetBeans.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.util.Random;
diff --git a/src/commands/CommandBetHistory.java b/src/commands/general/CommandBetHistory.java
similarity index 96%
rename from src/commands/CommandBetHistory.java
rename to src/commands/general/CommandBetHistory.java
index 0f7b541..0e7a872 100644
--- a/src/commands/CommandBetHistory.java
+++ b/src/commands/general/CommandBetHistory.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandBlurry.java b/src/commands/general/CommandBlurry.java
similarity index 96%
rename from src/commands/CommandBlurry.java
rename to src/commands/general/CommandBlurry.java
index 221cc80..145510e 100644
--- a/src/commands/CommandBlurry.java
+++ b/src/commands/general/CommandBlurry.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.awt.Color;
import java.awt.image.BufferedImage;
diff --git a/src/commands/CommandBoop.java b/src/commands/general/CommandBoop.java
similarity index 98%
rename from src/commands/CommandBoop.java
rename to src/commands/general/CommandBoop.java
index fc4a1c3..cb9104b 100644
--- a/src/commands/CommandBoop.java
+++ b/src/commands/general/CommandBoop.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.*;
import dataStructures.KittyChannel;
diff --git a/src/commands/CommandCatch.java b/src/commands/general/CommandCatch.java
similarity index 98%
rename from src/commands/CommandCatch.java
rename to src/commands/general/CommandCatch.java
index ceaa01d..394bee6 100644
--- a/src/commands/CommandCatch.java
+++ b/src/commands/general/CommandCatch.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.io.File;
import java.io.IOException;
diff --git a/src/commands/CommandChangeIndicator.java b/src/commands/general/CommandChangeIndicator.java
similarity index 93%
rename from src/commands/CommandChangeIndicator.java
rename to src/commands/general/CommandChangeIndicator.java
index e3d73e8..f26ca52 100644
--- a/src/commands/CommandChangeIndicator.java
+++ b/src/commands/general/CommandChangeIndicator.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandChoose.java b/src/commands/general/CommandChoose.java
similarity index 93%
rename from src/commands/CommandChoose.java
rename to src/commands/general/CommandChoose.java
index bb71dd4..7fc258e 100644
--- a/src/commands/CommandChoose.java
+++ b/src/commands/general/CommandChoose.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.*;
import dataStructures.KittyChannel;
diff --git a/src/commands/CommandColiru.java b/src/commands/general/CommandColiru.java
similarity index 92%
rename from src/commands/CommandColiru.java
rename to src/commands/general/CommandColiru.java
index 9dc39c1..e2a2ad1 100644
--- a/src/commands/CommandColiru.java
+++ b/src/commands/general/CommandColiru.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandColor.java b/src/commands/general/CommandColor.java
similarity index 99%
rename from src/commands/CommandColor.java
rename to src/commands/general/CommandColor.java
index a4c2059..d159bc0 100644
--- a/src/commands/CommandColor.java
+++ b/src/commands/general/CommandColor.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.awt.Color;
import java.awt.Graphics2D;
diff --git a/src/commands/CommandCrouton.java b/src/commands/general/CommandCrouton.java
similarity index 97%
rename from src/commands/CommandCrouton.java
rename to src/commands/general/CommandCrouton.java
index 7552b87..f25c81f 100644
--- a/src/commands/CommandCrouton.java
+++ b/src/commands/general/CommandCrouton.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.awt.Color;
diff --git a/src/commands/CommandDBFlush.java b/src/commands/general/CommandDBFlush.java
similarity index 91%
rename from src/commands/CommandDBFlush.java
rename to src/commands/general/CommandDBFlush.java
index 982c0fa..9af292d 100644
--- a/src/commands/CommandDBFlush.java
+++ b/src/commands/general/CommandDBFlush.java
@@ -1,7 +1,7 @@
-package commands;
+package commands.general;
import core.Command;
-import core.Config;
+import core.Constants;
import core.DatabaseManager;
import core.LocStrings;
import dataStructures.KittyChannel;
@@ -28,7 +28,7 @@ public class CommandDBFlush extends Command
KittyEmbed embed = new KittyEmbed();
embed.title = "Database queue flushed";
embed.descriptionText = "**Dirty:** " + numUpdated;
- embed.color = Config.ColorDefault;
+ embed.color = Constants.ColorDefault;
res.send(embed);
}
diff --git a/src/commands/CommandDBStats.java b/src/commands/general/CommandDBStats.java
similarity index 93%
rename from src/commands/CommandDBStats.java
rename to src/commands/general/CommandDBStats.java
index de1fcd5..0ba3c51 100644
--- a/src/commands/CommandDBStats.java
+++ b/src/commands/general/CommandDBStats.java
@@ -1,10 +1,10 @@
-package commands;
+package commands.general;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import core.Command;
-import core.Config;
+import core.Constants;
import core.DatabaseManager;
import core.LocStrings;
import dataStructures.KittyChannel;
@@ -36,7 +36,7 @@ public class CommandDBStats extends Command
embed.descriptionText = "**Tracked Items:** " + DatabaseManager.instance.getTrackedObjectsSize();
embed.descriptionText += "\n";
embed.descriptionText += "**Last Upkeep:** " + dateFormat.format(DatabaseManager.instance.getLastUpkeep()) + " UTC-7";
- embed.color = Config.ColorDefault;
+ embed.color = Constants.ColorDefault;
res.send(embed);
}
diff --git a/src/commands/CommandDoWork.java b/src/commands/general/CommandDoWork.java
similarity index 97%
rename from src/commands/CommandDoWork.java
rename to src/commands/general/CommandDoWork.java
index 1cbc063..734ff3f 100644
--- a/src/commands/CommandDoWork.java
+++ b/src/commands/general/CommandDoWork.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.*;
import dataStructures.KittyChannel;
diff --git a/src/commands/CommandEightBall.java b/src/commands/general/CommandEightBall.java
similarity index 94%
rename from src/commands/CommandEightBall.java
rename to src/commands/general/CommandEightBall.java
index 2b97f79..f902f32 100644
--- a/src/commands/CommandEightBall.java
+++ b/src/commands/general/CommandEightBall.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandFetch.java b/src/commands/general/CommandFetch.java
similarity index 95%
rename from src/commands/CommandFetch.java
rename to src/commands/general/CommandFetch.java
index 29c578a..0834467 100644
--- a/src/commands/CommandFetch.java
+++ b/src/commands/general/CommandFetch.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandGiveBeans.java b/src/commands/general/CommandGiveBeans.java
similarity index 94%
rename from src/commands/CommandGiveBeans.java
rename to src/commands/general/CommandGiveBeans.java
index 51f55bb..d17d005 100644
--- a/src/commands/CommandGiveBeans.java
+++ b/src/commands/general/CommandGiveBeans.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandHelp.java b/src/commands/general/CommandHelp.java
similarity index 93%
rename from src/commands/CommandHelp.java
rename to src/commands/general/CommandHelp.java
index 41d33ec..7408040 100644
--- a/src/commands/CommandHelp.java
+++ b/src/commands/general/CommandHelp.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.*;
import dataStructures.KittyChannel;
diff --git a/src/commands/CommandHelpBuilder.java b/src/commands/general/CommandHelpBuilder.java
similarity index 99%
rename from src/commands/CommandHelpBuilder.java
rename to src/commands/general/CommandHelpBuilder.java
index 85c46f5..4f8e0c7 100644
--- a/src/commands/CommandHelpBuilder.java
+++ b/src/commands/general/CommandHelpBuilder.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.io.File;
import java.io.FileNotFoundException;
diff --git a/src/commands/CommandInfo.java b/src/commands/general/CommandInfo.java
similarity index 92%
rename from src/commands/CommandInfo.java
rename to src/commands/general/CommandInfo.java
index 8869203..a784274 100644
--- a/src/commands/CommandInfo.java
+++ b/src/commands/general/CommandInfo.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandInvite.java b/src/commands/general/CommandInvite.java
similarity index 92%
rename from src/commands/CommandInvite.java
rename to src/commands/general/CommandInvite.java
index efb2f71..a94587b 100644
--- a/src/commands/CommandInvite.java
+++ b/src/commands/general/CommandInvite.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandJDoodle.java b/src/commands/general/CommandJDoodle.java
similarity index 92%
rename from src/commands/CommandJDoodle.java
rename to src/commands/general/CommandJDoodle.java
index 67165f0..7d44a23 100644
--- a/src/commands/CommandJDoodle.java
+++ b/src/commands/general/CommandJDoodle.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandLeaderboard.java b/src/commands/general/CommandLeaderboard.java
similarity index 97%
rename from src/commands/CommandLeaderboard.java
rename to src/commands/general/CommandLeaderboard.java
index 79a1ff6..3d5c54d 100644
--- a/src/commands/CommandLeaderboard.java
+++ b/src/commands/general/CommandLeaderboard.java
@@ -1,10 +1,10 @@
-package commands;
+package commands.general;
import java.util.ArrayList;
import java.util.List;
import core.Command;
-import core.Config;
+import core.Constants;
import core.DatabaseManager;
import core.LocStrings;
import core.ObjectBuilderFactory;
@@ -79,7 +79,7 @@ public class CommandLeaderboard extends Command
// Configure output
final int listSize = 10;
KittyEmbed embed = new KittyEmbed();
- embed.color = Config.ColorDefault;
+ embed.color = Constants.ColorDefault;
embed.title = LocStrings.stub("LeaderboardTitle");
embed.descriptionText = "";
diff --git a/src/commands/CommandMap.java b/src/commands/general/CommandMap.java
similarity index 99%
rename from src/commands/CommandMap.java
rename to src/commands/general/CommandMap.java
index 0edf9de..cadd84f 100644
--- a/src/commands/CommandMap.java
+++ b/src/commands/general/CommandMap.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.util.Random;
diff --git a/src/commands/CommandPerish.java b/src/commands/general/CommandPerish.java
similarity index 98%
rename from src/commands/CommandPerish.java
rename to src/commands/general/CommandPerish.java
index d372510..74d426c 100644
--- a/src/commands/CommandPerish.java
+++ b/src/commands/general/CommandPerish.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.awt.Color;
import java.awt.image.BufferedImage;
diff --git a/src/commands/CommandPing.java b/src/commands/general/CommandPing.java
similarity index 96%
rename from src/commands/CommandPing.java
rename to src/commands/general/CommandPing.java
index e5f8d62..ed155e6 100644
--- a/src/commands/CommandPing.java
+++ b/src/commands/general/CommandPing.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.*;
import dataStructures.KittyChannel;
diff --git a/src/commands/CommandPollManage.java b/src/commands/general/CommandPollManage.java
similarity index 93%
rename from src/commands/CommandPollManage.java
rename to src/commands/general/CommandPollManage.java
index 5457a1b..a1ecd32 100644
--- a/src/commands/CommandPollManage.java
+++ b/src/commands/general/CommandPollManage.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.*;
import dataStructures.KittyChannel;
diff --git a/src/commands/CommandPollResults.java b/src/commands/general/CommandPollResults.java
similarity index 93%
rename from src/commands/CommandPollResults.java
rename to src/commands/general/CommandPollResults.java
index 638bb81..016439b 100644
--- a/src/commands/CommandPollResults.java
+++ b/src/commands/general/CommandPollResults.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.util.ArrayList;
diff --git a/src/commands/CommandPollShow.java b/src/commands/general/CommandPollShow.java
similarity index 92%
rename from src/commands/CommandPollShow.java
rename to src/commands/general/CommandPollShow.java
index c92ab2d..bb2d277 100644
--- a/src/commands/CommandPollShow.java
+++ b/src/commands/general/CommandPollShow.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.*;
import dataStructures.*;
diff --git a/src/commands/CommandPollVote.java b/src/commands/general/CommandPollVote.java
similarity index 93%
rename from src/commands/CommandPollVote.java
rename to src/commands/general/CommandPollVote.java
index b3012f1..af37b14 100644
--- a/src/commands/CommandPollVote.java
+++ b/src/commands/general/CommandPollVote.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.*;
import dataStructures.*;
diff --git a/src/commands/CommandRPEnd.java b/src/commands/general/CommandRPEnd.java
similarity index 93%
rename from src/commands/CommandRPEnd.java
rename to src/commands/general/CommandRPEnd.java
index 355b691..e3da256 100644
--- a/src/commands/CommandRPEnd.java
+++ b/src/commands/general/CommandRPEnd.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.io.File;
import java.io.FileNotFoundException;
diff --git a/src/commands/CommandRPG.java b/src/commands/general/CommandRPG.java
similarity index 97%
rename from src/commands/CommandRPG.java
rename to src/commands/general/CommandRPG.java
index 6230dc0..8f62d7d 100644
--- a/src/commands/CommandRPG.java
+++ b/src/commands/general/CommandRPG.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandRPStart.java b/src/commands/general/CommandRPStart.java
similarity index 92%
rename from src/commands/CommandRPStart.java
rename to src/commands/general/CommandRPStart.java
index 866b6f8..f0794f1 100644
--- a/src/commands/CommandRPStart.java
+++ b/src/commands/general/CommandRPStart.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.util.ArrayList;
diff --git a/src/commands/CommandRaffleEnd.java b/src/commands/general/CommandRaffleEnd.java
similarity index 96%
rename from src/commands/CommandRaffleEnd.java
rename to src/commands/general/CommandRaffleEnd.java
index 735c604..bc89124 100644
--- a/src/commands/CommandRaffleEnd.java
+++ b/src/commands/general/CommandRaffleEnd.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandRaffleJoin.java b/src/commands/general/CommandRaffleJoin.java
similarity index 96%
rename from src/commands/CommandRaffleJoin.java
rename to src/commands/general/CommandRaffleJoin.java
index 0b6a78f..3003a8e 100644
--- a/src/commands/CommandRaffleJoin.java
+++ b/src/commands/general/CommandRaffleJoin.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandRaffleSpin.java b/src/commands/general/CommandRaffleSpin.java
similarity index 96%
rename from src/commands/CommandRaffleSpin.java
rename to src/commands/general/CommandRaffleSpin.java
index 3889252..ff6111d 100644
--- a/src/commands/CommandRaffleSpin.java
+++ b/src/commands/general/CommandRaffleSpin.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandRaffleStart.java b/src/commands/general/CommandRaffleStart.java
similarity index 97%
rename from src/commands/CommandRaffleStart.java
rename to src/commands/general/CommandRaffleStart.java
index 57468a3..0c72142 100644
--- a/src/commands/CommandRaffleStart.java
+++ b/src/commands/general/CommandRaffleStart.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandRating.java b/src/commands/general/CommandRating.java
similarity index 98%
rename from src/commands/CommandRating.java
rename to src/commands/general/CommandRating.java
index 6947e77..19be0c2 100644
--- a/src/commands/CommandRating.java
+++ b/src/commands/general/CommandRating.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/general/CommandRemind.java b/src/commands/general/CommandRemind.java
new file mode 100644
index 0000000..156e8dd
--- /dev/null
+++ b/src/commands/general/CommandRemind.java
@@ -0,0 +1,40 @@
+package commands.general;
+
+import core.Command;
+import core.LocStrings;
+import dataStructures.*;
+
+public class CommandRemind extends Command
+{
+public CommandRemind(KittyRole level, KittyRating rating) { super(level, rating); }
+
+ @Override
+ public String getHelpText() { return LocStrings.stub("RemindInfo"); };
+
+ @Override
+ public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
+ {
+ long time;
+ try
+ {
+ time = Long.parseLong(input.args.split(" ")[0]);
+ }
+ catch(Exception e)
+ {
+ res.send("That's not a valid time");
+ return;
+ }
+
+ res.send("Ok! I'll remind you!");
+
+ try
+ {
+ Thread.sleep(time * 1000 * 60);
+ res.send("<@" + user.discordID + "> don't forget: " + input.args.substring(input.args.indexOf(" ")));
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/commands/CommandRole.java b/src/commands/general/CommandRole.java
similarity index 94%
rename from src/commands/CommandRole.java
rename to src/commands/general/CommandRole.java
index 1abee3a..ca4c742 100644
--- a/src/commands/CommandRole.java
+++ b/src/commands/general/CommandRole.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandRoll.java b/src/commands/general/CommandRoll.java
similarity index 94%
rename from src/commands/CommandRoll.java
rename to src/commands/general/CommandRoll.java
index 046c2c0..30c9d31 100644
--- a/src/commands/CommandRoll.java
+++ b/src/commands/general/CommandRoll.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.util.Stack;
diff --git a/src/commands/CommandShutdown.java b/src/commands/general/CommandShutdown.java
similarity index 98%
rename from src/commands/CommandShutdown.java
rename to src/commands/general/CommandShutdown.java
index b6de2ea..beb901d 100644
--- a/src/commands/CommandShutdown.java
+++ b/src/commands/general/CommandShutdown.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.DatabaseManager;
diff --git a/src/commands/CommandStark.java b/src/commands/general/CommandStark.java
similarity index 94%
rename from src/commands/CommandStark.java
rename to src/commands/general/CommandStark.java
index 9795b6e..c412adc 100644
--- a/src/commands/CommandStark.java
+++ b/src/commands/general/CommandStark.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.awt.Color;
import java.awt.image.BufferedImage;
diff --git a/src/commands/CommandStats.java b/src/commands/general/CommandStats.java
similarity index 96%
rename from src/commands/CommandStats.java
rename to src/commands/general/CommandStats.java
index 3e6217a..b6aa642 100644
--- a/src/commands/CommandStats.java
+++ b/src/commands/general/CommandStats.java
@@ -1,9 +1,9 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
import core.CommandManager.ThreadData;
-import core.Config;
+import core.Constants;
import dataStructures.KittyChannel;
import dataStructures.KittyEmbed;
import dataStructures.KittyGuild;
@@ -82,7 +82,7 @@ public class CommandStats extends Command
KittyEmbed embed = new KittyEmbed();
embed.title = "Bot Stats";
embed.descriptionText = out;
- embed.color = Config.ColorDefault;
+ embed.color = Constants.ColorDefault;
res.send(embed);
}
diff --git a/src/commands/CommandTeey.java b/src/commands/general/CommandTeey.java
similarity index 90%
rename from src/commands/CommandTeey.java
rename to src/commands/general/CommandTeey.java
index e25a9b8..5c5b924 100644
--- a/src/commands/CommandTeey.java
+++ b/src/commands/general/CommandTeey.java
@@ -1,10 +1,10 @@
-package commands;
+package commands.general;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import core.Command;
-import core.Config;
+import core.Constants;
import core.LocStrings;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
@@ -54,7 +54,7 @@ public class CommandTeey extends Command
return;
teeyeeFile = new File(yeeteeFilename);
- ImageOverlayBuilder builder = new ImageOverlayBuilder(Config.AssetDirectory + "teey/frames/", "teey ", 24, 18);
+ ImageOverlayBuilder builder = new ImageOverlayBuilder(Constants.AssetDirectory + "teey/frames/", "teey ", 24, 18);
builder.overlay(ImageIO.read(teeyeeFile), name);
}
catch (IOException e)
diff --git a/src/commands/CommandTradeBeans.java b/src/commands/general/CommandTradeBeans.java
similarity index 98%
rename from src/commands/CommandTradeBeans.java
rename to src/commands/general/CommandTradeBeans.java
index efb7627..5829c0e 100644
--- a/src/commands/CommandTradeBeans.java
+++ b/src/commands/general/CommandTradeBeans.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandTweet.java b/src/commands/general/CommandTweet.java
similarity index 92%
rename from src/commands/CommandTweet.java
rename to src/commands/general/CommandTweet.java
index 5334900..6a16e9b 100644
--- a/src/commands/CommandTweet.java
+++ b/src/commands/general/CommandTweet.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import core.Command;
import core.LocStrings;
diff --git a/src/commands/CommandWolfram.java b/src/commands/general/CommandWolfram.java
similarity index 93%
rename from src/commands/CommandWolfram.java
rename to src/commands/general/CommandWolfram.java
index ee341cc..e6a63a5 100644
--- a/src/commands/CommandWolfram.java
+++ b/src/commands/general/CommandWolfram.java
@@ -1,4 +1,4 @@
-package commands;
+package commands.general;
import java.io.File;
import java.io.IOException;
diff --git a/src/commands/CommandYeet.java b/src/commands/general/CommandYeet.java
similarity index 90%
rename from src/commands/CommandYeet.java
rename to src/commands/general/CommandYeet.java
index ecfc18a..cc9f56d 100644
--- a/src/commands/CommandYeet.java
+++ b/src/commands/general/CommandYeet.java
@@ -1,10 +1,10 @@
-package commands;
+package commands.general;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import core.Command;
-import core.Config;
+import core.Constants;
import core.LocStrings;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
@@ -54,7 +54,7 @@ public class CommandYeet extends Command
return;
yeeteeFile = new File(yeeteeFilename);
- ImageOverlayBuilder builder = new ImageOverlayBuilder(Config.AssetDirectory + "yeet/frames/", "yeet ", 24, 18);
+ ImageOverlayBuilder builder = new ImageOverlayBuilder(Constants.AssetDirectory + "yeet/frames/", "yeet ", 24, 18);
builder.overlay(ImageIO.read(yeeteeFile), name);
}
catch (IOException e)
diff --git a/src/commands/guildrole/CommandGuildRoleMain.java b/src/commands/guildrole/CommandGuildRoleMain.java
new file mode 100644
index 0000000..2c5807d
--- /dev/null
+++ b/src/commands/guildrole/CommandGuildRoleMain.java
@@ -0,0 +1,37 @@
+package commands.guildrole;
+
+import core.Command;
+import core.LocStrings;
+import core.SubCommandFramework;
+import dataStructures.KittyChannel;
+import dataStructures.KittyGuild;
+import dataStructures.KittyRating;
+import dataStructures.KittyRole;
+import dataStructures.KittyUser;
+import dataStructures.Response;
+import dataStructures.UserInput;
+
+public class CommandGuildRoleMain extends Command
+{
+ SubCommandFramework framework = new SubCommandFramework();
+ public CommandGuildRoleMain(KittyRole level, KittyRating rating)
+ {
+ super(level, rating);
+ framework.addCommand("add", new SubCommandAdd (KittyRole.General, KittyRating.Safe));
+ framework.addCommand("remove", new SubCommandRemove(KittyRole.General, KittyRating.Safe));
+ framework.addCommand("allowed", new SubCommandAllowed(KittyRole.Admin, KittyRating.Safe));
+ framework.addCommand("unallowed", new SubCommandNotAllowed(KittyRole.Admin, KittyRating.Safe));
+ }
+
+ @Override
+ public String getHelpText() { return LocStrings.stub("GuildRoleInfo"); }
+
+
+
+
+ @Override
+ public void onRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res)
+ {
+ framework.run(guild, channel, user, input.args).Call(res);
+ }
+}
diff --git a/src/commands/guildrole/SubCommandAdd.java b/src/commands/guildrole/SubCommandAdd.java
new file mode 100644
index 0000000..37c9617
--- /dev/null
+++ b/src/commands/guildrole/SubCommandAdd.java
@@ -0,0 +1,36 @@
+package commands.guildrole;
+
+import core.SubCommand;
+import core.SubCommandFormattable;
+import dataStructures.KittyChannel;
+import dataStructures.KittyGuild;
+import dataStructures.KittyRating;
+import dataStructures.KittyRole;
+import dataStructures.KittyUser;
+
+public class SubCommandAdd extends SubCommand
+{
+ public SubCommandAdd(KittyRole level, KittyRating rating) { super(level, rating); }
+
+ @Override
+ public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, String input)
+ {
+ String role = input.split(" ")[0];
+ if(guild.roleList.contains(role))
+ {
+ if(guild.control.addRole(user.discordID, role))
+ {
+ return new SubCommandFormattable("ADDED RIN YOU NEED TO FIX THIS");
+ }
+ else
+ {
+ return new SubCommandFormattable("FAILED RIN YOU NEED TO FIX THIS TOO");
+ }
+ }
+ else
+ {
+ return new SubCommandFormattable("NOT ALLOWED FIX THIS ONE TOO SNEP FACE");
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/commands/guildrole/SubCommandAllowed.java b/src/commands/guildrole/SubCommandAllowed.java
new file mode 100644
index 0000000..95fd093
--- /dev/null
+++ b/src/commands/guildrole/SubCommandAllowed.java
@@ -0,0 +1,37 @@
+package commands.guildrole;
+
+import core.LocStrings;
+import core.SubCommand;
+import core.SubCommandFormattable;
+import dataStructures.KittyChannel;
+import dataStructures.KittyGuild;
+import dataStructures.KittyRating;
+import dataStructures.KittyRole;
+import dataStructures.KittyUser;
+
+public class SubCommandAllowed extends SubCommand
+{
+ public SubCommandAllowed(KittyRole level, KittyRating rating) { super(level, rating); }
+
+ @Override
+ public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, String input)
+ {
+ String [] roles = input.split(",");
+ String role;
+ String formatted = "";
+ for(int i = 0; i < roles.length; i++)
+ {
+ role = roles[i].trim();
+ if(guild.roleList.contains(role))
+ {
+ formatted += String.format(LocStrings.stub("GuildRoleAllowedDuplicate"), role);
+ }
+ else
+ {
+ guild.roleList.add(role);
+ formatted += (String.format(LocStrings.stub("GuildRoleAllowedSuccess"), role));
+ }
+ }
+ return new SubCommandFormattable(formatted);
+ }
+}
\ No newline at end of file
diff --git a/src/commands/guildrole/SubCommandList.java b/src/commands/guildrole/SubCommandList.java
new file mode 100644
index 0000000..5bf3163
--- /dev/null
+++ b/src/commands/guildrole/SubCommandList.java
@@ -0,0 +1,33 @@
+package commands.guildrole;
+
+import core.LocStrings;
+import core.SubCommand;
+import core.SubCommandFormattable;
+import dataStructures.KittyChannel;
+import dataStructures.KittyGuild;
+import dataStructures.KittyRating;
+import dataStructures.KittyRole;
+import dataStructures.KittyUser;
+
+public class SubCommandList extends SubCommand
+{
+
+ public SubCommandList(KittyRole level, KittyRating rating) { super(level, rating);}
+
+ @Override
+ public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, String input)
+ {
+ String roles = "";
+ if(guild.roleList.isEmpty())
+ {
+ return new SubCommandFormattable(String.format(LocStrings.stub("GuildRoleListEmpty")));
+ }
+ for(int i = 0; i < guild.roleList.size(); i++)
+ {
+ if(i > 0)
+ roles += "\n";
+ roles += guild.roleList.get(i);
+ }
+ return new SubCommandFormattable(String.format(LocStrings.stub("GuildRoleListOutput"), roles));
+ }
+}
\ No newline at end of file
diff --git a/src/commands/guildrole/SubCommandNotAllowed.java b/src/commands/guildrole/SubCommandNotAllowed.java
new file mode 100644
index 0000000..f11ec28
--- /dev/null
+++ b/src/commands/guildrole/SubCommandNotAllowed.java
@@ -0,0 +1,35 @@
+package commands.guildrole;
+
+import core.LocStrings;
+import core.SubCommand;
+import core.SubCommandFormattable;
+import dataStructures.KittyChannel;
+import dataStructures.KittyGuild;
+import dataStructures.KittyRating;
+import dataStructures.KittyRole;
+import dataStructures.KittyUser;
+
+public class SubCommandNotAllowed extends SubCommand
+{
+ public SubCommandNotAllowed(KittyRole level, KittyRating rating) { super(level, rating); }
+
+ @Override
+ public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, String input)
+ {
+ input = input.toLowerCase();
+ String [] roles = input.split(",");
+ for(String role:roles)
+ {
+ if(guild.roleList.contains(role.trim()))
+ {
+ guild.roleList.remove(role);
+ return new SubCommandFormattable(LocStrings.stub("GuildRoleNotAllowedSuccess"));
+ }
+ else
+ {
+ return new SubCommandFormattable(String.format(LocStrings.stub("GuildRoleNotAllowedFailure"), role));
+ }
+ }
+ return new SubCommandFormattable(String.format(LocStrings.stub("GuildRoleNotAllowedNoArgs")));
+ }
+}
\ No newline at end of file
diff --git a/src/commands/guildrole/SubCommandRemove.java b/src/commands/guildrole/SubCommandRemove.java
new file mode 100644
index 0000000..ad5fd53
--- /dev/null
+++ b/src/commands/guildrole/SubCommandRemove.java
@@ -0,0 +1,35 @@
+package commands.guildrole;
+
+import core.LocStrings;
+import core.SubCommand;
+import core.SubCommandFormattable;
+import dataStructures.*;
+
+public class SubCommandRemove extends SubCommand
+{
+ public SubCommandRemove(KittyRole level, KittyRating rating) { super(level, rating); }
+
+ @Override
+ public SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, String input)
+ {
+ String role = input.split(" ")[0];
+ String formatted = "";
+ if(guild.roleList.contains(role))
+ {
+ if(guild.control.removeRole(user.discordID, role))
+ {
+ formatted += (String.format(LocStrings.stub("GuildRoleRemoveSuccess"), role, user.name));
+ }
+ else
+ {
+ formatted += (String.format(LocStrings.stub("GuildRoleRemoveFailure"), role, user.name));
+ }
+ }
+ else
+ {
+ formatted += (String.format(LocStrings.stub("GuildRoleRemoveNotAllowed"), role));
+ }
+
+ return new SubCommandFormattable(formatted);
+ }
+}
\ No newline at end of file
diff --git a/src/core/BaseKeyValueFile.java b/src/core/BaseKeyValueFile.java
deleted file mode 100644
index b2b19bd..0000000
--- a/src/core/BaseKeyValueFile.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package core;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.function.Consumer;
-
-import dataStructures.Pair;
-import utils.GlobalLog;
-import utils.LogFilter;
-import utils.io.FileUtils;
-
-public class BaseKeyValueFile
-{
- // Variables
- public static final String headerStart = "[";
- public static final String headerEnd = "]";
- public static final String pairSplit = "=";
- public static final char pairSeparator = '\n';
-
- protected final String filename;
- protected final String header;
-
-
- // Constructor
- public BaseKeyValueFile(String filename)
- {
- this.filename = filename;
- this.header = headerStart + this.getClass().getSimpleName() + headerEnd;
- }
-
- // Reads in and calls the specifid function for each keyvalue pair we find
- protected void parse(Consumer super Pair> keyValueCallback)
- {
- File f = new File(filename);
- if(f.isFile() && f.canRead())
- {
- String content = FileUtils.readContent(f).trim();
- String[] lines = content.split("" + pairSeparator);
-
- for(int i = 0; i < lines.length; ++i)
- {
- if(lines[i].contains(header))
- continue;
-
- String[] pair = lines[i].split(pairSplit);
-
- if(pair.length < 2)
- continue;
-
- String key = pair[0].trim().toLowerCase();
- String value = pair[1].trim().toLowerCase();
-
- keyValueCallback.accept(new Pair(key, value));
- }
- }
- }
-
- // Writes out a set of keyvalue pairs
- protected void write(List> toWrite)
- {
- try
- {
- ListIterator> iter = toWrite.listIterator();
-
- String outString = "";
- outString += header + pairSeparator;
-
- while(iter.hasNext())
- {
- Pair pair = iter.next();
- String key = pair.First.toLowerCase();
- String value = pair.Second.toLowerCase();
-
- outString += key + pairSplit + value + pairSeparator;
- }
-
- BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
- writer.write(outString);
- writer.close();
- }
- catch (IOException e)
- {
- GlobalLog.error(LogFilter.Core, "Issue writing file " + filename + ": " + e.getMessage());
- }
- }
-}
diff --git a/src/core/BaseLocFile.java b/src/core/BaseLocFile.java
index a139857..2d6b396 100644
--- a/src/core/BaseLocFile.java
+++ b/src/core/BaseLocFile.java
@@ -1,67 +1,66 @@
package core;
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.ArrayList;
-import dataStructures.TaggedPairStore;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Vector;
+
import utils.GlobalLog;
import utils.LogFilter;
-import utils.io.FileMonitor;
import utils.io.FileUtils;
-import utils.io.MonitoredFile;
+
// A quick-and-dirty localization tool that scrapes the project for calls to itself, then
// generates/updates a file externally with all the stub values as keys that are localized.
-public abstract class BaseLocFile
+public abstract class BaseLocFile implements IConfigSection
{
- // Pre-defined values
- public static final String KittySourceDirectory = "./src";
-
- // Filename
- public final String filename; // Example: "localization.config";
- public final String functionName; // Example: "Localizer.Stub";
-
- // Local translation storage
- protected TaggedPairStore stringStore;
+ // Variables
+ protected final String headerName; // Example: Loc Strings
+ protected final String functionName; // Example: "Localizer.Stub";
+ protected Map localized;
// Logging
private void log(String str) { GlobalLog.log(LogFilter.Strings, str); }
private void warn(String str) { GlobalLog.warn(LogFilter.Strings, str); }
private void error(String str) { GlobalLog.error(LogFilter.Strings, str); }
- // File monitoring
- protected FileMonitor fileMonitor;
-
// Constructor
- public BaseLocFile(String filename, String functionName)
+ public BaseLocFile(String headerName, String functionName)
{
- this.filename = filename;
+ this.headerName = headerName;
this.functionName = functionName;
+ localized = new HashMap();
}
+
+ //////////////////////////////////////////////////
+ // First Step: Populating with existing strings //
+ //////////////////////////////////////////////////
- // Checks the file specified for updates
- public void update()
+ private void buildLocalized(List pairs)
{
- synchronized(stringStore)
+ for(ConfigItem item : pairs)
{
- fileMonitor.update(this::onFileChange);
+ if(item.value.trim().length() <= 0)
+ {
+ localized.put(item.key, item.key);
+ }
+ else
+ {
+ localized.put(item.key, item.value);
+ }
}
}
- // When the file is changed
- protected void onFileChange(MonitoredFile file)
- {
- log("Loc file was modified at path " + file.path);
- updateLocFromDisk();
- }
+ //////////////////////////////////////////
+ // Second Step: Scraping existing files //
+ //////////////////////////////////////////
// Structure used for holding a pair of strings and any other info we need
// about localized information that is being looked up.
+ @SuppressWarnings("unused")
private class LocInfo
{
public String file;
@@ -74,8 +73,21 @@ public abstract class BaseLocFile
}
}
+ // Try to perform stripping java files for contents to localize
+ private void tryStripSpecified(Path path, ArrayList toFill)
+ {
+ try
+ {
+ stripForContents(path, toFill);
+ }
+ catch(Exception e)
+ {
+ error("issue with file: " + path.toString());
+ }
+ }
+
// Do processing on each path in the scraped directory here, assuming it's .java
- public void stripForContents(Path path, ArrayList strings)
+ private void stripForContents(Path path, ArrayList strings)
{
String filename = path.getFileName().toString();
if(filename.contains(".java"))
@@ -93,8 +105,8 @@ public abstract class BaseLocFile
{
if(noWhitespace.charAt(noWhitespace.indexOf(")") - 1) == '"' && split[i].charAt(loc - 2) != '\\')
{
- // At this point, we find the first ), then verify there's a ") behind it, and that
- // the " is not an escaped character.
+ // At this point we find the first ), then verify there's a ") behind it,
+ // and that the " is not an escaped character.
try
{
String toLocalize = split[i].substring(2, loc - 1);
@@ -113,99 +125,77 @@ public abstract class BaseLocFile
}
}
- // Nothing for now, but in the future will return a parsed and localized version of
- // the string in question if one can be found. If the localized string is empty,
- // returns a the key instead which is the default phrase.
+ // Returns the localized string if available.
+ // If the localized string is empty, returns a the key instead as the default phrase.
public String getKey(String input)
{
- if(stringStore == null)
+ if(localized == null)
+ {
return input;
+ }
- String value = stringStore.getKey(input);
+ String value = localized.get(input);
if(value == null || value.trim().length() < 1)
+ {
return input;
+ }
return value;
}
- // Reads a file to string, adapted from https://stackoverflow.com/a/326440/5383198
- private String readFileAsString(String path, Charset encoding)
- {
- try
- {
- byte[] encoded = Files.readAllBytes(Paths.get(path));
- return new String(encoded, encoding);
- }
- catch (IOException e)
- {
- warn("No file found to read from!");
- }
-
- return null;
- }
-
- // Update localization from the disk on file. Creates the file if it doesn't exist.
- // This file is internally formatted as an ini file.
- public void updateLocFromDisk()
- {
- log("Attempting to read localization file: " + filename);
-
- try
- {
- String fileContents = readFileAsString(filename, Charset.defaultCharset());
-
- if(fileContents == null)
- {
- File file = new File(filename);
- file.createNewFile();
- }
-
- stringStore = new TaggedPairStore(fileContents);
- }
- catch(IOException e)
- {
- error("IO exception during localization file read");
- }
- }
-
- // Rewrites out at the specified filename with existing stubs.
- // This preserves existing localized phrases.
- public void saveLocToDisk()
- {
- log("Attempting to write updated localization file");
-
- try
- {
- PrintWriter pw = new PrintWriter(filename);
- pw.println(stringStore.toString());
- pw.close();
- }
- catch(IOException e)
- {
- error("IO exception during localization file write");
- }
- }
-
- private void tryStripSpecified(Path path, ArrayList toFill)
- {
- try
- {
- stripForContents(path, toFill);
- }
- catch(Exception e)
- {
- error("issue with file: " + path.toString());
- }
- }
-
// Scrape the project and generate all the possible localizeable phrases.
- // This stubs out phrases to be localized.
+ // This stubs out phrases to be localized, by default placing the key in as the value.
public void scrapeAll()
{
ArrayList localizeList = new ArrayList();
- FileUtils.acquireAllFiles(KittySourceDirectory).forEach((path) -> tryStripSpecified(path, localizeList));
+ FileUtils.acquireAllFiles(Constants.SourceDirectory).forEach((path) -> tryStripSpecified(path, localizeList));
for(LocInfo toStub : localizeList)
- stringStore.addKeyValue(toStub.file, toStub.phrase, toStub.phrase);
+ {
+ localized.putIfAbsent(toStub.phrase, toStub.phrase);
+ }
+ }
+
+ ///////////////////////////////////
+ // IConfigSection Implementation //
+ ///////////////////////////////////
+
+ @Override
+ public String getSectionTitle()
+ {
+ return headerName;
+ }
+
+ @Override
+ public void consume(List pairs)
+ {
+ localized.clear();
+ buildLocalized(pairs);
+ scrapeAll();
+ }
+
+ @Override
+ public List produce()
+ {
+ List items = new Vector();
+
+ for(Entry keyValuePair : localized.entrySet())
+ {
+ String key = keyValuePair.getKey();
+ String value = keyValuePair.getValue();
+
+ if(key.equalsIgnoreCase(value))
+ {
+ items.add(new ConfigItem(headerName, key, ""));
+ }
+ else
+ {
+ items.add(new ConfigItem(headerName, key, value));
+ }
+ }
+
+ items.sort((item1, item2) -> item1.key.compareToIgnoreCase(item2.key));
+
+ return items;
}
}
diff --git a/src/core/CommandEnabler.java b/src/core/CommandEnabler.java
index 1bba27e..fff6e78 100644
--- a/src/core/CommandEnabler.java
+++ b/src/core/CommandEnabler.java
@@ -5,7 +5,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
-import dataStructures.Pair;
import utils.GlobalLog;
import utils.LogFilter;
@@ -13,48 +12,75 @@ import utils.LogFilter;
// commands that are being looked up will behave slightly differently so trimming
// rules for this file are different than the localization ones - this is more
// aggresive with whitespace removal.
-public class CommandEnabler extends BaseKeyValueFile
+public class CommandEnabler implements IConfigSection
{
// Config/const variables
public static final String enabled = "1";
public static final String disabled = "0";
public static final boolean defaultEnabledState = true;
+ public static final String commandSplit = ",";
+ public static final String HeaderName = "Command Enabler";
// Local variables
private HashMap enabledMap; // Quick lookup
- private ArrayList keyList; // Tracking ordering for later
- private final static String name = Config.AssetDirectory + "commands.config";
+ private HashMap likeNames; // Single names mapped to multiple names for use in enabledMap.
+ private ArrayList keyList; // Tracking ordering for later
+
+ // Instance
+ public static CommandEnabler instance;
// Constructor
public CommandEnabler()
{
- super(name);
+ super();
- // Create/Init variables
- GlobalLog.log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName());
- enabledMap = new HashMap<>();
- keyList = new ArrayList<>();
-
- // Startup
- readIn();
- getTrackedCommands();
- writeOut();
+ if(instance == null)
+ {
+ // Create/Init variables
+ GlobalLog.log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName());
+ enabledMap = new HashMap<>();
+ keyList = new ArrayList<>();
+ likeNames = new HashMap();
+
+ instance = this;
+ }
+ else
+ {
+ GlobalLog.error(LogFilter.Core, "You can't have two of the following: " + this.getClass().getSimpleName());
+ }
}
// Reads in the config file and parses it, keeping tabs on the order it read things
- private void readIn()
+ private void readIn(List items)
{
- parse((pair) ->{
- String key = pair.First;
- String value = pair.Second;
+ keyList.clear();
+ enabledMap.clear();
+
+ for(ConfigItem item : items)
+ {
+ String key = item.key;
+ String value = item.value;
+ // Keep track of the key itself
keyList.add(key);
-
+
+ // Write if it's enabled or disabled.
if(value.equalsIgnoreCase(enabled))
+ {
enabledMap.putIfAbsent(key, true);
+ }
else
+ {
enabledMap.putIfAbsent(key, false);
- });
+ }
+
+ // Keep track of alternate names
+ String[] keys = key.split(commandSplit);
+ for(int i = 0; i < keys.length; ++i)
+ {
+ likeNames.putIfAbsent(keys[i], key);
+ }
+ }
}
// Look up the already scraped values from the localizer and store them if they
@@ -76,9 +102,10 @@ public class CommandEnabler extends BaseKeyValueFile
}
// Write out enabled/disabled file info.
- private void writeOut()
+ private List writeOut()
{
- List> list = new Vector>();
+ // Parse in original format
+ List configItems = new Vector();
for(int i = 0; i < keyList.size(); ++i)
{
@@ -86,14 +113,16 @@ public class CommandEnabler extends BaseKeyValueFile
String value = enabled.toLowerCase();
if(enabledMap.get(key) == false)
+ {
value = disabled.toLowerCase();
+ }
- list.add(new Pair(key, value));
+ configItems.add(new ConfigItem(HeaderName, key, value));
}
- Collections.sort(list, (c1, c2) -> { return c1.First.compareTo(c2.First); });
-
- write(list);
+ Collections.sort(configItems, (c1, c2) -> { return c1.key.compareTo(c2.key); });
+
+ return configItems;
}
// Looks up a key to see if it's enabled or not
@@ -101,9 +130,33 @@ public class CommandEnabler extends BaseKeyValueFile
{
String toCheck = key.toLowerCase();
- if(enabledMap.containsKey(toCheck))
- return enabledMap.get(toCheck);
+ // Look up to see if we have the key anywhere. If not, default to enabled.
+ // It should be noted that this is just checking for disabled commands, we don't
+ // determine if a key is actually a real command in here or not.
+ String fullKey = likeNames.getOrDefault(toCheck, null);
+ if(fullKey == null)
+ return true;
- return true;
+ // If we have it, look it up. If we can't find it, default to true.
+ return enabledMap.getOrDefault(fullKey, true);
+ }
+
+ @Override
+ public String getSectionTitle()
+ {
+ return HeaderName;
+ }
+
+ @Override
+ public void consume(List pairs)
+ {
+ readIn(pairs);
+ getTrackedCommands();
+ }
+
+ @Override
+ public List produce()
+ {
+ return writeOut();
}
}
diff --git a/src/core/CommandManager.java b/src/core/CommandManager.java
index 73befc7..970100f 100644
--- a/src/core/CommandManager.java
+++ b/src/core/CommandManager.java
@@ -3,8 +3,16 @@ package core;
import java.util.*;
import java.util.Map.Entry;
+import commands.characters.CommandCharacterEditBio;
+import commands.characters.CommandCharacterEditName;
+import commands.characters.CommandCharacterEditURL;
+import commands.characters.CommandCharacterSearch;
+import commands.general.*;
+import commands.guildrole.CommandGuildRoleMain;
import dataStructures.KittyChannel;
import dataStructures.KittyGuild;
+import dataStructures.KittyRating;
+import dataStructures.KittyRole;
import dataStructures.KittyUser;
import dataStructures.Pair;
import dataStructures.Response;
@@ -20,13 +28,97 @@ public class CommandManager
private CommandEnabler commandEnabler;
private long invokeCount;
+ // Singleton
+ public static CommandManager instance;
+
// Default Constructor
public CommandManager(CommandEnabler commandEnabler)
{
- this.commands = new HashMap();
- this.threadAccumulator = new ArrayList();
- this.invokeCount = 0;
- this.commandEnabler = commandEnabler;
+ GlobalLog.log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName());
+
+ if(instance == null)
+ {
+ this.commands = new HashMap();
+ this.threadAccumulator = new ArrayList();
+ this.invokeCount = 0;
+ this.commandEnabler = commandEnabler;
+
+ registerAllCommands();
+
+ instance = this;
+ }
+ else
+ {
+ GlobalLog.error(LogFilter.Core, "You can't have two of the following: " + this.getClass().getSimpleName());
+ }
+ }
+
+ // Registers all the commands for the instance
+ public void registerAllCommands()
+ {
+ this.commands.clear();
+
+ // Dev
+ this.register(LocCommands.stub("work"), new CommandDoWork(KittyRole.Dev, KittyRating.Safe));
+ this.register(LocCommands.stub("shutdown"), new CommandShutdown(KittyRole.Dev, KittyRating.Safe));
+ this.register(LocCommands.stub("stats"), new CommandStats(KittyRole.Dev, KittyRating.Safe));
+ this.register(LocCommands.stub("invite"), new CommandInvite(KittyRole.Dev, KittyRating.Safe));
+ this.register(LocCommands.stub("buildHelp"), new CommandHelpBuilder(KittyRole.Dev, KittyRating.Safe));
+ this.register(LocCommands.stub("tweet"), new CommandTweet(KittyRole.Dev, KittyRating.Safe));
+ this.register(LocCommands.stub("dbflush"), new CommandDBFlush(KittyRole.Dev, KittyRating.Safe));
+ this.register(LocCommands.stub("dbstats"), new CommandDBStats(KittyRole.Dev, KittyRating.Safe));
+
+ // Admin
+ this.register(LocCommands.stub("rating"), new CommandRating(KittyRole.Admin, KittyRating.Safe));
+ this.register(LocCommands.stub("indicator"), new CommandChangeIndicator(KittyRole.Admin, KittyRating.Safe));
+
+ // Mod
+ this.register(LocCommands.stub("poll"), new CommandPollManage(KittyRole.Mod, KittyRating.Safe));
+ this.register(LocCommands.stub("givebeans"), new CommandGiveBeans(KittyRole.Mod, KittyRating.Safe));
+ this.register(LocCommands.stub("rpg"), new CommandRPG(KittyRole.Mod, KittyRating.Safe));
+ this.register(LocCommands.stub("rafflestart"), new CommandRaffleStart(KittyRole.Mod, KittyRating.Safe));
+ this.register(LocCommands.stub("rafflespin"), new CommandRaffleSpin(KittyRole.Mod, KittyRating.Safe));
+ this.register(LocCommands.stub("raffleend"), new CommandRaffleEnd(KittyRole.Mod, KittyRating.Safe));
+
+ // General
+ this.register(LocCommands.stub("fetch"), new CommandFetch(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("teey"), new CommandTeey(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("perish, thenperish"), new CommandPerish(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("yeet"), new CommandYeet(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("ping"), new CommandPing(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("boop"), new CommandBoop(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("roll"), new CommandRoll(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("choose"), new CommandChoose(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("help"), new CommandHelp(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("info, about"), new CommandInfo(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("vote"), new CommandPollVote(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("results"), new CommandPollResults(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("showpoll"), new CommandPollShow(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("wolfram"), new CommandWolfram(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("c++, g++, cplus, cpp"), new CommandColiru(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("java, jdoodle"), new CommandJDoodle(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("beans"), new CommandBeansShow(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("kittyrole"), new CommandRole(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("bet"), new CommandBetBeans(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("map"), new CommandMap(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("rpstart"), new CommandRPStart(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("rpend"), new CommandRPEnd(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("tony, stark, dontfeelgood, dontfeelsogood"), new CommandStark(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("blur"), new CommandBlurry(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("eightball, 8ball"), new CommandEightBall(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("catch"), new CommandCatch(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("bethistory"), new CommandBetHistory(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("crouton"), new CommandCrouton(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("benchmark, bench"), new CommandBenchmark(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("rafflejoin"), new CommandRaffleJoin(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("searchcharacter"), new CommandCharacterSearch(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("charactereditbio"), new CommandCharacterEditBio(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("charactereditname"), new CommandCharacterEditName(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("charactereditURL"), new CommandCharacterEditURL(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("leaderboard"), new CommandLeaderboard(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("color, colour"), new CommandColor(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("remind"), new CommandRemind(KittyRole.General, KittyRating.Safe));
+ this.register(LocCommands.stub("role"), new CommandGuildRoleMain(KittyRole.General, KittyRating.Safe));
}
// Allows the command manager to keep track of a command. Takes a pair (the un-localized and localzied commands)
@@ -36,41 +128,23 @@ public class CommandManager
if(pair == null || pair.Second == null)
return;
- // If we haven't already split a multisplit command (or even assessed that),
- // then verify if we even need to register the commands at all. If it's
- // not enabled, don't register it.
- if(pair.First != null && !commandEnabler.isEnabled(pair.First))
- return;
-
- String key = pair.Second;
-
- if(key.contains(","))
- {
-
- String[] keys = key.split(",");
- register(keys, command);
- return;
- }
-
- key = key.toLowerCase();
- command.registeredNames.add(key);
-
- Command old = commands.put(key, command);
-
- if(old != null)
- {
- GlobalLog.warn(LogFilter.Core, "Writing over a command with the key " + key);
- return;
- }
-
- GlobalLog.log(LogFilter.Core, "Command registered under key " + key);
- }
-
- // Registers a command under multiple names!
- public void register(String[] keys, Command command)
- {
+ String[] keys = pair.Second.split(",");
+
for(int i = 0; i < keys.length; ++i)
- register(new Pair(null, keys[i].trim()), command);
+ {
+ String key = keys[i].trim().toLowerCase();
+
+ command.registeredNames.add(key);
+ Command old = commands.put(key, command);
+
+ if(old != null)
+ {
+ GlobalLog.warn(LogFilter.Core, "Writing over a command with the key " + key);
+ return;
+ }
+
+ GlobalLog.log(LogFilter.Core, "Command registered under key " + key);
+ }
}
// Calls the command but on a whole new thread!
@@ -80,6 +154,12 @@ public class CommandManager
if(input == null || !input.isValid())
return false;
+ // At this point, verify that the command is enabled. If we don't have any info
+ // on if it's enabled or not, we assume it's enabled to prevent broken functionality due
+ // to formatting or casing issues.
+ if(input.key != null && !commandEnabler.isEnabled(input.key))
+ return false;
+
Command command = commands.get(input.key);
if(command != null)
{
diff --git a/src/core/Config.java b/src/core/Config.java
index a34b8e2..c76c9c2 100644
--- a/src/core/Config.java
+++ b/src/core/Config.java
@@ -1,9 +1,109 @@
package core;
-import java.awt.Color;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
-public final class Config
-{
- public static final Color ColorDefault = new Color(7*16, 8*16, 9*16); // A slate-grey
- public static final String AssetDirectory = "./assets/";
+import utils.GlobalLog;
+import utils.LogFilter;
+import utils.io.FileMonitor;
+
+public class Config
+{
+ private static final String filepath = Constants.AssetDirectory + Constants.ConfigFilename;
+
+ private ConfigCSV configCSV;
+ private List sections;
+ private FileMonitor monitoredConfigFile;
+
+ public static Config instance;
+
+ public Config()
+ {
+ if(instance == null)
+ {
+ try
+ {
+ sections = new Vector();
+
+ // Add all sections
+ sections.add(new LocCommands());
+ sections.add(new LocStrings());
+ sections.add(new CommandEnabler());
+
+ // Build the config file, then start monitoring it.
+ buildConfigFile(filepath);
+ monitoredConfigFile = new FileMonitor(filepath);
+
+ instance = this;
+ }
+ catch(Exception e)
+ {
+ String logText = "Failure during config startup. The config must start correctly, or the bot cannot run - aborting. Error: " + e.getMessage();
+ GlobalLog.error(LogFilter.Core, logText);
+ System.exit(-1);
+ }
+ }
+ else
+ {
+ GlobalLog.error(LogFilter.Core, "Only one config class is allowed, period. Aborting.");
+ System.exit(-1);
+ }
+ }
+
+ // This has more overhead but safely builds the file.
+ // It returns if it succeeded or not.
+ private boolean safelyBuildConfigFile(String path)
+ {
+ try
+ {
+ buildConfigFile(path);
+ }
+ catch (Exception e)
+ {
+ GlobalLog.error("Failure during config file updating, aborting update immediately and attempting to salvage operation! The error was: " + e);
+ return false;
+ }
+
+ return true;
+ }
+
+ // Builds the config file and will throw an exception if it fails
+ public void buildConfigFile(String path) throws IOException
+ {
+ configCSV = new ConfigCSV(sections, path);
+
+ Map> groupedSections = ConfigCSV.groupByColumn(configCSV.getItems(), 0);
+
+ if(groupedSections != null)
+ {
+ for(IConfigSection section : sections)
+ {
+ List items = groupedSections.getOrDefault(section.getSectionTitle(), new Vector());
+ section.consume(items);
+ }
+ }
+
+ configCSV.writeFile();
+ }
+
+ // Call very frequently, but lazily. This will update the file content.
+ public void upkeep()
+ {
+ monitoredConfigFile.update((monitoredFile) ->
+ {
+ GlobalLog.log("File updated at " + monitoredFile.path);
+
+ // Attempt to rebuild. If we do it safely, then force-sync the DB and re-register.
+ if(safelyBuildConfigFile(monitoredFile.path.toString()))
+ {
+ // Re-register all commands now that we've updated the config.
+ // Before we do that tho, sync off anything that needs syncing.
+ // TODO: This is not thread safe.
+ DatabaseManager.instance.upkeep();
+ CommandManager.instance.registerAllCommands();
+ }
+ });
+ }
}
diff --git a/src/core/ConfigCSV.java b/src/core/ConfigCSV.java
new file mode 100644
index 0000000..7b644d0
--- /dev/null
+++ b/src/core/ConfigCSV.java
@@ -0,0 +1,159 @@
+package core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import com.opencsv.CSVReader;
+import com.opencsv.CSVReaderBuilder;
+import com.opencsv.CSVWriter;
+
+import utils.GlobalLog;
+
+public class ConfigCSV
+{
+ // Variables
+ private final String path;
+ private List fileContents;
+ private List sections;
+
+ // Constructor
+ public ConfigCSV(List sections, String path) throws IOException
+ {
+ this.path = path;
+ this.sections = sections;
+
+ fileContents = new Vector();
+
+ read(path);
+ }
+
+ // Creates the writer in the format we desire.
+ public static CSVWriter makeWriter(Writer writer)
+ {
+ return new CSVWriter(writer,
+ CSVWriter.DEFAULT_SEPARATOR,
+ CSVWriter.DEFAULT_QUOTE_CHARACTER,
+ '\\',
+ CSVWriter.DEFAULT_LINE_END);
+ }
+
+ // Read the file. This is internal only.
+ private void read(String filepath) throws IOException
+ {
+ File configFile = new File(filepath);
+
+ // If we had to create a new file, write the default header into it.
+ if(configFile.createNewFile())
+ {
+ Writer writer = Files.newBufferedWriter(Paths.get(path));
+ CSVWriter csvWriter = makeWriter(writer);
+ csvWriter.writeNext(ConfigItem.header);
+ csvWriter.close();
+ }
+
+ Reader reader = Files.newBufferedReader(Paths.get(filepath));
+ CSVReader csvReader = new CSVReaderBuilder(reader).withSkipLines(1).build();
+ fileContents.clear();
+
+ // Read contents. As for the line number, we not only start counting at 1, we also skip the header.
+ int line = 2;
+ String[] record = null;
+ while ((record = csvReader.readNext()) != null)
+ {
+ if(record.length < ConfigItem.items)
+ {
+ GlobalLog.warn("Incorrect number of items on line " + line + " in " + path);
+ continue;
+ }
+
+ ConfigItem parsedLine = new ConfigItem(record[0], record[1], record[2]);
+ fileContents.add(parsedLine);
+ ++line;
+ }
+
+ // Close down
+ csvReader.close();
+ reader.close();
+ }
+
+ // Get a copy of the internal items
+ public List getItems()
+ {
+ List out = new Vector();
+
+ for(ConfigItem item : fileContents)
+ {
+ out.add(new ConfigItem(item.type, item.key, item.value));
+ }
+
+ return out;
+ }
+
+ // Set the internal items
+ public void setItems(List newList)
+ {
+ fileContents = newList;
+ }
+
+ // Write out the file, header then body.
+ public void writeFile()
+ {
+ try
+ {
+ List toWrite = new Vector();
+ toWrite.add(ConfigItem.header);
+
+ for(IConfigSection section : sections)
+ {
+ List items = section.produce();
+
+ for(ConfigItem item : items)
+ {
+ toWrite.add(item.getAll());
+ }
+ }
+
+ Writer writer = Files.newBufferedWriter(Paths.get(path));
+
+ CSVWriter csvWriter = makeWriter(writer);
+ csvWriter.writeAll(toWrite);
+ csvWriter.flush();
+ csvWriter.close();
+
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ // Static utility function
+ public static Map> groupByColumn(List items, int columnNumber)
+ {
+ if(items == null || items.size() <= 0 || columnNumber < 0)
+ {
+ return null;
+ }
+
+ Map> sortedItems = new HashMap>();
+
+ for(ConfigItem item : items)
+ {
+ String key = item.getColumn(columnNumber);
+ List list = sortedItems.getOrDefault(key, new Vector());
+ list.add(item);
+ sortedItems.put(key, list);
+ }
+
+ return sortedItems;
+ }
+}
diff --git a/src/core/ConfigItem.java b/src/core/ConfigItem.java
new file mode 100644
index 0000000..5e73eb5
--- /dev/null
+++ b/src/core/ConfigItem.java
@@ -0,0 +1,40 @@
+package core;
+
+// Everything in here must be a string type. This class does not
+// perform any parsing past naming columns, and just holds the raw data.
+public class ConfigItem
+{
+ public String type;
+ public String key;
+ public String value;
+ public static final int items = 3;
+ public static final String[] header = {"Type","Key","Value"};
+
+ public ConfigItem(String type, String key, String value)
+ {
+ this.type = type;
+ this.key = key;
+ this.value = value;
+ }
+
+ public String getColumn(int column)
+ {
+ switch(column)
+ {
+ case 0: return type;
+ case 1: return key;
+ case 2: return value;
+ default: return null;
+ }
+ }
+
+ public String[] getAll()
+ {
+ return new String[] {type, key, value};
+ }
+
+ public String toString()
+ {
+ return "type: " + type + ", key: " + key + ", value: " + value;
+ }
+}
diff --git a/src/core/Constants.java b/src/core/Constants.java
new file mode 100644
index 0000000..9fa2a1a
--- /dev/null
+++ b/src/core/Constants.java
@@ -0,0 +1,12 @@
+package core;
+
+import java.awt.Color;
+
+// Things that are internal only and aren't put inside an external config file.
+public final class Constants
+{
+ public static final Color ColorDefault = new Color(7*16, 8*16, 9*16); // A slate-grey
+ public static final String AssetDirectory = "./assets/";
+ public static final String ConfigFilename = "config.csv";
+ public static final String SourceDirectory = "./src";
+}
diff --git a/src/core/IConfigSection.java b/src/core/IConfigSection.java
new file mode 100644
index 0000000..03300ce
--- /dev/null
+++ b/src/core/IConfigSection.java
@@ -0,0 +1,16 @@
+package core;
+
+import java.util.List;
+
+// A config section is a unit of config that holds data.
+public abstract interface IConfigSection
+{
+ // Get the title of the section
+ public abstract String getSectionTitle();
+
+ // Provide the parsed key and values for a given section
+ public abstract void consume(List pairs);
+
+ // Ask the section to produce a list of pairs to be written out to the key and value columns in the csv
+ public abstract List produce();
+}
diff --git a/src/core/LocCommands.java b/src/core/LocCommands.java
index b32e690..30d071e 100644
--- a/src/core/LocCommands.java
+++ b/src/core/LocCommands.java
@@ -1,35 +1,32 @@
package core;
import java.util.ArrayList;
+
import utils.GlobalLog;
import utils.LogFilter;
-import utils.io.FileMonitor;
import dataStructures.Pair;
// Performs the same localization for the strings associated with command names as
// is performed with general strings in the application
-public class LocCommands extends BaseLocFile
+public class LocCommands extends BaseLocFile implements IConfigSection
{
- public static final String fileName = Config.AssetDirectory + "locCommands.config";
+ // Defined const variables
+ public static final String HeaderName = "Localized Commands";
public static final String function = "LocCommands.stub";
+ // Instance
private static LocCommands instance;
+ // Constructor
public LocCommands()
{
- super(fileName, function);
+ super(HeaderName, function);
GlobalLog.log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName());
if(instance == null)
{
instance = this;
-
- updateLocFromDisk();
- scrapeAll();
- saveLocToDisk();
-
- fileMonitor = new FileMonitor(filename);
}
else
{
@@ -47,12 +44,7 @@ public class LocCommands extends BaseLocFile
public static ArrayList getUnlocalizedCommands()
{
ArrayList raw = new ArrayList<>();
- instance.stringStore.forEach((pair) -> raw.add((String)((Pair, ?>)pair).First ));
+ instance.localized.keySet().forEach((key) -> raw.add(key));
return raw;
}
-
- public static void upkeep()
- {
- instance.update();
- }
}
diff --git a/src/core/LocStrings.java b/src/core/LocStrings.java
index d3c6ad6..e1cb260 100644
--- a/src/core/LocStrings.java
+++ b/src/core/LocStrings.java
@@ -2,33 +2,26 @@ package core;
import utils.GlobalLog;
import utils.LogFilter;
-import utils.io.FileMonitor;
// A quick-and-dirty localization tool that scrapes the project for calls to itself, then
// generates/updates a file externally (phrases.config) with all the stub values as keys that
// can then be localized.
public class LocStrings extends BaseLocFile
{
- public static final String fileName = Config.AssetDirectory + "locStrings.config";
+ public static final String HeaderName = "Localized Strings";
public static final String function = "LocStrings.stub";
private static LocStrings instance;
public LocStrings()
{
- super(fileName, function);
+ super(HeaderName, function);
GlobalLog.log(LogFilter.Core, "Initializing " + this.getClass().getSimpleName());
if(instance == null)
{
instance = this;
-
- updateLocFromDisk();
- scrapeAll();
- saveLocToDisk();
-
- fileMonitor = new FileMonitor(filename);
}
else
{
@@ -46,9 +39,4 @@ public class LocStrings extends BaseLocFile
{
return instance.getKey(stubbedPreviously);
}
-
- public static void upkeep()
- {
- instance.update();
- }
}
\ No newline at end of file
diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java
index 986187f..d778739 100644
--- a/src/core/ObjectBuilderFactory.java
+++ b/src/core/ObjectBuilderFactory.java
@@ -7,18 +7,16 @@ import java.util.concurrent.Semaphore;
import javax.security.auth.login.LoginException;
-import commands.*;
+import commands.characters.*;
+import commands.general.*;
+import commands.guildrole.CommandGuildRoleMain;
import core.lua.PluginManager;
import dataStructures.*;
import main.Main;
import net.dv8tion.jda.core.AccountType;
import net.dv8tion.jda.core.JDA;
import net.dv8tion.jda.core.JDABuilder;
-import net.dv8tion.jda.core.entities.Emote;
-import net.dv8tion.jda.core.entities.Game;
-import net.dv8tion.jda.core.entities.Guild;
-import net.dv8tion.jda.core.entities.Member;
-import net.dv8tion.jda.core.entities.User;
+import net.dv8tion.jda.core.entities.*;
import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent;
import offline.Ref;
import utils.AdminControl;
@@ -51,14 +49,17 @@ public class ObjectBuilderFactory
// Plugin manager
private static PluginManager pluginManager;
-
+
+ // Command manager
+ private static CommandManager commandManager;
+
// Localization classes - these are singletons, but should be initialized before almost all other
// things so their inclusion in the factory is to ensure they're started at the correct time.
@SuppressWarnings("unused") private static LocStrings locStrings;
@SuppressWarnings("unused") private static LocCommands locCommands;
- // Handles if we can or can't use specific commands, parsing a config file based on loc data to do so.
- private static CommandEnabler commandEnabler;
+ // Config
+ @SuppressWarnings("unused") private static Config config;
// Lazy initialization multithreaded mutex stuff to prevent explosions.
// TODO: Investigate using 'synchronized' instead potentially
@@ -88,8 +89,7 @@ public class ObjectBuilderFactory
// Start by reading from things that are external. Because
// we require these things to be resolved before the rest of the application,
// we place them here.
- locStrings = new LocStrings();
- locCommands = new LocCommands();
+ config = new Config();
}
finally
{
@@ -371,86 +371,10 @@ public class ObjectBuilderFactory
{
lazyInit();
- CommandManager manager = new CommandManager(commandEnabler);
+ if(commandManager == null)
+ commandManager = new CommandManager(commandEnabler);
- // Dev
- manager.register(LocCommands.stub("work"), new CommandDoWork(KittyRole.Dev, KittyRating.Safe));
- manager.register(LocCommands.stub("shutdown"), new CommandShutdown(KittyRole.Dev, KittyRating.Safe));
- manager.register(LocCommands.stub("stats"), new CommandStats(KittyRole.Dev, KittyRating.Safe));
- manager.register(LocCommands.stub("invite"), new CommandInvite(KittyRole.Dev, KittyRating.Safe));
- manager.register(LocCommands.stub("buildHelp"), new CommandHelpBuilder(KittyRole.Dev, KittyRating.Safe));
- manager.register(LocCommands.stub("tweet"), new CommandTweet(KittyRole.Dev, KittyRating.Safe));
- manager.register(LocCommands.stub("dbflush"), new CommandDBFlush(KittyRole.Dev, KittyRating.Safe));
- manager.register(LocCommands.stub("dbstats"), new CommandDBStats(KittyRole.Dev, KittyRating.Safe));
-
- // Admin
- manager.register(LocCommands.stub("rating"), new CommandRating(KittyRole.Admin, KittyRating.Safe));
- manager.register(LocCommands.stub("indicator"), new CommandChangeIndicator(KittyRole.Admin, KittyRating.Safe));
- manager.register(LocCommands.stub("guildroleallowed"), new CommandGuildRoleAllowed(KittyRole.Admin, KittyRating.Safe));
- manager.register(LocCommands.stub("guildrolenotallowed"), new CommandGuildRoleNotAllowed(KittyRole.Admin, KittyRating.Safe));
-
- // Mod
- manager.register(LocCommands.stub("poll"), new CommandPollManage(KittyRole.Mod, KittyRating.Safe));
- manager.register(LocCommands.stub("givebeans"), new CommandGiveBeans(KittyRole.Mod, KittyRating.Safe));
- manager.register(LocCommands.stub("rpg"), new CommandRPG(KittyRole.Mod, KittyRating.Safe));
- manager.register(LocCommands.stub("rafflestart"), new CommandRaffleStart(KittyRole.Mod, KittyRating.Safe));
- manager.register(LocCommands.stub("rafflespin"), new CommandRaffleSpin(KittyRole.Mod, KittyRating.Safe));
- manager.register(LocCommands.stub("raffleend"), new CommandRaffleEnd(KittyRole.Mod, KittyRating.Safe));
-
- // General
- manager.register(LocCommands.stub("fetch"), new CommandFetch(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("guildroleadd"), new CommandGuildRoleAdd(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("guildroleremove"), new CommandGuildRoleRemove(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("teey"), new CommandTeey(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("perish, thenperish"), new CommandPerish(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("yeet"), new CommandYeet(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("ping"), new CommandPing(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("boop"), new CommandBoop(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("roll"), new CommandRoll(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("choose"), new CommandChoose(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("help"), new CommandHelp(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("info, about"), new CommandInfo(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("vote"), new CommandPollVote(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("results"), new CommandPollResults(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("showpoll"), new CommandPollShow(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("wolfram"), new CommandWolfram(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("c++, g++, cplus, cpp"), new CommandColiru(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("java, jdoodle"), new CommandJDoodle(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("beans"), new CommandBeansShow(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("role"), new CommandRole(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("bet"), new CommandBetBeans(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("map"), new CommandMap(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("rpstart"), new CommandRPStart(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("rpend"), new CommandRPEnd(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("tony, stark, dontfeelgood, dontfeelsogood"), new CommandStark(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("blur"), new CommandBlurry(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("eightball, 8ball"), new CommandEightBall(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("catch"), new CommandCatch(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("guildrolelist"), new CommandGuildRoleList(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("bethistory"), new CommandBetHistory(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("crouton"), new CommandCrouton(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("benchmark, bench"), new CommandBenchmark(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("rafflejoin"), new CommandRaffleJoin(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("charactercreate"), new CommandCharacterCreate(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("searchcharacter"), new CommandCharacterSearch(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("charactereditbio"), new CommandCharacterEditBio(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("charactereditname"), new CommandCharacterEditName(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("charactereditURL"), new CommandCharacterEditURL(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("leaderboard"), new CommandLeaderboard(KittyRole.General, KittyRating.Safe));
- manager.register(LocCommands.stub("color, colour"), new CommandColor(KittyRole.General, KittyRating.Safe));
-
- return manager;
- }
-
- // Constructs a CommandEnabler if it doesn't exist, and gets the existing one if it does.
- public static CommandEnabler constructCommandEnabler()
- {
- lazyInit();
-
- if(commandEnabler == null)
- commandEnabler = new CommandEnabler();
-
- return commandEnabler;
+ return commandManager;
}
// Default database manager construction. It can be constructed
@@ -492,7 +416,7 @@ public class ObjectBuilderFactory
lazyInit();
if(pluginManager == null)
- pluginManager = new PluginManager(Config.AssetDirectory + "plugins/");
+ pluginManager = new PluginManager(Constants.AssetDirectory + "plugins/");
return pluginManager;
}
diff --git a/src/core/Settings.java b/src/core/Settings.java
deleted file mode 100644
index 9ffdf42..0000000
--- a/src/core/Settings.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package core;
-
-public class Settings {
-
-}
diff --git a/src/core/SubCommand.java b/src/core/SubCommand.java
new file mode 100644
index 0000000..2b0b81f
--- /dev/null
+++ b/src/core/SubCommand.java
@@ -0,0 +1,64 @@
+package core;
+
+import dataStructures.*;
+import utils.GlobalLog;
+import utils.LogFilter;
+
+public abstract class SubCommand
+{
+ private KittyRole roleLevel;
+ private KittyRating contentRating;
+
+
+ public SubCommand(KittyRole roleLevel, KittyRating contentRating)
+ {
+ this.roleLevel = roleLevel;
+ this.contentRating = contentRating;
+ }
+
+ private void Reject(KittyUser user, String reason)
+ {
+ GlobalLog.warn(LogFilter.Command, this.getClass().getSimpleName() + " from " + user.name + " rejected due to command's " + reason);
+ }
+
+ private boolean CanCall(KittyGuild guild, KittyChannel channel, KittyUser user)
+ {
+ if(guild.contentRating.getValue() < contentRating.getValue())
+ {
+ Reject(user, "content rating");
+ return false;
+ }
+
+ //TODO: ADD CHANNEL CHECK HERE
+
+ if(user.getRole().getValue() >= roleLevel.getValue())
+ {
+ return true;
+ }
+
+ Reject(user, "permissions");
+ return false;
+ }
+
+ // Called by the Command manager - this will run the command
+ // if the issuing user has the permission to do so!
+ protected final void Invoke(KittyGuild guild, KittyChannel channel, KittyUser user, String input)
+ {
+ if(!CanCall(guild, channel, user))
+ return;
+
+ OnRun(guild, channel, user, input);
+ }
+
+ public KittyRating Rating()
+ {
+ return contentRating;
+ }
+
+ public KittyRole RequiredRole()
+ {
+ return roleLevel;
+ }
+
+ public abstract SubCommandFormattable OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, String input);
+}
\ No newline at end of file
diff --git a/src/core/SubCommandFormattable.java b/src/core/SubCommandFormattable.java
new file mode 100644
index 0000000..a76d2f4
--- /dev/null
+++ b/src/core/SubCommandFormattable.java
@@ -0,0 +1,40 @@
+package core;
+
+import dataStructures.KittyEmbed;
+import dataStructures.Response;
+
+// Only one isn't null!
+public class SubCommandFormattable
+{
+ public final KittyEmbed resEmbed;
+ public final String resString;
+
+ // Default constructor is hidden and disabled.
+ // If somehow it is called, defaults to an empty string and no embed.
+ @SuppressWarnings("unused")
+ private SubCommandFormattable()
+ {
+ this.resEmbed = null;
+ this.resString = "";
+ }
+
+ public SubCommandFormattable(String res)
+ {
+ this.resEmbed = null;
+ this.resString = res;
+ }
+
+ public SubCommandFormattable(KittyEmbed embed)
+ {
+ this.resEmbed = embed;
+ this.resString = null;
+ }
+
+ public void Call(Response res)
+ {
+ if(resEmbed == null)
+ res.send(resString);
+ else
+ res.send(resEmbed);
+ }
+}
diff --git a/src/core/SubCommandFramework.java b/src/core/SubCommandFramework.java
new file mode 100644
index 0000000..ee44eaf
--- /dev/null
+++ b/src/core/SubCommandFramework.java
@@ -0,0 +1,34 @@
+package core;
+
+import java.util.HashMap;
+
+import dataStructures.KittyChannel;
+import dataStructures.KittyGuild;
+import dataStructures.KittyUser;
+import utils.GlobalLog;
+
+public class SubCommandFramework
+{
+ HashMap commands = new HashMap();
+
+ public SubCommandFramework()
+ {
+
+ }
+
+ public void addCommand(String name, SubCommand command)
+ {
+ name = name.toLowerCase();
+ if(commands.put(name, command) != null)
+ GlobalLog.error("Multiple registration of a name with name '" + name + "'!");
+
+ GlobalLog.log("Registered SubCommand " + name);
+ }
+
+ public SubCommandFormattable run(KittyGuild guild, KittyChannel channel, KittyUser user, String input)
+ {
+ System.out.print(input);
+ SubCommandFormattable res = commands.get(input.split(" ")[0].toLowerCase()).OnRun(guild, channel, user, input.substring(input.indexOf(" ")));
+ return res;
+ }
+}
diff --git a/src/core/benchmark/BenchmarkInput.java b/src/core/benchmark/BenchmarkInput.java
index 3773c36..84be8bf 100644
--- a/src/core/benchmark/BenchmarkInput.java
+++ b/src/core/benchmark/BenchmarkInput.java
@@ -30,7 +30,5 @@ public class BenchmarkInput
key = raw.substring(0, whitespacePos).trim();
value = raw.substring(whitespacePos).trim();
}
-
-
}
diff --git a/src/core/benchmark/BenchmarkManager.java b/src/core/benchmark/BenchmarkManager.java
index bb9711e..63bb096 100644
--- a/src/core/benchmark/BenchmarkManager.java
+++ b/src/core/benchmark/BenchmarkManager.java
@@ -5,7 +5,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import core.Config;
+import core.Constants;
import dataStructures.Pair;
import utils.io.DirectoryMonitor;
import utils.io.FileUtils;
@@ -17,7 +17,7 @@ import utils.io.MonitoredFile;
public class BenchmarkManager
{
// Variables
- public final String directory = Config.AssetDirectory + "userbench/";
+ public final String directory = Constants.AssetDirectory + "userbench/";
public final String extension = ".csv";
public final String lineDelimiter = "\n";
diff --git a/src/dataStructures/TaggedPairStore.java b/src/dataStructures/TaggedPairStore.java
deleted file mode 100644
index 8513b11..0000000
--- a/src/dataStructures/TaggedPairStore.java
+++ /dev/null
@@ -1,212 +0,0 @@
-package dataStructures;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-
-import utils.StringUtils;
-
-// This is a class designed to parse ini inspired key-value pairs that are sectioned off.
-// The difference here is that this is more permissive than an ini file, and only accepts
-// a single split character, not the traditional set an ini does. All of the following are valid:
-//
-// [ExampleSection]
-// Key=Value
-// Valid Ridiculous Key&\n\t_.:;foo = \tValid Ridiculous Value*&%$()^.[]{}@
-// EmptyValue=
-//
-// Note that the sections are NOT designed to allow for duplicate keys across them.
-// This is a restriction of the structure, but can be changed later potentially.
-// The only value not allowed in a key or value is the KeyValueSplit.
-public class TaggedPairStore
-{
- // Variables
- public final char SectionStart = '[';
- public final char SectionEnd = ']';
- public final char PairLineSeparator = '\n';
- public final String PairSplit = "=";
-
- // [Key: SectionName, [Key: KeyString, Value: ValueString]]
- private HashMap> taggedPairs;
-
- // [Key: KeyString, Value: ValueString]]
- private HashMap allPairs;
-
- // String constructor that parses the input string into the object
- public TaggedPairStore(String input)
- {
- taggedPairs = new HashMap>();
- allPairs = new HashMap();
- parse(input);
- }
-
- // Calls back on each item in the entire structure. Provides section, then a pair of the keyString and valueString.
- @SuppressWarnings({"rawtypes", "unchecked"})
- public void forEach(BiConsumer super String, Pair super String, ? super String>> action)
- {
- Iterator it = taggedPairs.entrySet().iterator();
- while (it.hasNext())
- {
- Map.Entry pair = (Map.Entry)it.next();
- Iterator internal = ((HashMap)pair.getValue()).entrySet().iterator();
-
- while(internal.hasNext())
- {
- Map.Entry internalPair = (Map.Entry)internal.next();
- action.accept((String)pair.getKey(), new Pair((String)internalPair.getKey(), (String)internalPair.getValue()));
- }
- }
- }
-
- // Calls back each item in the structure but does not priv
- @SuppressWarnings({"rawtypes"})
- public void forEach(Consumer> action)
- {
- Iterator it = allPairs.entrySet().iterator();
- while (it.hasNext())
- {
- Map.Entry pair = (Map.Entry)it.next();
- action.accept(new Pair((String)pair.getKey(), (String)pair.getValue()));
- }
- }
-
- // Parses the internal hashmap as a string then reutrns it, featuring sections.
- // Iterates over all key/value pairs in the section and print them. Does not print
- // the value of a given key if it is the same as the key.
- @SuppressWarnings({"rawtypes", "unchecked"})
- public String toString()
- {
- String out = "";
-
- // Iterates over the sections and
- Iterator it = taggedPairs.entrySet().iterator();
- while (it.hasNext())
- {
- Map.Entry pair = (Map.Entry)it.next();
- out += ("" + SectionStart + pair.getKey() + SectionEnd + PairLineSeparator);
-
- Iterator internal = ((HashMap)pair.getValue()).entrySet().iterator();
- while(internal.hasNext())
- {
- Map.Entry internalPair = (Map.Entry)internal.next();
- String key = (String)internalPair.getKey();
- String value = (String)internalPair.getValue();
- key = StringUtils.reEscape(key);
- value = StringUtils.reEscape(value);
-
- if(key.endsWith("\\r"))
- {
- if(!key.endsWith("\\r\\r"))
- key = key.substring(0, key.length() - 2);
- }
-
- if(value.endsWith("\\r"))
- {
- if(!value.endsWith("\\r\\r"))
- value = value.substring(0, value.length() - 2);
- }
-
- if(key == value)
- out += (key + PairSplit) + PairLineSeparator;
- else
- out += (key + PairSplit + value) + PairLineSeparator;
- }
-
- out += PairLineSeparator;
- }
-
- return out;
- }
-
- // Parses out the string passed in into the sectionkeyValue HashMap.
- // Any character used in a split call is escaped just in case on
- // account of some characters having specific regex meanings.
- private void parse(String input)
- {
- if(input == null)
- return;
-
- String[] sections = input.split("\\" + SectionStart);
-
- for(int sec = 0; sec < sections.length; ++sec)
- {
- // Gather information about the contents of the section, and the header.
- String section = sections[sec];
- if(section.length() < 2)
- continue;
-
- int pos = section.indexOf(SectionEnd);
- if(pos == -1)
- continue;
-
- // Parse section name. If it already exists, don't bother making it.
- String sectionName = section.substring(0, pos);
- addSection(sectionName);
-
- // Parse out the pairs within the section, split them all out.
- String unparsedPairs = section.substring(pos + 1);
- String[] pairs = unparsedPairs.split("\\" + PairLineSeparator);
-
- // Parse out valid key-value pairs, and store them in the specified section.
- // At this point, we can be guarenteed that sectionName is in the Hashmap.
- for(int pair = 0; pair < pairs.length; ++pair)
- {
- String line = pairs[pair];
- int splitPos = line.indexOf(PairSplit);
- if(splitPos < 0)
- continue;
-
- String key = line.substring(0, splitPos);
- String value = line.substring(splitPos + PairSplit.length());
- key = StringUtils.unEscape(key);
- value = StringUtils.unEscape(value);
-
- taggedPairs.get(sectionName).putIfAbsent(key, value);
- allPairs.putIfAbsent(key, value);
- }
- }
- }
-
- // Dumps out a string array
- @SuppressWarnings("unused")
- private void dump(String[] toPrint)
- {
- System.out.println("Length: " + toPrint.length);
-
- for(int i = 0; i < toPrint.length; ++i)
- System.out.println(toPrint[i]);
- }
-
- // Adds a KeyValue pair to the specified section if it's not already there.
- // Also creates the section if it's not already present.
- public void addKeyValue(String sectionName, String key, String value)
- {
- addSection(sectionName);
- taggedPairs.get(sectionName).putIfAbsent(key, value);
- allPairs.putIfAbsent(key, value);
- }
-
- // Adds a given section to the hashmap if it's not already present
- public void addSection(String sectionName)
- {
- taggedPairs.putIfAbsent(sectionName, new HashMap());
- }
-
- // Returns a HashMap of Keys to Values for a given section
- @SuppressWarnings("unchecked")
- public HashMap getSection(String sectionName)
- {
- return (HashMap) taggedPairs.get(sectionName).clone();
- }
-
- // Look up a global key
- public String getKey(String key)
- {
- if(allPairs.containsKey(key))
- return allPairs.get(key);
-
- return null;
- }
-}
diff --git a/src/main/Main.java b/src/main/Main.java
index c0387a8..a69aba9 100644
--- a/src/main/Main.java
+++ b/src/main/Main.java
@@ -36,7 +36,6 @@ public class Main extends ListenerAdapter
// Variables and bot specific objects
private static KittyCore kittyCore;
private static DatabaseManager databaseManager;
- private static CommandEnabler commandEnabler;
private static CommandManager commandManager;
private static Stats stats;
private static RPManager rpManager;
@@ -49,8 +48,7 @@ public class Main extends ListenerAdapter
// Factory startup. The ordering is intentional.
GlobalLog.initialize();
databaseManager = ObjectBuilderFactory.constructDatabaseManager();
- commandEnabler = ObjectBuilderFactory.constructCommandEnabler();
- commandManager = ObjectBuilderFactory.constructCommandManager(commandEnabler);
+ commandManager = ObjectBuilderFactory.constructCommandManager(CommandEnabler.instance); // TODO: Untangle this singleton
stats = ObjectBuilderFactory.constructStats(commandManager);
charManager = new CharacterManager();
rpManager = ObjectBuilderFactory.constructRPManager();
diff --git a/src/main/Superintendent.java b/src/main/Superintendent.java
index aae634c..1b49ecf 100644
--- a/src/main/Superintendent.java
+++ b/src/main/Superintendent.java
@@ -2,9 +2,8 @@ package main;
import java.util.concurrent.atomic.AtomicInteger;
+import core.Config;
import core.DatabaseManager;
-import core.LocCommands;
-import core.LocStrings;
import core.RPManager;
import core.Stats;
import dataStructures.KittyChannel;
@@ -74,9 +73,8 @@ public class Superintendent
// Happens just before the command / plugin runs.
public static boolean perCommandUpkeepPre()
{
- // Upkeep localization system's file monitoring
- LocStrings.upkeep();
- LocCommands.upkeep();
+ // Upkeep the config file monitoring
+ Config.instance.upkeep();
return true;
}
diff --git a/src/utils/GlobalLog.java b/src/utils/GlobalLog.java
index e0652ba..e1c43aa 100644
--- a/src/utils/GlobalLog.java
+++ b/src/utils/GlobalLog.java
@@ -36,13 +36,14 @@ public class GlobalLog
System.out.println(logLine);
}
- public static void log(String msg) { write(log, LogFilter.Debug, msg); }
- public static void warn(String msg) { write(warn, LogFilter.Debug, msg); }
- public static void error(String msg) { write(error, LogFilter.Debug, msg); }
- public static void fatal(String msg) throws Exception { write(fatal, LogFilter.Debug, msg); throw new Exception(msg); }
-
public static void log(LogFilter filter, String msg) { write(log, filter, msg); }
public static void warn(LogFilter filter, String msg) { write(warn, filter, msg); }
- public static void error(LogFilter filter, String msg) { write(error, filter, msg); }
+ public static void error(LogFilter filter, String msg) { write(error, filter, msg); System.err.println(msg); System.err.flush(); }
public static void fatal(LogFilter filter, String msg) throws Exception { write(fatal, filter, msg); throw new Exception(msg); }
+
+ public static void log(String msg) { log(LogFilter.Debug, msg); }
+ public static void warn(String msg) { warn(LogFilter.Debug, msg); }
+ public static void error(String msg) { error(LogFilter.Debug, msg); }
+ public static void fatal(String msg) throws Exception { fatal(LogFilter.Debug, msg); }
+
}
diff --git a/src/utils/io/FileMonitor.java b/src/utils/io/FileMonitor.java
index f634e45..700d1c6 100644
--- a/src/utils/io/FileMonitor.java
+++ b/src/utils/io/FileMonitor.java
@@ -44,8 +44,11 @@ public class FileMonitor
if(last.longValue() != file.lastModified.longValue())
{
IOLog.log("Most recently modified at " + last + ", stored version at " + file.lastModified);
+
file = new MonitoredFile(file.path, last);
fileChanged.accept(file);
+
+ file = new MonitoredFile(file.path, FileUtils.lastModified(file.path));
}
}
}
diff --git a/src/utils/io/MonitoredFile.java b/src/utils/io/MonitoredFile.java
index 4ceb6c3..d4fb294 100644
--- a/src/utils/io/MonitoredFile.java
+++ b/src/utils/io/MonitoredFile.java
@@ -12,7 +12,7 @@ public class MonitoredFile implements Comparable